304ee8c2a7
Portal-gated rooms: new RunLifecycle.RoomExplore loot window; room+nodes persist past the last kill; PortalInteractRequest -> server-only PortalCommand advances (client derives the portal pos). RunDirectorSystem moves teardown off the InRoom edge, relocates the boss-branch/route-gate into the RoomExplore exit, and advances an empty expedition immediately (incl. a boss clear). Class-at-base via a shared ClassSwapUtil (meta-band strip + per-class MetaTierState replay, so the base RPC and the dev SetClass can't drift); ClassSelectRequest Staging-gated. Per-run PREP buffs (PrepPurchaseRequest, PrepCatalog): once-per-run == the row's prep StatModifier band is present, TotalOf-before-Withdraw atomic, stripped on Returning beside the boon band. Health.Max promoted to [GhostField] (the one ghost-hash re-bake) so the boss + floating enemy HP bars read it directly. Feel: melee cone connect-thunk (C3), hit-stop throttle so a horde wipe can't stutter (C4), Spitter cornered-hold. 456/456 EditMode; two adversarial reviews (pre-code 13-confirmed folded; post-impl clean bar the RoomExplore boss-clear dead-time, fixed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
2.1 KiB
C#
43 lines
2.1 KiB
C#
namespace ProjectM.Simulation
|
|
{
|
|
/// <summary>One base "prep loadout" option: spend a base resource before launch for a RUN-SCOPED stat buff
|
|
/// (stripped on the Returning edge like a boon). Mechanical fields only — the HUD supplies display labels.</summary>
|
|
public struct PrepRow
|
|
{
|
|
public byte Id;
|
|
public byte CostResId; // ResourceId.*
|
|
public int Cost;
|
|
public byte Target; // StatTarget
|
|
public byte Op; // ModOp
|
|
public float Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The base PREP-LOADOUT catalog (DR-046): the player funds each run's power from base resources at Staging. A
|
|
/// purchase appends ONE run-scoped <see cref="StatModifier"/> in the prep SourceId band
|
|
/// (<see cref="Tuning.PrepSourceIdBase"/> + Id), which <see cref="Server"/>'s PrepPurchaseSystem gates once-per-run
|
|
/// by that SourceId's PRESENCE (its lifetime == the band, stripped on Returning — so it re-buys next run for free,
|
|
/// no separate latch). A plain managed static table (read by the non-Burst receiver + the managed HUD).
|
|
/// </summary>
|
|
public static class PrepCatalog
|
|
{
|
|
public static readonly PrepRow[] Rows =
|
|
{
|
|
new PrepRow { Id = 0, CostResId = ResourceId.Ore, Cost = 30, Target = (byte)StatTarget.MaxHealth, Op = (byte)ModOp.Flat, Value = 30f },
|
|
new PrepRow { Id = 1, CostResId = ResourceId.Biomass, Cost = 40, Target = (byte)StatTarget.MoveSpeed, Op = (byte)ModOp.PercentMult, Value = 0.12f },
|
|
new PrepRow { Id = 2, CostResId = ResourceId.Aether, Cost = 25, Target = (byte)StatTarget.MeleeDamage, Op = (byte)ModOp.PercentMult, Value = 0.20f },
|
|
new PrepRow { Id = 3, CostResId = ResourceId.Aether, Cost = 25, Target = (byte)StatTarget.Damage, Op = (byte)ModOp.PercentMult, Value = 0.20f },
|
|
};
|
|
|
|
public static int Count => Rows.Length;
|
|
|
|
public static bool TryGet(byte id, out PrepRow row)
|
|
{
|
|
for (int i = 0; i < Rows.Length; i++)
|
|
if (Rows[i].Id == id) { row = Rows[i]; return true; }
|
|
row = default;
|
|
return false;
|
|
}
|
|
}
|
|
}
|