Retune the case ramp, and let leading a phase earn experience

The ramp made every phase after the first Difficult (halving the lead's skill) and
stacked a cumulative -5% on top. Separated in phaseRampFor() in rules.mjs:
difficulty belongs to the phase (only Containment is Difficult, and it does not
also ramp), the modifier is attrition (-5 a phase, capped at -15).

  lead 55%   was 55 -> 22 -> 17 -> 12 -> 7      now 55 -> 50 -> 45 -> 27 -> 40

Over 20,000 simulated cases with destitution modelled, phases passed roughly
double and destitution incidence roughly halves.

R-222: resolveLegDialog passed no skillFamilyId, so the choke point could not
resolve the skill item and leading a phase never earned a tick — Tradecraft, the
skill the job most uses, could never improve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
slaguru666
2026-08-10 21:12:04 +01:00
co-authored by Claude Opus 5
parent 1a0bdbd2df
commit 1b44fccb79
31 changed files with 171 additions and 82 deletions
+29
View File
@@ -368,6 +368,35 @@ export function defencePenaltyFor(defencesUsed = 0) {
return DEFENCE_STEP * Math.max(0, Number(defencesUsed) || 0);
}
/**
* HOW HARD A CASE PHASE IS.
*
* The old ramp made every phase after the first Difficult — which HALVES the lead's
* skill — and then stacked a cumulative −5% on top. Measured across two played
* cases, a realistic lead of 40–55% (Tradecraft is a support skill on most postings
* that train it at all) faced 20% → 15% → 10% → 5% → 1%, and both cases were decided
* by Resources running out rather than by anything the players did.
*
* The two pressures are now separated, because they were never the same idea:
*
* DIFFICULTY is about the phase. Only Containment is Difficult — the step the case
* is actually about — and it does not also take the ramp. It is hard because it is
* containment, not because you are tired.
*
* The MODIFIER is about attrition. It accumulates as the case wears on, and it
* stops accumulating, because a fifth phase is not four times worse than a second.
*/
export const PHASE_RAMP = { step: -5, cap: -15, hardKinds: ["containment"] };
export function phaseRampFor(index, kindId = "") {
const hard = PHASE_RAMP.hardKinds.includes(String(kindId));
return {
difficulty: hard ? "difficult" : "average",
// A hard phase carries its difficulty INSTEAD of the ramp, never both.
modifier: hard ? 0 : Math.max(PHASE_RAMP.cap, PHASE_RAMP.step * (Number(index) || 0))
};
}
/* -------------------------------------------- */
/* Borrowed Authority */
/* -------------------------------------------- */