R-273: the opposed roll, built where the authority lives
The content has called for 'opposed POWx5' since before the rule existed -- the hollow man's tactics, CLEAN GROUND twice, slice-text three times -- and rules.mjs defined none. A scenario carried a local ruling that said in its own text it was a ruling and not a rule. Generalises that ruling rather than inventing another: both sides roll, the better band wins, only the ladder the game already has. Ties go to whoever is being acted upon, which is what defenceOutcomeFor has always said; the scenario's 'favour the agent' gave the same answer only because no agent ever initiates one. Neither side succeeding leaves the contest unsettled rather than won, which the two beats need in opposite directions. Two exports at the scenario session's request: opposedOutcomeFor compares graded levels and carries both, so a caller can price a fumbled attempt without this file deciding what a fumble costs; opposedContestFor runs it from ratings and rolls with per-side difficulty, so 'resists at Difficult' does not put applyDifficulty back into a document. Spot-checked against the real Act Four beat: 55 against 85 at Difficult, which is 42. Page 1 states it by asking it -- the tie-break and the margin are computed from the rule at build time, so the book cannot drift from the engine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d03b3208e5
commit
cdbb2e34ee
@@ -506,6 +506,31 @@ const checks = [
|
||||
["defenceOutcomeFor(special, special)", RULES.defenceOutcomeFor("special","special").turnedAside, true],
|
||||
["defenceOutcomeFor(success, success)", RULES.defenceOutcomeFor("success","success").turnedAside, true],
|
||||
["defenceOutcomeFor(success, fumble)", RULES.defenceOutcomeFor("success","fumble").landsAt, "success"],
|
||||
// Opposed rolls. The better band wins; ties go to whoever is being acted upon, which is
|
||||
// the same answer defenceOutcomeFor gives a defender; and if nobody reached a success
|
||||
// the contest is unsettled rather than won, so it can be tried again.
|
||||
["opposedOutcomeFor(crit, success).winner", RULES.opposedOutcomeFor("critical","success").winner, "active"],
|
||||
["opposedOutcomeFor(crit, success).margin", RULES.opposedOutcomeFor("critical","success").margin, 2],
|
||||
["opposedOutcomeFor(success, crit)", RULES.opposedOutcomeFor("success","critical").winner,"resisting"],
|
||||
["opposedOutcomeFor(success, success)", RULES.opposedOutcomeFor("success","success").winner, "resisting"],
|
||||
["opposedOutcomeFor(crit, crit)", RULES.opposedOutcomeFor("critical","critical").winner,"resisting"],
|
||||
["opposedOutcomeFor(success, success).margin", RULES.opposedOutcomeFor("success","success").margin, 0],
|
||||
["opposedOutcomeFor(special, success)", RULES.opposedOutcomeFor("special","success").winner, "active"],
|
||||
["opposedOutcomeFor(success, failure)", RULES.opposedOutcomeFor("success","failure").winner, "active"],
|
||||
["opposedOutcomeFor(failure, failure).settled", RULES.opposedOutcomeFor("failure","failure").settled, false],
|
||||
["opposedOutcomeFor(failure, failure).winner", RULES.opposedOutcomeFor("failure","failure").winner, null],
|
||||
["opposedOutcomeFor(fumble, failure).settled", RULES.opposedOutcomeFor("fumble","failure").settled, false],
|
||||
["opposedOutcomeFor(success, fumble)", RULES.opposedOutcomeFor("success","fumble").winner, "active"],
|
||||
// Both sides' levels travel with the verdict, so a caller can price a fumbled attempt
|
||||
// without this file deciding what fumbling costs.
|
||||
["opposedOutcomeFor(fumble, failure).activeLevel", RULES.opposedOutcomeFor("fumble","failure").activeLevel, "fumble"],
|
||||
["opposedOutcomeFor(fumble, failure).resistingLevel", RULES.opposedOutcomeFor("fumble","failure").resistingLevel, "failure"],
|
||||
// The whole contest, each side at its own difficulty. CLEAN GROUND's Act Four beat:
|
||||
// the understudy at POWx5 55 against Ashcroft's 85 resisting at Difficult, which is 42.
|
||||
["opposedContestFor(...).resisting.bands.effective", RULES.opposedContestFor({rating:55,roll:12},{rating:85,roll:40,difficulty:"difficult"}).resisting.bands.effective, 42],
|
||||
["opposedContestFor(...).winner", RULES.opposedContestFor({rating:55,roll:12},{rating:85,roll:40,difficulty:"difficult"}).winner, "resisting"],
|
||||
["opposedContestFor(aggressor specials)", RULES.opposedContestFor({rating:55,roll:8},{rating:85,roll:40,difficulty:"difficult"}).winner, "active"],
|
||||
["opposedContestFor(both miss).settled", RULES.opposedContestFor({rating:55,roll:90},{rating:85,roll:90,difficulty:"difficult"}).settled, false],
|
||||
// Hit locations. Moved out of ringbrp.mjs so the harness can locate damage; these are
|
||||
// the spot-checks they never had while the engine held the only copy. A species that
|
||||
// has no head must not be able to return one, which is the whole point of the tables.
|
||||
|
||||
Reference in New Issue
Block a user