simpler enemy split

This commit is contained in:
Ian Woods 2026-07-28 22:34:25 -07:00
parent 11ad19992d
commit 0a70f36838
3 changed files with 43 additions and 22 deletions

View file

@ -457,7 +457,8 @@ namespace TD.Gameplay
private void SpawnEnemy(EnemyDefinition def, Vector2Int spawnerTile, PlayerSlot ownerSlot,
float xHalfExtent = 0f, float zHalfExtent = 0f, bool held = false,
Direction facing = Direction.South)
Direction facing = Direction.South, bool canRollAbility = true,
float hpMultiplier = 1f, float visualScale = 1f)
{
if (def.EnemyPrefab == null)
{
@ -491,6 +492,12 @@ namespace TD.Gameplay
spawnPos,
Quaternion.Euler(0f, yaw, 0f));
// Scales the whole prefab hierarchy uniformly (used for split-on-death minions).
// Relies on the enemy prefab's NetworkTransform syncing scale to clients — verify
// that's enabled if a scaled spawn doesn't look smaller on remote peers.
if (visualScale != 1f)
go.transform.localScale *= visualScale;
var health = go.GetComponent<EnemyHealth>();
var movement = go.GetComponent<EnemyMovement>();
@ -502,14 +509,16 @@ namespace TD.Gameplay
return;
}
health.InitializeServer(def.MaxHp, def.LivesCost, def.IsFlying, held);
health.InitializeServer(def.MaxHp * hpMultiplier, 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.
// canRollAbility is false for split-spawned minions (see ServerSpawnSplitEnemies) so
// they can never chain into further splits or pick up any other ability.
var ability = go.GetComponent<EnemyAbility>();
if (ability != null)
ability.InitializeServer(EnemyAbilityPool.Instance?.RollRandom());
ability.InitializeServer(canRollAbility ? EnemyAbilityPool.Instance?.RollRandom() : null);
if (held) heldEnemies.Add(health);
@ -530,12 +539,19 @@ namespace TD.Gameplay
/// position. Reuses <see cref="SpawnEnemy"/> so split children get the same
/// <c>activeEnemyCount</c>/event-wiring bookkeeping as any other spawn.
/// </summary>
/// <remarks>
/// Split-spawned minions never roll an ability of their own — they're always plain,
/// so a split can't chain into further splits (or any other ability) regardless of
/// which EnemyDefinition/prefab is used for <paramref name="def"/>.
/// </remarks>
public void ServerSpawnSplitEnemies(EnemyDefinition def, int count, Vector2Int atTile,
PlayerSlot ownerSlot, float scatterRadius)
PlayerSlot ownerSlot, float scatterRadius,
float hpMultiplier = 1f, float visualScale = 1f)
{
if (!IsServer) return;
for (int i = 0; i < count; i++)
SpawnEnemy(def, atTile, ownerSlot, scatterRadius, scatterRadius);
SpawnEnemy(def, atTile, ownerSlot, scatterRadius, scatterRadius, canRollAbility: false,
hpMultiplier: hpMultiplier, visualScale: visualScale);
}
// ----- Enemy event handlers (server-only) -------------------------
@ -580,8 +596,6 @@ 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<EnemyAbility>();
Debug.Log($"[WaveManager] HandleEnemyKilled: ability={(ability != null)}, " +
$"definition={(ability != null ? ability.Definition?.name ?? "null" : "n/a")}");
ability?.Definition?.ServerOnDeath(ability, health);
UnsubscribeEnemy(health);