LANTERN purge B3+B5: delete the cycle/core/win-lose spine + onboarding; save epoch v7

Deletes CyclePhaseSystem, GoalReachedSystem, CoreDamage/CoreRestore, ThreatDirector,
CoreIntegrity/GoalProgress/RunPhase/RunOutcome/ThreatState components,
CoreVisualFeedbackSystem, and the whole Client/Onboarding slice (+6 test files).

Keepers reworked: RunDirectorSystem (UpdateBefore attr + launch guard + goal/threat
bank removed; sole SaveRequest raiser now), CycleDirectorSpawnSystem (ledger/meta
host only), WaveSystem UNGATED (waves run wherever a WaveDirector is baked),
EnemyAISystem core-fallback stripped, AmbientAudioSystem reworked (bed + run cues;
no CycleState gate), MusicSystem RunInfo-only, HudSystem big trim (goal meter, core
bar, siege banner, terminal banner, outcome flash, onboarding hook all gone),
MetaShop/ClassPrep/AimReticle siege gates dropped, DebugOverlay/ops re-meant
(SpawnWave=force next wave, EndSiege=quiet arena; SetCalm/AdvanceGoal/SetHeat
retired, bytes reserved), TuningConfig Core knobs retired (ids 20-23 reserved),
StorageMath.DrainFraction deleted, HowToPlay copy rewritten.

Save epoch v7 (fresh epoch, operator-approved): SaveData drops goal/core/outcome +
conveyor/machine-IO fields; MinLoadableVersion=7; PendingSave/PendingStructure
trimmed; RollTerminalCampaignForward deleted; SaveStructureScan signature slimmed.

390 tests green; Play world-creation clean (player + waves live, no exceptions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 15:27:12 -07:00
parent 835dace213
commit b34945c2d2
74 changed files with 233 additions and 3955 deletions
@@ -25,17 +25,17 @@ namespace ProjectM.Simulation
/// <summary>Opcodes for <see cref="DebugCommandRequest.Op"/> (bytes — never an enum on the wire).</summary>
public static class DebugOp
{
/// <summary>Arm + immediately fire a siege of ArgA Husks (ArgA = size).</summary>
/// <summary>Force the NEXT wave to start this tick (re-meant from the old arm-a-siege op; args unused).</summary>
public const byte SpawnWave = 0;
/// <summary>Collapse the current siege (cull Husks, stop spawning, clear pending) -> back to Calm.</summary>
/// <summary>Quiet the arena: cull Husks + push the next wave ~1 h out (re-meant from the old end-siege op).</summary>
public const byte EndSiege = 1;
/// <summary>Cull every living Husk now (leaves the phase alone).</summary>
/// <summary>Cull every living Husk now (leaves wave state alone).</summary>
public const byte ClearEnemies = 2;
/// <summary>Hard-reset the run-state to Calm (clears any siege/pending).</summary>
public const byte SetCalm = 3;
// RETIRED (LANTERN purge — keep the byte values reserved, never renumber a wire byte):
// 3 = SetCalm · 10 = AdvanceGoal · 11 = SetHeat
/// <summary>Deposit ArgB of resource ArgA (a <see cref="ResourceId"/>) into the shared ledger.</summary>
public const byte GrantResource = 4;
@@ -55,11 +55,6 @@ namespace ProjectM.Simulation
/// <summary>Kill the sender (Health -> 0; the normal death/respawn loop takes over).</summary>
public const byte KillPlayer = 9;
/// <summary>Add ArgA to the long-arc goal charge.</summary>
public const byte AdvanceGoal = 10;
/// <summary>Set ThreatState.Heat to ArgA (inert until the Heat source ships).</summary>
public const byte SetHeat = 11;
/// <summary>Set the <see cref="TuningKnob"/> ArgA to ArgB/1000f (live dash/Charger feel-tuning; MC-0).</summary>
public const byte SetTuning = 12;
@@ -50,16 +50,6 @@ namespace ProjectM.Simulation
// preferred targets); a closer player 'in the way' still wins. Read server-side by EnemyAISystem.
public float StructureAggroWeight;
// END-1 Engine Core (live feel knobs; read server-side by CoreDamageSystem/CoreRestoreSystem/CyclePhaseSystem).
// CoreDamagePerHusk + CoreOverrunDrainPct are value knobs (>=0); CoreRegenIntervalTicks is a tick knob (>=1).
public float CoreDamagePerHusk; // integrity drained by one breaching Husk (~5 unintercepted = serious dent)
public float CoreRegenIntervalTicks; // ticks between +1 regen in Calm (18 -> +1/0.3s -> ~full over one short Calm)
public float CoreOverrunDrainPct; // fraction (0..1) of the shared ledger lost on a breach (soft-loss penalty)
// END-2 final siege: the would-be-next normal siege size is multiplied by this for the FINAL siege so the
// climax reads visibly larger. Floors at 1 (the default ClampKnob bucket) — a final siege is never smaller
// than a normal one; GoalReachedSystem also math.max(1, ...) at the use-site.
public float FinalSiegeMultiplier;
// Phase 1 B1/B2 (design review wf_fd177263): poise threshold on the EXISTING KnockbackState.Speed channel
// (light melee 6 nudges; finisher 6x1.8=10.8 and cone 8 stagger), and the separation pass's push-speed cap.
@@ -89,10 +79,6 @@ namespace ProjectM.Simulation
MeleeFinisherMult = 1.8f, // finisher (last hit) scales dmg/range/recover/knockback
MeleeComboLength = 3f, // light, light, finisher
StructureAggroWeight = 0.7f, // EB-1: <1 prefers structures (fortress aggro); live-tunable
CoreDamagePerHusk = 10f, // END-1: 10 breaching Husks = full loss; ~5 = a serious dent
CoreRegenIntervalTicks = 18f, // END-1: +1 integrity / 0.3s in Calm (~30s to refill 100 from 0)
CoreOverrunDrainPct = 0.5f, // END-1: a breach costs half the shared ledger (soft-loss penalty)
FinalSiegeMultiplier = 2.5f, // END-2: the final siege is ~2.5x the would-be-next normal siege
StaggerKnockbackSpeed = 7f, // B2 poise: kb.Speed >= this interrupts windups/lunges; below = nudge only
SeparationMaxSpeed = 3f, // B1: max separation push (units/s) so soft-collision can't fling
};
@@ -114,8 +100,6 @@ namespace ProjectM.Simulation
case TuningKnob.MeleeKnockbackSpeed:
case TuningKnob.MeleeFinisherMult:
case TuningKnob.StructureAggroWeight:
case TuningKnob.CoreDamagePerHusk:
case TuningKnob.CoreOverrunDrainPct:
case TuningKnob.StaggerKnockbackSpeed:
case TuningKnob.SeparationMaxSpeed:
return math.max(0f, value);
@@ -152,10 +136,6 @@ namespace ProjectM.Simulation
case TuningKnob.MeleeFinisherMult: c.MeleeFinisherMult = value; break;
case TuningKnob.MeleeComboLength: c.MeleeComboLength = value; break;
case TuningKnob.StructureAggroWeight: c.StructureAggroWeight = value; break;
case TuningKnob.CoreDamagePerHusk: c.CoreDamagePerHusk = value; break;
case TuningKnob.CoreRegenIntervalTicks: c.CoreRegenIntervalTicks = value; break;
case TuningKnob.CoreOverrunDrainPct: c.CoreOverrunDrainPct = value; break;
case TuningKnob.FinalSiegeMultiplier: c.FinalSiegeMultiplier = value; break;
case TuningKnob.StaggerKnockbackSpeed: c.StaggerKnockbackSpeed = value; break;
case TuningKnob.SeparationMaxSpeed: c.SeparationMaxSpeed = value; break;
// unknown index -> no-op (matches the no-default switch convention in DebugCommandReceiveSystem)
@@ -187,10 +167,6 @@ namespace ProjectM.Simulation
case TuningKnob.MeleeFinisherMult: return c.MeleeFinisherMult;
case TuningKnob.MeleeComboLength: return c.MeleeComboLength;
case TuningKnob.StructureAggroWeight: return c.StructureAggroWeight;
case TuningKnob.CoreDamagePerHusk: return c.CoreDamagePerHusk;
case TuningKnob.CoreRegenIntervalTicks: return c.CoreRegenIntervalTicks;
case TuningKnob.CoreOverrunDrainPct: return c.CoreOverrunDrainPct;
case TuningKnob.FinalSiegeMultiplier: return c.FinalSiegeMultiplier;
case TuningKnob.StaggerKnockbackSpeed: return c.StaggerKnockbackSpeed;
case TuningKnob.SeparationMaxSpeed: return c.SeparationMaxSpeed;
default: return 0f;
@@ -220,10 +196,6 @@ namespace ProjectM.Simulation
MeleeFinisherMult = c.MeleeFinisherMult,
MeleeComboLength = c.MeleeComboLength,
StructureAggroWeight = c.StructureAggroWeight,
CoreDamagePerHusk = c.CoreDamagePerHusk,
CoreRegenIntervalTicks = c.CoreRegenIntervalTicks,
CoreOverrunDrainPct = c.CoreOverrunDrainPct,
FinalSiegeMultiplier = c.FinalSiegeMultiplier,
StaggerKnockbackSpeed = c.StaggerKnockbackSpeed,
SeparationMaxSpeed = c.SeparationMaxSpeed,
};
@@ -251,10 +223,6 @@ namespace ProjectM.Simulation
MeleeFinisherMult = r.MeleeFinisherMult,
MeleeComboLength = r.MeleeComboLength,
StructureAggroWeight = r.StructureAggroWeight,
CoreDamagePerHusk = r.CoreDamagePerHusk,
CoreRegenIntervalTicks = r.CoreRegenIntervalTicks,
CoreOverrunDrainPct = r.CoreOverrunDrainPct,
FinalSiegeMultiplier = r.FinalSiegeMultiplier,
StaggerKnockbackSpeed = r.StaggerKnockbackSpeed,
SeparationMaxSpeed = r.SeparationMaxSpeed,
};
@@ -283,10 +251,8 @@ namespace ProjectM.Simulation
public const byte MeleeFinisherMult = 17;
public const byte MeleeComboLength = 18;
public const byte StructureAggroWeight = 19;
public const byte CoreDamagePerHusk = 20;
public const byte CoreRegenIntervalTicks = 21;
public const byte CoreOverrunDrainPct = 22;
public const byte FinalSiegeMultiplier = 23;
// RETIRED knob ids (LANTERN purge — keep 20-23 reserved, never renumber):
// 20 = CoreDamagePerHusk · 21 = CoreRegenIntervalTicks · 22 = CoreOverrunDrainPct · 23 = FinalSiegeMultiplier
public const byte StaggerKnockbackSpeed = 24;
public const byte SeparationMaxSpeed = 25;
@@ -322,10 +288,6 @@ namespace ProjectM.Simulation
public float MeleeFinisherMult;
public float MeleeComboLength;
public float StructureAggroWeight;
public float CoreDamagePerHusk;
public float CoreRegenIntervalTicks;
public float CoreOverrunDrainPct;
public float FinalSiegeMultiplier;
public float StaggerKnockbackSpeed;
public float SeparationMaxSpeed;
}