Files
Project-M/Assets/_Project/Scripts/Simulation/Combat/ProjectileEffectState.cs
T
kronic 36950ca21d LANTERN P1 Group B: 5-Spark systems — Aoe/Hitscan dispatch + reel/zone/decoy
Aoe/Hitscan archetype dispatch in AbilityFireSystem (both-worlds cooldown;
server-only ecb.Instantiate — the client-never-instantiates invariant; ZoneEffect
vs DecoyTag chosen by prefab membership). Harpooner REEL as a homing state
(ReelState + ReelSystem re-aim the hit Husk's KnockbackState toward the caster's
live position each tick; EnemyAISystem stays sole Position writer), stamped by
ProjectileDamageSystem on a Reel-flag hit. ZonePulseSystem (enemy-only periodic
AoE, caster attribution, no friendly fire, Vortex pull, born-0 lazy-stamp).
Decoy aggro in EnemyAISystem + DecoySystem despawn. AbilityDefBlob gains
EffectFlags (Reel) + DurationTicks. +3 ZonePulseSystem EditMode tests (497 green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 00:00:41 -07:00

38 lines
2.1 KiB
C#

using Unity.Collections;
using Unity.Entities;
namespace ProjectM.Simulation
{
/// <summary>
/// Phase 1.7 per-projectile mechanic-changer state — SERVER-ONLY, NOT a <c>[GhostField]</c> (mirrors
/// <see cref="KnockbackState"/>): it adds no replicated surface, so the <see cref="Projectile"/> ghost hash
/// stays FROZEN (adding fields to the ghost <see cref="Projectile"/> component itself would change its
/// StableTypeHash → serializer hash → ghost re-bake; a separate server-only component does not). Baked inert
/// on the projectile prefab; seeded server-side at spawn (<c>AbilityFireSystem</c>) from the owner's
/// <see cref="BoonEffects"/>, and read only by <c>ProjectileDamageSystem</c> (also server-only) — the owner's
/// predicted projectile needs no local copy (pierce = server delays despawn → client reconciles via ghost
/// persistence; chain = server rewrites the replicated <see cref="Projectile.Direction"/>; pull just flips the
/// server-stamped <see cref="KnockbackState.Dir"/>).
/// </summary>
public struct ProjectileEffectState : IComponentData
{
/// <summary>Enemy hits remaining before the projectile despawns (0 = destroy on next hit).</summary>
public byte PierceRemaining;
/// <summary>Chain-to-next-target hops remaining after a hit.</summary>
public byte ChainRemaining;
/// <summary>bit0 = Pull (stamp knockback TOWARD the shooter instead of away).</summary>
public byte Flags;
/// <summary>Targets already hit by this projectile — excluded DURING target selection so a surviving
/// (pierced/chained) projectile never re-hits the same enemy across ticks. Overflow ⇒ destroy (natural cap).</summary>
public FixedList64Bytes<Entity> Hit;
}
/// <summary>Bit masks for <see cref="ProjectileEffectState.Flags"/>.</summary>
public static class ProjectileEffectFlag
{
/// <summary>bit1 = Reel (HookPull): stamp the homing <see cref="ReelState"/> toward the CASTER instead of a frozen knockback.</summary>
public const byte Reel = 2;
public const byte Pull = 1;
}
}