// Assets/_Project/Scripts/Gameplay/EnemyAbilities/GoldTheftAbilityDefinition.cs using UnityEngine; using TD.Core; namespace TD.Gameplay.EnemyAbilities { /// /// An enemy that reaches the defense point doesn't just cost a life — it robs the player whose /// maze it escaped. /// /// /// Charged to the origin zone, not the whole team. Lives are a shared pool, so a leak /// already punishes everyone equally; billing the gold to whoever let it through is the part /// that makes this card bite differently from "enemies cost 2 lives". It also keeps the blame /// legible — the player who leaked is the player who pays. /// /// Deducting more gold than a player has simply empties them; there is no debt. Going /// negative would silently disable building until they clawed back to zero, which reads as a /// broken HUD rather than a penalty. /// [CreateAssetMenu(fileName = "GoldTheftAbility", menuName = "TD/Enemy Abilities/Gold Theft")] public class GoldTheftAbilityDefinition : EnemyAbilityDefinition { public override EnemyAbilityKind Kind => EnemyAbilityKind.GoldTheft; [Header("Theft")] [Tooltip("Flat gold taken from the leaking player, on top of the normal life cost.")] [Min(0)] public int GoldStolen = 15; public override void ServerOnReachedGoal(EnemyAbility instance, PlayerSlot originZone) { if (GoldStolen <= 0 || originZone == PlayerSlot.None) return; var pms = PlayerMatchState.GetForSlot(originZone); if (pms == null) return; var gold = PlayerGoldManager.GetForClient(pms.OwnerClientId); if (gold == null) return; // Clamp to what they actually hold — a leak shouldn't be able to put a player in debt. int taken = Mathf.Min(GoldStolen, gold.CurrentGold); if (taken <= 0) return; gold.DeductGold(taken); // Surface it in-world on every peer so the loss isn't just a number quietly ticking // down in the corner. Routed through WaveManager because the popup has to reach // clients and a ScriptableObject has no NetworkBehaviour to send from. WaveManager.Instance?.ServerBroadcastGoldLoss(instance.transform.position, taken); } } }