Polishes
This commit is contained in:
@@ -56,8 +56,8 @@ namespace ProjectM.Server
|
||||
playerRegions.Add(region.ValueRO.Region);
|
||||
}
|
||||
|
||||
// EB-1 fortress aggro: also snapshot live structures (Turret/Wall/Pylon carry Health; automation
|
||||
// machines lack it so the query excludes them). Snapshot ABOVE the early-return so Husks keep razing
|
||||
// EB-1 fortress aggro: also snapshot live structures (Turret/Wall/Pylon AND the Fabricator all carry
|
||||
// Health since the DR-032 parity fix; the query keys on it). Snapshot ABOVE the early-return so Husks keep razing
|
||||
// the base even with every player dead/away (the locked 'push for structures' fork).
|
||||
var structureEntities = new NativeList<Entity>(Allocator.Temp);
|
||||
var structurePositions = new NativeList<float3>(Allocator.Temp);
|
||||
|
||||
@@ -45,7 +45,6 @@ namespace ProjectM.Server
|
||||
float3 center = haveAnchor ? BaseGridMath.PlotCenter(baseAnchor) : spawner.SpawnPoint;
|
||||
float ringRadius = haveSpawner ? spawner.SpawnRingRadius : 2f;
|
||||
int ringSlots = haveSpawner ? spawner.RingSlots : 4;
|
||||
center = BaseGridMath.PlotCenter(baseAnchor);
|
||||
|
||||
foreach (var (health, respawn, invuln, xform, region, owner, eff) in
|
||||
SystemAPI.Query<RefRW<Health>, RefRW<RespawnState>, RefRW<RespawnInvuln>, RefRW<LocalTransform>,
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace ProjectM.Server
|
||||
zs.SeededEpoch = run.RoomEpoch;
|
||||
zs.SpawnCounter = 0;
|
||||
zs.RemainingToSpawn = bossRoom ? 1 : ZoneEnemyMath.WaveSlots(plan.DifficultyEpoch, bands);
|
||||
zs.NextSpawnTick = TickUtil.NonZero(now); // first slot this tick
|
||||
zs.NextSpawnTick = TickUtil.NonZero(now + Tuning.RoomEntryGraceTicks); // landing grace — let the party orient
|
||||
}
|
||||
|
||||
if (zs.RemainingToSpawn > 0)
|
||||
|
||||
@@ -139,6 +139,16 @@ namespace ProjectM.Server
|
||||
bool due = info.LaunchTick == 0u || !new NetworkTick(info.LaunchTick).IsNewerThan(serverTick);
|
||||
if (due)
|
||||
{
|
||||
// Conscript the party: the launch roster is EVERYONE connected (N7 co-location — all at
|
||||
// base, all ready). Room advances teleport ONLY RunParticipants, so a mid-run late joiner
|
||||
// is never yanked into the fight; the tag is released on the Returning edge.
|
||||
var conscript = new EntityCommandBuffer(Allocator.Temp);
|
||||
foreach (var (_, playerE) in
|
||||
SystemAPI.Query<RefRO<PlayerReady>>().WithAll<PlayerTag>().WithEntityAccess())
|
||||
conscript.AddComponent<RunParticipant>(playerE);
|
||||
conscript.Playback(state.EntityManager);
|
||||
conscript.Dispose();
|
||||
|
||||
// Enter room 0 (the guaranteed Combat landing at column 0, sub-slot 0).
|
||||
var map = RunMapMath.Generate(run.RunSeed);
|
||||
EnterRoom(ref state, ref info, ref run, in map, layer: 0, col: 0, baseCenter, bumpEpoch: true);
|
||||
@@ -187,15 +197,24 @@ namespace ProjectM.Server
|
||||
|
||||
// Exit gate: every SURVIVING player has picked (BoonOffer.Pending==0 — inert until Step 10)
|
||||
// OR the grace elapsed (wrap-safe IsNewerThan, never raw uint — F4).
|
||||
// Only EXPEDITION players hold the gate (BoonOfferSystem's documented contract): a player who
|
||||
// died and respawned to base must not stall the party (post-impl review, confirmed major).
|
||||
bool anyPending = false;
|
||||
foreach (var offer in SystemAPI.Query<RefRO<BoonOffer>>().WithAll<PlayerTag>())
|
||||
if (offer.ValueRO.Pending != 0) { anyPending = true; break; }
|
||||
foreach (var (offer, pregion) in
|
||||
SystemAPI.Query<RefRO<BoonOffer>, RefRO<RegionTag>>().WithAll<PlayerTag>())
|
||||
if (pregion.ValueRO.Region == RegionId.Expedition && offer.ValueRO.Pending != 0)
|
||||
{ anyPending = true; break; }
|
||||
bool graceElapsed = run.RewardGraceTick == 0u
|
||||
|| !new NetworkTick(run.RewardGraceTick).IsNewerThan(serverTick);
|
||||
if (anyPending && !graceElapsed)
|
||||
break;
|
||||
|
||||
run.RewardGraceTick = 0u;
|
||||
// NO offer survives this gate: zero every straggler (a dead-respawned base player the
|
||||
// auto-pick deliberately skips, a grace-expired AFK) so a stale Pending can never wedge the
|
||||
// HUD modal open or stall a later reward gate (post-impl review, confirmed major).
|
||||
foreach (var offer in SystemAPI.Query<RefRW<BoonOffer>>().WithAll<PlayerTag>())
|
||||
offer.ValueRW = default;
|
||||
if (run.LastTerminalCleared != 0)
|
||||
{
|
||||
info.Lifecycle = RunLifecycle.Returning; // boss cleared — go home a winner
|
||||
@@ -279,18 +298,25 @@ namespace ProjectM.Server
|
||||
|
||||
case RunLifecycle.Returning:
|
||||
{
|
||||
// Party teleport HOME + region flip back to Base.
|
||||
// PARTICIPANT teleport home + region flip + roster release. Only the launch roster comes
|
||||
// home (a mid-run joiner already at base keeps its position); the tag removal re-opens the
|
||||
// next run's conscription cleanly (post-impl review, confirmed medium).
|
||||
int idx = 0;
|
||||
foreach (var (region, xform) in
|
||||
SystemAPI.Query<RefRW<RegionTag>, RefRW<LocalTransform>>().WithAll<PlayerTag>())
|
||||
var homebound = new EntityCommandBuffer(Allocator.Temp);
|
||||
foreach (var (region, xform, playerE) in
|
||||
SystemAPI.Query<RefRW<RegionTag>, RefRW<LocalTransform>>()
|
||||
.WithAll<PlayerTag, RunParticipant>().WithEntityAccess())
|
||||
{
|
||||
region.ValueRW.Region = RegionId.Base;
|
||||
var p = baseCenter;
|
||||
p.x += 1.5f * idx;
|
||||
p.y = xform.ValueRO.Position.y;
|
||||
xform.ValueRW.Position = p;
|
||||
homebound.RemoveComponent<RunParticipant>(playerE);
|
||||
idx++;
|
||||
}
|
||||
homebound.Playback(state.EntityManager);
|
||||
homebound.Dispose();
|
||||
|
||||
// THE terminal bank — once per RunEpoch (equality latch, F7), CLEAR-GATED (D-F3).
|
||||
if (run.LastBankedRunEpoch != run.RunEpoch)
|
||||
@@ -393,7 +419,7 @@ namespace ProjectM.Server
|
||||
float3 roomOrigin = RegionMath.ExpeditionRoomOrigin(baseCenter, run.ActiveSubSlot);
|
||||
int idx = 0;
|
||||
foreach (var (region, xform) in
|
||||
SystemAPI.Query<RefRW<RegionTag>, RefRW<LocalTransform>>().WithAll<PlayerTag>())
|
||||
SystemAPI.Query<RefRW<RegionTag>, RefRW<LocalTransform>>().WithAll<PlayerTag, RunParticipant>())
|
||||
{
|
||||
region.ValueRW.Region = RegionId.Expedition;
|
||||
var p = roomOrigin;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace ProjectM.Server
|
||||
/// hand-off is <see cref="ThreatState.PendingSiegeSize"/> (this system sets it; CyclePhaseSystem consumes it).
|
||||
/// This slice wires ONE source — POST-EXPEDITION retaliation: a completed RUN (banked on the boss-clear
|
||||
/// return by <see cref="RunDirectorSystem"/> into <see cref="ThreatState.PendingReturns"/> — the retired
|
||||
/// walk-in ExpeditionGateSystem's carry, Step 11) arms a siege ofe of
|
||||
/// walk-in ExpeditionGateSystem's carry, Step 11) arms a siege of
|
||||
/// <see cref="ThreatConfig.SizeBase"/> Husks after a <see cref="ThreatConfig.PostExpeditionDelayTicks"/>
|
||||
/// telegraph. The Heat/Schedule sources are reserved (config baked-but-inert) so they drop in additively with
|
||||
/// no re-bake. It also enforces a BOUNDED siege lifetime (<see cref="ThreatConfig.SiegeTimeoutTicks"/>): an
|
||||
|
||||
Reference in New Issue
Block a user