using Unity.Entities; namespace ProjectM.Simulation { /// /// SERVER-ONLY periodic-AoE state on a player-cast zone ghost (Vortex / LightZone) — the LANTERN Aoe/zone /// archetype. NOT a [GhostField]: the zone is a server-spawned INTERPOLATED ownerless ghost whose /// position replicates via the stock LocalTransform variant; only its damage schedule lives here, server-side. /// ZonePulseSystem borrows the GeyserEruptSystem skeleton (the INVERTED invalid-tick guard so a /// born-0 tick never storm-fires + the = now + period reschedule) but is ENEMY-ONLY (no friendly fire), /// stamps = (kills credit the caster, /// feeding KillRewardSystem — NOT the -1 environment convention), and has NO region gate (a no-world gym). /// DestroyEntity when elapses. /// public struct ZoneEffect : IComponentData { /// NetworkId of the casting player (damage/kill attribution). public int CasterNetworkId; /// Planar (XZ) damage radius, world units. public float Radius; /// Damage dealt to each living enemy in radius per pulse. public float DamagePerPulse; /// Raw next-pulse tick (NonZero). 0 = unscheduled → lazy-stamped born-correct (GeyserErupt H2 rule, never storm-fires). public uint NextTick; /// Raw tick the zone despawns (NonZero). Active while .IsNewerThan(serverTick). public uint ExpireTick; /// See . bit0 = Vortex (also pull enemies toward the zone center each pulse). public byte Flags; } /// Bit masks for . public static class ZoneEffectFlag { public const byte Vortex = 1; } /// /// SERVER-ONLY decoy-wisp state (the Aoe/spawn Spark) — a server-spawned INTERPOLATED ownerless ghost that /// draws Husk aggro. EnemyAISystem gathers DecoyTag entities into its target set so Husks path to and /// strike the decoy (soaking hits via its Health/DamageEvent buffer); it despawns on Health <= 0 or /// when elapses (both handled where EnemyAISystem already iterates decoys). Position /// replicates via the stock LocalTransform variant — NOT a [GhostField]. /// public struct DecoyTag : IComponentData { /// Raw tick the decoy despawns (NonZero). 0 = no timeout; active while .IsNewerThan(serverTick). public uint ExpireTick; } }