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>
This commit is contained in:
@@ -50,6 +50,12 @@ 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)
|
||||
|
||||
/// <summary>The baked feel defaults == the pre-MC-0 consts. Single source of truth for the fallback path.</summary>
|
||||
public static TuningConfig Defaults() => new TuningConfig
|
||||
{
|
||||
@@ -73,6 +79,9 @@ 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)
|
||||
};
|
||||
|
||||
/// <summary>Clamp a knob to its safe floor: tick knobs >= 1, value knobs >= 0. Used by every write path
|
||||
@@ -92,6 +101,8 @@ namespace ProjectM.Simulation
|
||||
case TuningKnob.MeleeKnockbackSpeed:
|
||||
case TuningKnob.MeleeFinisherMult:
|
||||
case TuningKnob.StructureAggroWeight:
|
||||
case TuningKnob.CoreDamagePerHusk:
|
||||
case TuningKnob.CoreOverrunDrainPct:
|
||||
return math.max(0f, value);
|
||||
// tick knobs: >= 1 (a 0 tick count is degenerate; a 0 i-frame window divides-by-zero in DashSystem)
|
||||
default:
|
||||
@@ -125,6 +136,9 @@ 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;
|
||||
// unknown index -> no-op (matches the no-default switch convention in DebugCommandReceiveSystem)
|
||||
}
|
||||
}
|
||||
@@ -154,6 +168,9 @@ 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;
|
||||
default: return 0f;
|
||||
}
|
||||
}
|
||||
@@ -181,6 +198,9 @@ namespace ProjectM.Simulation
|
||||
MeleeFinisherMult = c.MeleeFinisherMult,
|
||||
MeleeComboLength = c.MeleeComboLength,
|
||||
StructureAggroWeight = c.StructureAggroWeight,
|
||||
CoreDamagePerHusk = c.CoreDamagePerHusk,
|
||||
CoreRegenIntervalTicks = c.CoreRegenIntervalTicks,
|
||||
CoreOverrunDrainPct = c.CoreOverrunDrainPct,
|
||||
};
|
||||
|
||||
/// <summary>Reconstruct the full config from a wire snapshot (FULL state, not a delta).</summary>
|
||||
@@ -206,6 +226,9 @@ namespace ProjectM.Simulation
|
||||
MeleeFinisherMult = r.MeleeFinisherMult,
|
||||
MeleeComboLength = r.MeleeComboLength,
|
||||
StructureAggroWeight = r.StructureAggroWeight,
|
||||
CoreDamagePerHusk = r.CoreDamagePerHusk,
|
||||
CoreRegenIntervalTicks = r.CoreRegenIntervalTicks,
|
||||
CoreOverrunDrainPct = r.CoreOverrunDrainPct,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -232,9 +255,12 @@ 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;
|
||||
|
||||
/// <summary>Knob count (overlay iteration bound).</summary>
|
||||
public const byte Count = 20;
|
||||
public const byte Count = 23;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,5 +291,8 @@ namespace ProjectM.Simulation
|
||||
public float MeleeFinisherMult;
|
||||
public float MeleeComboLength;
|
||||
public float StructureAggroWeight;
|
||||
public float CoreDamagePerHusk;
|
||||
public float CoreRegenIntervalTicks;
|
||||
public float CoreOverrunDrainPct;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user