first pass at enemy upgrades

This commit is contained in:
Ian Woods 2026-07-28 20:59:43 -07:00
parent a26d0acbfb
commit 8714885efa
13 changed files with 351 additions and 0 deletions

View file

@ -5,6 +5,7 @@ using UnityEngine;
using TD.Core;
using TD.Gameplay.BuilderEffects;
using TD.Gameplay.Draft;
using TD.Gameplay.EnemyAbilities;
using TD.Levels;
using TD.UI;
@ -503,6 +504,13 @@ namespace TD.Gameplay
health.InitializeServer(def.MaxHp, def.LivesCost, def.IsFlying, held);
movement.InitializeServer(def.MoveSpeed, spawnerTile, ownerSlot, def.IsFlying);
// Optional — only prefabs with an EnemyAbility component roll an ability. See
// EnemyAbility's remarks for why on-death abilities aren't event-subscription driven.
var ability = go.GetComponent<EnemyAbility>();
if (ability != null)
ability.InitializeServer(EnemyAbilityPool.Instance?.RollRandom());
if (held) heldEnemies.Add(health);
health.OnDied += HandleEnemyKilled;
@ -514,6 +522,22 @@ namespace TD.Gameplay
go.GetComponent<NetworkObject>().Spawn();
}
/// <summary>
/// Server-only: spawns <paramref name="count"/> copies of <paramref name="def"/> at
/// <paramref name="atTile"/>, continuing that tile's A* path onward rather than
/// restarting from a wave spawner. Used by on-death abilities (e.g.
/// <c>SplitOnDeathAbilityDefinition</c>) to spawn smaller enemies from a corpse's
/// position. Reuses <see cref="SpawnEnemy"/> so split children get the same
/// <c>activeEnemyCount</c>/event-wiring bookkeeping as any other spawn.
/// </summary>
public void ServerSpawnSplitEnemies(EnemyDefinition def, int count, Vector2Int atTile,
PlayerSlot ownerSlot, float scatterRadius)
{
if (!IsServer) return;
for (int i = 0; i < count; i++)
SpawnEnemy(def, atTile, ownerSlot, scatterRadius, scatterRadius);
}
// ----- Enemy event handlers (server-only) -------------------------
private void HandleEnemyKilled(EnemyHealth health)
@ -551,6 +575,13 @@ namespace TD.Gameplay
if (totalReward > 0)
ShowGoldRewardClientRpc(health.transform.position, totalReward);
// Resolve any on-death ability BEFORE unsubscribing/decrementing. A split-spawn's
// activeEnemyCount++ (inside ServerSpawnSplitEnemies -> SpawnEnemy) must land before
// 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<EnemyAbility>();
ability?.Definition?.ServerOnDeath(ability, health);
UnsubscribeEnemy(health);
DecrementAndCheckComplete();
}