diff --git a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset index b63d958..e713412 100644 --- a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset +++ b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset @@ -15,7 +15,7 @@ MonoBehaviour: DisplayName: Fireball Description: Shoot a fireball Icon: {fileID: 21300000, guid: eff45e5e3dab24f438c054a095d34578, type: 3} - Cooldown: 1 + Cooldown: 15 TargetType: 0 Radius: 5 enemyLayerMask: diff --git a/Assets/_Project/Definitions/EnemyAbilities.meta b/Assets/_Project/Definitions/EnemyAbilities.meta new file mode 100644 index 0000000..d927cf3 --- /dev/null +++ b/Assets/_Project/Definitions/EnemyAbilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 37cbc8b63ce7ae2e4b4abcfd7274bee7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Definitions/EnemyAbilities/SplitOnDeathAbility.asset b/Assets/_Project/Definitions/EnemyAbilities/SplitOnDeathAbility.asset new file mode 100644 index 0000000..6ca1f9e --- /dev/null +++ b/Assets/_Project/Definitions/EnemyAbilities/SplitOnDeathAbility.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 21543cb1b54f0b16e9c80584f68988b3, type: 3} + m_Name: SplitOnDeathAbility + m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.SplitOnDeathAbilityDefinition + DisplayName: Split on Death + Description: The enemy splits when it dies. + Weight: 100 + SplitInto: {fileID: 11400000, guid: a05af37e2256f164d80a66cc2a582466, type: 2} + SplitCount: 2 + ScatterRadius: 0.5 diff --git a/Assets/_Project/Definitions/EnemyAbilities/SplitOnDeathAbility.asset.meta b/Assets/_Project/Definitions/EnemyAbilities/SplitOnDeathAbility.asset.meta new file mode 100644 index 0000000..fae7041 --- /dev/null +++ b/Assets/_Project/Definitions/EnemyAbilities/SplitOnDeathAbility.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0305468bc8f912d429a8b20bf23f947c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab index 546fd71..cef9c0c 100644 --- a/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab +++ b/Assets/_Project/Prefabs/Enemies/Enemy_CrystalGolem_Blue.prefab @@ -17,6 +17,7 @@ GameObject: - component: {fileID: 3756613737869398948} - component: {fileID: 6036713598566100742} - component: {fileID: -1575784752119152190} + - component: {fileID: 154042129325690845} m_Layer: 10 m_Name: Enemy_CrystalGolem_Blue m_TagString: Untagged @@ -53,7 +54,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 2814637749 + GlobalObjectIdHash: 1115713368 InScenePlacedSourceGlobalObjectIdHash: 0 DeferredDespawnTick: 0 Ownership: 1 @@ -224,6 +225,19 @@ MonoBehaviour: volume: 0.75 minPitch: 0.95 maxPitch: 1.05 +--- !u!114 &154042129325690845 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455822126534880203} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9d1a26a32e8969cd29bce6010126a5f6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbility + ShowTopMostFoldoutHeaderGroup: 1 --- !u!1 &5361867751622119598 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity index 9a4d028..dd7bef0 100644 --- a/Assets/_Project/Scenes/Levels/9Player.unity +++ b/Assets/_Project/Scenes/Levels/9Player.unity @@ -2276,6 +2276,53 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &181002639 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 181002641} + - component: {fileID: 181002640} + m_Layer: 0 + m_Name: EnemyAbilityPool + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &181002640 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 181002639} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4409eb25a8be555de8dc3a73d4ed95db, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.EnemyAbilities.EnemyAbilityPool + abilities: + - {fileID: 11400000, guid: 0305468bc8f912d429a8b20bf23f947c, type: 2} + noAbilityWeight: 100 +--- !u!4 &181002641 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 181002639} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 15.94346, y: 0, z: 194.22044} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!43 &203092944 Mesh: m_ObjectHideFlags: 0 @@ -29189,3 +29236,4 @@ SceneRoots: - {fileID: 993870445} - {fileID: 759470735} - {fileID: 954434161} + - {fileID: 181002641} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs index cc9270e..30fe26c 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/EnemyAbilityPool.cs @@ -28,7 +28,7 @@ namespace TD.Gameplay.EnemyAbilities [Tooltip("Relative weight of an enemy rolling no ability at all, vs. the combined " + "weight of every entry in 'abilities'. Higher = abilities are rarer.")] [Min(0f)] - [SerializeField] private float noAbilityWeight = 20f; + [SerializeField] private float noAbilityWeight = 100f; // Fixed-size, enum-indexed lookup built once in Awake. Sized to the enum's entry count, // not authored count, so an out-of-range Kind is a compile-time impossibility rather diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs index 364e16b..687e676 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyAbilities/SplitOnDeathAbilityDefinition.cs @@ -28,12 +28,17 @@ namespace TD.Gameplay.EnemyAbilities public override void ServerOnDeath(EnemyAbility instance, EnemyHealth health) { + Debug.Log($"[SplitOnDeathAbility] ServerOnDeath fired for {instance.name}. " + + $"SplitInto={(SplitInto != null ? SplitInto.name : "null")}, " + + $"WaveManager.Instance={(WaveManager.Instance != null)}"); + if (SplitInto == null) return; var movement = instance.GetComponent(); var atTile = GridCoordinates.WorldToGrid(instance.transform.position); var ownerSlot = movement != null ? movement.OriginZone : PlayerSlot.None; + Debug.Log($"[SplitOnDeathAbility] Spawning {SplitCount}x {SplitInto.name} at tile {atTile}."); WaveManager.Instance?.ServerSpawnSplitEnemies(SplitInto, SplitCount, atTile, ownerSlot, ScatterRadius); } } diff --git a/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs b/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs index 34c7d79..93a577c 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyAbility.cs @@ -70,6 +70,9 @@ namespace TD.Gameplay kind.Value = (byte)(Definition != null ? Definition.Kind : EnemyAbilityKind.None); hasPendingInit = false; + if (Definition != null) + Debug.Log($"[EnemyAbility] {name} rolled {Definition.Kind}."); + Definition?.ServerOnSpawn(this); } diff --git a/Assets/_Project/Scripts/Gameplay/WaveManager.cs b/Assets/_Project/Scripts/Gameplay/WaveManager.cs index 67beb6c..c4af7e3 100644 --- a/Assets/_Project/Scripts/Gameplay/WaveManager.cs +++ b/Assets/_Project/Scripts/Gameplay/WaveManager.cs @@ -580,6 +580,8 @@ namespace TD.Gameplay // this kill's activeEnemyCount-- below, or a split on a wave's last enemy could let // CheckWaveComplete see activeEnemyCount hit 0 and advance the wave prematurely. var ability = health.GetComponent(); + Debug.Log($"[WaveManager] HandleEnemyKilled: ability={(ability != null)}, " + + $"definition={(ability != null ? ability.Definition?.name ?? "null" : "n/a")}"); ability?.Definition?.ServerOnDeath(ability, health); UnsubscribeEnemy(health);