// Assets/_Project/Scripts/Gameplay/EnemyUpgrades/AbilityEnemyUpgradeOption.cs
using UnityEngine;
using TD.Gameplay.EnemyAbilities;
using TD.Gameplay.Waves;
namespace TD.Gameplay.EnemyUpgrades
{
///
/// The workhorse enemy-buff card: grants an to a wave
/// slot. Every enemy spawned by that wave, in every later cycle of the phase, carries the
/// ability.
///
///
/// There is nothing to do at vote-resolution time — recording the option id on the slot IS the
/// effect, because the spawn path builds each enemy's ability set from the slot's recorded
/// options. is what that lookup resolves to.
///
[CreateAssetMenu(fileName = "EnemyUpgrade_Ability",
menuName = "TD/Enemy Upgrades/Ability Card", order = 20)]
public class AbilityEnemyUpgradeOption : EnemyUpgradeOption
{
[Header("Payload")]
[Tooltip("The ability every enemy in this wave gains. Must also be present in the scene's " +
"EnemyAbilityPool so it can be resolved at spawn time.")]
public EnemyAbilityDefinition Ability;
public override bool IsValidForSlot(RunState run, int slot)
{
if (Ability == null) return false;
// Don't offer an ability the slot already has by another card's hand. Exact-id repeats
// are filtered by the caller, but two different cards can grant the same ability, and
// stacking one twice is a no-op the players would rightly feel cheated by.
return !SlotAlreadyHasAbility(run, slot);
}
// Shared scratch: validation runs on the server during vote generation, which is
// single-threaded, so one reused list beats allocating per candidate per slot.
private static readonly System.Collections.Generic.List s_idScratch
= new System.Collections.Generic.List();
private bool SlotAlreadyHasAbility(RunState run, int slot)
{
var pool = EnemyUpgradePool.Instance;
if (run == null || pool == null) return false;
var ids = s_idScratch;
run.GetUpgradesForSlot(slot, ids);
foreach (int id in ids)
{
if (pool.Get(id) is AbilityEnemyUpgradeOption other && other.Ability == Ability)
return true;
}
return false;
}
/// Inherits nothing automatically — carries no
/// icon, so the card's own is the only source.
public override Sprite ResolveIcon() => Icon;
}
}