diff --git a/docs/REVIEW_LOG.md b/docs/REVIEW_LOG.md index 357c248..91b6b7f 100644 --- a/docs/REVIEW_LOG.md +++ b/docs/REVIEW_LOG.md @@ -3717,3 +3717,49 @@ players did. This is a design decision rather than a defect — a case is meant survived rather than won — but if phases are supposed to be passable, the ramp (−5 per phase, on top of `difficult`) is the dial, not `DEFENCE_STEP` and not the skill ratings. + +## The case ramp, retuned + +The old ramp made every phase after the first Difficult — which HALVES the lead's +skill — and then stacked a cumulative −5% on top of that. The two pressures were +never the same idea, and they are now separated in `phaseRampFor(index, kindId)` in +`rules.mjs`, with six spot-checks: + +- **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 attrition.** −5 per phase, capped at −15, because a fifth phase is + not four times worse than a second. + +``` + was now +lead 40% 40 → 15 → 10 → 5 → 1 40 → 35 → 30 → 20 → 25 +lead 55% 55 → 22 → 17 → 12 → 7 55 → 50 → 45 → 27 → 40 +lead 70% 70 → 30 → 25 → 20 → 15 70 → 65 → 60 → 35 → 55 +``` + +Simulated over 20,000 full five-phase cases per row, WITH the destitution rule +modelled (a spent track upgrades every remaining phase to Difficult): + +``` +lead 40% passed 0.72 → 1.37 of 5 hit destitution 87% → 63% of cases +lead 55% passed 1.14 → 2.06 of 5 hit destitution 72% → 40% +lead 70% passed 1.60 → 2.78 of 5 hit destitution 54% → 20% +``` + +Destitution almost always lands on the final phase rather than compounding, so it +stings rather than spirals — my first description of it as a death spiral was +overstated. + +Played two cases on the new numbers. SHORT ORCHARD passed 2 of 5 and ended scraped +clean at Resources 0 but Containment 7. PALE VERGE passed 4 of 5 including two +specials, failed the Containment step, and came home at Containment 9, Resources 4. +Both read as cases rather than as arithmetic. + +**R-222 · leading a phase earned no experience.** `resolveLegDialog` called +`skillRoll` with an actor and a rating but **no skill family**, so the choke point +could not resolve the skill item and the tick never fired. This is the same fault the +internal-callers fix addressed — that fix resolves the item FROM the family, and this +caller supplied none — so Tradecraft, the skill the job most uses, was still the one +that could never improve. Fixed and verified: PALE VERGE's lead ticked Tradecraft and +took it 62% → 66% at close. diff --git a/packs/armour/LOG b/packs/armour/LOG index 8d7d7fe..81db68d 100644 --- a/packs/armour/LOG +++ b/packs/armour/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.141023 174647000 Recovering log #3 -2026/08/10-20:41:41.141046 174647000 Level-0 table #5: started -2026/08/10-20:41:41.141166 174647000 Level-0 table #5: 1902 bytes OK -2026/08/10-20:41:41.141467 174647000 Delete type=0 #3 -2026/08/10-20:41:41.141512 174647000 Delete type=3 #2 +2026/08/10-21:10:35.033759 175517000 Recovering log #3 +2026/08/10-21:10:35.033780 175517000 Level-0 table #5: started +2026/08/10-21:10:35.033929 175517000 Level-0 table #5: 1902 bytes OK +2026/08/10-21:10:35.034226 175517000 Delete type=0 #3 +2026/08/10-21:10:35.034283 175517000 Delete type=3 #2 diff --git a/packs/armour/LOG.old b/packs/armour/LOG.old index ba254b7..f71abab 100644 --- a/packs/armour/LOG.old +++ b/packs/armour/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.871312 16fbcb000 Delete type=3 #1 +2026/08/10-21:10:26.742472 172977000 Delete type=3 #1 diff --git a/packs/expedition/LOG b/packs/expedition/LOG index 61a4c1e..a89a9bd 100644 --- a/packs/expedition/LOG +++ b/packs/expedition/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.147740 175e6b000 Recovering log #3 -2026/08/10-20:41:41.147761 175e6b000 Level-0 table #5: started -2026/08/10-20:41:41.147869 175e6b000 Level-0 table #5: 4129 bytes OK -2026/08/10-20:41:41.148109 175e6b000 Delete type=0 #3 -2026/08/10-20:41:41.148134 175e6b000 Delete type=3 #2 +2026/08/10-21:10:35.042390 175d23000 Recovering log #3 +2026/08/10-21:10:35.042410 175d23000 Level-0 table #5: started +2026/08/10-21:10:35.042554 175d23000 Level-0 table #5: 4129 bytes OK +2026/08/10-21:10:35.042821 175d23000 Delete type=0 #3 +2026/08/10-21:10:35.042870 175d23000 Delete type=3 #2 diff --git a/packs/expedition/LOG.old b/packs/expedition/LOG.old index 882dabc..9a8d6b7 100644 --- a/packs/expedition/LOG.old +++ b/packs/expedition/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.894989 16ebb3000 Delete type=3 #1 +2026/08/10-21:10:26.766828 173183000 Delete type=3 #1 diff --git a/packs/gear/LOG b/packs/gear/LOG index f09e80b..4fc69e1 100644 --- a/packs/gear/LOG +++ b/packs/gear/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.142024 175e6b000 Recovering log #3 -2026/08/10-20:41:41.142110 175e6b000 Level-0 table #5: started -2026/08/10-20:41:41.142362 175e6b000 Level-0 table #5: 27954 bytes OK -2026/08/10-20:41:41.142565 175e6b000 Delete type=0 #3 -2026/08/10-20:41:41.142606 175e6b000 Delete type=3 #2 +2026/08/10-21:10:35.034917 175d23000 Recovering log #3 +2026/08/10-21:10:35.035011 175d23000 Level-0 table #5: started +2026/08/10-21:10:35.035308 175d23000 Level-0 table #5: 27954 bytes OK +2026/08/10-21:10:35.035591 175d23000 Delete type=0 #3 +2026/08/10-21:10:35.035641 175d23000 Delete type=3 #2 diff --git a/packs/gear/LOG.old b/packs/gear/LOG.old index 868370a..f00b55c 100644 --- a/packs/gear/LOG.old +++ b/packs/gear/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.873111 1703d7000 Delete type=3 #1 +2026/08/10-21:10:26.744343 17419b000 Delete type=3 #1 diff --git a/packs/npcs/LOG b/packs/npcs/LOG index 31a58c8..837a43b 100644 --- a/packs/npcs/LOG +++ b/packs/npcs/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.134409 174647000 Recovering log #3 -2026/08/10-20:41:41.134636 174647000 Level-0 table #5: started -2026/08/10-20:41:41.135086 174647000 Level-0 table #5: 60660 bytes OK -2026/08/10-20:41:41.135295 174647000 Delete type=0 #3 -2026/08/10-20:41:41.135327 174647000 Delete type=3 #2 +2026/08/10-21:10:35.025087 175517000 Recovering log #3 +2026/08/10-21:10:35.025512 175517000 Level-0 table #5: started +2026/08/10-21:10:35.026438 175517000 Level-0 table #5: 60660 bytes OK +2026/08/10-21:10:35.026776 175517000 Delete type=0 #3 +2026/08/10-21:10:35.026817 175517000 Delete type=3 #2 diff --git a/packs/npcs/LOG.old b/packs/npcs/LOG.old index a646b26..9942779 100644 --- a/packs/npcs/LOG.old +++ b/packs/npcs/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.883213 16f3bf000 Delete type=3 #1 +2026/08/10-21:10:26.754647 172977000 Delete type=3 #1 diff --git a/packs/powers/LOG b/packs/powers/LOG index 747e711..2045096 100644 --- a/packs/powers/LOG +++ b/packs/powers/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.138725 174647000 Recovering log #3 -2026/08/10-20:41:41.138746 174647000 Level-0 table #5: started -2026/08/10-20:41:41.138865 174647000 Level-0 table #5: 3295 bytes OK -2026/08/10-20:41:41.139133 174647000 Delete type=0 #3 -2026/08/10-20:41:41.139175 174647000 Delete type=3 #2 +2026/08/10-21:10:35.031149 1744ff000 Recovering log #3 +2026/08/10-21:10:35.031171 1744ff000 Level-0 table #5: started +2026/08/10-21:10:35.031288 1744ff000 Level-0 table #5: 3295 bytes OK +2026/08/10-21:10:35.031521 1744ff000 Delete type=0 #3 +2026/08/10-21:10:35.031553 1744ff000 Delete type=3 #2 diff --git a/packs/powers/LOG.old b/packs/powers/LOG.old index 6b46830..080d557 100644 --- a/packs/powers/LOG.old +++ b/packs/powers/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.889425 16f3bf000 Delete type=3 #1 +2026/08/10-21:10:26.760755 17419b000 Delete type=3 #1 diff --git a/packs/pregens/LOG b/packs/pregens/LOG index 0071685..09c7b2a 100644 --- a/packs/pregens/LOG +++ b/packs/pregens/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.132366 174647000 Recovering log #3 -2026/08/10-20:41:41.132578 174647000 Level-0 table #5: started -2026/08/10-20:41:41.133060 174647000 Level-0 table #5: 54921 bytes OK -2026/08/10-20:41:41.133331 174647000 Delete type=0 #3 -2026/08/10-20:41:41.133365 174647000 Delete type=3 #2 +2026/08/10-21:10:35.021326 175517000 Recovering log #3 +2026/08/10-21:10:35.021545 175517000 Level-0 table #5: started +2026/08/10-21:10:35.022420 175517000 Level-0 table #5: 54921 bytes OK +2026/08/10-21:10:35.022844 175517000 Delete type=0 #3 +2026/08/10-21:10:35.022893 175517000 Delete type=3 #2 diff --git a/packs/pregens/LOG.old b/packs/pregens/LOG.old index 68549ea..a8fde99 100644 --- a/packs/pregens/LOG.old +++ b/packs/pregens/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.878370 16fbcb000 Delete type=3 #1 +2026/08/10-21:10:26.750048 17419b000 Delete type=3 #1 diff --git a/packs/rules/LOG b/packs/rules/LOG index 4e814ba..7b84bc8 100644 --- a/packs/rules/LOG +++ b/packs/rules/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.144398 175e6b000 Recovering log #3 -2026/08/10-20:41:41.144451 175e6b000 Level-0 table #5: started -2026/08/10-20:41:41.144690 175e6b000 Level-0 table #5: 23316 bytes OK -2026/08/10-20:41:41.144892 175e6b000 Delete type=0 #3 -2026/08/10-20:41:41.144919 175e6b000 Delete type=3 #2 +2026/08/10-21:10:35.037687 175d23000 Recovering log #3 +2026/08/10-21:10:35.037745 175d23000 Level-0 table #5: started +2026/08/10-21:10:35.038003 175d23000 Level-0 table #5: 23316 bytes OK +2026/08/10-21:10:35.038279 175d23000 Delete type=0 #3 +2026/08/10-21:10:35.038312 175d23000 Delete type=3 #2 diff --git a/packs/rules/LOG.old b/packs/rules/LOG.old index 316e315..a682cbf 100644 --- a/packs/rules/LOG.old +++ b/packs/rules/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.893484 16ebb3000 Delete type=3 #1 +2026/08/10-21:10:26.765165 173183000 Delete type=3 #1 diff --git a/packs/skills/LOG b/packs/skills/LOG index e0e4384..aab4d6d 100644 --- a/packs/skills/LOG +++ b/packs/skills/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.136311 174647000 Recovering log #3 -2026/08/10-20:41:41.136348 174647000 Level-0 table #5: started -2026/08/10-20:41:41.136491 174647000 Level-0 table #5: 6679 bytes OK -2026/08/10-20:41:41.136799 174647000 Delete type=0 #3 -2026/08/10-20:41:41.136837 174647000 Delete type=3 #2 +2026/08/10-21:10:35.028347 175517000 Recovering log #3 +2026/08/10-21:10:35.028398 175517000 Level-0 table #5: started +2026/08/10-21:10:35.028587 175517000 Level-0 table #5: 6679 bytes OK +2026/08/10-21:10:35.028935 175517000 Delete type=0 #3 +2026/08/10-21:10:35.029009 175517000 Delete type=3 #2 diff --git a/packs/skills/LOG.old b/packs/skills/LOG.old index 944ef88..265661d 100644 --- a/packs/skills/LOG.old +++ b/packs/skills/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.865001 16fbcb000 Delete type=3 #1 +2026/08/10-21:10:26.736502 172977000 Delete type=3 #1 diff --git a/packs/slice/LOG b/packs/slice/LOG index 226334b..b7366cc 100644 --- a/packs/slice/LOG +++ b/packs/slice/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.145560 174e53000 Recovering log #3 -2026/08/10-20:41:41.145600 174e53000 Level-0 table #5: started -2026/08/10-20:41:41.145824 174e53000 Level-0 table #5: 16892 bytes OK -2026/08/10-20:41:41.146032 174e53000 Delete type=0 #3 -2026/08/10-20:41:41.146059 174e53000 Delete type=3 #2 +2026/08/10-21:10:35.039746 1744ff000 Recovering log #3 +2026/08/10-21:10:35.039788 1744ff000 Level-0 table #5: started +2026/08/10-21:10:35.040037 1744ff000 Level-0 table #5: 16892 bytes OK +2026/08/10-21:10:35.040363 1744ff000 Delete type=0 #3 +2026/08/10-21:10:35.040421 1744ff000 Delete type=3 #2 diff --git a/packs/slice/LOG.old b/packs/slice/LOG.old index c99e09a..207dcd4 100644 --- a/packs/slice/LOG.old +++ b/packs/slice/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.887732 16ebb3000 Delete type=3 #1 +2026/08/10-21:10:26.759088 173183000 Delete type=3 #1 diff --git a/packs/tables/LOG b/packs/tables/LOG index 9602f01..4e04f5c 100644 --- a/packs/tables/LOG +++ b/packs/tables/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.146606 174647000 Recovering log #3 -2026/08/10-20:41:41.146628 174647000 Level-0 table #5: started -2026/08/10-20:41:41.146719 174647000 Level-0 table #5: 3739 bytes OK -2026/08/10-20:41:41.146990 174647000 Delete type=0 #3 -2026/08/10-20:41:41.147036 174647000 Delete type=3 #2 +2026/08/10-21:10:35.041184 175517000 Recovering log #3 +2026/08/10-21:10:35.041207 175517000 Level-0 table #5: started +2026/08/10-21:10:35.041346 175517000 Level-0 table #5: 3739 bytes OK +2026/08/10-21:10:35.041618 175517000 Delete type=0 #3 +2026/08/10-21:10:35.041664 175517000 Delete type=3 #2 diff --git a/packs/tables/LOG.old b/packs/tables/LOG.old index 3ea6a53..92285dd 100644 --- a/packs/tables/LOG.old +++ b/packs/tables/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.885357 1703d7000 Delete type=3 #1 +2026/08/10-21:10:26.757057 173183000 Delete type=3 #1 diff --git a/packs/talents/LOG b/packs/talents/LOG index 2ef6008..8906fbc 100644 --- a/packs/talents/LOG +++ b/packs/talents/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.137507 17565f000 Recovering log #3 -2026/08/10-20:41:41.137545 17565f000 Level-0 table #5: started -2026/08/10-20:41:41.137683 17565f000 Level-0 table #5: 5105 bytes OK -2026/08/10-20:41:41.137984 17565f000 Delete type=0 #3 -2026/08/10-20:41:41.138042 17565f000 Delete type=3 #2 +2026/08/10-21:10:35.029938 174d0b000 Recovering log #3 +2026/08/10-21:10:35.029970 174d0b000 Level-0 table #5: started +2026/08/10-21:10:35.030128 174d0b000 Level-0 table #5: 5105 bytes OK +2026/08/10-21:10:35.030410 174d0b000 Delete type=0 #3 +2026/08/10-21:10:35.030446 174d0b000 Delete type=3 #2 diff --git a/packs/talents/LOG.old b/packs/talents/LOG.old index f731097..54be61d 100644 --- a/packs/talents/LOG.old +++ b/packs/talents/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.867714 16fbcb000 Delete type=3 #1 +2026/08/10-21:10:26.739179 173183000 Delete type=3 #1 diff --git a/packs/vehicles/LOG b/packs/vehicles/LOG index b9d21ac..953ee0e 100644 --- a/packs/vehicles/LOG +++ b/packs/vehicles/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.143254 174647000 Recovering log #3 -2026/08/10-20:41:41.143279 174647000 Level-0 table #5: started -2026/08/10-20:41:41.143426 174647000 Level-0 table #5: 5012 bytes OK -2026/08/10-20:41:41.143706 174647000 Delete type=0 #3 -2026/08/10-20:41:41.143760 174647000 Delete type=3 #2 +2026/08/10-21:10:35.036441 175517000 Recovering log #3 +2026/08/10-21:10:35.036467 175517000 Level-0 table #5: started +2026/08/10-21:10:35.036615 175517000 Level-0 table #5: 5012 bytes OK +2026/08/10-21:10:35.036909 175517000 Delete type=0 #3 +2026/08/10-21:10:35.036961 175517000 Delete type=3 #2 diff --git a/packs/vehicles/LOG.old b/packs/vehicles/LOG.old index 99ef50a..07a3f70 100644 --- a/packs/vehicles/LOG.old +++ b/packs/vehicles/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.874846 1703d7000 Delete type=3 #1 +2026/08/10-21:10:26.746192 173183000 Delete type=3 #1 diff --git a/packs/weapons/LOG b/packs/weapons/LOG index dca32d1..fd48b42 100644 --- a/packs/weapons/LOG +++ b/packs/weapons/LOG @@ -1,5 +1,5 @@ -2026/08/10-20:41:41.139842 175e6b000 Recovering log #3 -2026/08/10-20:41:41.139878 175e6b000 Level-0 table #5: started -2026/08/10-20:41:41.140047 175e6b000 Level-0 table #5: 7240 bytes OK -2026/08/10-20:41:41.140366 175e6b000 Delete type=0 #3 -2026/08/10-20:41:41.140415 175e6b000 Delete type=3 #2 +2026/08/10-21:10:35.032367 175d23000 Recovering log #3 +2026/08/10-21:10:35.032410 175d23000 Level-0 table #5: started +2026/08/10-21:10:35.032599 175d23000 Level-0 table #5: 7240 bytes OK +2026/08/10-21:10:35.032954 175d23000 Delete type=0 #3 +2026/08/10-21:10:35.033016 175d23000 Delete type=3 #2 diff --git a/packs/weapons/LOG.old b/packs/weapons/LOG.old index 4cb2c99..0829054 100644 --- a/packs/weapons/LOG.old +++ b/packs/weapons/LOG.old @@ -1 +1 @@ -2026/08/10-20:41:32.869495 16ebb3000 Delete type=3 #1 +2026/08/10-21:10:26.740769 17419b000 Delete type=3 #1 diff --git a/ringbrp.mjs b/ringbrp.mjs index b9ebfad..64dc8fb 100644 --- a/ringbrp.mjs +++ b/ringbrp.mjs @@ -5015,6 +5015,13 @@ async function resolveLegDialog(expedition) { actor: best.actor, label: game.i18n.format("RINGBRP.Expedition.LegRoll", { n: idx + 1, terrain: leg.terrain ?? "" }), rating: best.rating, + // R-222. The family was never passed, so skillRoll could not resolve the skill + // item, and a phase led successfully earned no experience tick. This is the same + // fault the internal-callers fix addressed — it resolves the item FROM the + // family, and this caller supplied none. The skill the job most uses was still + // the one that could never improve. + skillFamilyId: best.skill, + categoryId: "mental", difficulty, situational: (cancelled ? 0 : Number(leg.modifier) || 0) + rewardBonus, flavourLines: [ diff --git a/rules.mjs b/rules.mjs index bcd68da..b58766c 100644 --- a/rules.mjs +++ b/rules.mjs @@ -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 */ /* -------------------------------------------- */ diff --git a/tools/check-rules.mjs b/tools/check-rules.mjs index 7b9a93a..3356f55 100644 --- a/tools/check-rules.mjs +++ b/tools/check-rules.mjs @@ -197,6 +197,13 @@ const checks = [ ["defenceTypeAllowed('','parry')", RULES.defenceTypeAllowed("","parry"), "parry"], // defences are graded: a defence stops its own quality or worse, and only // shaves a better blow by as many steps as it was outclassed by + // the case ramp: attrition accumulates and stops; only Containment is Difficult + ["phaseRampFor(0) is the way in", RULES.phaseRampFor(0,"approach").difficulty, "average"], + ["phaseRampFor(0) modifier", RULES.phaseRampFor(0,"approach").modifier, 0], + ["phaseRampFor(2) modifier", RULES.phaseRampFor(2,"search").modifier, -10], + ["phaseRampFor(9) is capped", RULES.phaseRampFor(9,"search").modifier, -15], + ["containment is Difficult", RULES.phaseRampFor(3,"containment").difficulty, "difficult"], + ["containment does NOT also ramp", RULES.phaseRampFor(3,"containment").modifier, 0], // access is a record: scope is a hard ceiling, not a difficulty ["scopeRank('routine')", RULES.scopeRank("routine"), 2], ["scopeRank(unknown)", RULES.scopeRank("nonesuch"), 0], diff --git a/tools/mission.mjs b/tools/mission.mjs index 38ab451..e88f0e6 100644 --- a/tools/mission.mjs +++ b/tools/mission.mjs @@ -19,6 +19,7 @@ import { NAMES_FIRST, NAMES_LAST, NPC_ROLES, PHASE_KINDS, COMPLICATIONS, CLOCKS, COHERENCE_HOOKS, RESOLUTIONS, DEBRIEF_QUESTIONS, FAILURE_STATES, GROUPS } from "./mission-tables.mjs"; +import { phaseRampFor } from "../rules.mjs"; /* ---------------- picking ---------------- */ const pick = (arr, r) => arr[Math.floor(r() * arr.length)]; @@ -111,13 +112,12 @@ function buildPhases(r, { anomaly, gap }) { name: k.name, terrain: pick(k.terrains, r), about: k.verb, - difficulty: i === 0 ? "average" : "difficult", // The classification modifier belongs to the CROSSING, not to every phase. Both // applied, so a Wrong-class extraction came out at -35% on top of Difficult, // which floors a 71% Tradecraft to 1% and makes the case unplayable rather than - // hard. Phases carry their own gentle ramp; the classification bites on the way - // home, where the fiction says it should. - modifier: -(i * 5), + // hard. Phases carry their own ramp; the classification bites on the way home, + // where the fiction says it should. The ramp itself lives in rules.mjs. + ...phaseRampFor(i, k.id), // Costs must be affordable from the starting budget. They totalled 7 against a // starting 6 for every non-Near class, so half of all cases were arithmetically // unfinishable before the extraction phase.