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>
This commit is contained in:
2026-06-12 19:14:52 -07:00
parent e04cdea44f
commit 2da29783fd
10 changed files with 94 additions and 28 deletions
@@ -6,19 +6,23 @@ namespace ProjectM.Authoring
{
/// <summary>
/// Authoring for a Fabricator machine ghost prefab. Bakes <see cref="PlacedStructure"/>{Type=Fabricator} +
/// <see cref="Fabricator"/> recipe + an empty <see cref="MachineInput"/> buffer (a conveyor fills it; the
/// fabricator deposits its output directly into the GLOBAL ledger, so it needs no output buffer). Default
/// recipe: 2 Ore -> 1 Aether (both existing resources — the "auto-gather existing resources" terminal).
/// <see cref="Fabricator"/> recipe + a (kept) empty <see cref="MachineInput"/> buffer — the production query
/// needs the buffer as a column, but a ledger-fed Fabricator ignores it. It deposits its output directly into
/// the GLOBAL ledger, so it needs no output buffer. Default recipe (EB-2): 1 Ore -> 3 Charge, ledger-fed
/// (<see cref="Fabricator.InputFromLedger"/> != 0) — mints the turret-ammo Charge that <c>TurretFireSystem</c>
/// spends per shot.
/// </summary>
public class FabricatorAuthoring : MonoBehaviour
{
[Tooltip("Input resource id consumed per run (1=Aether, 2=Ore, 3=Biomass).")]
public byte InResourceId = 2; // Ore
[Min(1)] public int InAmount = 2;
[Tooltip("Output resource id deposited to the global ledger.")]
public byte OutResourceId = 1; // Aether
[Min(1)] public int OutAmount = 1;
[Min(1)] public int PeriodTicks = 90;
[Min(1)] public int InAmount = 1;
[Tooltip("Output resource id deposited to the global ledger (4 = EB-2 Charge / turret ammo).")]
public byte OutResourceId = 4; // Charge
[Min(1)] public int OutAmount = 3;
[Min(1)] public int PeriodTicks = 30;
[Tooltip("EB-2: 1 = ledger-fed (consume the input from the shared ledger; no conveyor). 0 = M7 MachineInput chain.")]
public byte InputFromLedger = 1;
private class FabricatorBaker : Baker<FabricatorAuthoring>
{
@@ -39,6 +43,7 @@ namespace ProjectM.Authoring
OutResourceId = authoring.OutResourceId,
OutAmount = authoring.OutAmount,
PeriodTicks = authoring.PeriodTicks,
InputFromLedger = authoring.InputFromLedger,
});
AddBuffer<MachineInput>(entity);
}