From 2f4ee083b85adb41cf1c862c3f01999d792bdb48 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 18:37:34 +0000 Subject: [PATCH 1/3] Duties roll provider for Pathfinder 2e, and sheet fixes from a playtest duties-pf2e 1.0.0 rolls a skill, Perception or a save against the roller's level DC with pf2e's degrees of success, counts a helper as Aid, and gives XP or money as rewards. pf2e 0.3.1 adds TRIG`PURSE`PUT so another package can write a ledger entry: an @include from outside pf2e resolves pf2e's own object references against the wrong object and overwrote entry 1. Playtest fixes: - duties-pbta 1.0.2: CAN answers 1 or 0 for a move. - sheet-brp 2.3.0 adds API`BEST; duties-brp 1.0.2 uses it so Improvise reads the sheet once instead of once per skill, which went over the function invocation limit with two party members. - duties-salvage-union 1.0.2: "1 Training Point". - sheet-d20, sheet-pbta, sheet-fitd, sheet-brp, sheet-ironsworn: the sheet footer no longer prints the +app/submit hint twice. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Rqqt7SRfDwJ7jHJPqVA5oS --- README.md | 17 +++-- duties-brp/package.yaml | 11 +-- duties-pbta/package.yaml | 7 +- duties-pf2e/README.md | 21 ++++++ duties-pf2e/package.yaml | 121 ++++++++++++++++++++++++++++++ duties-salvage-union/package.yaml | 4 +- index.yaml | 22 +++--- pf2e/package.yaml | 10 ++- sheet-brp/package.yaml | 14 +++- sheet-d20/package.yaml | 4 +- sheet-fitd/package.yaml | 4 +- sheet-ironsworn/package.yaml | 4 +- sheet-pbta/package.yaml | 4 +- 13 files changed, 202 insertions(+), 41 deletions(-) create mode 100644 duties-pf2e/README.md create mode 100644 duties-pf2e/package.yaml diff --git a/README.md b/README.md index 758070d..b10c37b 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ constraints checked before anything is planned. | [`profile-handler/`](profile-handler/) | 1.0.0 | Read-only character directory and profile API; depends on HTTP Handler | | [`roll-tables/`](roll-tables/) | 1.0.0 | Random tables as softcode data: `+table/roll` tells the room, table keepers edit them by command, and a table can be published to a wiki page | | [`pf2e-remaster/`](pf2e-remaster/) | 1.4.0 | Pathfinder Second Edition (Remaster) core rules as wiki pages: classes, ancestries, heritages, backgrounds, feats, spells, actions, equipment, skills, conditions and DC tables; a content pack under the ORC License | -| [`sheet-d20/`](sheet-d20/) | 2.2.0 | d20 character sheet built from a ledger: six abilities, a skill list the game edits, training, level, hit points, coin and gear, guided character creation and XP advances; `+check` against a DC or a foe; `+encounter` plays scenes from copies of the sheets, with a bestiary of foes, initiative, turns and conditions | +| [`sheet-d20/`](sheet-d20/) | 2.2.1 | d20 character sheet built from a ledger: six abilities, a skill list the game edits, training, level, hit points, coin and gear, guided character creation and XP advances; `+check` against a DC or a foe; `+encounter` plays scenes from copies of the sheets, with a bestiary of foes, initiative, turns and conditions | | [`sheet-d20-help/`](sheet-d20-help/) | 1.0.1 | Bridge: the D20 sheet's topics in `+help` | | [`sheet-d20-config/`](sheet-d20-config/) | 1.0.2 | Bridge: the D20 sheet's settings, trait table and bestiary in `+config` | | [`sheet-d20-chargen/`](sheet-d20-chargen/) | 1.1.0 | Bridge: sheet edits follow the player's `+app` application; reviewers read the sheets they review | @@ -67,30 +67,31 @@ constraints checked before anything is planned. | [`fate-system-toolkit-help/`](fate-system-toolkit-help/) | 1.1.0 | Bridge: the Fate System Toolkit topics in `+help` | | [`fate-system-toolkit-config/`](fate-system-toolkit-config/) | 1.1.0 | Bridge: the Fate System Toolkit settings, conditions, storms and augs in `+config` | | [`fate-system-toolkit-wiki/`](fate-system-toolkit-wiki/) | 1.1.0 | Unofficial Fate System Toolkit rules reference as wiki pages: conditions, Wealth, Stormcallers, supers, gadgets, cyberware | -| [`sheet-pbta/`](sheet-pbta/) | 2.3.0 | Powered by the Apocalypse character sheet built from a ledger: playbooks, stats and moves the game edits, guided character creation, advances, forward, ongoing, hold, harm and XP; `+check` on 2d6; `+encounter` plays scenes from copies of the sheets, with foes from a bestiary and GM moves. Dungeon World moves under CC BY 3.0 (see its NOTICE) | +| [`sheet-pbta/`](sheet-pbta/) | 2.3.1 | Powered by the Apocalypse character sheet built from a ledger: playbooks, stats and moves the game edits, guided character creation, advances, forward, ongoing, hold, harm and XP; `+check` on 2d6; `+encounter` plays scenes from copies of the sheets, with foes from a bestiary and GM moves. Dungeon World moves under CC BY 3.0 (see its NOTICE) | | [`sheet-pbta-help/`](sheet-pbta-help/) | 1.0.1 | Bridge: the PbtA sheet's topics in `+help` | | [`sheet-pbta-config/`](sheet-pbta-config/) | 1.0.2 | Bridge: the PbtA sheet's settings and tables, the bestiary and GM moves among them, in `+config` | | [`sheet-pbta-chargen/`](sheet-pbta-chargen/) | 1.1.0 | Bridge: sheet edits follow the player's `+app` application; reviewers read the sheets they review | | [`duties-d20/`](duties-d20/) | 1.0.1 | Duties roll provider `d20` on the D20 sheet | +| [`duties-pf2e/`](duties-pf2e/) | 1.0.0 | Duties roll provider `pf2e` on the Pathfinder 2e sheet: skills, Perception and saves against the roller's level DC, Aid, XP and money as rewards | | [`d20-wiki/`](d20-wiki/) | 1.1.0 | Wiki pages for the d20 sheet: checks and DCs, making a character, abilities and skills, hit points, gear and advancement, and encounters with foes and turns | | [`duties-fate/`](duties-fate/) | 1.0.0 | Duties roll provider `fate` on the Fate sheet: teamwork, paid invokes, fate points as rewards | -| [`duties-pbta/`](duties-pbta/) | 1.0.1 | Duties roll provider `pbta` on the PbtA sheet: aid, forward and ongoing, XP as a reward | +| [`duties-pbta/`](duties-pbta/) | 1.0.2 | Duties roll provider `pbta` on the PbtA sheet: aid, forward and ongoing, XP as a reward | | [`pbta-wiki/`](pbta-wiki/) | 1.1.0 | Wiki pages for the PbtA sheet: how to play, making a character, the playbooks, the basic and special moves, advancement, and encounters with foes and harm. Dungeon World moves under CC BY 3.0 | -| [`sheet-fitd/`](sheet-fitd/) | 2.2.0 | Forged in the Dark character sheet: twelve actions under three attributes built from a ledger, XP for each attribute spent on advances, stress, trauma, harm, coin, an audited log of XP and coin, encounters played from copies of the sheets, with threats that each have a clock, positions and effect, and progress clocks; `+check` on a d6 pool against a position. Blades in the Dark SRD under CC BY 3.0 (see its NOTICE) | +| [`sheet-fitd/`](sheet-fitd/) | 2.2.1 | Forged in the Dark character sheet: twelve actions under three attributes built from a ledger, XP for each attribute spent on advances, stress, trauma, harm, coin, an audited log of XP and coin, encounters played from copies of the sheets, with threats that each have a clock, positions and effect, and progress clocks; `+check` on a d6 pool against a position. Blades in the Dark SRD under CC BY 3.0 (see its NOTICE) | | [`sheet-fitd-help/`](sheet-fitd-help/) | 1.0.1 | Bridge: the FitD sheet's topics in `+help` | | [`sheet-fitd-config/`](sheet-fitd-config/) | 1.0.2 | Bridge: the FitD sheet's settings and lists, the threats among them, in `+config` | | [`sheet-fitd-chargen/`](sheet-fitd-chargen/) | 1.1.0 | Bridge: sheet edits follow the player's `+app` application; reviewers read the sheets they review | -| [`sheet-brp/`](sheet-brp/) | 2.2.0 | Percentile character sheet on Basic Roleplaying: characteristics and a skill list with base chances built from a ledger, point-buy character creation, experience checks that raise skills, hit points, power points, coin, an audited log of coin and skill gains, and encounters played from copies of the sheets, with creatures from a bestiary, hit locations and an order of play by DEX or strike rank; `+check` on 1d100. ORC Licensed Material (see its NOTICE) | +| [`sheet-brp/`](sheet-brp/) | 2.3.0 | Percentile character sheet on Basic Roleplaying: characteristics and a skill list with base chances built from a ledger, point-buy character creation, experience checks that raise skills, hit points, power points, coin, an audited log of coin and skill gains, and encounters played from copies of the sheets, with creatures from a bestiary, hit locations and an order of play by DEX or strike rank; `+check` on 1d100. ORC Licensed Material (see its NOTICE) | | [`sheet-brp-help/`](sheet-brp-help/) | 1.0.1 | Bridge: the BRP sheet's topics in `+help` | | [`sheet-brp-config/`](sheet-brp-config/) | 1.0.2 | Bridge: the BRP sheet's settings, skill list and bestiary in `+config` | | [`sheet-brp-chargen/`](sheet-brp-chargen/) | 1.1.0 | Bridge: sheet edits follow the player's `+app` application; reviewers read the sheets they review | -| [`sheet-ironsworn/`](sheet-ironsworn/) | 2.2.0 | Ironsworn character sheet: five stats and assets built from a ledger, guided character creation, experience spent on new assets and abilities with an audited log, meters, momentum, companion health, iron vows with progress, and encounters that play from copies of the sheets, with foes from a bestiary fought on progress tracks; `+check` action rolls and `+vow`. Ironsworn SRD under CC BY 4.0 (see its NOTICE) | +| [`sheet-ironsworn/`](sheet-ironsworn/) | 2.2.1 | Ironsworn character sheet: five stats and assets built from a ledger, guided character creation, experience spent on new assets and abilities with an audited log, meters, momentum, companion health, iron vows with progress, and encounters that play from copies of the sheets, with foes from a bestiary fought on progress tracks; `+check` action rolls and `+vow`. Ironsworn SRD under CC BY 4.0 (see its NOTICE) | | [`sheet-ironsworn-help/`](sheet-ironsworn-help/) | 1.0.1 | Bridge: the Ironsworn sheet's topics in `+help` | | [`sheet-ironsworn-config/`](sheet-ironsworn-config/) | 1.0.2 | Bridge: the Ironsworn sheet's settings, stat and asset lists and bestiary in `+config` | | [`sheet-ironsworn-chargen/`](sheet-ironsworn-chargen/) | 1.1.0 | Bridge: sheet edits follow the player's `+app` application; reviewers read the sheets they review | | [`duties-fitd/`](duties-fitd/) | 1.0.1 | Duties roll provider `fitd` on the FitD sheet: assists and pushes paid in stress, coin and stress relief as rewards | | [`fitd-wiki/`](fitd-wiki/) | 1.1.0 | Wiki pages for the FitD sheet: how to play, making a character, actions and attributes, stress, harm and advancement, encounters with threats, and clocks. Based on the Blades in the Dark SRD under CC BY 3.0 | -| [`duties-brp/`](duties-brp/) | 1.0.1 | Duties roll provider `brp` on the BRP sheet: help as an augment, skill increases and healing as rewards | +| [`duties-brp/`](duties-brp/) | 1.0.2 | Duties roll provider `brp` on the BRP sheet: help as an augment, skill increases and healing as rewards | | [`brp-wiki/`](brp-wiki/) | 1.1.0 | Wiki pages for the BRP sheet: how to play, making a character, characteristics and skills, hit points, coin and experience, and encounters with creatures. ORC Licensed Material | | [`ironsworn-wiki/`](ironsworn-wiki/) | 1.1.0 | Wiki pages for the Ironsworn sheet: action rolls, making a character, assets and experience, meters and momentum, iron vows, and encounters with foes. Ironsworn SRD under CC BY 4.0 | | [`duties-ironsworn/`](duties-ironsworn/) | 1.1.0 | Duties roll provider `ironsworn` on the Ironsworn sheet: help adds 1, experience (logged) and momentum as rewards | @@ -104,7 +105,7 @@ constraints checked before anything is planned. | [`sheet-salvage-union-help/`](sheet-salvage-union-help/) | 1.0.0 | Bridge: the Salvage Union sheet's topics in `+help` | | [`sheet-salvage-union-config/`](sheet-salvage-union-config/) | 1.0.0 | Bridge: the Salvage Union sheet's settings in `+config` | | [`sheet-salvage-union-chargen/`](sheet-salvage-union-chargen/) | 1.0.0 | Bridge: sheet and mech edits follow the player's `+app` application; reviewers read the sheets they review | -| [`duties-salvage-union/`](duties-salvage-union/) | 1.0.1 | Duties roll provider `salvage` on the Salvage Union sheet: abilities and mech parts as traits, Training Points and crawler scrap as rewards | +| [`duties-salvage-union/`](duties-salvage-union/) | 1.0.2 | Duties roll provider `salvage` on the Salvage Union sheet: abilities and mech parts as traits, Training Points and crawler scrap as rewards | | [`salvage-union-wiki/`](salvage-union-wiki/) | 1.0.3 | Salvage Union rules as wiki pages: the core rules, Pilot Bay, Mech Workshop, every chassis blueprint, the Union Crawler, salvaging, the denizens of the wasteland, and a page for every ability, system, module, piece of equipment and table. Unofficial, under the Salvage Union Open Game Licence 1.0b (see its NOTICE) | | [`sheet-charge/`](sheet-charge/) | 1.2.0 | Charge character sheet: details, twelve actions in dots, momentum, a stress clock and condition, milestones and talents on a ledger, encounters with their own sheet copies, threats and consequences, and clocks; `+check` on a d6 pool against a risk, with assists, pushes, determination and fortune rolls. Charge SRD under CC BY 4.0 (see its NOTICE) | | [`sheet-charge-help/`](sheet-charge-help/) | 1.0.0 | Bridge: the Charge sheet's topics in `+help` | diff --git a/duties-brp/package.yaml b/duties-brp/package.yaml index c7594c4..26229b6 100644 --- a/duties-brp/package.yaml +++ b/duties-brp/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: duties-brp title: "Duties: percentile (BRP) rolls" -version: 1.0.1 +version: 1.0.2 authors: [SharpMUSH] description: "Lets Duties roll on the percentile (BRP) sheet: a roll provider called brp, so a duty's checks roll 1d100 under a skill or characteristic roll, doubled or halved for difficulty, with help making a roll one step easier, and skill gains or healing as rewards. Pick it with +config duties/system=brp." license: MIT @@ -21,7 +21,7 @@ depends: path: examples/packages/duties/ branch: main - package: sheet-brp - version: ">=2.0 <3.0" + version: ">=2.3 <3.0" source: repo: https://github.com/SharpMUSH/SharpMUSH.Packages path: sheet-brp/ @@ -55,7 +55,7 @@ objects: # %: the roll this character improvises with, their highest (the first of equals). FN`DUTIES`FALLBACK: value: |- - setq(provider_roller,%)[last(sortkey(%!/FUN`TRAIT`SORTKEY,revwords(u({{sheet-brp/sheet}}/API`ALWAYS)),n))] + u({{sheet-brp/sheet}}/API`BEST,%) flags: [funsyntax] # %, %: 1 when a skill stands above its base chance. FN`DUTIES`TRAINED: @@ -110,11 +110,6 @@ objects: value: |- if(cand(strlen(%0),strmatch(json_query(json_query(%0,get,helpers)),array)),json_query(json_query(%0,get,helpers),size),0) flags: [funsyntax] - # %0 a key: its percentage for provider_roller, for sorting. - FUN`TRAIT`SORTKEY: - value: |- - u({{sheet-brp/sheet}}/API`RATING,%q,%0) - flags: [funsyntax] - ref: provider_registration target: "{{duties/duties}}" diff --git a/duties-pbta/package.yaml b/duties-pbta/package.yaml index 451f9a4..00c95c8 100644 --- a/duties-pbta/package.yaml +++ b/duties-pbta/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: duties-pbta title: "Duties: PbtA sheet rolls" -version: 1.0.1 +version: 1.0.2 authors: [SharpMUSH] description: "Lets Duties roll on the PbtA sheet: a roll provider called pbta, so a duty's checks make a move or roll a stat, 2d6 plus the stat, with aid from helpers, forward and ongoing, and XP as a reward. Pick it with +config duties/system=pbta." license: MIT @@ -57,10 +57,11 @@ objects: value: |- setq(provider_roller,%)[last(sortkey(%!/FUN`STAT`SORTKEY,revwords(u(%!/FUN`STAT`KEYS)),n))] flags: [funsyntax] - # %, %: a playbook move the roller does not have is refused; every stat and basic move is fine. + # %, %: 1 when the roller may roll it, 0 for a playbook move they do not have. Every stat + # and basic move is 1. FN`DUTIES`CAN: value: |- - if(cand(strmatch(%,move-*),not(u({{sheet-pbta/sheet}}/API`HAS,%,%))),You don't have [u({{sheet-pbta/sheet}}/API`LABEL,%)].) + if(strmatch(%,move-*),t(u({{sheet-pbta/sheet}}/API`HAS,%,%)),1) flags: [funsyntax] # %, %, %, %, %. A trivial task is a success with no roll. Otherwise # 2d6 plus the stat, the difficulty's modifier, the roller's forward (spent) and ongoing, and +1 for each diff --git a/duties-pf2e/README.md b/duties-pf2e/README.md new file mode 100644 index 0000000..717545d --- /dev/null +++ b/duties-pf2e/README.md @@ -0,0 +1,21 @@ +# duties-pf2e + +A Duties roll provider called `pf2e`, over [`pf2e`](../pf2e/). Pick it with +`+config duties/system=pf2e`. A bridge between `duties` and `pf2e`. + +| Contract attribute | Answer | +|---|---| +| `` FN`DUTIES`TRAITS `` | every skill, Perception and the three saves, all `always` | +| `` FN`DUTIES`TIERS `` | `crit-fail fail success crit-success` | +| `` FN`DUTIES`DC `` | `Level DC +2 (hard)`: the roller's level DC with the difficulty's adjustment | +| `` FN`DUTIES`FALLBACK `` | the roller's statistic with the highest modifier | +| `` FN`DUTIES`TRAINED `` | trained or better in the statistic | +| `` FN`DUTIES`REWARDS `` | `xp`, `gp`, `sp` and `cp`, each with `amount` | +| `` ON`DUTIES`GRANT `` | an entry in the character's experience or money ledger, written by pf2e's `` TRIG`PURSE`PUT ``, which tells the player | +| `` FN`DUTIES`CHECK `` | 1d20 plus the statistic's stacked modifiers against the level DC; a helper in `%` is Aid, +1. `system` holds `dc`, `total`, `natural`, `degree` and `helpers` | + +Difficulty words use the level DC for the roller's level, adjusted as Pathfinder adjusts DCs: trivial +-10 (incredibly easy), easy -2, standard +0, hard +2, extreme +5. + +The provider is **Duties PF2e Provider**, inside PF2e Rules, WIZARD so it may read each character's +ledger. Its only writes are rewards. Duties reads `` PROVIDER`PF2E `` on the Duties object with `u()`. diff --git a/duties-pf2e/package.yaml b/duties-pf2e/package.yaml new file mode 100644 index 0000000..2f732d1 --- /dev/null +++ b/duties-pf2e/package.yaml @@ -0,0 +1,121 @@ +format: "1.16" +package: duties-pf2e +title: "Duties: Pathfinder 2e rolls" +version: 1.0.0 +authors: [SharpMUSH] +description: "Lets Duties roll on the Pathfinder 2e sheet: a roll provider called pf2e, so a duty's checks roll a skill, Perception or a save against a DC for the roller's level, with Pathfinder's four degrees of success. Pick it with +config duties/system=pf2e." +license: MIT +homepage: https://github.com/SharpMUSH/SharpMUSH.Packages +keywords: [duties, pf2e, pathfinder, dice, bridge] +category: Characters +requires_server: ">=1.0" + +# A bridge: it joins two packages that do not know about each other. Duties asks the game's one active roll +# provider for every check, and pf2e keeps the sheet as a ledger and works out each statistic from it. This +# package is a provider that answers Duties' questions with pf2e's own functions, and the one leaf that +# registers it. +depends: + - package: duties + version: ">=1.0 <2.0" + source: + repo: https://github.com/SharpMUSH/SharpMUSH + path: examples/packages/duties/ + branch: main + - package: pf2e + version: ">=0.3.1 <1.0" + source: + repo: https://github.com/SharpMUSH/SharpMUSH.Packages + path: pf2e/ + branch: main + +objects: + # The provider. Duties calls each FN`DUTIES` attribute with u() and named arguments, so it runs as this + # object; WIZARD because it reads the ledger on each character, which carries the wizard flag. Its only + # writes are rewards, as entries in the character's experience or money ledger. + - ref: provider + type: thing + name: Duties PF2e Provider + location: "{{pf2e/core}}" + flags: [WIZARD, no_command] + attributes: + # Every skill, Perception and the three saves. Anyone may roll any of them: untrained is a rank too. + FN`DUTIES`TRAITS: + value: |- + json_array(iter(get({{pf2e/core}}/DATA`STATISTICS),json(object,key,json(string,%i0),label,json(string,capstr(%i0)),group,json(string,switch(first(get({{pf2e/core}}/DATA`STATISTIC`[ucstr(%i0)])),skill,Skills,save,Saves,Perception)),always,true),%b,|),|) + flags: [funsyntax] + # Pathfinder's four degrees of success; there is no partial success. + FN`DUTIES`TIERS: + value: |- + crit-fail fail success crit-success + flags: [funsyntax] + # %, %: the DC's name. The number depends on the roller's level, so it is named here + # and worked out in CHECK. + FN`DUTIES`DC: + value: |- + if(isint(u(%!/FUN`DC`ADJUST,%)),Level DC [u(%!/FUN`DC`ADJUSTTEXT,%)],#-1 NO SUCH DIFFICULTY) + flags: [funsyntax] + # %: the statistic this character improvises with, the one with the highest modifier (the first of + # equals, in the order the core lists them). + FN`DUTIES`FALLBACK: + value: |- + null(u(%!/FUN`PREPARE,%))[setq(fallback_pairs,iter(get({{pf2e/core}}/DATA`STATISTICS),%i0:[u(%!/FUN`STAT`TOTAL,%i0)]))][setq(fallback_best,lmax(iter(%q,after(%i0,:))))][first(iter(%q,if(eq(after(%i0,:),%q),before(%i0,:))))] + flags: [funsyntax] + # %, %: 1 when the statistic is trained or better. + FN`DUTIES`TRAINED: + value: |- + null(u(%!/FUN`PREPARE,%))[gt(u({{pf2e/core}}/FUN`CHECK`RANK,%),0)] + flags: [funsyntax] + # %, %, %, %, %. 1d20 plus the statistic's stacked modifiers + # against the level DC for the difficulty; a helper in % is Aid, +1 circumstance. The degree is + # pf2e's own: 10 over or under, and a natural 20 or 1 a step up or down. Returns {"tier","text","roll", + # "margin","system"}, system holding dc, total, natural, degree and helpers. + FN`DUTIES`CHECK: + value: |- + setqm(provider_adjust,u(%!/FUN`DC`ADJUST,%),provider_stat,grab(get({{pf2e/core}}/DATA`STATISTICS),lcstr(%)))[cond(not(isint(%q)),#-1 NO SUCH DIFFICULTY,not(strlen(%q)),#-1 NO SUCH TRAIT,u(%!/FUN`CHECK`ROLL,%,%q,%q,u(%!/FUN`MODS`HELPERS,%)))] + flags: [funsyntax] + # The rewards a duty may give: experience, and money in each coin. + FN`DUTIES`REWARDS: + value: |- + lit([{"kind":"xp","label":"Experience","fields":[{"key":"amount","type":"integer"}]},{"kind":"gp","label":"Gold pieces","fields":[{"key":"amount","type":"integer"}]},{"kind":"sp","label":"Silver pieces","fields":[{"key":"amount","type":"integer"}]},{"kind":"cp","label":"Copper pieces","fields":[{"key":"amount","type":"integer"}]}]) + flags: [funsyntax] + # Queued once for each reward and member: %, % {"kind","amount"}, % {"duty"}. pf2e + # writes the entry in the character's experience or money ledger and tells the player. + ON`DUTIES`GRANT: + value: |- + @assert hastype(%,player); think setqm(grant_kind,lcstr(json_query(%,extract,$.kind)),grant_amount,firstof(json_query(%,extract,$.amount),1)); @assert cand(match(xp gp sp cp,%q),isint(%q),gt(%q,0)); @trigger/args {{pf2e/commands}}/TRIG`PURSE`PUT=target,%,kind,if(strmatch(%q,xp),xp,money),amount,mul(%q,switch(%q,gp,100,sp,10,1)),reason,Duty [json_query(%,extract,$.duty)],shown,%q [if(strmatch(%q,xp),XP,%q)] + flags: [cmdsyntax] + # %0 a character: sets pf2e's check_ registers from their ledger. + FUN`PREPARE: + value: |- + u({{pf2e/core}}/FUN`CHECK`PREPARE,u({{pf2e/commands}}/FUN`LEDGER`OF,%0)) + flags: [funsyntax] + # %0 a statistic: its total modifier, once FUN`PREPARE has run. + FUN`STAT`TOTAL: + value: |- + ladd(0 [iter(u({{pf2e/core}}/FUN`CHECK`CHOSEN,%0),elements(%i0,2,~))]) + flags: [funsyntax] + # %0 the roller, %1 the statistic, %2 the DC adjustment, %3 how many helped. + FUN`CHECK`ROLL: + value: |- + null(u(%!/FUN`PREPARE,%0))[setqm(roll_total,add(u(%!/FUN`STAT`TOTAL,%1),if(%3,1,0)),roll_dc,add(extract(get({{pf2e/core}}/DATA`DC`LEVEL),inc(max(0,min(25,%q))),1),%2))][setq(roll_record,roll(1d20[if(gte(%q,0),+)]%q,,record))][setqm(roll_face,json_query(%q,extract,$.dice\[0\].results\[0\].result),roll_result,json_query(%q,extract,$.total))][setq(roll_degree,u({{pf2e/core}}/FUN`DEGREE`OF`CHECK,%q,%q,%q))][json(object,tier,json(string,extract(crit-fail fail success crit-success,inc(%q),1)),text,json(string,[capstr(%1)]: [json_query(%q,extract,$.text)] vs DC %q[if(%3,%b%(+1 from Aid%))]),roll,json_query(%q,extract,$.id),margin,sub(%q,%q),system,json(object,dc,%q,total,%q,natural,%q,degree,%q,helpers,%3))] + flags: [funsyntax] + # %0 a difficulty word: what it adds to the level DC (pf2e's own adjustments), else nothing. + FUN`DC`ADJUST: + value: |- + switch(lcstr(%0),trivial,-10,easy,-2,standard,0,hard,2,extreme,5,) + flags: [funsyntax] + FUN`DC`ADJUSTTEXT: + value: |- + switch(lcstr(%0),trivial,-10 %(incredibly easy%),easy,-2 %(easy%),standard,%(normal%),hard,+2 %(hard%),extreme,+5 %(very hard%)) + flags: [funsyntax] + # %0 %, a JSON object: how many helpers it names. + FUN`MODS`HELPERS: + value: |- + if(cand(strlen(%0),strmatch(json_query(json_query(%0,get,helpers)),array)),json_query(json_query(%0,get,helpers),size),0) + flags: [funsyntax] + + - ref: provider_registration + target: "{{duties/duties}}" + attributes: + PROVIDER`PF2E: |- + {{provider}} diff --git a/duties-salvage-union/package.yaml b/duties-salvage-union/package.yaml index 939b1d8..ce7222c 100644 --- a/duties-salvage-union/package.yaml +++ b/duties-salvage-union/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: duties-salvage-union title: "Duties: Salvage Union rolls" -version: 1.0.1 +version: 1.0.2 authors: [SharpMUSH] description: "Lets Duties roll on the Salvage Union sheet: a roll provider called salvage, so a duty's checks roll the d20 on the Core Mechanic table with one of the pilot's abilities or the mech's systems and modules, and Training Points or scrap for the Union Crawler as rewards. Pick it with +config duties/system=salvage." license: MIT @@ -89,7 +89,7 @@ objects: # amount of "3 2", which is 3 Tech 2 scrap. ON`DUTIES`GRANT: value: |- - @assert hastype(%,player); think setqm(grant_kind,json_query(%,extract,$.kind),grant_amount,first(firstof(json_query(%,extract,$.amount),1)),grant_tech,firstof(json_query(%,extract,$.tech),extract(json_query(%,extract,$.amount),2,1),1)); @assert cand(isint(%q),gt(%q,0)); @switch %q=tp,{@pemit %=notice(DUTIES,You gain %q Training Points. You have [u({{sheet-salvage-union/sheet}}/API`ADJUST,%,TP,%q,a duty)].,ok)},scrap,{@assert cand(isint(%q),gte(%q,1),lte(%q,6)); @pemit %=notice(DUTIES,You haul %q Tech %q scrap back to the Union Crawler. Its hold has [u({{sheet-salvage-union/sheet}}/API`SCRAP,%q,%q,a duty,%)].,ok)} + @assert hastype(%,player); think setqm(grant_kind,json_query(%,extract,$.kind),grant_amount,first(firstof(json_query(%,extract,$.amount),1)),grant_tech,firstof(json_query(%,extract,$.tech),extract(json_query(%,extract,$.amount),2,1),1)); @assert cand(isint(%q),gt(%q,0)); @switch %q=tp,{@pemit %=notice(DUTIES,You gain %q Training Point[if(neq(%q,1),s)]. You have [u({{sheet-salvage-union/sheet}}/API`ADJUST,%,TP,%q,a duty)].,ok)},scrap,{@assert cand(isint(%q),gte(%q,1),lte(%q,6)); @pemit %=notice(DUTIES,You haul %q Tech %q scrap back to the Union Crawler. Its hold has [u({{sheet-salvage-union/sheet}}/API`SCRAP,%q,%q,a duty,%)].,ok)} flags: [cmdsyntax] - ref: provider_registration diff --git a/index.yaml b/index.yaml index f20e7f3..ee8e6a4 100644 --- a/index.yaml +++ b/index.yaml @@ -40,7 +40,7 @@ packages: - path: sheet-d20/ name: D20 Sheet package: sheet-d20 - version: 2.2.0 + version: 2.2.1 description: d20 character sheet built from a ledger (abilities, skills, training, level, hit points, coin, gear), guided character creation, +check against a DC or a foe, and encounters with their own sheet copies, foes from a bestiary, initiative and conditions - path: sheet-d20-help/ package: sheet-d20-help @@ -130,6 +130,10 @@ packages: package: duties-d20 version: 1.0.1 description: Duties roll provider "d20" on the D20 sheet + - path: duties-pf2e/ + package: duties-pf2e + version: 1.0.0 + description: Duties roll provider "pf2e" on the Pathfinder 2e sheet - path: duties-fate/ package: duties-fate version: 1.0.0 @@ -137,7 +141,7 @@ packages: - path: sheet-pbta/ name: PbtA Sheet package: sheet-pbta - version: 2.3.0 + version: 2.3.1 description: Powered by the Apocalypse character sheet built from a ledger (playbooks, stats, moves, guided character creation, advances, forward, ongoing, hold, harm, XP), +check on 2d6 and encounters on sheet copies with foes and GM moves; Dungeon World moves under CC BY 3.0 - path: sheet-pbta-help/ package: sheet-pbta-help @@ -153,7 +157,7 @@ packages: description: Joins the PbtA sheet to +app character applications - path: duties-pbta/ package: duties-pbta - version: 1.0.1 + version: 1.0.2 description: Duties roll provider "pbta" on the PbtA sheet - path: pbta-wiki/ name: PbtA rules @@ -183,7 +187,7 @@ packages: - path: pf2e/ name: Pathfinder 2e rules package: pf2e - version: 0.3.0 + version: 0.3.1 description: Pathfinder Second Edition rules read the way Foundry VTT's pf2e system reads them, with ledger character sheets, a character builder, encounters with a bestiary, hazards and GM tools, exploration, skill challenges, audited awards and levels (ORC License) - path: pf2e-help/ name: Pathfinder 2e help @@ -193,7 +197,7 @@ packages: - path: sheet-fitd/ name: FitD Sheet package: sheet-fitd - version: 2.2.0 + version: 2.2.1 description: Forged in the Dark character sheet (ledger-built actions, XP advances, stress, trauma, harm, coin, audited log, encounters with threats and positions, clocks) with +check on a d6 pool; Blades in the Dark SRD under CC BY 3.0 - path: sheet-fitd-help/ package: sheet-fitd-help @@ -210,7 +214,7 @@ packages: - path: sheet-brp/ name: BRP Sheet package: sheet-brp - version: 2.2.0 + version: 2.3.0 description: Percentile character sheet on Basic Roleplaying (ledger-built characteristics and skills, point-buy chargen, experience checks, hit points, power points, coin, audited log, encounters with creatures, hit locations and strike ranks) with +check on 1d100; ORC Licensed Material - path: sheet-brp-help/ package: sheet-brp-help @@ -227,7 +231,7 @@ packages: - path: sheet-ironsworn/ name: Ironsworn Sheet package: sheet-ironsworn - version: 2.2.0 + version: 2.2.1 description: Ironsworn character sheet (stats and assets built from a ledger, meters, experience spent on assets with an audited log, companion health, iron vows, encounters with their own copies, foes on progress tracks) with +check action rolls and +vow; Ironsworn SRD under CC BY 4.0 - path: sheet-ironsworn-help/ package: sheet-ironsworn-help @@ -247,7 +251,7 @@ packages: description: Duties roll provider "fitd" on the FitD sheet - path: duties-brp/ package: duties-brp - version: 1.0.1 + version: 1.0.2 description: Duties roll provider "brp" on the BRP sheet - path: duties-ironsworn/ package: duties-ironsworn @@ -298,7 +302,7 @@ packages: description: Joins the Salvage Union sheet to +app character applications - path: duties-salvage-union/ package: duties-salvage-union - version: 1.0.1 + version: 1.0.2 description: Duties roll provider "salvage" on the Salvage Union sheet - path: salvage-union-wiki/ name: Salvage Union rules diff --git a/pf2e/package.yaml b/pf2e/package.yaml index cee1d84..612b393 100644 --- a/pf2e/package.yaml +++ b/pf2e/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: pf2e title: Pathfinder 2e rules -version: "0.3.0" +version: "0.3.1" authors: [SharpMUSH] description: "Pathfinder Second Edition rules in softcode, read the way Foundry VTT's pf2e system reads them, with character sheets kept as a ledger: +build, +sheet, +check, encounters that keep their own copy of each character, built from the bestiary with elite and weak creatures and hazards (+enc), exploration, skill challenges, Recall Knowledge, and audited awards with levels and runes (+pf2e/award)." license: MIT @@ -1416,6 +1416,14 @@ objects: value: |- @assert cand(match(money xp,%q),isint(%q))=@pemit %#=notice(PF2E,The [firstof(%q,money)] entry could not be written: %q,error); think setqm(purse_attr,PF2E`[ucstr(%q)],purse_n,inc(lmax(0 [u({{commands}}/FUN`PURSE`ENTRIES,%q,%q)]))); &%q`%q %q=[json(object,switch(%q,money,cp,xp),%q,reason,json(string,%q),by,json(string,objid(%#)),at,secs())]; @set %q/%q`%q=wizard; &PF2E`TOTAL`[ucstr(%q)] %q=[u({{commands}}/FUN`PURSE`SUM,%q,%q)]; @set %q/PF2E`TOTAL`[ucstr(%q)]=wizard flags: [cmdsyntax] + # @trigger/args with target (a character), kind (money or xp), amount (copper pieces or XP), reason and + # shown (the amount as the character reads it, such as 5 gp): the entry INC`PURSE`PUT writes, for a + # package that cannot include it, such as a Duties provider; the character is told. Only an object that + # controls this one can trigger it. + TRIG`PURSE`PUT: + value: |- + @assert hastype(%,player); think setqm(sheet_target,%,purse_kind,%,purse_amount,%,purse_reason,%); @include %!/INC`PURSE`PUT; @pemit %=notice(PF2E,You gain %: %q %(entry %q%).[if(strmatch(%q,xp),%b[u(%!/FUN`SHOW`XP,u(%!/FUN`PURSE`TOTAL,%,xp))])],ok) + flags: [cmdsyntax] # Revoke every entry of build_step; what came with them goes too. INC`BUILD`CLEAR: value: |- diff --git a/sheet-brp/package.yaml b/sheet-brp/package.yaml index 6e8b7f1..3a9decc 100644 --- a/sheet-brp/package.yaml +++ b/sheet-brp/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: sheet-brp title: "Percentile sheet (BRP)" -version: 2.2.0 +version: 2.3.0 authors: [SharpMUSH] description: "A percentile character sheet on the Basic Roleplaying rules: seven characteristics and a skill list with base chances the game edits, built from a ledger, with point-buy character creation, experience checks that raise skills, hit points, power points and coin, an audited coin ledger, and encounters that play from copies of the sheets, with creatures from a bestiary the game edits, hit locations and an order of play. +check rolls 1d100 under a skill or a characteristic roll, doubled or halved for difficulty, and reads critical, special, success, failure or fumble. The skill list is ORC Licensed Material from Basic Roleplaying: Universal Game Engine." license: MIT @@ -1544,7 +1544,7 @@ objects: # %0 the character, %1 who reads it: what they can do next. FUN`DISPLAY`FOOTER: value: |- - setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows the steps.[u(%!/FUN`HINT,FOOTER)],not(comp(objid(%1),%0)),+check = rolls. A success marks an experience check%, and +sheet/improve rolls them.,+check rolls 1d100 under the percentage.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] + setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows the steps.,not(comp(objid(%1),%0)),+check = rolls. A success marks an experience check%, and +sheet/improve rolls them.,+check rolls 1d100 under the percentage.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] flags: [funsyntax] FUN`DISPLAY`SIGNED: value: |- @@ -1665,6 +1665,16 @@ objects: value: |- null(u(%!/FUN`BUILD`OF,%0))[u(%!/FUN`RATE,%q,%q,ucstr(%1))] flags: [VISUAL] + # %0 a character, %1 keys, else every characteristic roll and skill: the key with the highest percentage, + # the first of equals. Reads the build once. + API`BEST: + value: |- + null(u(%!/FUN`BUILD`OF,%0))[lcstr(last(sortkey(%!/FUN`BEST`KEY,revwords(ucstr(if(strlen(%1),%1,u(%!/FUN`TRAIT`ROLLS) [u(%!/FUN`LIST`ALL,SKILL)]))),n)))] + flags: [VISUAL] + FUN`BEST`KEY: + value: |- + u(%!/FUN`RATE,%q,%q,%0) + flags: [funsyntax] # %0 a character, %1 a key: 1 when a skill stands above its base chance; a characteristic roll always. API`TRAINED: value: |- diff --git a/sheet-d20/package.yaml b/sheet-d20/package.yaml index 34c2b96..c4c5622 100644 --- a/sheet-d20/package.yaml +++ b/sheet-d20/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: sheet-d20 title: "D20 sheet" -version: 2.2.0 +version: 2.2.1 authors: [SharpMUSH] description: "A d20 character sheet built from a ledger: six ability scores, a skill list the game edits, training, level, hit points, coin and gear, with separate audited ledgers for XP, coin and gear. Guided character creation, XP advances, +check rolls 1d20 plus a trait against a DC, and encounters that keep their own copy of each sheet, with foes from a bestiary the game edits, initiative, turns and conditions." license: MIT @@ -1504,7 +1504,7 @@ objects: # %0 the character, %1 who reads it: what they can do next. FUN`DISPLAY`FOOTER: value: |- - setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows every step.[u(%!/FUN`HINT,FOOTER)],not(comp(objid(%1),%0)),+check rolls. +sheet/advance spends XP.,+check rolls 1d20 plus what a trait adds.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] + setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows every step.,not(comp(objid(%1),%0)),+check rolls. +sheet/advance spends XP.,+check rolls 1d20 plus what a trait adds.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] flags: [funsyntax] # %0 the character, %1 who reads it: the steps of making a character. FUN`SCREEN`CHARGEN: diff --git a/sheet-fitd/package.yaml b/sheet-fitd/package.yaml index e0b4b5b..838a5b4 100644 --- a/sheet-fitd/package.yaml +++ b/sheet-fitd/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: sheet-fitd title: "Forged in the Dark sheet" -version: 2.2.0 +version: 2.2.1 authors: [SharpMUSH] description: "A Forged in the Dark character sheet: twelve action ratings under three attributes, built from a ledger, with XP for each attribute spent on advances, stress, trauma, harm and coin, separate audited ledgers for XP and coin, encounters that play from copies of the sheets, with threats from a list the game edits and positions and effect, and progress clocks. +check rolls a pool of six-sided dice and reads the highest against a position for the room; +check/resist rolls an attribute to resist a consequence. Based on the Blades in the Dark SRD under CC BY 3.0." license: MIT @@ -1340,7 +1340,7 @@ objects: # %0 the character, %1 who reads it: what they can do next. FUN`DISPLAY`FOOTER: value: |- - setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows the steps.[u(%!/FUN`HINT,FOOTER)],not(comp(objid(%1),%0)),+check = rolls. +sheet/advance spends XP.,+check rolls a die for each point of the rating.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] + setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows the steps.,not(comp(objid(%1),%0)),+check = rolls. +sheet/advance spends XP.,+check rolls a die for each point of the rating.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] flags: [funsyntax] # %0 the character, %1 who reads it: the steps of making a character. FUN`SCREEN`CHARGEN: diff --git a/sheet-ironsworn/package.yaml b/sheet-ironsworn/package.yaml index f638d94..be1416a 100644 --- a/sheet-ironsworn/package.yaml +++ b/sheet-ironsworn/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: sheet-ironsworn title: "Ironsworn sheet" -version: 2.2.0 +version: 2.2.1 authors: [SharpMUSH] description: "An Ironsworn character sheet: five stats and assets built from a ledger, health, spirit, supply and momentum, experience spent on new assets and their abilities, with its own audited ledger, companion health, iron vows with progress tracks, and encounters that play from copies of the sheets. +check makes an action roll, a six-sided die plus a stat against two ten-sided challenge dice, for the room; +vow swears, marks and fulfils vows. Based on the Ironsworn SRD under CC BY 4.0." license: MIT @@ -1484,7 +1484,7 @@ objects: # %0 the character, %1 who reads it: what they can do next. FUN`DISPLAY`FOOTER: value: |- - setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows the steps.[u(%!/FUN`HINT,FOOTER)],not(comp(objid(%1),%0)),+check rolls. +sheet/asset and +sheet/upgrade spend experience.,+check rolls a six-sided die plus the stat against two ten-sided dice.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] + setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows the steps.,not(comp(objid(%1),%0)),+check rolls. +sheet/asset and +sheet/upgrade spend experience.,+check rolls a six-sided die plus the stat against two ten-sided dice.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] flags: [funsyntax] # %0 the character, %1 who reads it: the steps of making a character. FUN`SCREEN`CHARGEN: diff --git a/sheet-pbta/package.yaml b/sheet-pbta/package.yaml index 3ce9577..687cb24 100644 --- a/sheet-pbta/package.yaml +++ b/sheet-pbta/package.yaml @@ -1,7 +1,7 @@ format: "1.16" package: sheet-pbta title: "PbtA sheet" -version: 2.3.0 +version: 2.3.1 authors: [SharpMUSH] description: "A Powered by the Apocalypse character sheet built from a ledger: playbooks, stats and moves the game edits, guided character creation, advances, forward, ongoing, hold, harm, and XP with its own audited ledger. +sheet shows and builds it, +check rolls 2d6 plus a stat for a move, and +encounter plays a scene from copies of the sheets, with foes from a bestiary the game edits, and GM moves. Ships the Dungeon World basic and special moves (CC BY 3.0) as its example set." license: MIT @@ -1363,7 +1363,7 @@ objects: # %0 the character, %1 who reads it. FUN`DISPLAY`FOOTER: value: |- - setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows every step.[u(%!/FUN`HINT,FOOTER)],not(comp(objid(%1),%0)),+check rolls. +sheet/move shows a move's text.,+check rolls 2d6 plus a stat.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] + setq(footer_n,u(%!/FUN`ENC`JOINED,%0))[cond(cand(not(comp(objid(%1),%0)),not(isapproved(%1)),not(u(%!/FUN`PERM`KEEPER,%1))),u(%!/FUN`CHARGEN`NEXT,%0) +sheet/chargen shows every step.,not(comp(objid(%1),%0)),+check rolls. +sheet/move shows a move's text.,+check rolls 2d6 plus a stat.)][if(words(%q),%b[name(%0)] plays from a copy in encounter[if(gt(words(%q),1),s)] [itemize(%q)]: +encounter shows [if(gt(words(%q),1),them,it)].)] flags: [funsyntax] # %0 the character, %1 who reads it: the steps of making a character. FUN`SCREEN`CHARGEN: From b70f95285ea9182d7257de714fdd263a8d8ecb4d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 18:48:02 +0000 Subject: [PATCH 2/3] duties-pf2e: stack Aid as a circumstance bonus Aid was added after pf2e had stacked the statistic's modifiers, so a +2 circumstance bonus and Aid gave +3. It now goes through pf2e's FUN`MODIFIER`STACK with the other modifiers, so the larger circumstance bonus wins. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Rqqt7SRfDwJ7jHJPqVA5oS --- duties-pf2e/package.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/duties-pf2e/package.yaml b/duties-pf2e/package.yaml index 2f732d1..132d421 100644 --- a/duties-pf2e/package.yaml +++ b/duties-pf2e/package.yaml @@ -89,15 +89,16 @@ objects: value: |- u({{pf2e/core}}/FUN`CHECK`PREPARE,u({{pf2e/commands}}/FUN`LEDGER`OF,%0)) flags: [funsyntax] - # %0 a statistic: its total modifier, once FUN`PREPARE has run. + # %0 a statistic, %1 1 when someone Aids: its total modifier, once FUN`PREPARE has run. Aid is a +1 + # circumstance bonus, stacked with the statistic's own modifiers the way pf2e stacks them. FUN`STAT`TOTAL: value: |- - ladd(0 [iter(u({{pf2e/core}}/FUN`CHECK`CHOSEN,%0),elements(%i0,2,~))]) + ladd(0 [iter(if(%1,u({{pf2e/core}}/FUN`MODIFIER`STACK,u({{pf2e/core}}/FUN`CHECK`CHOSEN,%0) circumstance~1~aid~0),u({{pf2e/core}}/FUN`CHECK`CHOSEN,%0)),elements(%i0,2,~))]) flags: [funsyntax] # %0 the roller, %1 the statistic, %2 the DC adjustment, %3 how many helped. FUN`CHECK`ROLL: value: |- - null(u(%!/FUN`PREPARE,%0))[setqm(roll_total,add(u(%!/FUN`STAT`TOTAL,%1),if(%3,1,0)),roll_dc,add(extract(get({{pf2e/core}}/DATA`DC`LEVEL),inc(max(0,min(25,%q))),1),%2))][setq(roll_record,roll(1d20[if(gte(%q,0),+)]%q,,record))][setqm(roll_face,json_query(%q,extract,$.dice\[0\].results\[0\].result),roll_result,json_query(%q,extract,$.total))][setq(roll_degree,u({{pf2e/core}}/FUN`DEGREE`OF`CHECK,%q,%q,%q))][json(object,tier,json(string,extract(crit-fail fail success crit-success,inc(%q),1)),text,json(string,[capstr(%1)]: [json_query(%q,extract,$.text)] vs DC %q[if(%3,%b%(+1 from Aid%))]),roll,json_query(%q,extract,$.id),margin,sub(%q,%q),system,json(object,dc,%q,total,%q,natural,%q,degree,%q,helpers,%3))] + null(u(%!/FUN`PREPARE,%0))[setqm(roll_total,u(%!/FUN`STAT`TOTAL,%1,gt(%3,0)),roll_dc,add(extract(get({{pf2e/core}}/DATA`DC`LEVEL),inc(max(0,min(25,%q))),1),%2))][setq(roll_record,roll(1d20[if(gte(%q,0),+)]%q,,record))][setqm(roll_face,json_query(%q,extract,$.dice\[0\].results\[0\].result),roll_result,json_query(%q,extract,$.total))][setq(roll_degree,u({{pf2e/core}}/FUN`DEGREE`OF`CHECK,%q,%q,%q))][json(object,tier,json(string,extract(crit-fail fail success crit-success,inc(%q),1)),text,json(string,[capstr(%1)]: [json_query(%q,extract,$.text)] vs DC %q[if(%3,%b%(+1 from Aid%))]),roll,json_query(%q,extract,$.id),margin,sub(%q,%q),system,json(object,dc,%q,total,%q,natural,%q,degree,%q,helpers,%3))] flags: [funsyntax] # %0 a difficulty word: what it adds to the level DC (pf2e's own adjustments), else nothing. FUN`DC`ADJUST: From eea817f9d1ac0a6286f37438a59efaf97f912086 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 23:12:10 +0000 Subject: [PATCH 3/3] pf2e: start the level DC table at level -1 FUN`DC`OF indexed DATA`DC`LEVEL as if it began at level -1, but the table began at level 0, so every level read the next level's DC and level 25 read past the end. The table now holds GM Core's level -1 DC (13), and the Duties provider indexes it the same way. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Rqqt7SRfDwJ7jHJPqVA5oS --- duties-pf2e/package.yaml | 2 +- pf2e/package.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/duties-pf2e/package.yaml b/duties-pf2e/package.yaml index 132d421..8807e46 100644 --- a/duties-pf2e/package.yaml +++ b/duties-pf2e/package.yaml @@ -98,7 +98,7 @@ objects: # %0 the roller, %1 the statistic, %2 the DC adjustment, %3 how many helped. FUN`CHECK`ROLL: value: |- - null(u(%!/FUN`PREPARE,%0))[setqm(roll_total,u(%!/FUN`STAT`TOTAL,%1,gt(%3,0)),roll_dc,add(extract(get({{pf2e/core}}/DATA`DC`LEVEL),inc(max(0,min(25,%q))),1),%2))][setq(roll_record,roll(1d20[if(gte(%q,0),+)]%q,,record))][setqm(roll_face,json_query(%q,extract,$.dice\[0\].results\[0\].result),roll_result,json_query(%q,extract,$.total))][setq(roll_degree,u({{pf2e/core}}/FUN`DEGREE`OF`CHECK,%q,%q,%q))][json(object,tier,json(string,extract(crit-fail fail success crit-success,inc(%q),1)),text,json(string,[capstr(%1)]: [json_query(%q,extract,$.text)] vs DC %q[if(%3,%b%(+1 from Aid%))]),roll,json_query(%q,extract,$.id),margin,sub(%q,%q),system,json(object,dc,%q,total,%q,natural,%q,degree,%q,helpers,%3))] + null(u(%!/FUN`PREPARE,%0))[setqm(roll_total,u(%!/FUN`STAT`TOTAL,%1,gt(%3,0)),roll_dc,add(extract(get({{pf2e/core}}/DATA`DC`LEVEL),add(2,max(-1,min(25,%q))),1),%2))][setq(roll_record,roll(1d20[if(gte(%q,0),+)]%q,,record))][setqm(roll_face,json_query(%q,extract,$.dice\[0\].results\[0\].result),roll_result,json_query(%q,extract,$.total))][setq(roll_degree,u({{pf2e/core}}/FUN`DEGREE`OF`CHECK,%q,%q,%q))][json(object,tier,json(string,extract(crit-fail fail success crit-success,inc(%q),1)),text,json(string,[capstr(%1)]: [json_query(%q,extract,$.text)] vs DC %q[if(%3,%b%(+1 from Aid%))]),roll,json_query(%q,extract,$.id),margin,sub(%q,%q),system,json(object,dc,%q,total,%q,natural,%q,degree,%q,helpers,%3))] flags: [funsyntax] # %0 a difficulty word: what it adds to the level DC (pf2e's own adjustments), else nothing. FUN`DC`ADJUST: diff --git a/pf2e/package.yaml b/pf2e/package.yaml index 612b393..dd8f8d7 100644 --- a/pf2e/package.yaml +++ b/pf2e/package.yaml @@ -88,8 +88,8 @@ objects: DATA`PREP`VERSION: 2 # The proficiencies other than the statistics: weapon categories, armor categories, spellcasting and the class DC. DATA`PROFICIENCIES: simple martial advanced unarmed unarmored light medium heavy spellcasting classdc - # GM Core's DC for each level, from level 0 to 25, and how much each difficulty moves it. - DATA`DC`LEVEL: 14 15 16 18 19 20 22 23 24 26 27 28 30 31 32 34 35 36 38 39 40 42 44 46 48 50 + # GM Core's DC for each level, from level -1 to 25, and how much each difficulty moves it. + DATA`DC`LEVEL: 13 14 15 16 18 19 20 22 23 24 26 27 28 30 31 32 34 35 36 38 39 40 42 44 46 48 50 DATA`DC`ADJUST: incredibly-easy~-10 very-easy~-5 easy~-2 normal~0 hard~2 very-hard~5 incredibly-hard~10 DATA`DC`RARITY: common~0 uncommon~2 rare~5 unique~10 # Simple DCs by proficiency rank, untrained to legendary.