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
@@ -6,13 +6,12 @@ using UnityEngine;
namespace ProjectM.Client
{
/// <summary>
/// Client-only AMBIENT audio + cycle-phase stingers. A managed presentation <see cref="SystemBase"/>
/// (<see cref="PresentationSystemGroup"/>, main thread, no Burst) that OBSERVES the replicated
/// <see cref="CycleState"/> and never touches the simulation. On start it plays a low, seamless-looping
/// procedural drone (asset-free, <c>AudioClip.Create</c> like <c>CombatFeedbackSystem.MakeClip</c>); each
/// time the cycle phase changes it plays a short procedural stinger and eases the drone's intensity by phase
/// (calmer at base, tenser during Defend / "wave incoming"). Lives only in the client world, so the server
/// never creates audio and nothing here affects determinism. Volumes are deliberately conservative + tunable.
/// Client-only AMBIENT audio bed + run cues. A managed presentation <see cref="SystemBase"/>
/// (<see cref="PresentationSystemGroup"/>, main thread, no Burst) that plays a low, seamless-looping
/// procedural drone (asset-free, <c>AudioClip.Create</c> like <c>CombatFeedbackSystem.MakeClip</c>) plus
/// launch-countdown beeps and the boss-arrival roar — replicated-state observations only. Lives only in the
/// client world, so the server never creates audio and nothing here affects determinism. Volumes are
/// deliberately conservative. (The cycle-phase stingers + Core alarm retired with the siege loop — LANTERN purge.)
/// </summary>
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
[UpdateInGroup(typeof(PresentationSystemGroup))]
@@ -20,29 +19,17 @@ namespace ProjectM.Client
{
AudioSource _ambient;
AudioClip _ambientClip;
AudioClip _stingExpedition;
AudioClip _stingDefend;
AudioClip _stingBuild;
GameObject _root;
byte _lastPhase;
bool _phaseInit;
AudioClip _stingCoreHit;
int _lastCore = -1;
float _coreStingCooldown;
AudioClip _stingBeep, _stingRoar;
int _lastCountdownSec = -1;
bool _bossRoared;
const float AmbientBaseVolume = 0.10f; // low bed; Defend eases up to ~1.7x
const float AmbientBaseVolume = 0.10f; // low ambient bed
protected override void OnCreate()
{
_ambientClip = MakeDrone();
_stingExpedition = MakeSting(520f, 880f, 0.45f, 0.30f); // airy rising "deploy"
_stingDefend = MakeSting(300f, 140f, 0.55f, 0.42f); // tense falling "wave incoming"
_stingBuild = MakeSting(440f, 660f, 0.40f, 0.26f); // soft confirm
_stingCoreHit = MakeSting(240f, 70f, 0.30f, 0.55f); // harsh falling "Core hit" alarm
_stingBeep = MakeSting(880f, 880f, 0.09f, 0.30f); // countdown tick
_stingRoar = MakeSting(90f, 38f, 0.90f, 0.60f); // boss-arrival roar (low falling growl)
}
@@ -68,36 +55,8 @@ namespace ProjectM.Client
protected override void OnUpdate()
{
if (_ambient == null) return;
if (!SystemAPI.TryGetSingleton<CycleState>(out var cyc)) return;
byte phase = cyc.Phase;
if (!_phaseInit)
{
_lastPhase = phase; // adopt the current phase silently (no stinger on first observe)
_phaseInit = true;
}
else if (phase != _lastPhase)
{
PlaySting(phase);
_lastPhase = phase;
}
// Ease the drone intensity toward the phase target (tenser during Defend).
float target = phase == CyclePhase.Siege ? AmbientBaseVolume * 1.7f : AmbientBaseVolume;
_ambient.volume = Mathf.MoveTowards(_ambient.volume, target * GameVolume.Music, SystemAPI.Time.DeltaTime * 0.25f);
// Core-under-attack alarm: a falling sting on each CoreIntegrity drop (rate-limited) so a base
// breach is AUDIBLE even when the fight has the player's eyes elsewhere.
_coreStingCooldown -= SystemAPI.Time.DeltaTime;
if (SystemAPI.TryGetSingleton<CoreIntegrity>(out var core))
{
if (_lastCore >= 0 && core.Current < _lastCore && _coreStingCooldown <= 0f)
{
_ambient.PlayOneShot(_stingCoreHit, 0.8f * GameVolume.Sfx);
_coreStingCooldown = 0.7f;
}
_lastCore = core.Current;
}
_ambient.volume = Mathf.MoveTowards(_ambient.volume, AmbientBaseVolume * GameVolume.Music, SystemAPI.Time.DeltaTime * 0.25f);
// Launch countdown beeps (3-2-1) + the boss-arrival roar — replicated-state observations only.
if (SystemAPI.TryGetSingleton<RunInfo>(out var runAudio))
@@ -131,13 +90,6 @@ namespace ProjectM.Client
}
}
void PlaySting(byte phase)
{
AudioClip clip = phase == CyclePhase.Siege ? _stingDefend : _stingBuild;
if (clip != null && _ambient != null)
_ambient.PlayOneShot(clip, 0.6f * GameVolume.Music);
}
// ---- Procedural audio (asset-free; mirrors CombatFeedbackSystem.MakeClip) ----
// A low, seamless-looping pad: each partial completes an integer number of cycles over the buffer
@@ -176,6 +128,6 @@ namespace ProjectM.Client
}
// Short one-shot tone sweeping f0->f1 with an exponential decay envelope.
static AudioClip MakeSting(float f0, float f1, float dur, float vol) => FeedbackFx.MakeClip("sting", f0, f1, dur, vol, decay: 3.5f);
static AudioClip MakeSting(float f0, float f1, float dur, float vol) => FeedbackFx.MakeClip("sting", f0, f1, dur, vol, decay: 3.5f);
}
}