// Assets/_Project/Scripts/Gameplay/WaveDefinition.cs using System; using UnityEngine; namespace TD.Gameplay { /// /// A single spawn group within a wave: one enemy type and how many of them. /// [Serializable] public struct WaveEntry { [Tooltip("The enemy type to spawn for this group.")] public EnemyDefinition EnemyType; [Tooltip("How many enemies of this type to spawn.")] public int Count; } /// /// Defines the composition of a single wave. One asset per wave; referenced in /// order by . /// /// /// Entries are processed in array order. Multiple entries let designers mix enemy /// types within one wave (e.g. 10 fast scouts followed by 3 armoured brutes). /// All enemies spawn held at wave start; they are released in 10% chunks separated /// by seconds. The wave is not complete until all /// enemies are dead or have leaked. /// [CreateAssetMenu(fileName = "WaveDefinition", menuName = "TD/Wave Definition", order = 4)] public class WaveDefinition : ScriptableObject { [Tooltip("Seconds between the wave-number advancing (start of prep) and the " + "first enemies becoming visible. Gives players time to build before the horde appears.")] public float PrepTime = 10f; [Tooltip("Seconds between each chunk release. All enemies spawn held at wave " + "start and are released 10% at a time on this interval.")] public float ReleaseInterval = 2f; [Tooltip("Enemy groups that make up this wave. Processed in order.")] public WaveEntry[] Entries; /// /// The enemy type this wave is "about" — the first assigned entry's type. Null if the /// wave has no usable entries. /// /// /// The 2.0 design gives each wave a single enemy type, and enemy upgrades are keyed to a /// wave slot, so this is the identity the phase draw uses to keep slots distinct and the /// HUD uses to label an upcoming wave. still supports multiple /// groups (useful for staggering counts of the same type), but mixing types within /// one wave makes this ambiguous — see . /// public EnemyDefinition PrimaryEnemyType { get { if (Entries == null) return null; foreach (var e in Entries) { if (e.EnemyType != null && e.Count > 0) return e.EnemyType; } return null; } } /// /// True if every usable entry in this wave spawns the same enemy type. False means /// is only telling part of the story — the run validator /// warns on these rather than rejecting them, since a mixed wave still plays fine, it /// just labels and upgrades oddly. /// public bool HasSingleEnemyType { get { var first = PrimaryEnemyType; if (first == null) return false; foreach (var e in Entries) { if (e.EnemyType != null && e.Count > 0 && e.EnemyType != first) return false; } return true; } } /// Total enemies spawned per zone by this wave, across all entries. public int TotalEnemyCount { get { if (Entries == null) return 0; int total = 0; foreach (var e in Entries) { if (e.EnemyType != null && e.Count > 0) total += e.Count; } return total; } } } }