Phase 1.5 environmental hazard v1 (design-review wf_2cb10454-fdf: 13
findings confirmed + folded; Build Spec in the vault). ~25% of room
clutter seeds as EXPLOSIVE (Variant 3 on the existing replicated byte
- zero new GhostFields/prefabs/RPCs).
The FUSE is the review's fold - one mechanism closes both HIGHs:
- Pop sites (projectile sweep + isServer-gated melee harvest) do NOT
destroy an explosive: they zero the replicated Remaining + add a
server-only BarrelFuse (~36 ticks). The client sees Remaining=0 on a
still-alive barrel across snapshots -> unambiguous fuse cue, and
booms at despawn ONLY when cached Remaining<=0 - a teardown despawn
carries Remaining>0, so portal-advance teardowns can never fire
false booms (HIGH #1).
- HazardExplosionSystem (server, plain group, presence-gated on
BarrelFuse, never lifecycle-gated) detonates at ExplodeTick: radius
damage to LIVING enemies AND players (boss-slam player filter
verbatim; friendly fire = the bait mechanic), SourceTick stamped at
detonation = the authoring moment (HIGH #2: the authored-tick
contract dash i-frames negate against), SourceNetworkId=-1 (the
environment convention - a player id would consume Charger
whiff-punish windows). Fuse rides the RoomTag'd barrel -> teardown
cleans lit barrels free.
- Lit barrels are unhittable at both snapshot sites (no double-pop).
- Client: WorldFeedback caches Variant -> boom-vs-puff split (big
burst + light flash + boom SFX vs the old puff); DynamicLightSystem
gives Variant-3 barrels a red danger glow that STROBES once fused.
Verified: 470/470 EditMode (4 new: fused pop instead of destroy +
unhittable, both-sides damage w/ -1 source + authored tick, dead-player
+ radius filters, unelapsed-fuse inert); live smoke - seeded 3/8
explosive, real-sweep pop, CLIENT observed the fuse cue on the live
ghost, pinned bait enemy took exactly 26 (30->4), walk-out escape
confirmed; console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Restore swallowed [Test] on EnemyAIMathTests.SlideVelocity_DegenerateNormal_DeflectsToTangent (dead regression guard for the shipped enemy-stuck-on-cover fix; now runs + passes).
- Extract shared HarvestMath.DepositYield used by ResourceHarvestSystem + MeleeComboSystem; fixes melee mining silently ignoring per-item StackMax (it hard-coded DefaultStackMax) and hoists the melee ledger-buffer fetch out of the per-target loop.
- StatMath.Apply switches on the raw byte (case (byte)ModOp.X) instead of casting to the enum inside the Bursted fold — removes the latent cross-assembly enum-in-Burst ICE trap.
- Add [Min] guards on CycleDirectorAuthoring loss-critical ints (CoreIntegrityMax>=1 so a mis-authored 0 can't bake an instant-loss core; siege sizes >=0).
456/456 EditMode tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consolidate the divorced combat + economy halves into one base-local loop. BaseFieldSpawnSystem tops up RegionTag{Base} Ore nodes around the plot; harvest routes Base->shared ledger and Expedition/untagged->personal inventory for BOTH the projectile (ResourceHarvestSystem) and melee (MeleeComboSystem server-only block, writes Remaining back for VFX). Activate the reserved Schedule source in ThreatDirectorSystem so base sieges arm WITHOUT an expedition trip (the loop-closer: previously zero waves ever attacked a base-only player). Region-filter the ExpeditionFieldSystem teardown so it no longer wipes the permanent base field. HudSystem shows phase-aware loop copy. See DR-031.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Data-driven ItemDatabase catalog + per-player replicated InventorySlot ([GhostField] OwnerSendType.All, a StatModifier twin). Harvest reroutes to the firing player's personal inventory (optional ComponentLookup<GhostOwner> in ResourceHarvestSystem; remainder/un-owned -> ledger); the G-key InventoryDepositRequest RPC moves the bag into the shared ledger the build economy spends. Catalog asset (Aether/Ore/Biomass + Stone Pickaxe) wired into the Gameplay subscene; read-only HUD inventory panel. ushort ItemId subsumes ResourceId; byte Category/Tier baked for gear-tier progression. Session-only (no SaveData bump).
Play-validated host+client: catalog baked into both worlds, the re-baked player ghost carries InventorySlot with a clean handshake, a server write replicates to the client owner, the deposit RPC round-trips, and the HUD renders catalog names. See DR-026.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>