Boss becomes a real fight + readable-but-fair enemy threat
BossState (server-only) + BossAISystem: sole mover, seek -> telegraphed radial slam (AttackWindup) -> phase-2 speed + swarmer summon. Excluded from the EnemyAISystem Charger pass; knockback-immune at all 3 stamp sites; arena-anchored spawn; scaled Health/HitRadius/AttackRange. Grunt windup now commits in its last ~30% (whiffs out-of-range); Charger stagger roots; grunt speed 4.2->5.2; swarmer telegraph synced. SweptMove + zone-enemy spawn-stamp extracted to shared helpers. Zero new [GhostField]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,11 +37,17 @@ namespace ProjectM.Simulation
|
||||
[BurstCompile]
|
||||
public partial struct AbilityFireSystem : ISystem
|
||||
{
|
||||
// C3/A4: knockback stamp for the Warrior CONE (guarded HasComponent + boss-immune). Server-only use.
|
||||
ComponentLookup<KnockbackState> m_KnockbackLookup;
|
||||
ComponentLookup<BossState> m_BossLookup;
|
||||
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<AbilityDatabase>();
|
||||
state.RequireForUpdate<NetworkTime>();
|
||||
m_KnockbackLookup = state.GetComponentLookup<KnockbackState>(isReadOnly: false);
|
||||
m_BossLookup = state.GetComponentLookup<BossState>(isReadOnly: true);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
@@ -63,6 +69,8 @@ namespace ProjectM.Simulation
|
||||
var abilityDb = SystemAPI.GetSingleton<AbilityDatabase>();
|
||||
|
||||
bool isServer = state.WorldUnmanaged.IsServer();
|
||||
m_KnockbackLookup.Update(ref state);
|
||||
m_BossLookup.Update(ref state);
|
||||
|
||||
// Server-only target set (LIVING enemies/dummies), collected once: positions feed the gamepad
|
||||
// auto-target assist, and entities+positions feed the Warrior CONE archetype's server-only cleave.
|
||||
@@ -132,6 +140,19 @@ namespace ProjectM.Simulation
|
||||
SourceNetworkId = owner.ValueRO.NetworkId,
|
||||
SourceTick = cStamp,
|
||||
});
|
||||
// C3: the cone reads as weak vs the melee cleave without knockback — stamp it like melee
|
||||
// (guarded: dummies lack KnockbackState → ECB throw; the boss is knockback-immune, A4).
|
||||
if (m_KnockbackLookup.HasComponent(coneTargets[ci]) && !m_BossLookup.HasComponent(coneTargets[ci]))
|
||||
{
|
||||
float3 kd3 = coneTargetPos[ci] - xform.ValueRO.Position;
|
||||
float2 kdir = math.lengthsq(kd3.xz) > 1e-6f ? math.normalize(kd3.xz) : cFace;
|
||||
m_KnockbackLookup[coneTargets[ci]] = new KnockbackState
|
||||
{
|
||||
Dir = kdir,
|
||||
Speed = Tuning.KnockbackSpeed,
|
||||
UntilTick = TickUtil.NonZero(serverTick.TickIndexForValidTick + (uint)math.max(1, Tuning.KnockbackDurationTicks)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
uint coneCd = (uint)math.max(1, eff.ValueRO.CooldownTicks);
|
||||
|
||||
Reference in New Issue
Block a user