Commit graph Aetheria/Assets/Scripts/Gameplay/ActionGameManager.cs
Author SHA1 Message Date
Meta Vens
c47ced9cfd Paints carry search or track; a ping sweep warns every ship it crosses in its beam; allies hear the return silently
LockWarning becomes PaintWarning with a PaintMode (Search for a ping sweep, Track for a lock);
Entity.IncomingLocks becomes IncomingPaints. Sensor replaces the _pingedEntities set with a stateless
crossing rule over the previous and current wavefront radius, limited to a new BeamWidth stat (key 12,
absent reads 360), and credits allied pings from the receiving sensor's own sensitivity and distance.
The HUD lock indicator follows Track paints only. Folds in the radiator sampling-instant pin.

Unverified at this commit (first build still to run).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:05:16 +02:00
Meta Vens
1c5c602054 Lock warning fix 1: publish paints in a zone phase, one lock-indicator curve, strength and progress-term pins
- Zone.Update publishes every entity's paints before any entity updates (Entity.PublishPaints), so a broken lock clears on the same tick whatever the entity order.
- ActionGameManager.ApplyLockProgress is the one lock-indicator curve, called by the outgoing and the incoming indicator.
- LockWarningTests drive the real LockWeapon through Zone.Update; pins on strength across 0.15..1.0, the direction and sensor progress terms, and both entity orders.

Not yet run: this commit's tests have not been built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 23:29:27 +02:00
Meta Vens
e5cfc0d676 Lock warning: a painted ship owns a typed incoming-lock warning carrying the lock's strength
LockWeapon.Execute paints its target with its own Lock (the one value the outgoing indicator also reads);
Entity publishes the one-tick inbox as IncomingLocks; the HUD shows one incoming indicator on the strongest
warning with the outgoing indicator's curves. Unity HUD code not compiled here; tests not yet run at this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:25:22 +02:00
Meta Vens
f28d4b4b12 Merge eureka/aetheria-release-sim-speed: one SimClock steps the zone, presenters draw ahead by Lead
AetherDrive.cs: master deleted the behaviour (2cfdc728); the branch only added a
TurnRate line to it. Deletion kept. Thruster remains the one rotation actuator
and feeds Entity.TurnRate. No sim stepping outside the clock on master
(mines presenter, Pirates AI, lot-product all step through Zone.Update).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 02:29:37 +02:00
Meta Vens
257a8a4795 Sim speed fix: scripted poses are not drawn ahead; a step cannot reset its clock; DrawAhead.Time deleted
DrawAhead leaves a ship in a wormhole animation where the step put it. The clock is
one static instance; a zone entered inside a step ends that frame's stepping and the
clock resets between frames (SimClock.Reset throws inside Advance). DrawAhead.Time had
no consumer.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 23:39:30 +02:00
Meta Vens
284231f4c1 Merge origin/master (2403a5f3, gear-without-presence) into eureka/aetheria-release-retire-longinusx
Lands retire-longinusx on master after gear-without-presence. The catalog
is regenerated from master's catalog with retire-longinusx apply (next commit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	GameData/Aetheria.cc
2026-10-08 18:59:38 +02:00
Meta Vens
c4bd6e153e Sim speed: one SimClock steps the zone; presenters draw ahead by Lead
SimClock (engine-free) turns real frame seconds into whole fixed steps; ActionGameManager.Update feeds it outside the pause gate and Zone.Update(Time.deltaTime) is gone, with IntroCutscene (dead, Unity-driven pose writes). Entity.TurnRate is the sum of the rotation actuators' applied turn per sim second, zeroed each Update; DrawAhead reads it so EntityInstance and ShipInstance draw the latest sim state ahead by Lead. Unverified at this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:26:02 +02:00
Meta Vens
ace8171929 Merge origin/master into eureka/aetheria-release-product-titles 2026-10-08 16:27:49 +02:00
Meta Vens
8761b3707f Loot scan label and FIRE CONTROL overlay read Title, not the design name
Every item-title display site now routes through ItemManager.Title. The grep
for design-name reads under Assets/Scripts outside ServerShared leaves only
log lines, exception text, console parsing and the Type row.
Does not build-verified yet; the Unity compile runs at the end of the batch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:30:48 +02:00
Meta Vens
2cfdc72853 Delete the aether drive: behaviour, union 12, hardpoint type, aggregates, settings, presenters, prefab
AetherDriveData and AetherDrive, Union(12) (now a retired-do-not-reuse comment, as 26 is),
HardpointType.AetherDrive (last member, nothing shifts), Ship's drive sets, aggregates and
Axis write, the five request-field rows, GameplaySettings Aether multipliers, ShipInstance's
drive particles, SchematicDisplay's RPM display and AetherDriveUi, the undock refusal's drive
clause, the drive prefab and material, and AetherDb's drive roles and brownout row. The
design is kept at parked/aether-drive.
Adds EveryShippedShipHullHasATopSpeed. ARPG.unity still holds stale serialized references to
the removed SchematicDisplay fields and the RPM Display object; the next commit removes them.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 14:04:28 +02:00
Meta Vens
e3a457793b Merge eureka/aetheria-release-boss-gate (with eureka/aetheria-release-demo-galaxy) into master
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:03:32 +02:00
Meta Vens
179ab92abc Merge evasion-term: evasion is changes of vector plus a per-gun mount term; authored tracking rates in the catalog; the aether drive leaves the envelope
Soul gate closed at verdict cut-evasion-term.s5 (head 473a4bcc); remaining Low
test gaps are deferred to a follow-up. Merged under operator ruling
aetheria-release:ruling:completed-cuts-merge. Carries the migrated
GameData/Aetheria.cc (LFS sha256 63250cf2...7ae25); master did not change the
catalog.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 22:29:51 +02:00
Meta Vens
b6487afd95 FireControl: the mount factor, AngularVelocity, TrackingRate and PMount, in the price, the freeze, Inspect and the HUD
PMount(AngularVelocity(source, target), TrackingRate(weapon, source)) multiplies HitProbability after the pFire gate;
Fire freezes it into PendingShot.PFire; Inspect and the debug HUD show omega, rate and the factor. TrackingRate is the
one product of the gun's rate and the ship's gear (ruling tracking-per-gun). Tracking(Entity) in metres still alone
forgives the changes of vector (ruling jink-per-ship).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 16:40:00 +02:00
Meta Vens
5960beb3e7 Helm split, player input: A/D turn, Q/E strafe, Shift holds and Caps Lock latches face-the-aim
The player writes Ship.Turn through HelmInput.Demand, and the FACE AIM mark shows while the latch is
on. Bindings keep their ids so saved overrides still apply; Face Aim and Toggle Face Aim are new
actions, and the wrapper is regenerated to match the asset.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:33:22 +02:00
Meta Vens
9883d08dcd Exit gate: the exit zone shows a gate that ends the run as won once RunGoal says the boss is dead
ZoneRenderer adds an exit wormhole at RunGoal.ExitGatePosition; Interact asks RunGoal.ExitOpen and either
calls Win or names the boss that seals it. Die and Win share one EndRun.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 01:13:09 +02:00
Meta Vens
c204397cb0 TradeMenu sells and repairs through StationServices; credits seed from the stage or the save
The hardcoded credits initializer and its stale scene serialization go. Buy charges the hull price it checked. Sell is a
mode of the trade list over the selected bay; Repair is a foldout option for the docked ship.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:30:34 +02:00
Meta Vens
d9f85dc639 Merge origin/master into mining: resolve five conflicts by owner, delete the belt-task machine
Mining owns belts, chunks and target picking; scenarios owns admission and run
staging; master owns ships and fire control (rule scenarios-cut.md S4).

- AetheriaStores.CatalogTypes: nine-type union, master's list plus FieldKindData, no Scenario.
- tools/AetherDb/Program.cs: both cases (ship-authoring, field-kinds), one usage string.
- Zone.cs: master's MineAsteroid dropped (mining deleted its inputs); scenarios' SettleBelts and its three calls deleted.
- RunStartTests: the two belt-task tests deleted (they read belt.Transforms and MineAsteroid).
- FireControlCut124Tests: master's strict Exact assertions; mining's CompatibleDrift allowance and its comment dropped.
- GameData/Aetheria.cc: master's pointer 70a7b0a9. This commit lacks the Asteroid field kind in the catalog, so
  TheShippedCatalogHasAPickableFieldKind fails here by design; the next commit rebuilds it.

Builds: this commit builds (verified at the end with commit 2); the catalog pin test fails at this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:29:29 +02:00
Meta Vens
ec2042b390 Mining target queries: reticle, next, previous and nearest are Entity's best-first index queries
The four handlers in ActionGameManager call Entity.TargetUnderReticle, TargetNext,
TargetPrevious and TargetNearestEnemy. TargetCandidates, which built, sorted and
searched every visible ship and rock per press, is gone. Previous with no target
takes the farthest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:38:20 +02:00
Meta Vens
8a1e205cf0 A new run replaces the saved run only once it has staged; a failed start says why and leaves the saved run
Launch cleared the run store before generating, and a generation or staging failure only reached the log: the
Generating Galaxy dialog stayed up, StartGame threw, and the saved run was already gone.

RunSave.Replace runs a start with the saved run still stored: when it returns a staged run the saved run's records go,
and when it returns null or throws, only the records it wrote (the arena's orbits and bodies) go. StartGame's
new-run branch is StartScenario, chosen by PendingScenario rather than by the absence of a SavedGame; it mints into an
empty ledger, and a failed start clears CurrentGalaxy (so quitting saves nothing) and refuses on the main menu with
every failure. Launch no longer clears; a galaxy that throws is refused on the title menu. The menu offers Continue
whenever no run is live, which replaces MainMenu.InGame (cut, with its prefab value and scene override), so a
failed start can resume the saved run in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:03:50 +02:00
Meta Vens
d0782a7d14 Every new run is a scenario: the script harness, the tutorial and main galaxies as scenarios, the New Game submenu and six test arenas
A Scenario is an abstract C# class compiled with the game: Generate picks the galaxy through GalaxyStage (Main or
Prelude, at the scenario's seed, the background noise drawn from the same seed), Stage places the run's first
entities through ScenarioStage (Fit, Bare, Generated, Preset, Player, Place, Cargo), which collects named failures
and admits nothing. RunStart generates the galaxy, the arena under Ambient and admits everything through Zone.Admit,
all or nothing. The aetheria.scenario record, ScenarioShip, ScenarioEntity, RunStart.Check and the null-scenario
branch are cut.

New Game opens a submenu: Tutorial Galaxy and Main Galaxy, then (editor and development builds) Djinni Shakedown,
Starved Reactor, Arcs, Duel, Launcher Angles and Long Haul, each with its brief. MainMenu.Launch is the one way into a
new run; ActionGameManager.PendingScenario carries the scenario to StartGame once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:33:55 +02:00
Meta Vens
8a0a29e0de Galaxy.IsPrelude is the one owner of whether a run is the prelude: ActionGameManager.IsTutorial and PlayerSettings.TutorialPassed are cut
IsTutorial duplicated Galaxy.IsPrelude; its readers read CurrentGalaxy.IsPrelude, and RunSave.Capture writes
SavedGame.IsTutorial from galaxy.IsPrelude with no isTutorial argument. TutorialPassed was never written and its only
reader was New Game's unreachable main-galaxy branch, which goes with it (S2 brings the main galaxy back as a
scenario). spawnturret's two identical generator branches collapse to one. Old player.cc files still load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:26:30 +02:00
Meta Vens
5ea59ac6b5 Entity: an equipped item keeps the hardpoint it occupies
The placement rule (HardpointAt) already finds the one hardpoint an item lies
in at equip; TryEquip threw that answer away and eighteen readers recomputed it
from the item's origin cell, which need not lie in the hardpoint (Soul's
scenarios batch-4 P30). EquippedItem.Hardpoint now carries the answer, null for
Tool gear and the hull, and every origin-cell lookup reads it instead:
FireControl.ArcFor, the eleven weapon managers, EntityInstance, ShipInstance
and ActionGameManager's articulation grouping. Entity.Hardpoints[,] stays the
per-cell map for armour and display.

TryFindSpace's hardpoint search tries every origin the fit rule can accept,
including ones up and left of the hardpoint, so a design whose shape lacks its
origin cell is found wherever ItemFits would place it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:57:27 +02:00
Meta Vens
2d39c83504 Merge master into eureka/aetheria-release-scenarios: adopt the scenarios lane onto master's base
The one conflict is AetheriaStores.CatalogTypes: keep ShipAuthoring from the
ships lane and Scenario from the scenarios lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:53:29 +02:00
Meta Vens
15723f4037 Mining Cut 3: a chunk is a target, detected by reflected light
- Entity.Target is one slot of TargetRef, read-only from outside
  (IReadOnlyReactiveProperty); Entity.SetTarget is its one writer. A chunk is
  taken only while the entity can see it, so a rock in darkness cannot be
  picked. Every handler, agent, turret and test writes through SetTarget.
- Entity.ChunkInfo (Q14 A): the value the per-tick sensor rule settles at,
  computed on demand through Sensor.PassiveRate/Sensor.Gain -- sum of the
  active sensors' passive rates over (sensors x TargetInfoDecay), capped at 1.
  Stored nowhere; no per-tick loop over chunks. ChunkVisible is the detection
  threshold through the chunk path.
- The lost-track rule reads through the chunk path: Activate's reconciliation
  and a per-tick check of the one slot drop a chunk target that has gone dark.
- Entity.VisibleChunksInReach (Q13 A): visible chunks within the longest range
  among active weapons -- the one reach rule for cycling and programmatic picks.
- Entity-only readers take .Entity: TargetedBy/TargetedByCount, target items,
  the stance gate (a chunk has no stance), lock (Q12 A: never on a chunk),
  turrets, Combat, Minion, FireControl (a chunk fires untargeted until Cut 4).
  TargetRange and the arc gate read a chunk's planar position.
- ActionGameManager: the reticle and next/previous offer visible ships and
  visible chunks in reach; nearest stays enemies-only; the target panel,
  indicator and fire-control debug take TargetRef. EntityInstance reads .Entity.
- MiningCut3Tests pin parity, darkness, monotone brightness, wear and break,
  reach, the chunk query, target survival and loss, TargetRef equality, lock,
  and field-kind assignment at generation and first load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:56:39 +02:00
Meta Vens
f527154e26 Scenarios Cut 1: StartGame stages through RunStart; the game's joins admit
StartGame's new-run branch no longer generates, unpacks or admits the
player: RunStart generates the arena and stages the run, and StartGame
enters the zone and binds the returned player (docs/scenarios-cut.md, 2.2,
deletion line). PopulateLevel's warp arrival and the spawnturret console
command admit through Zone.Admit, unpiloted. The console commands stay (Q4);
give's hull route moors a ship at the docked entity and joins a zone only
through Entity.TryUndock, which already admits.

Needs the Unity batchmode compile; Assembly-CSharp is not built headless.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:35:19 +02:00
Meta Vens
54917bb39d Ship S2 fixes: structural anchors are not mounts, mod presets refused, one bad mod never bricks the boot
- Validate: a hardpoint's anchor role is fixed by its type (thruster-emitter, radiator-mesh, else articulation); ShipModPlan's
  duplicate role check is deleted.
- Loadouts.Commit refuses a preset naming a mod design (mod-hull:/mod-ship:), so the shipped catalog never references a mod.
- Compose quarantines each package: a bad package is excluded and named, a collision excludes every package involved; the
  game boots on the rest (or the shipped catalog) and the main menu lists the exclusions.
- RequireDesigns refuses a save with a null item or lot instead of throwing NullReferenceException.
- Tests: per structural role, muzzle id ties, every slot/zone/lot in RequireDesigns, listing order, exclusion cases.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 08:30:52 +02:00
Meta Vens
460bb85ed0 Ship S2: the game composes and loads mod ships
Boot opens the derived catalog when GameData/Mods holds packages
(ShipModCatalog.ResolveCatalog), preloads each hull's GLB into an assembled
inactive prototype (ShipModShips), and LoadEntity clones it when the hull names
a Visual. ShipModPlan decides which anchor fills which ShipInstance slot; a
ShipModTemplate prefab carries the shared effects. Continue refuses a run that
names a design the catalog no longer holds (RunSave.RequireDesigns).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 06:43:52 +02:00
Meta Vens
f935c29b4b Fix console text input and route give through ship commissioning
- ConsoleView appended the control characters text input delivers (\b, \r),
  so Backspace inserted a glyph and Enter's \r got every command refused
  since d503f076 made the parser refuse instead of strip. Control characters
  are no longer text; Backspace deletes like Delete.
- give reports an unknown name or a full cargo bay. A ship hull is refused
  unless docked, and when docked is commissioned through
  ActionGameManager.CommissionShip, the primitive TradeMenu.Buy now uses: a
  bare player ship moored at the docked entity, no docking bay. Non-ship
  hulls are refused.
- Record play smoke results for steps 3-6 and the docking bay finding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:04:11 +02:00
Meta Vens
e0a802084e Use the generated accessor for Cycle Target Item
Regenerate AetheriaInput.cs from the committed Aetheria.inputactions so the
wrapper carries Cycle Target Item, and bind it through Input.Player like the
other target actions. The by-name FindAction lookup was a stopgap from when
the generator could not be run outside the editor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:38:48 +02:00
Meta Vens
57c2560fc0 Fuse fixes: arming holds for every burst, no-lock rounds stop on the first hull, settle before user code
Operator ruling 2026-09-30: a no-lock round of any fuse stops at the first hull
on its aim line and detonates there (bomb fishing still bursts at max range on
a clear line). CommitBurst no longer special-cases Contact.

Soul's findings on 14f66634..7e620ff9:
- Arming (HIGH): a contact or delayed blast on a hull nearer the muzzle than the
  blast radius detonated at the hull. Armed is now the one owner of the arming
  rule; Solve plans its burst point through it and ApplyBlastHit pushes the hull
  point through it.
- A refused beam never starts (ConstantWeapon.Activate asks Refuses), so
  OnStartFiring no longer flashes visuals and audio for a beam that fires nothing.
- Step removes a shot from the queue before Apply runs damage observers, so a
  throwing observer cannot make the blast repeat every tick.
- AgentFires consults Solve for a fused weapon: a refused weapon is never fired
  and Combat's group pick no longer counts its damage.
- SingleAmmoBurst pays at its first unrefused round in Execute, judged with the
  Range that round flies with, instead of at the trigger on the previous tick's.
- Inspect reads Designated from Solve (FireSolution.Designated) instead of
  recomputing visible, in-range and locked; FireControlDiagnostic drops those
  three fields and the debug HUD shows the one. Combat's group range test is
  FireControl.InReach, the range half of Designated (a LockWeapon must be
  activated to acquire its lock, so Combat cannot ask Designated itself).

Tests pin each rule, plus the two surviving gaps: a pushed-out targeted round's
arrival at the arming distance, and the AgentMinHitProbability boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:31:59 +02:00
Meta Vens
a193853d34 Fuse batch 5: agents fire per weapon, Solve owns the burst, refusal is free, arming is the blast radius
Operator rulings 2026-09-30.

* Combat and TurretController ask FireControl.AgentFires for each weapon. A
  fused weapon fires whenever its target is designated (Designated, the one
  visible / in-range / locked predicate PFire already used), whatever the arc;
  an agent never fires one at nothing. A direct-hit weapon keeps the
  AgentMinHitProbability threshold. The group's first weapon no longer speaks
  for the group, and the turret's own range test is gone.
* FireControl.Solve is the one decision about what a round does, extracted
  from Fire: Direct, Burst at a reach, or Refused. Fire, Inspect and the
  weapons' refusal check all read it. Inspect gains Outcome and BurstReach and
  the debug HUD prints them for fused weapons.
* A refused round costs nothing. InstantWeapon asks before its ammo and energy
  spend (at the trigger and at each round), ConstantWeapon folds the refusal
  into the gate its power request and Execute already share, so a refused beam
  draws no power, wear, heat or visibility and stops.
* The arming distance is BlastRadius, measured from the shooter's position and
  blind to hull size. HullAhead's exit, ArmingDistance and
  PendingShot.ArmingDistance are deleted; HullAhead survives as HullEntry for
  the contact fuse. A round fired at a valid target inside the radius is pushed
  out along its line but keeps its target, so a departed target cancels it.
* Step settles a shot's queue state before publishing about it, so a throwing
  presentation observer costs its own notification and cannot re-commit or
  re-resolve the shot on every later tick.

Tests: FireControlPerWeaponTests (new; includes a fused-beam fixture), the
arming tests in FireControlCut124Tests rewritten to the literal distance,
the hull-inclusive probe premises deleted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 18:36:59 +02:00
Meta Vens
543edee358 Guided rounds follow the committed burst and resolution; no-target launcher no longer throws
- GuidedProjectileManager passed target.transform to OnFireGuided for a
  no-target fused round: a NullReferenceException inside InstantWeapon.Execute
  after the shot was queued, which skipped audio, wear, heat and visibility
  and unwound Zone.Update. The tuple's transform is null-safe now, and the
  trackmissile console command falls back to the missile.
- Presentation follows the commit rather than predicting it. The manager binds
  each guided round to Zone.ShotCommitted (retarget to the burst point the
  commit names, so a Contact round bursts at its hull and a Range-clamped
  burst is not overshot) and ShotResolved (burst there, then). The binding is
  disposed when the projectile dies, so a pooled round does not accumulate them.
- Beams and barrel-fired projectiles stay with F5.

Unity-only; compile-checked by reading.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 17:05:15 +02:00
Meta Vens
f5c6729e7a No-lock fused rounds: aim, invalid targets, contact stops, outlived shooters
Operator rulings 2026-09-30 after Soul's pass on 8c002637:

- A no-lock round flies along Entity.LookDirection restricted by the mount's
  arc (FireControl.AimDirection: inside InArc's cone as is, outside it turned
  to the cone's edge; no aim falls back to the mount). The simulation had no
  aim clamp before; the old code used the hull-fixed mount direction.
- An invalid target (out of range, out of arc, not visible, not locked) counts
  as no lock for a fused round. PFire's gate is the one decider and now also
  reports `bears`; Fire reads it. The round carries no target afterwards.
- A no-lock Contact round bursts at the first hull its aim line crosses
  before max range, read through Lane's own cell admission (CellsOnLine,
  split out of Lane). Proximity and Delayed keep the max-range burst. Such a
  round commits at Fire, since it has no target facing to read late, and
  arrives when it has flown to the burst point. The seam for mining chunks is
  FireControl.ContactDistance.
- A round outlives its shooter: Step no longer cancels a shot whose source
  left the zone. Resolution reads the zone and the target; the shooter is an
  identity a shot carries. PendingShot.FireOrigin freezes where it left from.
- ShotOutcome.Result (Miss, Hit, Burst) replaces the stored Hit bool, which
  is now derived. A burst without a target is no longer reported as a miss,
  and the debug HUD labels it BURST.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 13:27:43 +02:00
Meta Vens
7dbb3bcf7a Cut 12.2: where a hit lands is priced and drawn from one silhouette
FireControl.Silhouette replaces HullKernel/WeightedPick/POnHull: the hull's
lateral shadow at a bearing, merged into intervals, integrated exactly with
CultMath.erf/erfinv instead of a discrete per-cell Gaussian sum. FireControl.Lane
does exact slab traversal to pick the impact cell from a lateral offset; only
its first element (the entry-nearest occupied cell) is used here, per the cut
map -- the rest is 12.3's armour-first absorption march.

Bearing timing: PendingShot.PBase is renamed PFire and now carries only the
shooter-side factor (Accuracy x PSensor) behind the gates; TravelDirection,
Spread and FireRange are frozen alongside it. The target's facing is read live
at Commit through FireControl.CommitProbability (steps 1-5 of the spec's
"Bearing timing"), not frozen at Fire, so a target that turns its armour into
an incoming shot takes the hit there. ShotOutcome gains Bearing/Lateral,
frozen at commit; Apply reads only those, never a live position or facing.
Entity.ApplyHit takes an already-schematic bearing instead of a world
direction, and the ToSchematic call 12.1 put inside it is gone.

Superseded tests: PlacementAndProbabilityShareOneKernel, EveryHitLandsOnMetal
and AimingAtTheSternHitsTheStern are replaced by
FireControlCut12Tests.PlacementAndProbabilityShareOneSilhouette,
HitsLandOnTheFacingEdge and AimingAtAnItemCentresTheScatterOnItsLane.
FireAuthorityTests.AimedHitLandsOnSelectedItem and PenetrationMarchIsPlanar are
updated for ApplyHit's new bearing parameter and Lane's entry-nearest-cell
placement (a solid hull's Tool item is never itself the entry cell; reaching
it now needs the same penetration march the new tests exercise).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 20:40:50 +02:00
Meta Vens
72c0109cf1 Add live fire control diagnostics 2026-09-20 21:58:44 +02:00
Meta Vens
04c0943fa0 Wire subsystem selection and reveal into player input and the HUD
A new "Cycle Target Item" action (hand-authored into Aetheria.inputactions;
no Unity editor here to regenerate AetheriaInput.cs, so ActionGameManager
looks it up by name through Input.asset.FindAction instead of a typed
accessor) cycles the local player's aim point among the current target's
revealed items via TrySelectTargetItem. SchematicDisplay's enemy view now
filters to what FireControl.IsRevealed actually resolves for the viewer,
and marks whichever row is the current ResolvedTargetItem through a new
SchematicListElement.SelectedIndicator (unwired in any prefab yet -- a
no-op until an editor pass assigns one).

Presentation only; decides nothing. Unverified here -- Unity batchmode
is unavailable in this environment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 13:02:54 +02:00
Meta Vens
0c2da217f3 Cut 0: give Entity its own EntitySettings copy, delete the duplicate copies
Entity's constructor now takes a MessagePack round-trip copy of the settings
it is given, so no entity can alias GameplaySettings.DefaultEntitySettings.
That makes ActionGameManager.NewEntitySettings and EntitySerializer.Unpack's
null-coalescing copy redundant; both are deleted, and TradeMenu buys a ship
straight off the template (Entity's ctor copies it).

EntitiesDoNotShareDefaultEntitySettings pins the invariant: writing
ShutdownPerformance on one ship must not move the default for a sibling or
the template (settings-globals-cut.md, Cut 0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 18:22:22 +02:00
Meta Vens
00ebe46abe Move mouse-look sensitivity into the PlayerSettings CultCache global
ActionGameManager.Sensitivity was a Unity-serialized public float2, but
CultMath's float2 isn't Unity-serializable, so ARPG.unity's stored value
loaded as zero and mouse look went dead. Sensitivity is a player
preference, so it belongs in PlayerInputSettings (key 2) with the prior
default (-0.001, 0.001) as a field initializer, so a pre-existing player
store missing the key still deserializes to the working default instead
of zero. ActionGameManager now reads PlayerSettings.InputSettings.Sensitivity
directly; no cached copy on the MonoBehaviour. Adds a pinning test that
simulates an old store lacking key 2 and asserts the default, plus a
round-trip test for a non-default value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 17:22:09 +02:00
Meta Vens
a5fd8f1d1d Let the player target and mark neutrals, and fix the HUD lock direction
TargetReticle, TargetNext and TargetPrevious now consider all visible
entities except self (hostile and neutral), not just VisibleEnemies, so a
neutral wanderer can be selected. TargetNearest stays enemies-only (it drives
weapon lock) but now picks the nearest target: it was using MaxBy, which
picked the farthest.

Adds a "Toggle Stance" input action (bound to the N key; report names which)
that flips the player's own stance on the current target between hostile and
neutral via Entity.SetIff -- one button for the whole affordance, per the
operator's request. Also keeps the "iff hostile"/"iff neutral"/"iff clear"
console commands next to the existing ones, since they cost nothing extra
alongside the hotkey.

Fixes the HUD lock indicator's hostility check, which read
Target.IsHostileTo(CurrentEntity) instead of CurrentEntity.IsHostileTo(Target)
-- the same backwards direction as LockWeapon, fixed in the prior commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 14:01:15 +02:00
Meta Vens
415f8e1152 Add the lot ledger and mint every crafted instance through it
Quality, Ingredients and Product leave CraftedItemInstance; a unit now
carries only a LotId into the run-scoped ProvenanceLedger. ItemManager
gains the one lot-minting path (CreateLot/CreateInstance(int)), GetLot,
and Brand(), which derives a maker and product from provenance instead
of a stored field. RunSave persists the ledger pruned to what the saved
zones' entities still reach; the live ledger is never pruned, so a
floor pickup collected after a save still resolves. CopyBuild is gone:
matching hardpoints now share the same lot instead of copying values.
PropertiesPanel shows the derived brand where the design's manufacturer
used to be. AetherDb's census flags duplicate (maker, design) products
and its save command checks every crafted instance's lot against a real
run store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 04:16:23 +02:00
Meta Vens
69801bbb2c Delete the re-mint path and the dead debug menu
Cut A of docs/item-provenance-cut.md. TradeMenuDebug.cs was dead (its
script GUID appears in no scene/prefab/asset and no other .cs names the
type). ItemManager.Instantiate and CreateInstance(SimpleCommodityData,
int) re-rolled quality and dropped provenance on every load; nothing
outside EntitySerializer called them once the instantiate parameter is
gone. EntitySerializer.Unpack/Restore no longer thread an instantiate
flag, so Temperature and Armor are restored unconditionally like every
other caller already got. The starting ship and spawnturret now keep
what the generator built instead of re-minting.

Verification: Aetheria.Shared, tools/AetherDb build green against
CultLib a0813c6; tests/Aetheria.Shared.Tests 29 passed (unchanged); the
four negative greps in the map are empty. Unity compile is still owed
(the editor is open on this project; batchmode was not run per
instructions).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:42:12 +02:00
Meta Vens
d503f076e1 Capture presets through their own cache; keep the catalog read-only
Opening the process cache's catalog writable in the editor was the wrong cut.
It made catalog read-only only by convention, so a stray catalog write in play
succeeded and a later flush could land play-mutated instances in Aetheria.cc.

- The process cache opens the catalog read-only in every build again, so the
  missing-global check runs for it as it did before db83cd29. The writable
  empty-seed exemption from ab4ced0f stays for AetherDb and fixtures.
- Loadouts.Commit(catalogPath, loadout, replace) is the only preset writer. It
  opens its own short-lived cache over the catalog, writable, commits the one
  preset conditionally on its key and disposes it. No other cache or instance
  is touched. The running game sees the preset only after the catalog reloads.
  CultLib at a0813c6 allows this: a read-only single-file store takes no lock
  and holds no handle, and the writer's commit takes the exclusive sidecar
  <path>.lock and replaces the file atomically.
- Capture refuses, writing nothing, when Aetheria.cc is missing (it never
  creates the catalog), when a preset of that name exists under another key
  (CultCache does not reject duplicate names on write), or when the key holds a
  preset and replace is not given.
- The console refuses a command with any character outside letters, digits,
  spaces and hyphens instead of stripping it, so "Mk.II" can no longer become
  "MkII". capturepreset refuses a second argument other than replace, so an
  unquoted capturepreset My Ship refuses instead of saving "My".
- The capture log line says the session sees the preset after a reload, and
  that a Studio session opened earlier overwrites captured presets on save.
- Tests: capture while the process cache holds the catalog read-only leaves it
  unchanged; a missing catalog refuses and creates nothing; a same name under a
  Studio-minted key refuses, with or without replace; a game-shaped read-only
  open missing a global throws. The existing preset tests now commit through
  the catalog path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:32:52 +02:00
Meta Vens
db83cd290d Make loadouts authored catalog presets with an editor capture command
Loadouts are ship presets (variants) for spawners, not a player feature.

- Route Loadout to the catalog; the player store no longer holds it.
- Materialize takes no credits: affordability, the charge and Loadouts.Price
  are deleted, since only the player menu priced loadouts. Availability,
  key-order product choice, all-or-nothing failures and the weapon-group
  rules stay.
- Delete the InventoryPanel Save Loadout and Restore Loadout entries and
  RestoreLoadout, which also removes its docking-bay overwrite.
- The editor opens the catalog writable in the one process cache, and the
  editor-only console command capturepreset "<name>" [replace] captures the
  piloted ship. Loadouts.Commit keys a preset by name, refuses a same-name
  replace unless asked, and commits conditionally on that key. The single-file
  store then lands only that record onto the file as it is on disk. An
  unconditional commit would re-serialize every live catalog instance,
  including any that play has mutated.
- Tests: capture -> commit -> fresh reopen round-trip, explicit replace with
  no duplicate, and a preset commit that does not persist a mutated live
  Faction. The money-only tests are removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:09:43 +02:00
Meta Vens
95e164adce Land RunSave and the one-cache run and player lifecycle (Cut 10)
Owner: ActionGameManager composes the process's one cache. Its CultCache
getter attaches the catalog, GameData/run.cc and GameData/player.cc on
first access, in either scene, and nothing reopens it.

- RunSave (SavedGame.cs) replaces the SavedGame constructor:
  - Capture builds the live run as plain documents and writes nothing. Zone
    contents are `zone.Contents?.PackZone() ?? zone.PackedContents`, so a
    zone generated earlier but not loaded this session keeps its contents
    and its orbit and body records instead of being erased by the next save.
  - Commit is the only writer of SavedGame and SavedZone: one Commit with
    zone i at `savedzone-{i}`, SavedGame.Zones set to those refs, and every
    stored SavedZone outside that set removed. Orbits and bodies staged by
    zone generation land in the same single-file write.
  - Clear removes every run record in one Commit.
- Run begins: New Game's first statement is RunSave.Clear. Run saves:
  ActionGameManager.SaveRun at wormhole arrival and quit. Run ends: Die
  clears the run, then saves settings.
- Run exists only as the run store's SavedGame global: MainMenu enables
  Continue from it (and logs when the run store holds records but no
  SavedGame), and StartGame reads it once to pick the new-run or resume
  branch.
- PlayerSettings: the getter returns the player store's global and, on
  first launch, commits GetDefaultPlayerSettings; it is the only creator.
  SavePlayerSettings commits the instance.
- InputDisplayLayout reads its InputLayout from the catalog by the layout
  asset's name and throws when the catalog has none.

Tests: new RunSaveTests (5): RepeatedSavesKeepRecordCountConstant,
SaveRemovesZonesNoLongerInTheRun, SaveWritesOnlyTheRunStore,
ResumeThenSaveKeepsUnloadedZoneContents, ClearRemovesEveryRunRecord. Each
fails with its rule mutated out.

Builds: headless, 11 tests pass, Unity batchmode compile reports no error CS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:00:27 +02:00
Meta Vens
5c5c3d5e19 Delete the old run, settings, layout and loadout authorities (Cut 10)
The deletion line lands before RunSave, as the spec orders. Deleted, not
demoted:
- PlayerSettings.SavedRun (Key 1 stays unclaimed) and the SavedGame
  constructor that upserted a fresh SavedZone per zone on every save.
- ActionGameManager: the PlayerSettings.msgpack getter, file path and
  writer; the .loadout format (_loadoutPath, Loadouts, SaveLoadout and its
  default-options serializer, the commented loader); OnApplicationQuit and
  SaveState; SaveZone, which had no caller.
- MainMenu's SavedRun Continue branch and both `SavedRun = null` writes.
- InventoryPanel's Save Loadout and Restore Loadout bodies.
- InputDisplayLayout's KeyboardLayouts file reader, ParseJson,
  AssociateInputKeys, SaveLayout and the usings they alone needed.
- AetherDb's Cut 9 importer (Import.cs, legacy-census, import).
- The three-gates note on loading writes; Cut 3 made loading non-writing.
- .gitignore ignores GameData/run.cc and GameData/player.cc instead of
  PlayerSettings.msgpack.

DOES NOT BUILD in Unity: ActionGameManager, MainMenu and InputDisplayLayout
still reference the deleted members until the next commit wires RunSave,
the settings getter and the catalog layout read. Headless builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:51:10 +02:00
Meta Vens
9bdf6ef23f Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.

Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.

The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
  writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
  value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
  drew the item's schematic texture and tinted hull hardpoints, which need
  the parent document. The tagged Studio hands a drawer only the value, so
  those wait on the Studio exposing the open record.

Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
  the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
  belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
  CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
  reaches CultMath values and refs. Keyboard layouts need no resolver and
  keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.

Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
Meta Vens
2281793154 Convert engine types through CultMath.UnityBridge
CultMath has no implicit conversions to or from Vector*, Quaternion or
Color, so Assembly-CSharp converts explicitly with ToCultMath/ToUnity at
each engine boundary: FieldDriver, GuidedProjectile(Manager),
EntityInstance, ActionGameManager, HullCollider, GridObject, ShipInstance,
ShieldManager, ItemPickup, FieldTester, PlaceUIElementWorldspace,
MapMenuInput, MapRenderer, SectorRenderer and ZoneRenderer. CultMath math
calls that were handed Unity vectors now take converted values;
Vector3.Scale in FieldDriver becomes a float3 product, and ItemPickup's
Vector3.Dot on float3s becomes dot. packages-lock.json records the
cultmath git package at f0605367 and demotes com.unity.mathematics to a
transitive dependency.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:47:33 +02:00
Meta Vens
6140a06a0a Swap Unity.Mathematics usings for CultMath
Every Unity.Mathematics using, alias and qualified name under Assets\Scripts
and tools now names CultMath. The nine `using static ...noise;` lines are
gone: snoise lives on CultMath's math. UnityExtensions loses float4.ToColor
and Color.ToFloat4, which duplicate the bridge's ToColor and ToCultMath; the
float3 colour pair stays because the bridge has none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:39:12 +02:00
Meta Vens
3dcfaf9783 Delete commented-out code blocks
Git keeps the history. SimpleCommodityData records its retired
MessagePack keys so they are not reused against old data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 22:14:58 +02:00
Meta Vens
f568a7d14f Cut RethinkDB
Remove the vendored RethinkDb driver and its Linq provider, the Rethink
backing store, the already-stubbed RethinkConnection, the Rethink test
window, and the Rethink-only Remotion.Linq and Logging.Abstractions DLLs.
The database editor now works only on GameData/AetherDB.msgpack, with a
Save button replacing the dead Connect UI and broken JSON export.
RethinkTable becomes DatabaseCategory, which only groups editor entries.

Economy.Server still references Rethink; it was already unbuildable and
is handled separately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 21:48:45 +02:00