Commit Graph

114 Commits

Author SHA1 Message Date
kronic ca38c2b16d Melee clarity: the swing-arc now SWEEPS across + ramps per combo step (reads as a directional escalating cleave)
Operator: "the melee ability needs visual clarity, on what it does." The cleave is instant (kept — operator chose
instant + VFX), and the arc already matched the exact cone range/half-angle — but it popped whole then faded
(read as a flash) and all 3 combo steps looked byte-identical.

Client-only, observe-only (PresentationSystemGroup), no sim/netcode change, rollback-safe by construction:
- SWEEP: BuildSlashMesh takes a reveal fraction + sweep sign; UpdateSlash rebuilds the crescent each frame so the
  blade wipes across the arc over the first ~60% of life, then holds + fades. Leading edge is brightest. Sweep
  direction alternates per combo step -> reads as alternating strikes.
- PER-STEP RAMP: TriggerSlash takes step + comboLen; tint/brightness/life ramp per link so the chain visibly
  builds to the warm-HDR finisher (steps were indistinguishable before). Facing is already snapped at the swing
  edge.

Compiles clean, no runtime exceptions (per-frame 33-vert rebuild is negligible). The on-screen feel is the
operator's eyes. Deferred to a feel follow-up (they share the enemy-cache / damage-edge code path): connect-vs-
whiff flash, co-op remote-swing rendering, and enemy hit-flash. Investigation: wf_c6c87dc5-9c3 (melee lane).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:13:17 -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 1b704ca0b9 Combat tuning: lift sluggish chasers toward kiteable band + snappier dash (research-backed)
Deep-research-backed ratios (GDKeys, gamedeveloper.com twin-stick study, Hades/RoR, critpoints i-frames):
enemies should sit ~0.5-0.85x of player move speed (kiteable but pressing), telegraphs >= ~250ms.

- Enemy move speed (on the RIGGED prefabs the directors actually spawn - verified the live ZoneEnemy/Wave
  rosters at runtime: Grunt=EnemyWerewolf, Charger=EnemyChargerMuscle, Spitter=EnemySpitter, Swarmer=
  EnemySwarmerUndead): Grunt 3.0->4.2 (0.70x base), Charger walk 2.6->3.0, Spitter 2.8->3.0. The 0.43-0.50x
  cluster was trivially out-walked by the 6.9 Ranger; lifted to credible pressure while still kiteable.
  Swarmer kept at 6.5 (intentional surround/rush). Telegraph windups unchanged (already research-aligned).
- Dash (live TuningConfig defaults): IFrameWindowTicks 12->14 (0.20->0.23s, covers a reacted telegraph),
  DashCooldownTicks 45->36 (0.75->0.60s, horde-kiter cadence). Dash distance/arc unchanged.

Play-verified the baked rosters: Grunt 4.2 / Charger 3 / Spitter 3 / Swarmer 6.5; dash 14/36. 390/390 EditMode.
All are live-tunable (dash) or one re-bake (enemy speeds). Investigation: wf_c6c87dc5-9c3 (tuning lane).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 22:55:42 -07:00
kronic 3c1b5c44cd Fix: dying on an expedition soft-bricked the player — respawn now resets RegionTag to Base
PlayerRespawnSystem teleported a recovered player to base coords but never reset its server-only RegionTag
(every other region-mover flips RegionTag + Position together). So dying ON an expedition left you at base
still tagged Expedition: GhostRelevancy hid all base ghosts from you, base enemies ignored you, and the
expedition field/zone-director kept counting you as "still out there" (waves never stopped). No self-recovery.

- PlayerRespawnSystem: add RefRW<RegionTag> to the recovery query + set Region=Base alongside the reposition.
- Harden: drop the hard RequireForUpdate<PlayerSpawner> (a transiently-missing spawner could strand dead
  players downed forever) -> TryGetSingleton with a BaseAnchor fallback, early-return only if both are absent.
- PlayerRespawnSystemTests: add RegionTag to the harness + a regression (expedition death -> respawn at base
  with RegionTag reset to Base). 390/390 EditMode.

Investigation: combat-overhaul workflow wf_c6c87dc5-9c3 (death lane). Base-death case was already correct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 22:44:33 -07:00
kronic 8596cc74b1 Docs: DR-042 Phase C build record (legibility C5-C7 complete) + Backlog
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 21:27:55 -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 03f778085b Docs: loop re-shape to expedition-driven (DR-042) + consolidate; fix enemy health-bar fill
- DR-042 (new): canonical loop re-shape — win-driver moves from base-siege
  survival to expedition clears; blind scheduled siege retired; base siege
  becomes retaliation consequence. Build order A (coherence) -> B (retaliation)
  -> C (legibility) -> D (Slice 4 persistent meta).
- Backlog/Path_to_Fun/Home reconciled to the expedition-driven direction;
  Slice 3 + Combat Depth marked built.
- DR-036 (END-2) flagged superseded-in-part; DR-034 (END-1) repurposed (Core
  is a consequence, not the win-gate); DR-037 forward-pointer to DR-042.
- CombatFeedbackSystem: fix enemy health bar (sprite-less Filled Image ignored
  fillAmount -> size via anchorMax.x).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 20:07:33 -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 cf45ec82ae Add Unity AI Assistant package + editor settings migration
Adds com.unity.ai.assistant 2.12.0-pre.2 (+ transitive com.unity.ai.inference 2.6.1 and the com.unity.dt.app-ui EditorBuildSettings config) to the package manifest/lockfile, plus the package's ProjectSettings/Packages/com.unity.ai.assistant/Settings.json. ProjectSettings.asset migrated serializedVersion 28->29 (new iOS thermal-FPS / Android system-bar fields) by the editor. Editor/package tooling only; committed separately from the class-switch dev tool to keep concerns isolated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:29:01 -07:00
kronic a74b761363 Dev tool: switch player class (Warrior/Ranger) at runtime for testing
Editor-only class swap via the existing scalar dev-RPC family (new DebugOp.SetClass): F1/F2 keybind (ClassSwitchHotkeySystem), DebugOverlay '- Class -' buttons, and DebugCommandSendSystem.SetWarrior/SetRanger/SetClass statics. Server (DebugCommandReceiveSystem) swaps class in place on the spawned player: strips+re-seeds the ClassTraits StatModifier seeds, swaps the AbilityRef Fire slot, resets the ability cooldown, and heals a LIVING player to the new max (dead players skip the heal so respawn isn't raced). Server-authoritative + prediction-correct (same buffer-mutation path as GrantUpgrade); wire type unchanged so the RpcCollection hash is unaffected.

ClassTraits gains a shared Seeds core (spawn + swap can't drift), ClassSeedCount, IsClassSeed, a DynamicBuffer AppendSeeds overload, and Reapply. +3 EditMode tests (exact-count round-trip, value-equality fold, boundary/foreign-mod preservation); 351/351 green; Warrior<->Ranger round-trip Play-validated (server+client agree).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:23:33 -07:00
kronic 4ac1ae5a2e Rewrite /dots-dev skill: Workflow-first, two-review sandwich, 6.5 pins
Realigns the skill with how sessions actually run now — it predated the
Workflow tool and the ultracode two-review practice. Driven by an analysis
of the full session history + the 26-file memory corpus + skill-authoring
research, adversarially reviewed.

Key changes:
- Workflow-first orchestration: drop the dead manual "swarm (<=N agents)"
  model and the impossible 3-5-agent impl swarm; implementation is serial
  orchestrator MCP edits. New references/workflow-patterns.md (ground
  fan-out + design-review lens/critic) replaces agent-briefs.md.
- Pre-code design-review + post-impl diff-review are now first-class gated
  phases (the spine that catches what green tests + a clean Play miss).
- Size by blast-radius / netcode-heaviness, not time estimates.
- Lean SKILL.md (222 -> 131 lines, -25% KB): leans on CLAUDE.md instead of
  duplicating its MCP cheat-sheet / anti-patterns / error-recovery.
- ctx7 CLI / find-docs mechanism (the MCP verbs are gone); live-verified
  6.5-era library pins; kill the dead NetCodeTestWorld test path.
- Encode operator gates (no-time-estimates, present-forks, never-defer,
  tuning-autonomy) + the highest-recurrence MCP-edit / Workflow gotchas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:19:49 -07:00
kronic 6b368d1a29 Docs: DR-040 Slice 3 (Expedition Combat Spine) reviewed + scope-locked
Heaviest pre-code review done (1 ground + 3 lenses). v1 loop scope-locked: walk gate ->
epoch-seeded enemy wave in the expedition -> clear -> return + Ore -> escalated base siege.
4 netcode blockers fixed-in-spec (EnemyAISystem per-region targets; WaveSystem cleared-check
RegionTag{Base}; relevancy MaxAlive cap; reward per-epoch sentinel). Arena pool / zone-theme
byte / TimedModifier buff / SaveData v6 / mini-boss deferred to v2. Build is the next unit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:56:03 -07:00
kronic d6d75b4706 Docs: DR-039 Slice 2 (two classes) record + roadmap update
Slice 2 complete: Warrior/Ranger, DRG-asymmetric, aim-directed cone, menu picker,
class carrier via GoInGameRequest. Two VFX-polish items deferred (review-sanctioned).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:41:25 -07:00
kronic 431a7e2ed9 Slice 2: menu class picker (Warrior / Ranger)
MainMenuController gains a 2-class picker that sets WorldLauncher.SelectedClass;
WorldLauncher seeds a ClassSelection singleton into the client world at session start,
which GoInGameClientSystem carries on the spawn RPC. Default Warrior. Completes the
Slice 2 loop: pick a class in the menu -> spawn with its kit. Editor-default boot stays
Warrior (the menu path drives the choice). 348/348.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:39:38 -07:00
kronic 0a3a39e3d2 Slice 2 (WIP): WarriorCone ability + class tests; Warrior path validated
Authored the WarriorCone AbilityDefinition (archetype Cone, dmg 22, range 2.2, ~130deg
arc, 22-tick cd) and added it to the gameplay subscene's AbilityDatabase (re-baked).
ClassTraitsTests cover the class->ability mapping + the asymmetric seed folds. 348/348.
Play-validated the Warrior end-to-end, server==client: AbilityRef=WarriorCone, 4 seeds,
eff MaxHP 130 / MoveSpd 5.1 / cone dmg 22 / coneRad 1.13; conns=1 (re-bake handshake
intact); zero runtime errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:36:21 -07:00
kronic a7fdd6f71d Slice 2 (WIP): class carrier (GoInGameRequest.ClassId) + Warrior cone archetype
The per-player class travels on GoInGameRequest.ClassId (client reads a ClassSelection
singleton); GoInGameServerSystem seeds the class at spawn via ClassTraits (AbilityRef +
permanent trait StatModifiers on a reserved ClassSourceId; CharacterStatsRef stays Default
so the DRG-asymmetry deltas ride the replicated OwnerSendType.All buffer). AbilityFireSystem
gains the aim-directed Cone archetype: cooldown predicted both worlds, server-only cone
damage to living enemies (same-tick, SourceTick-stamped, like the melee cleave). 345/345.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:30:20 -07:00
kronic d9d67c4e78 Slice 2 (WIP): class data layer + melee-augment routing
Foundation for Two Classes (DR-037). New ids (CharacterId.Warrior/Ranger,
AbilityId.WarriorCone, StatTarget.MeleeDamage/MeleeRange); CharacterStatsRef.Id ->
[GhostField] so the owning client folds the right class stats; MeleeComboSystem
folds per-player MeleeDamage/MeleeRange off the replicated StatModifier buffer
(HasBuffer-guarded -> identity without class seeds, so behavior-preserving).
345/345 EditMode. Slice 2 design review + locked forks logged in the session note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:23:56 -07:00
kronic f98125f0b2 Docs: DR-038 Slice 1 record + session log
DR-038 records Slice 1 (combat readability + HUD declutter) with the two reusable
netcode patterns: bake-client-safe for client-needed/server-owned/never-changes
data (EnemyTelegraph), and a [GhostEnabledBit] derived once/tick (IsLunging). Open
item: the operator visual fun-gate. Session log captures the design redirect +
Slice 1 build/validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 12:48:16 -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 5292940f9d Docs: redirect to co-op roguelite — Expedition spine + classes + persistent meta
Playtest of the single-arena slice (Scratch Notes 6152026) found it stale fast.
Answer the post-END-2 Decision Gate as continue/expand: re-scope off the fixed
June-30 demo to a co-op roguelite-ARPG — base = persistent buildable hub (never
resets), the procedural Expedition region = the required combat spine, two classes
(Warrior/Ranger), persistent meta (SaveData v6 later). Mission-as-Sortie model:
fulfils locked pillar #4, preserves the never-a-run-reset pillar; reverses DR-031's
expedition pause. Backed by an 8-agent design+feasibility pass (feasibility GREEN:
server-spawns-ghosts removes seed replication). Slice doc archived/superseded.

See DR-037.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 12:47:54 -07:00
kronic 78ffa106b6 Chore: gitignore scratch areas (_visual_scratch, vault User Sessions)
Keep the local screenshot scratch dir and the personal vault "User Sessions"
notes on disk but out of git, so the worktree stays clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 00:35:03 -07:00
kronic 365d73e82f SL-4: leftover owned-cyan tint + Gameplay prop reposition
Uncommitted residue from the SL-4 visual-cohesion pass, swept up while
cleaning the worktree (unrelated to the 6.5 upgrade):
- Mat_StructureOwned_Cyan: _Color nudged to match _BaseColor (0.11,0.22,0.26)
- Gameplay.unity: a prop transform moved (0,1,8) -> (5.1,2.46,20.7)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 00:34:56 -07:00
kronic 4a6b7b6d2a Docs: Unity 6.5 upgrade validation (342/342 green, clean netcode boot)
Validated the 6.5 upgrade: 342/342 EditMode tests pass, no compile/Burst/
source-gen errors, and a clean netcode Play boot (ServerWorld+ClientWorld
connect, NetworkId handshake, in-game, ghost replication synced 23==23,
player owned-ghost spawned) -> the 6.6.0a6 "invalid wrapped network
interface" transport bug does NOT affect 6.5-stable. URP 17.5 render clean
(magenta scan 0/1564). The MaterialLocation.External FBX-import warnings are
benign 6.5 deprecation noise (2737 importers), import-time only.

Updates the CLAUDE.md stack table to 6.5.0 (net -13 bytes, under budget) and
adds the full session log.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 00:34:45 -07:00
kronic dc7a86fca4 Upgrade: Unity 6.4.7 -> 6.5.0 (DOTS stack onto unified 6.5)
Editor 6000.4.7f1 -> 6000.5.0f1. DOTS packages leave their independent
1.x/2.x lines for unified 6.5.0 versioning: netcode 1.13.2 -> 6.5.0,
physics 1.4.6 -> 6.5.0, transport 2.7.2 -> 6.5.0, entities/collections/
graphics 6.4.0 -> 6.5.0, mathematics 1.3.3 -> 1.4.0 (burst stays 1.8.29).
URP/ShaderGraph/VFX 17.4 -> 17.5, ugui 2.0 -> 2.5, test-framework 1.6 -> 1.7.
charactercontroller 1.4.2 + local rukhanka 2.9.0 unchanged (resolve on 6.5
via SemVer floor). Includes the URP global-settings + VFX/MPPM/package-manager
ProjectSettings migrations 6.5 wrote on first open.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 00:34:33 -07:00
kronic 03f287f93f Docs: SL-4 structure cyan pass done in Backlog
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:59:24 -07:00
kronic 5de30bd9c7 SL-4: structure cyan-emissive pass (owned faction colour)
Owned structures (Turret/Wall/Fabricator/Pylon) now read cyan-owned via a dedicated Mat_StructureOwned_Cyan (dark desaturated-cyan body + a subtle cyan self-illum below the bloom gate) - replacing the shared PolygonFantasyKingdom atlas + M_Turret so there's no atlas bleed. Tuned dimmer than the Core so the Engine Core stays the single luminance peak. Completes the faction palette: dark ground / cyan owned (Core bright, structures muted) / amber Ore / orange Husks. Edit-mode-instantiated + screenshot-verified. Follow-up (deferred): the research's dark-when-unpowered dynamic (emissive only on active/powered structures) needs a small presentation system reading structure state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:59:06 -07:00
kronic 40927de4a7 Docs: note the SL-4 clarity rebalance
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:48:05 -07:00
kronic b10605a8c4 SL-4: fix over-dark arena - rebalance lighting for clarity
The first pass crushed readability ('can't see anything'): dark ground x low ambient x dim sun x +12 contrast (clipped everything below midtone to black) x vignette x dark fog. Rebalanced toward legibility while keeping the dark-frontier mood: ColorAdjustments contrast 12->4 (the main fix), post-exposure 0.55->0.85, saturation 0->4; sun 0.9->1.5 cool-white; ambient intensity 0.62->1.0 with lifted cool ambient colors; vignette 0.32->0.20; ground material lifted ~18%->~28% value; fog pushed out (start 18->26, end 42->60); Core beacon range 9->13. Ground, player silhouette, Ore ring and shadows now all read; Core stays the bright cyan peak.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:47:40 -07:00
kronic cb3bdbbee9 Docs: SL-1/SL-4 visual-cohesion session log + Backlog status
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:09:45 -07:00
kronic fc27b9ff76 SL-1/SL-4: dark-frontier visual cohesion pass (camera, grade, bullseye)
Research-grounded transform of the base arena from a bright meadow into a dark 'Aether Siege Outpost' reading as a concentric bullseye (Core -> Ore ring -> dark perimeter). Camera (Game.unity): pitch 45->58, FOV 55->44, dist 13->17, lead 1->0.5, follow 8->6, targetH 1.3 (telephoto so Core + arena read together, near-iso enemy spacing). Lighting: sun dimmed+cooled 1.6->0.9, ambient 1.0->0.62 dark-cool, fog Linear 18->42 dark; WorldAtmosphere base darkened. Post-FX (PostFX_Daylight): ACES kept, bloom gated (thr 1.0->1.2 + clamp 10), exposure/contrast up, saturation +6->0, added ShadowsMidtonesHighlights cool-shadow/warm-highlight split, vignette 0.15->0.32. Ground re-tinted dark teal-grey; ~390 meadow-cheer objects cut. Core staged as hero (crystal 14m->4.6m cyan glow + cyan beacon light). Ore ring pulled into the arena (23.5-27m -> 6-11.5m, count 10->12) and recoloured AMBER (new Mat_OreNode_Amber, emissive, no atlas bleed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:07:53 -07:00
kronic db627b48b1 Docs: note SL-5 code portion (telegraph + retry/quit) shipped early
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:21:02 -07:00
kronic e94b2948c7 SL-5: retry/quit actions on the END-2 win/loss banner
The terminal banner gains PLAY AGAIN + QUIT TO MENU buttons so a finished run has a clear action (no Esc-hunting). PLAY AGAIN restarts a fresh Single run via WorldLauncher.StartSession (the proven menu lifecycle, no save load); QUIT TO MENU reuses TeardownToMenu (autosave + menu); both self-guard on WorldLauncher.Busy. The button row picks (Position) under the Ignore banner root, matching the build-palette idiom. AimReticleSystem (the sole Cursor.visible writer) keeps the cursor visible while RunOutcome != InProgress so the buttons are clickable regardless of aim state. 342/342 EditMode green. Co-op retry-together stays a cut slice-limit (a client's Play Again starts a solo run). See DR-036.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:20:22 -07:00
kronic 04ad707e3b SL-5: distinct final-siege telegraph on the HUD
The client derives the climactic final siege from the replicated Charge>=Target and marks it distinctly: 'FINAL SIEGE INCOMING - Ns' during the cap-reached arming window (vs the generic 'INCURSION'), 'HOLD THE ENGINE - FINAL SIEGE' + intense red during the wave, and a last-stand location line. Pure client presentation (no sim/replication change); 342/342 EditMode green. Serves the END-2 fun-gate (the Engine telegraphs the climax + prompts deliberate prep).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:13:29 -07:00
kronic 6769fc3de9 Docs: END-2 session log + DR-036; Backlog/Path_to_Fun/Milestones; CLAUDE.md END-2 line
Path A spine COMPLETE (14/14): Backlog SL-3 blocker cleared + marked done; Path_to_Fun END-2 done + banner; Milestones END-2 row. CLAUDE.md gains the END-2 gotcha line (replicate the outcome, don't client-derive; SiegeTimeout off during the final), net-zero via EB-1/EB-2/END-1/M7/inventory/build-grid condensations (40,445 then 40,510 w/ history note, under the 40,960 limit). DR-036 + session log capture the design, the operator forks (halt+banner, Target=4, SaveData v5), and the pre-coding + post-impl adversarial reviews.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:38:46 -07:00
kronic aac1813a93 Tests: END-2 win/lose + final-siege arming + SaveData v5 (342/342 EditMode)
EndgameWinLoseTests: arms-once+enter, Charge clamp, Victory/Loss edges, the END-1 soft-loss regression (normal overrun stays soft), restored-Victory-no-rearm, SiegeTimeout-not-culling-final, the full ThreatDirector->CyclePhase->GoalReached pipeline (arm-not-stomped-by-scheduler), and FinalSiegeMultiplier override + sub-1 floor. SavePersistenceTests: RunOutcome v5 round-trip + pre-v5 default-to-InProgress. TuningConfigTests: FinalSiegeMultiplier default pin. See DR-036.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:38:36 -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 33c85c4f9a Docs: adopt End-of-Month slice as Decision-Gate answer + SL-1..7 plan (DR-035)
Reconcile the roadmap to the just-committed End_Of_Month_Game_Jam_Slice
("Awakening Engine Last Stand"). 9-agent grounded code audit: 13/14 slice
systems already shipped; END-2 (final siege + latching win) is the one
blocker. Decision Gate answered early as ship-the-minimum.

- DR-035 (new): adopt the slice; END-2 charge cadence LOCKED siege-survived-only
- Backlog: NEXT reframed to the slice + SL-1..SL-7 milestones (END-2 = SL-3, critical path)
- Milestones: close ledger gap (MC-1 PASS / MC-4 / base-mining / EB-1 / EB-2 / END-1) + slice row
- Path_to_Fun: top pointer (stays long-term north-star; Path B untouched)
- Slice doc: Status & Navigation cross-links

CLAUDE.md intentionally unchanged (no budget headroom; conventions doc, uncontradicted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 13:23:21 -07:00
Luis Gonzalez 42691e5431 Docs 2026-06-13 00:00:50 -07:00
kronic 49cdec3a1e more 2026-06-12 22:21:12 -07:00
kronic f7c63b6f41 Docs: END-1 session log + DR-034; CLAUDE.md losable-core bullet
DR-034 records the losable-Core decisions: CoreIntegrity on the global ghost,
the soft-loss edge inside CyclePhaseSystem, the Core-as-fallback-target and
despawn-on-breach forks, the transient OverrunTick (vs END-2's latching
outcome), and SaveData v4. Session log captures the build + validation
(330/330 EditMode; Play-verified server==client drain->regen->replicate).
CLAUDE.md adds the END-1 bullet; EB-1/EB-2/inventory bullets condensed
net-neutral to stay under the size budget.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 21:52:03 -07:00
kronic 037ff66490 Tests: END-1 Core drain/regen/lose-edge + persistence v4 (330/330 EditMode)
CoreSystemsTests (new): a breaching Husk drains + is consumed; idles at 0;
regen fires once per interval in Calm only; no regen mid-Siege; caps at Max.
CyclePhaseSystemTests: the soft-loss overrun edge ends the siege, drains the
ledger, despawns husks, withholds the goal charge, and resolves once.
StorageMathTests: DrainFraction floors per row, drops zeroed rows, clamps.
SavePersistenceTests: CoreCurrent round-trips at v4; a pre-END-1 save with no
CoreCurrent defaults to 0 (-> born full); the v3->v4 version pin updated.
TuningConfig golden pin extended with the 3 Core defaults.

See DR-034.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 21:51:52 -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 3fdac3517b Docs: EB-2 session log + DR-033; CLAUDE.md felt-spend bullet
DR-033 records the felt-spend design (shared Charge ammo, atomic soft-fail,
ledger-fed Fabricator, no-ordering-edge trade-off, global HUD cue, no SaveData
bump). CLAUDE.md adds the EB-2 ★ bullet net-zero (trimmed bullets archived to
the gotchas archive under a 2026-06-12 heading).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:15:10 -07:00
kronic 44da26cdf6 Tests: EB-2 Charge spend + ledger-fed Fabricator (318/318 EditMode)
- TurretFireSystem: seed a Charge pool for existing tests; add soft-fail-when-dry,
  consume-one-Charge-per-shot, two-turrets-share-a-finite-pool.
- FabricatorProductionSystem: ledger-fed withdraw/deposit, two machines split via the
  live in-loop read, and a catch-up affordability-clamp regression pin.

See DR-033.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:14:58 -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 e04cdea44f Docs: EB-1 session log + DR-032; CLAUDE.md machines-can-die
Session log + DR-032 (structures reuse Health/DamageEvent, Destructible-not-PlacedStructure, fortress targeting, persistence v3, loss feedback; both adversarial reviews). CLAUDE.md: EB-1 build-gotcha bullet + persistence v3 floor-gate; net condensation of M7/inventory/UITK/juice reference bullets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 23:53:50 -07:00