Commit Graph

46 Commits

Author SHA1 Message Date
kronic 24800f4bcb Attack Boon Changes 2026-07-13 18:30:41 -07:00
kronic 4febf3dfe2 Hazard: Blight geyser — permanent periodic both-sides AoE (Phase 1.5b bundle 3)
Review-first netcode slice (design review wf_900e9965-8f0 -> 11 folded;
post-impl wf_5c8299f8-299 clean). A PERMANENT periodic telegraphed AoE in
Blight-biome rooms only; one new [GhostField] uint NextEruptTick.

- Geyser component + GeyserEruptSystem (server): inverted invalid-tick guard
  (a baked-0 tick must NEVER erupt -> lazy-stamps born-correct instead of the
  party-wiping per-tick barrage), inline both-sides gather (SourceNetworkId=-1),
  reschedule = now + period (never +=), never destroyed.
- GeyserTelegraphSystem (client): absolute-tick growing warning disc +
  erupt burst on the >0->=<0 crossing, latched per NextEruptTick + arm-guard
  (never edge-detects the replicated field -> no phantom on 0->stamp /
  relevancy re-entry). Reuses ScorchDecalSystem + DynamicLightSystem.
- Seeded in RoomFieldSystem (Blight-gated on plan.Biome, born-correct staggered
  stamp from live ServerTick), GeyserFieldSpawner + authoring wired into the
  Gameplay subscene. Geyser.prefab duplicated from ResourceNode (no collider).
- BuildDisc promoted to FeedbackFx (shared with the barrel fuse ring).
- 474/474 EditMode incl. the unstamped-storm regression; live no-storm end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 13:53:48 -07:00
kronic bbf418e779 Hazard: destructible cover — carve-able rocks that genuinely block until broken
Phase 1.5 long-term #8, the LAST 1.5 item (design review wf_e14dd739-069:
both HIGHs + the distinct MEDs verified before the session limit ate the
duplicate verifiers; unverified leftovers reasoned-closed in the spec).

Cover = a BlightClutter ghost (Variant 4) with a baked Environment-layer
BoxCollider: the runtime ghost's collider joins BuildPhysicsWorld ->
blocks the player CC and the enemy sweep while alive, and the gap opens
the instant the entity dies. Both hit paths already break it (the
clutter chassis); 8 hits to carve.

Review folds:
- HIGH: the 07-07 anti-stuck nudge would phase enemies THROUGH cover
  after ~1.5s (it exists to prevent room soft-locks). The nudge is now
  COVER-AWARE: a SphereCast identifies the blocker; a live BlightClutter
  ghost suppresses the phase (no soft-lock possible - the blocker is
  destructible); static-geometry wedges still nudge.
- HIGH: yield==durability made tanky cover an economy faucet. Deposit
  is DECOUPLED from the decrement at both hit sites: ScrapPerHit=0 =
  breaks in Remaining hits, yields NOTHING; fractional POSITIVE yields
  still credit >=1 (the B1 immortal-sink test pinned this - zero means
  zero, positive floors to 1).
- MEDs: HitRadius 1.2 (visual core, not a shot-eating disc), NO cover
  in Boss rooms (no boss depenetration backstop), scatter keep-out >=7u
  from the room origin (player landing + portal), Variant=4 explicit
  (the clutter block's explosive reroll cannot leak).
- Old static layer removed: 8 WorldColliders_RoomCover colliders
  (subscene) + the RoomCover_Visuals root (Game.unity).

Verified live: 3 cover ghosts spawned with SOLID baked colliders;
BLOCK - NudgeUntilTick stayed 0 across 3.5s of forced zero-progress
(old code arms at 1.5s); DEPENETRATE - an enemy shoved inside a live
rock exited to 1.7u (backstop holds against ghost colliders); CARVE -
the rock died to the real sweep and the spot probed OPEN. 470/470
EditMode; console clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 16:15:38 -07:00
kronic 53bc21143d Feel: breakable clutter reads as Hades-style barrels, one-hit pop
The BlightClutter destructible-ghost chain (per-room seeding, unified
DR-018-safe sweep, melee + projectile breaking, personal-inventory
drops) already existed end-to-end - the roadmap item's gap was FEEL:

- Visual: prefab Model mesh swapped SM_Env_Rock_Chunk_01 (read as
  scenery) -> SM_Prop_Barrel_01 (FantasyKingdom, same proven atlas
  material). Base-pivot barrel offset -1 on the Model child (scatter
  y=1 is the capsule plane - the base-pivot float gotcha).
- One-hit pop: prefab Remaining 8 -> 2 (both hit paths decrement by
  max(1,(int)ScrapPerHit)=2, so one swing/shot shatters); authoring
  default kept in sync.
- Density: MaxClutterPerRoom 6 -> 8.

Verified live: 8 barrels seeded in a combat room, grounded (screenshot);
an injected projectile through the real ResourceHarvestSystem sweep
popped one barrel in ONE hit (8 -> 7) and credited 2 Biomass; 466/466
EditMode, console clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 22:14:43 -07:00
kronic 21a4c71413 Hygiene B4c: clean dedup helpers (knockback, bakers, editor rig)
- KnockbackUtil.Stamp: shared knockback-stamp used by AbilityFireSystem + MeleeComboSystem (guard + planar normalize + write; speed passed in).
- BakerStructureExt: AddPlacedStructure/AddDamageable extensions on Baker<T>; rewired Turret/Structure/Harvester/Conveyor/Fabricator bakers (baked data + serialized fields unchanged).
- EnemyPrefabBakeExt.AddEnemyPrefabPool: shared prefab-buffer bake for ZoneEnemyDirector/WaveDirector authoring (fields stay flat — no serialization change).
- Editor AnimRigUtil (HasParam + root-yaw overlay clip) shared by PlayerRigTools/EnemyRigTools; EnemyRigTools.MakeMat now GUID-preserving (CopySerialized over existing) — the composite AnimatorController copy left as-is with a caveat comment.

466/466 EditMode tests pass, 0 warnings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 21:26:23 -07:00
kronic 7460ab9d1c Docs: hygiene sweep — stale/misattributed doc-comments + CLAUDE.md example
- Repoint CLAUDE.md testing example from the deleted HeartbeatSystemTests to HealthApplyDamageSystemTests.
- Stale deleted-system refs: ResourceFieldSpawner/ClutterFieldSpawner(+Authoring) now cite RoomFieldSystem (was ExpeditionFieldSystem); BuildPlaceRequest drops the deleted RegionTransitRequest from its 'mirrors' list.
- Stale package version: 'Netcode 1.13.2' -> 'Netcode 1.x' in ProjectileClassificationSystem + BuildPlaceRequest.
- WorldCollisionComponents: remove the duplicated EnvironmentMask summary line; FeelConfig: fix the mangled 'is hitmap)' sentence.

Comment/doc only; compiles clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:54:44 -07:00
kronic ba303e5fd0 Hygiene B3: single-sourcing & magic-number consolidation
- StructureCatalogAuthoring: WallCostOre -> WallCostBiomass (it bakes a Biomass cost; [FormerlySerializedAs] preserves the scene value).
- Harvester/Fabricator authoring: resource-id byte defaults reference ResourceId.Ore/.Charge instead of magic 2/4.
- RegionMath.RegionBoundaryX (= ExpeditionOffsetX*0.5) single-sources the region-flip X used by HudSystem + OnboardingSystem (was 500f in 3 places).
- CharacterComponent.DefaultGroundedSharpness single-sources the CC sharpness 15f (GetDefault, DashSystem, PlayerDeathStateSystem, PlayerCharacterAuthoring).
- InventorySlot [InternalBufferCapacity] references Tuning.InventoryMaxSlots.
- ConnectionMode enum -> byte-const class (project convention; removes the latent enum-in-Burst trap); field + one Seed() param become byte.
- Tuning.ChargerWindupTicks single-sources the Charger telegraph windup (EnemyBaker + TuningConfig.Defaults; was a bare 30 that could drift).
- (TicksPerSecond deliberately NOT added: no seconds->ticks conversion site exists; the tick-count fields are per-authoring designer tunables, so a const would be unreferenced.)

451/451 EditMode tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:29:43 -07:00
kronic 589e712db3 Hygiene B2: dead-code removal
Delete (unreferenced in any scene, per operator decision):
- TrainingDummy* chain (authoring/spawner/system/components/prefab) + UpgradePickup* chain (authoring/spawner/systems/components/prefab); remove TrainingDummyTag from the 3 live combat queries (AbilityFire/Melee/HealthApplyDamage now key on EnemyTag) and repoint HealthApplyDamageSystemTests to EnemyTag.
- Dead RPC RegionTransitSystem + RegionTransitRequest (no sender, ungated) + its test.
- Heartbeat + HeartbeatSystem (no WorldSystemFilter, ran no-op every tick) + its test.
- BuildSendSystem dead conveyor/pylon dev hooks (s_ConveyorDir, [/] rotation, Place{Pylon,Harvester,Conveyor} statics).
- Deprecated CyclePhase alias consts (Expedition/Defend/Build/*Ticks); repoint WaveSystemTests to Siege/Calm.
- Unread FeelConfig fields (HitFlashDurationMs, RumbleHeavy) + dangling HudUi doc-comments + stale crefs.

451/451 EditMode tests pass. CLAUDE.md HeartbeatSystemTests example ref to be repointed in B7.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:16:53 -07:00
kronic b1041003f0 Hygiene B0-B1: correctness & latent traps
- 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>
2026-07-07 22:53:32 -07:00
kronic cc2e7ad95e Polishes 2026-07-07 20:51:18 -07:00
kronic ab657fa578 Onboarding + loop flow for a hands-off demo; GoalTarget 4->2
Lap-1 Fabricator affordable (StartingOre 50->90); mine prompt shows IN the room;
Return no longer false-completes on death (WasOnExpedition latch + soft timeout,
never the 1-tick Returning edge); HUD keeps room/siege/ammo cues during combat
steps; Welcome needs an explicit confirm; READY panel shows FINAL DEFENSE when
goal-full; dev Force-Each-Launch hidden from public Settings. GoalProgress.Target
4->2 (~10-20 min demo). Onboarding tests updated to the new contracts (456/456).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 20:21:42 -07:00
kronic 3995af736c 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>
2026-07-05 20:21:18 -07:00
kronic c6b7890212 Polishes 2026-07-04 16:57:40 -07:00
kronic 16e396841e Run Re-Do 2026-07-02 20:41:43 -07:00
kronic 09183cc139 Turrets: 40 Ore + per-base cap of 6 + fit-one-cell textured model (fix cheap/spam/massive/untextured)
Operator: turrets were "super duper cheap", spammable "unlimited", "spaced weirdly", "massive and not textured".
All four were real and independently rooted (placement grid was actually fine).

- Cost: TurretCostOre 10 -> 40 (authoring default + the serialized Gameplay subscene value, which overrides the
  code default). A node yields 30 Ore, so a turret is now ~1.3 nodes instead of 1/3 of one.
- Cap: new Tuning.TurretCap=6, enforced server-authoritatively in BuildPlaceSystem (count live Base turrets while
  building the occupancy set; reject placement at the cap, same-tick-safe). Was unlimited.
- Model: the 1.6x Synty ballista (~5m on a 1m cell, clipping neighbours) scaled to 0.8 to fit one cell; the C5
  BoxCollider shrunk to match (0.8x1.2x0.8, center y 0.6); all 6 sub-renderers swapped off the flat untextured
  teal Mat_StructureOwned_Cyan to the Synty atlas PolygonFantasyKingdom_Mat_01_A (textured). Play-verified
  TurretCost=40 Ore / cap=6 baked; no exceptions.

Also fixes 3 EditMode tests that pinned the old dash knobs (the prior tuning commit changed iframe 12->14 /
cooldown 45->36 but I committed it without re-running tests): DashSystemTests now derives the expected dash speed
from TuningConfig.Defaults() (robust to future tuning) + asserts now+14/+36; TuningConfigTests pins the new
defaults. 390/390 EditMode green.

Investigation: wf_c6c87dc5-9c3 (turret lane). Operator fork: 40 Ore + cap 6 (stricter).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:07:57 -07:00
kronic bd8458853b DR-042 Phase C (legibility, part 2): walls block enemies (C5) — restore the fortress fantasy
Player-built structures now physically block enemies (husks walked straight through walls before). Dedicated
"Structure" physics layer (slot 9) so the player passes its own walls while enemies are stopped:

- New WorldCollisionConfig.StructureMask, baked from the "Structure" layer in WorldCollisionAuthoring (mirrors
  EnvironmentMask). EnemyAISystem ORs it into the movement sweep filter (CollidesWith = envMask | structMask) —
  no new system, same 1-2 SphereCasts per enemy.
- Wall/Turret/Pylon prefabs get a cell-sized BoxCollider on the Structure layer (Wall's existing one relayered).
- Physics matrix: Default x Structure unchecked, so the kinematic player CC (Default) passes its own walls while
  the enemy's explicit cast still hits them. Despawn frees collision for free (collider dies with the entity).

Play-verified baked filters: StructMask=512; structure colliders BelongsTo=512, CollidesWith=0xFFFFFFFE
(includes Environment for the enemy cast, EXCLUDES bit 0 so the player passes). 389/389 EditMode, no exceptions.
Server-only/static colliders -> deterministic, no client divergence. SaveData stays v5.

Phase C complete (C5-C7). A visual fun-gate (husk stops at wall, player walks through) is the operator's eyes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 21:26:56 -07:00
kronic 419debad74 DR-042 Phase C (legibility, part 1): expedition objective HUD, Aether button, cold-start seed, Biomass sink, palette declutter
Scoping/design-gated (wf_7c5a555e-136). Fixes "the base reads as inert after Phase A":

- C7b objective readout: new replicated ExpeditionObjective{[GhostField] byte State, short Remaining} on the
  untagged CycleDirector ghost (cross-region safe). Sole writer ZoneEnemyDirectorSystem, written ABOVE its
  early-returns (snapshot-above-early-return) so the HUD never freezes stale. Play-verified it replicates
  server->client.
- C7a gate prompt + C7b HUD readout: HudSystem shows "GO TO THE EXPEDITION GATE" / "EXPEDITION IN PROGRESS - N
  remaining" / "CLEARED - return to claim", below the siege/overrun overrides.
- C6a Aether upgrade button: un-gated BuildSendSystem.UpgradeAbility (was #if UNITY_EDITOR); HudSystem adds a
  MenuUi.Button with live affordability tint (the only Aether sink was U-key only).
- C6c cold-start seed: CycleDirectorSpawnSystem seeds Tuning.StartingOre (50) into the ledger on a NEW game only
  (born-correct, pre-Playback), killing the silent turret-before-fabricator deadlock. Play-verified seededOre=50.
- C6b Biomass sink: Wall cost Ore->Biomass (the dead currency now has a home). Play-verified WallCostRes=Biomass.
- C6d palette declutter: hide dead Pylon/Harvester/Conveyor from the build palette + trimmed their dev hotkeys
  (catalog/prefabs stay baked, code-intact per DR-020).

389/389 EditMode + clean netcode Play smoke (ghost re-hash OK, no exceptions). SaveData stays v5.
C5 (walls block enemies) is the remaining Phase C item, sequenced separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 21:18:17 -07:00
kronic ed65770cc9 DR-042 Phase A: expedition-driven win — move win-driver off base-siege survival, kill the AFK path
Design-review-gated (wf_ebef4e81-dba, GREEN-WITH-CHANGES). The win-driver moves
from "survive N base sieges" to "clear N expeditions". The review overturned the
literal plan: credit on RETURN, not at the clear edge (clear-edge crediting arms
the undefended final base siege -> uncontestable terminal Loss).

- ExpeditionGateSystem: now the sole production writer of GoalProgress.Charge —
  a clamped +1 per cleared expedition folded into the existing once-per-epoch
  reward block, reusing the LastRewardedEpoch latch (Ore + Charge share fate) +
  a SaveRequest checkpoint. No new latch, no new GhostField, no ordering change.
- CyclePhaseSystem: deleted the survived-siege +1 (the AFK win path). Victory
  latch unchanged; GoalReached still arms the final base siege at cap.
- CycleDirectorAuthoring + CycleDirector.prefab: ScheduleEnabled baked OFF
  (retaliation-only). A serialized prefab bool ignores the C# field initializer,
  so the value is flipped in the prefab, not just the code default.
- Tests: re-pointed CyclePhaseSystemTests + EndgameWinLoseTests survived-siege
  assertions; extended ExpeditionGateRewardTests (+1, no-double-credit, clamp).
  389/389 EditMode green; clean netcode Play smoke (no sort-cycle, Schedule=0).

SaveData stays v5. Docs: DR-042 build record + forks resolved, CLAUDE.md
base-loop line, Backlog (A done).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 20:49:27 -07:00
kronic e32dadbc66 Slice Combat Depth (MC-3 + wiring + review fixes): Spitter aim-line + player-hit punch, rigged enemies, in-band gate (DR-041)
Completes the Combat Depth slice on top of the MC-2 server spine (56cf60cce):

MC-3 impact juice (client, observe-only):
- 7 FeelConfig fields + ResetDefaults; magnitude-scaled player-dealt-hit camera
  PunchFov on the enemy-Health-decrease edge (camera-only hit-stop, never timeScale).
- Spitter Kind==2 aim-LANE telegraph (BuildLaneMesh) — reads baked SpitterState
  client-side, falls back to a fixed length. True freeze + material flash deferred.

Content / wiring:
- SpitterProjectilePrefabAuthoring (the SpitterProjectilePrefab singleton).
- Both directors rebuilt to a 4-entry KIND-INDEXED roster [Grunt,Charger,Spitter,
  Swarmer] + mix/MaxAlive config + the SpitterProjectileConfig singleton in the subscene.
- Real rigged models: EnemySpitter (re-skinned Kaiju, ranged poker) + EnemySwarmerUndead
  (Undead-Werewolf, fast/low-HP); grunt/charger keep Werewolf/ChargerMuscle. EnemySpit =
  ownerless interpolated ghost (no Health, no collider).

Post-impl adversarial review fixes (wf_febdcfdb-665):
- [MED] in-band fire gate: the Spitter committed its telegraph from ANY range (fired while
  advancing from far). Now commits only when sInBand || sCornered (gives CorneredRange a
  real read site) — a Spitter out-of-band holds fire and repositions.
- [LOW] EnemyProjectileDamageSystem early-returns on !ServerTick.IsValid (sibling parity).
- [LOW] EnemyAuthoring bake-time guard: errors if a prefab composes both Charger+Spitter
  (would match zero AI passes -> never move).
- [LOW] tests: Spitter brain fires from Expedition (kills the Base==0 region false-green);
  a direct partition-exclusion test replaces the order-masked claim; added out-of-band +
  cornered negative tests.

388/388 EditMode green + two Play smokes (clean boot, fire, swept-hit, region, server==
client; rigged Kaiju spitter bakes + fires with zero console errors). Accepted as-is
(documented in DR-041): global spit soft-cap, co-op punch attribution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:08:59 -07:00
kronic 56cf60cce3 Slice Combat Depth (MC-2): enemy-variety server spine — Spitter, Swarmer, 4-type mix (DR-041)
Adds the server-authoritative mechanics for three new enemy archetypes on top of
the Grunt/Charger base, plus the weighted wave-composition that introduces them:

- Spitter: a ranged Husk variant (SpitterState) that holds a preferred range-band
  (advance/retreat/hold via EnemyAIMath.BandVelocity) and fires a telegraphed,
  dodgeable EnemyProjectile. New server EnemyProjectileMoveSystem (integrate +
  store LastStep) + EnemyProjectileDamageSystem (region-filtered swept hit-test
  rebuilt from LastStep — DR-018 anti-tunnelling; players use HitRadius, structures
  a const radius; at-most-once destroy). Concurrent-spit soft cap, soft-fail retry.
- Swarmer: marker tag + deterministic cluster spawn (1 slot = 1 pack;
  EnemyAIMath.ClusterOffset), MaxAlive counts ENTITIES so a pack defers if it
  won't fit.
- 4-type weighted mix: MixBands -> ZoneEnemyMath.WaveSlots/KindForSlot/
  PackSizeForSlot drives both the expedition director and (fork-4a) the base siege,
  with a mandatory MaxAlive cap. Legacy WaveSize/IsChargerSlot kept + parity-tested.
- Discriminator stays component-presence (no enum in Bursted systems): query-
  partition guards keep each enemy moved by exactly one EnemyAISystem pass
  (sole-Position-writer). EnemyTelegraph.IsCharger -> Kind byte for the client cue.

New authoring (Spitter/Swarmer/EnemyProjectile) + expanded director authorings with
tunable mix/cluster defaults. 13 new EditMode tests (mix composition + legacy parity,
band/cluster math, projectile move + cross-region + swept anti-tunnelling regressions);
full suite green before commit.

Dormant until the prefab/subscene wiring lands (next): the new systems guard on
TryGetSingleton/RequireForUpdate, so with no prefabs wired the new types stay inert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:06:56 -07:00
kronic 3109b86d71 Slice 3: Expedition Combat Spine — epoch-seeded zone waves (DR-040)
Reactivate the dormant Expedition region as a procedural combat venue.
v1 loop: walk the gate -> fight an epoch-seeded enemy wave in the
expedition -> clear -> return -> flat Ore reward (once per epoch) ->
escalated retaliation base siege.

- New sim types: ZoneEnemyTag, ZoneEnemyDirector (+ ZoneEnemyPrefab
  buffer), ZoneEnemyState, ZoneEnemyMath (grunt->charger composition
  by epoch). ZoneEnemyDirectorSystem (server, Burst): drip-spawns the
  wave at a deterministic ring under a MaxAlive cap while a player is
  out and the base is Calm; marks ClearedThisEpoch on a real clear.
  [UpdateAfter(ExpeditionFieldSystem)] only (avoids a sort cycle).
- BLOCKER 1: EnemyAISystem region-filters target selection (player +
  structure snapshots gain parallel region lists; no base structures /
  no Core fallback for expedition husks).
- BLOCKER 3: WaveSystem, ThreatDirectorSystem timeout cull, and
  CyclePhaseSystem DefendCleared + Core-breach cull all count/cull
  RegionTag{Base} husks only (the breach cull was caught region-blind
  by the post-impl review: a base breach wiped the live expedition
  wave and spuriously paid the reward).
- BLOCKER 4: reward de-duped via CycleRuntime.LastRewardedEpoch +
  ClearedThisEpoch; ExpeditionGateSystem deposits RewardOre once/epoch.
- ExpeditionFieldSystem teardown also culls zone enemies + region-
  guards the clutter loop. Subscene wired with the director + roster.

368/368 EditMode green + clean netcode Play smoke. Docs: DR-040 ->
built, session log, CLAUDE.md cross-region tag-reaudit rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 22:58:26 -07:00
kronic f3eccec524 Slice 1: combat readability + HUD declutter (DR-038)
Four playtest do-now wins:
- Enemy health bars: pooled world-space Canvas, on-damage-sticky + fade,
  always-on <25% HP (CombatFeedbackSystem; no new replication).
- Telegraph fix: new baked client-safe EnemyTelegraph sizes the danger-cone ramp
  per enemy (0->1 ending at impact, fixes the Charger plateau); windup 18->22;
  a windup scale-pulse.
- Build-mode toggle: BuildPaletteState.PaletteOpen hides the palette by default,
  Tab / gamepad-Y toggles, with a discovery chip (HudSystem/BuildSendSystem).
- Charger committed-lunge tell: [GhostEnabledBit] IsLunging derived once/tick from
  LungeState (the Dead idiom); the danger cone persists through the lunge.

345/345 EditMode (+3 IsLunging derive tests); Play-validated: ghost-hash change
did not break the handshake, bake correct (telegraph on all enemies, IsLunging
baked-disabled on the Charger, replicated to client), no runtime errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 12:48:08 -07:00
kronic 4f0b4e8087 END-2: final siege + latching win/lose (SL-3)
At GoalProgress.Charge>=Target a new server-only GoalReachedSystem arms a larger final siege (x live FinalSiegeMultiplier) and flips RunPhase=FinalDefense; CyclePhaseSystem latches a REPLICATED RunOutcome (Victory on clear / Loss on Core breach) and halts the director. RunOutcome is a [GhostField] byte on the global CycleDirector ghost (the client banner observes it); RunPhase stays server-only. ThreatDirector/CoreRestore/CoreDamage halt once decided; SiegeTimeout is off during the final siege. SaveData v5 persists the outcome so a won/lost run loads finished. GoalProgress.Target 10->4. Completes Path A's spine. See DR-036.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:38:21 -07:00
kronic 60e1e21dd3 END-1: the base can be lost - a losable Engine Core with integrity
Adds CoreIntegrity{[GhostField] Current,Max,OverrunTick} on the GLOBAL
CycleDirector ghost (no new ghost/relevancy). CoreDamageSystem (server,
after EnemyAISystem): a Husk within ~3u of PlotCenter drains + is consumed;
CoreRestoreSystem regenerates only in Calm. The SOFT-loss edge lives inside
CyclePhaseSystem (sole Phase writer): Current<=0 in Siege flips to Calm with
NO goal reward, StorageMath.DrainFraction drains the shared ledger, all Husks
despawn, and OverrunTick is stamped (a transient HUD-flash pulse, not a
latching outcome - the Victory latch is END-2's). EnemyAISystem treats the
Core as a FALLBACK target so an undefended base is overrun instead of idling.
SaveData -> v4 persists CoreCurrent (0 -> born full, the EB-1 HP sentinel);
3 live TuningConfig knobs + a red HUD Core bar. Soft-loss + targeting +
breach-resolution forks operator-locked.

See DR-034.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 21:51:43 -07:00
kronic 2da29783fd EB-2: felt spend - turrets burn a shared Charge pool, ledger-fed Fabricator mints it from Ore
Mined Ore now has an ongoing sink: a ledger-fed Fabricator converts Ore->Charge
(1 Ore -> 3 Charge / 30t) and turrets spend Charge per shot, soft-failing (no
shot, no cooldown burn) when the shared pool runs dry.

- ResourceId.Charge=4 rides the existing [GhostField] StorageEntry ledger (no new wire).
- TurretFireSystem: single ledger resolve + atomic spend / soft-fail / partial-refund.
- Fabricator.InputFromLedger (byte, server-only) feeds input from the shared ledger,
  read live in-loop so two machines split a finite pool; both modes deposit to ledger.
- HudSystem: violet Charge chip + global quiet-turret cue when siege && Charge==0.
- StorageMath.TotalOf backs the affordability read; catalog re-enables the Fabricator (4 entries).

See DR-033.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:14:52 -07:00
kronic 73cfe2943d EB-1: machines can die - structures get HP, Husks raze them, wounded base persists
Structures (Turret/Wall/Pylon) reuse the combat spine: authoring bakes Health(GhostField)+DamageEvent buffer+a Destructible tag (no HitRadius -> no friendly projectile fire; no EffectiveCharacterStats -> clamp-to-0). HealthApplyDamageSystem destroys a Destructible at 0 (occupancy auto-frees). EnemyAISystem fortress-targets the weighted-nearest of players+structures via the shared EnemyAIMath.PickWeightedNearest (StructureAggroWeight TuningConfig knob, <1 prefers structures, squared factor; snapshot above the early-return so an undefended base is razed). Persistence v3: per-structure HP threaded through 5 sites (SaveData/PendingStructure/scan-guarded/BaseRestore same-ECB born-correct/WorldLauncher via SaveApply.ToPending); SaveService floor-gate [2,3] loads old saves. Loss feedback: proximity-gated StructureFeedbackSystem; CombatFeedbackSystem suppressed for structures. Pre-code review caught the DamageEvent-buffer crash blocker + 8 majors; post-code review clean. See DR-032.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 23:53:34 -07:00
kronic e1ed08a803 Economy: base-local mining loop (mine at base, any attack harvests, scheduled sieges)
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>
2026-06-11 14:59:51 -07:00
kronic 0948d49886 Combat: ability archetype byte (MC-6 dispatch spike)
byte Archetype on AbilityDefBlob (AbilityArchetype enum: Projectile/Hitscan/Cone/Aoe), authored on AbilityDefinition + baked in AbilityDatabaseAuthoring, read at dispatch in AbilityFireSystem -- NOT folded through EffectiveAbilityStats/StatRecomputeSystem (static identity, not a tunable stat; MC-4 review BURST-1). All current abilities are Projectile (0) -> zero behaviour change; the dispatch read-point is the de-risk spike for MC-6 hitscan/cone/aoe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:45:33 -07:00
kronic 3409c53148 Combat: MC-4 combo-chain melee as the primary verb (DR-030)
Melee combo (left-click / pad-West) becomes the player's primary verb; the ranged projectile is demoted to right-click / pad-left-trigger. Predicted, owner-replicated combo Step (path-dependent -> [GhostField] anchor + absolute-write idempotency, NOT derived like the dash), server-only cleave mirroring ProjectileDamageSystem (SourceTick-stamped DamageEvent + KnockbackState), dash-cancellable movement-commit, 9 live TuningConfig knobs, and swing juice scaling with the combo step. The MC-6 archetype byte is deferred (the melee is its own verb). See DR-030.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:22:57 -07:00
kronic da522efe7a Vault Re-Alignment 2026-06-09 23:26:20 -07:00
kronic 43f355c06b Equipment: weapon-granted abilities + gear mods (DR-027 Phase 1)
Equipment slots reusing the AbilityRef/StatModifier machinery: EquipmentSlot [GhostField] buffer (index=slot), server-only event-driven EquipSystem (RPC). Weapon -> AbilityRef.Id swaps the attack (prefab + base stats, prediction-correct); gear -> StatModifiers tagged a reserved per-slot EquipSourceId, stripped target-agnostically via RemoveBySourceId. Item mods are INLINE on ItemDefBlob (a nested BlobArray reads empty under the by-value TryGetItem copy). Atomic equip-over swap (no item loss); DefaultAbility restores the unarmed ability on weapon-unequip. Client keys + build-safe hooks; HUD equipment panel + click-to-equip. 4 catalog weapon/gear items wired + re-baked.

Play-validated host+client: weapon equip swaps AbilityRef on both worlds, gear folds into EffectiveCharacterStats, unequip reverses + restores DefaultAbility, all replicated to the owner. See DR-027.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:09:25 -07:00
kronic 599b9b4255 Inventory: per-player items backbone (DR-026 Phase 0)
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>
2026-06-08 09:43:31 -07:00
kronic 1ed2aa46c5 HUD and Height Changes 2026-06-07 22:29:25 -07:00
kronic f3f65bccbf M7 Automation: deterministic Harvester to Conveyor to Fabricator chains
Server-only production chains (never predicted): components + server systems + pure byte-only math (ProductionMath/ConveyorMath/MachineSlotMath), authoring + 3 machine prefabs wired into the Gameplay subscene, StructureCatalog rows, BuildPlace Direction/RuntimePlacedTag, Tuning, and 35 EditMode tests (catch-up gating, conveyor shuffle-invariance, SaveData v2 round-trip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:05:15 -07:00
kronic 15bc1022ee Map Updates 2026-06-04 21:49:03 -07:00
kronic 16b01bec38 Game Scene Split up 2026-06-04 13:45:46 -07:00
kronic 51401d2c2b Further Tests & Progress 2026-06-04 11:35:57 -07:00
kronic 5c11ff4fad Continued 2026-06-04 00:06:18 -07:00
kronic 8e9b4412ce Core Game Loop Additions 2026-06-03 22:41:27 -07:00
kronic e362aaeb43 Import art/VFX asset packs + game-feel systems; normalize texture extensions to lowercase for LFS
Add BefourStudios SciFi environment packs, Gabriel Aguiar VFX, and the
ShaderCrew Toon Shader embedded packages, plus combat/enemy/wave/death
gameplay systems and supporting vault docs/screenshots.

Rename 11 vendor textures from uppercase .PNG/.HDR to lowercase so the
case-sensitive Git LFS filters (*.png/*.hdr) match on case-sensitive
filesystems (Linux CI, case-sensitive macOS), not just locally where
core.ignorecase=true masks the gap. Each .meta moved with its asset so
GUID references are preserved. All ~1000 binaries tracked via LFS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:50:43 -07:00
kronic dd0064c377 Init Homebase 2026-06-02 18:28:23 -07:00
kronic 2ee30c01fd CC Package and Physics 2026-06-02 08:56:26 -07:00
Luis Gonzalez e851d5f8e9 Co-Op Layer 2026-06-01 10:48:18 -07:00
Luis Gonzalez 1f647dd5e1 Initial Combat Implementation 2026-05-31 21:35:12 -07:00
Luis Gonzalez 7fa77ce821 Netcode Bootstrap 2026-05-31 14:27:52 -07:00
Luis Gonzalez 99d8d2d2a9 Set up DOTS + Netcode for Entities foundation
One-time stack setup per Docs/dots-setup-task.md (Unity 6.4.7 / 6000.4.7f1).
Packages: entities 6.4.0, entities.graphics 6.4.0, netcode 1.13.2, physics 1.4.6.

- Assets/_Project asmdef split: ProjectM.Simulation/Client/Server/Authoring (root ns ProjectM)
- GameBootstrap : ClientServerBootstrap; verified separate client + server worlds in Play Mode
- Gameplay subscene wired into SampleScene as a baking target
- Heartbeat component + Burst ISystem; EditMode smoke test green (1/1)
- In-repo Obsidian vault (Docs/Vault) incl. DR-001 (plain-Entities test over internal NetCodeTestWorld)
- Portable .mcp.json (basic-memory + serena via ${CLAUDE_PROJECT_DIR}); CLAUDE.md conventions
- .gitignore for DOTS baking cache + machine-local config

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 22:06:44 -07:00