diff --git a/index.yaml b/index.yaml
index 34e9cb2..4c855e4 100644
--- a/index.yaml
+++ b/index.yaml
@@ -187,7 +187,7 @@ packages:
- path: pf2e/
name: Pathfinder 2e rules
package: pf2e
- version: 0.10.8
+ version: 0.10.9
description: Pathfinder Second Edition rules read the way Foundry VTT's pf2e system reads them, with ledger character sheets, a character builder, spellcasting, a deity table the game fills, alchemy, encounters with a bestiary, hazards, effects and GM tools, exploration, skill challenges, audited awards and levels (ORC License)
- path: pf2e-help/
name: Pathfinder 2e help
diff --git a/pf2e/package.yaml b/pf2e/package.yaml
index 5104789..98cdfce 100644
--- a/pf2e/package.yaml
+++ b/pf2e/package.yaml
@@ -1,7 +1,7 @@
format: "1.20"
package: pf2e
title: Pathfinder 2e rules
-version: "0.10.8"
+version: "0.10.9"
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, spellcasting (+spells, +prepare, +cast, +rest), a deity table the game fills (+deity), alchemy (+alchemy), encounters with effects and battle forms 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
@@ -113,7 +113,7 @@ objects:
# ledger read again costs a few hundred function calls. The key is the ledger with the package's
# version, the books and CACHE`STAMP, which the updater and the deity table change. CACHE lists
# the keys oldest first; past DATA`CACHE`KEEP the oldest goes.
- DATA`CACHE`VERSION: "0.10.8"
+ DATA`CACHE`VERSION: "0.10.9"
DATA`CACHE`KEEP: 200
DATA`CACHE`REGISTERS: check_actor check_actortraits check_adjstrike check_adjust check_ancestry check_armor check_background check_class check_conditions check_craftgrants check_crafting check_deity check_deity_spells check_deity_weapons check_domopts check_dynamic check_entries check_favored check_favoredrules check_flats check_form check_forms check_formulas check_gear check_grants check_heritage check_index check_itemalts check_level check_martial check_names check_options check_rankdyn check_resgrants check_resources check_rollopts check_rollrules check_shield check_shieldrules check_bulkrules check_bulk check_bulk_enc check_bulk_max check_static check_stats check_strikes check_synthetics check_toggles check_traits check_unapplied check_upgrades
# The ItemAlteration properties the core applies, by the kind of item they reach.
@@ -5970,7 +5970,7 @@ objects:
json(object,kind,"level",level,u(FUN`ENC`LEVEL,%0),n,1))]\,[
iter(setunion(setr(enc_keys,setunion(json_map(%!/FUN`JSON`KEY,%q,%b),iter(%q,first(%i0,~)))) [iter(%q,u(FUN`ENC`IMPLIED,%i0))],),if(strlen(setr(enc_cid,u({{core}}/FUN`ITEM`FIND,conditions,%i0))),json(object,kind,"grant",pack,"conditions",id,json(string,%q),badge,if(setr(enc_badge,firstof(json_query(%q,extract,$.%i0),after(grab(%q,%i0~*),~))),%q,null),n,add(100000,inum(0)))),%b,\,)]\,[
iter(json_map(%!/FUN`JSON`KEY,setr(enc_used,firstof(u(FUN`ENC`C,%0,used),json(object))),%b),json(object,kind,"gear",id,json(string,%i0),qty,first(json_query(%q,extract,$.%i0),|),where,json(string,rest(json_query(%q,extract,$.%i0),|)),n,add(200000,inum(0))),%b,\,)]\,[
- iter(json_map(%!/FUN`JSON`KEY,setr(enc_fx,firstof(u(FUN`ENC`C,%0,fx),json(object))),%b),json(object,kind,"grant",pack,json(string,edit(json_query(%q,extract,$\["%i0"\].pack),",)),id,json(string,%i0),choices,json_mod(firstof(json_query(%q,extract,$\["%i0"\].ch),json(object)),patch,json(object,effectLevel,json_query(%q,extract,$\["%i0"\].lvl))),badge,firstof(json_query(%q,extract,$\["%i0"\].badge),null),n,add(300000,inum(0))),%b,\,)]\,[
+ iter(u(FUN`FX`LIVE,setr(enc_fx,firstof(u(FUN`ENC`C,%0,fx),json(object)))),json(object,kind,"grant",pack,json(string,edit(json_query(%q,extract,$\["%i0"\].pack),",)),id,json(string,%i0),choices,json_mod(firstof(json_query(%q,extract,$\["%i0"\].ch),json(object)),patch,json(object,effectLevel,json_query(%q,extract,$\["%i0"\].lvl))),badge,firstof(json_query(%q,extract,$\["%i0"\].badge),null),n,add(300000,inum(0))),%b,\,)]\,[
iter(json_map(%!/FUN`JSON`KEY,setr(enc_tg,firstof(u(FUN`ENC`C,%0,tg),json(object))),%b),json(object,kind,"toggle",domain,json(string,before(%i0,|)),option,json(string,after(%i0,|)),value,if(first(json_query(%q,extract,$\["%i0"\]),|),true,false),selection,if(strlen(setr(enc_tgsel,rest(json_query(%q,extract,$\["%i0"\]),|))),json(string,%q),null),n,add(400000,inum(0))),%b,\,)]\,[
iter(squish([if(strmatch(u(FUN`ENC`C,%0,kind),npc),self:type:[if(t(u(FUN`ENC`C,%0,hazard)),hazard,npc)])] [if(t(u(FUN`ENC`C,%0,raised)),self:shield:raised self:effect:raise-a-shield)] [if(strlen(setr(enc_shst,u(FUN`ENC`C,%0,shst))),self:shield:%q)]),json(object,kind,"option",option,json(string,%i0),n,add(500000,inum(0))),%b,\,)],\,),\,)]\]]
flags: [funsyntax]
@@ -5980,7 +5980,7 @@ objects:
value: |-
@@(%0 a combatant's index)[
setq(efc_fx,firstof(u(FUN`ENC`C,%0,fx),json(object)))][
- squish(iter(json_map(%!/FUN`JSON`KEY,%q,%b),u(FUN`ENC`FXCONDS`ONE,edit(json_query(%q,extract,$\["%i0"\].pack),",),%i0,firstof(json_query(%q,extract,$\["%i0"\].ch),json(object)))))]
+ squish(iter(u(FUN`FX`LIVE,%q),u(FUN`ENC`FXCONDS`ONE,edit(json_query(%q,extract,$\["%i0"\].pack),",),%i0,firstof(json_query(%q,extract,$\["%i0"\].ch),json(object)))))]
flags: [funsyntax]
FUN`ENC`FXCONDS`ONE:
value: |-
@@ -6874,10 +6874,90 @@ objects:
# A cast in the encounter, by the character you play there, on their copy of the day.
INC`CAST`ENC:
value: |-
- @assert cor(%q,eq(%q,u(%!/FUN`ENC`ACTING)))=@pemit %#=notice(PF2E,It is [u(%!/FUN`ENC`C,u(%!/FUN`ENC`ACTING),name)]'s turn.,warn); think u(%!/FUN`ENC`PREPARE,%q); think u({{core}}/FUN`CAST`PREPARE); think u(%!/FUN`ACT`HOLD,by); think setqm(daily,firstof(u(%!/FUN`ENC`C,%q,daily),json(object)),cast_map,u(%!/FUN`ENC`C,%q,map),cast_side,u(%!/FUN`ENC`C,%q,side)); @include %!/INC`CAST`PICK; @assert cor(not(u(%!/FUN`ENC`C,%q,noshield)),comp(u({{core}}/FUN`ITEM`SLUG,u({{core}}/FUN`ITEM`GET,spells,%q)),shield))=@pemit %#=notice(PF2E,[u(%!/FUN`ENC`C,%q,name)]'s Shield blocked until it ended: it cannot be cast again for 10 minutes.,warn); think setq(cast_on,if(strlen(%q),u(%!/FUN`ENC`TARGETS,%q),%q)); @assert not(strlen(%q))=@pemit %#=notice(PF2E,No one in the encounter is called %q.,warn); @assert words(%q)=@pemit %#=notice(PF2E,No one is there to cast on.,warn); think u(%!/FUN`SPELL`PREPARE,strmatch(u(%!/FUN`ENC`C,first(%q),side),%q)); @assert cor(strlen(%q),strlen(%q),strlen(%q),not(cor(%q,strlen(%q),strlen(%q))))=@pemit %#=notice(PF2E,Name the targets: +cast [u({{commands}}/FUN`SHOW`SPELLNAME,%q)]=%, or foes%, characters or everyone.,warn); think u({{commands}}/FUN`DAILY`SPEND,%q); think u(%!/FUN`ENC`SET,%q,daily,%q); think u(%!/FUN`CAST`ROLLS); think setq(cast_atk,sub(%q,mul(min(2,%q),5))); think setqm(sb_at,,sb_dmg,0); think setq(fx_sus,if(strmatch(json_query(u({{core}}/FUN`ITEM`GET,spells,%q),extract,$.system.duration.sustained),true),u(%!/FUN`ENC`C,%q,k))); think setq(cast_lines,iter(%q,u(%!/FUN`CAST`ON,%i0),%b,%r)); think setq(fx_sus,); think if(%q,u(%!/FUN`ENC`SET,%q,map,inc(%q))); @include %!/INC`ENC`STORE; @include %!/INC`SB`MARK; @remit %l=notice(PF2E,[u(%!/FUN`CAST`HEAD)][if(strlen(%q),%r%q)][if(strlen(trim(%q)),%r[trim(squish(%q,%r),%r)])])
+ @assert cor(%q,eq(%q,u(%!/FUN`ENC`ACTING)))=@pemit %#=notice(PF2E,It is [u(%!/FUN`ENC`C,u(%!/FUN`ENC`ACTING),name)]'s turn.,warn); think u(%!/FUN`ENC`PREPARE,%q); think u({{core}}/FUN`CAST`PREPARE); think u(%!/FUN`ACT`HOLD,by); think setqm(daily,firstof(u(%!/FUN`ENC`C,%q,daily),json(object)),cast_map,u(%!/FUN`ENC`C,%q,map),cast_side,u(%!/FUN`ENC`C,%q,side)); @include %!/INC`CAST`PICK; @assert cor(not(u(%!/FUN`ENC`C,%q,noshield)),comp(u({{core}}/FUN`ITEM`SLUG,u({{core}}/FUN`ITEM`GET,spells,%q)),shield))=@pemit %#=notice(PF2E,[u(%!/FUN`ENC`C,%q,name)]'s Shield blocked until it ended: it cannot be cast again for 10 minutes.,warn); think setq(cast_on,if(strlen(%q),u(%!/FUN`ENC`TARGETS,%q),%q)); @assert not(strlen(%q))=@pemit %#=notice(PF2E,No one in the encounter is called %q.,warn); @assert words(%q)=@pemit %#=notice(PF2E,No one is there to cast on.,warn); @assert cor(not(strlen(%q)),strlen(%q),not(strmatch(json_query(u({{core}}/FUN`ITEM`GET,spells,%q),extract,$.system.counteraction),true)),not(strlen(setr(ctr_errs,trim(iter(%q,[null(u(%!/FUN`CAST`COUNTER`PREP,%i0))]%q,%b,%b))))))=@pemit %#=notice(PF2E,%q,warn); think u(%!/FUN`SPELL`PREPARE,strmatch(u(%!/FUN`ENC`C,first(%q),side),%q)); @assert cor(strlen(%q),strlen(%q),strlen(%q),not(cor(%q,strlen(%q),strlen(%q))))=@pemit %#=notice(PF2E,Name the targets: +cast [u({{commands}}/FUN`SHOW`SPELLNAME,%q)]=%, or foes%, characters or everyone.,warn); think u({{commands}}/FUN`DAILY`SPEND,%q); think u(%!/FUN`ENC`SET,%q,daily,%q); think u(%!/FUN`CAST`ROLLS); think setq(cast_atk,sub(%q,mul(min(2,%q),5))); think setqm(sb_at,,sb_dmg,0); think setq(fx_sus,if(strmatch(json_query(u({{core}}/FUN`ITEM`GET,spells,%q),extract,$.system.duration.sustained),true),u(%!/FUN`ENC`C,%q,k))); think setq(cast_lines,iter(%q,u(%!/FUN`CAST`ON,%i0),%b,%r)); think setq(fx_sus,); think if(%q,u(%!/FUN`ENC`SET,%q,map,inc(%q))); @include %!/INC`ENC`STORE; @include %!/INC`SB`MARK; @remit %l=notice(PF2E,[u(%!/FUN`CAST`HEAD)][if(strlen(%q),%r%q)][if(strlen(trim(%q)),%r[trim(squish(%q,%r),%r)])])
flags: [cmdsyntax]
# What the spell does to combatant %0: heals an ally it can heal, else a spell attack against AC, a save
# against the spell DC (basic or not), or damage with neither; an ally or the caster gets the spell's effect.
+ # Counteracting (+cast on =, for a spell that counteracts): a counteract check, the spell
+ # attack modifier without the multiple attack penalty, against the DC of what is counteracted, the spell's rank
+ # against its rank. is an effect, an affliction, or a condition: one an effect grants counteracts that
+ # effect, any other takes the DC of what imposed it (on frightened vs 20). An effect's rank is the rank it was
+ # cast at and its DC the caster's, or the DC for its level; an affliction's or a condition's rank is half the
+ # level its DC belongs to, rounded up. A critical success counteracts up to 3 ranks higher, a success 1, a
+ # failure only a lower rank. A spell that counteracts an effect imposing listed conditions (Clear Mind) takes
+ # only those, by its rank, and suppresses what it would have counteracted at 2 ranks lower. DATA`COUNTER`
+ # holds what a spell does to an affliction: reduce (its stage, once a case) and, by rank, the kinds it counteracts.
+ DATA`COUNTER`CLEANSE-AFFLICTION: '{"reduce":1,"kinds":{"3":"disease poison","4":"curse disease poison"}}'
+ FUN`CAST`COUNTER`FIND:
+ value: |-
+ @@(%0 a combatant's index; arg_on: 1 when it has that effect, affliction or condition; ctr_key, ctr_akey, ctr_cond)[
+ setqm(ctr_on,trim(if(regmatchi(%q,\\s+vs\\s+\\d+$),before(%q,%bvs%b),%q)),ctr_vs,if(regmatchi(%q,\\s+vs\\s+\\d+$),last(%q)),ctr_key,,ctr_akey,,ctr_cond,)][
+ setqm(ctr_fx,firstof(u(FUN`ENC`C,%0,fx),json(object)),ctr_aff,firstof(u(FUN`ENC`C,%0,aff),json(object)))][
+ setq(ctr_key,first(iter(json_map(%!/FUN`JSON`KEY,%q,%b),if(strmatch(u(FUN`FX`NAME,edit(json_query(%q,extract,$\["%i0"\].pack),",),%i0),%q*),%i0))))][
+ if(not(strlen(%q)),setq(ctr_akey,first(iter(json_map(%!/FUN`JSON`KEY,%q,%b),if(strmatch(edit(json_query(%q,extract,$\["%i0"\].name),",),%q*),%i0)))))][
+ if(not(strlen(%q%q)),
+ [setq(ctr_slug,u({{core}}/FUN`ITEM`SLUGGIFY,%q))][
+ setq(ctr_key,first(iter(json_map(%!/FUN`JSON`KEY,%q,%b),if(member(iter(u(FUN`ENC`FXCONDS`ONE,edit(json_query(%q,extract,$\["%i0"\].pack),",),%i0,firstof(json_query(%q,extract,$\["%i0"\].ch),json(object))),first(%i0,~)),%q),%i0))))][
+ if(cor(strlen(%q),strlen(json_query(u(FUN`ENC`C,%0,conds),extract,$\["%q"\]))),setq(ctr_cond,%q))])][
+ t(strlen(%q%q%q))]
+ flags: [funsyntax]
+ FUN`CAST`COUNTER`LIST:
+ value: |-
+ @@(cast_id, pick_rank: the conditions the spell counteracts an effect imposing, at its rank, or nothing)[
+ setq(ccl_text,edit(get(u({{core}}/DATA`PACK`SPELLS)/ITEM`%q`TEXT),Heightened %(,^))][
+ if(strmatch(%q,*imposing one of these conditions*),
+ setunion(iter([before(first(%q,^),
,^),if(lte(squish(edit(before(%i0,%)),th,,rd,,nd,,st,)),%q),before(%i0,
)),^,^)],
+ iter(rest(edit(%i0,@UUID\[Compendium.pf2e.conditionitems.Item.,~),~),u({{core}}/FUN`ITEM`SLUGGIFY,before(%i0,\])),~,%b),^,%b),))]
+ flags: [funsyntax]
+ FUN`CAST`COUNTER`PREP:
+ value: |-
+ @@(%0 a target's index; arg_on, pick_rank, cast_id: ctr_err when the spell cannot counteract it there, else ctr_what, ctr_rank, ctr_dc, ctr_reduce and ctr_roll)[
+ setqm(ctr_tname,u(FUN`ENC`C,%0,name),ctr_levels,get({{core}}/DATA`DC`LEVEL),ctr_what,,ctr_err,,ctr_reduce,0,ctr_roll,1)][
+ null(u(FUN`CAST`COUNTER`FIND,%0))][
+ setqm(ctr_list,u(FUN`CAST`COUNTER`LIST),ctr_data,get(%!/DATA`COUNTER`[ucstr(u({{core}}/FUN`ITEM`SLUG,u({{core}}/FUN`ITEM`GET,spells,%q)))]))][
+ switch(1,
+ not(strlen(%q%q%q)),setq(ctr_err,%q has no effect%, affliction or condition called %q.),
+ cand(strlen(%q),not(member(%q,%q))),setq(ctr_err,[u({{commands}}/FUN`SHOW`SPELLNAME,%q)] at rank %q counteracts an effect imposing [itemize(%q,%b,or)].),
+ t(strlen(%q)),[setqm(ctr_pack,edit(json_query(%q,extract,$\["%q"\].pack),",),ctr_lvl,firstof(json_query(%q,extract,$\["%q"\].lvl),1))][setqm(ctr_what,u(FUN`FX`NAME,%q,%q),ctr_rank,if(strmatch(%q,spell-effects),%q,max(1,ceil(fdiv(%q,2)))))][setq(ctr_dc,firstof(json_query(%q,extract,$\["%q"\].dc),extract(%q,max(1,min(words(%q),if(strmatch(%q,spell-effects),add(mul(2,%q),1),add(%q,2)))),1)))],
+ t(strlen(%q)),[setqm(ctr_what,edit(json_query(%q,extract,$\["%q"\].name),",),ctr_dc,firstof(json_query(%q,extract,$\["%q"\].def.dc),extract(%q,3,1)),ctr_kind,edit(json_query(%q,extract,$\["%q"\].kind),",),ctr_stage,json_query(%q,extract,$\["%q"\].stage))][
+ if(strlen(%q),setqm(ctr_reduce,cand(json_query(%q,extract,$.reduce),gt(%q,1),not(t(json_query(%q,extract,$\["%q"\].reduced)))),ctr_roll,t(member(last(squish(iter(json_map(%!/FUN`JSON`KEY,json_query(%q,get,kinds),%b),if(lte(%i0,%q),json_query(%q,extract,$.kinds\["%i0"\])),%b,|),|),|),%q))))][
+ if(not(cor(%q,%q)),setq(ctr_err,[u({{commands}}/FUN`SHOW`SPELLNAME,%q)] at rank %q does nothing to %q's %q[if(%q,%b at stage %q)].))][
+ setq(ctr_rank,max(1,ceil(fdiv(sub(words(iter(%q,if(lte(%i0,%q),x))),2),2))))],
+ not(isint(%q)),setq(ctr_err,Name the DC of what makes %q %q: +cast [u({{commands}}/FUN`SHOW`SPELLNAME,%q)] on %q vs =%q.),
+ [setqm(ctr_what,%q,ctr_dc,%q)][setq(ctr_rank,max(1,ceil(fdiv(sub(words(iter(%q,if(lte(%i0,%q),x))),2),2))))])]
+ flags: [funsyntax]
+ FUN`CAST`COUNTER:
+ value: |-
+ @@(%0 a target's index; arg_on, pick_rank and the cast_ registers)[
+ null(u(FUN`CAST`COUNTER`PREP,%0))][
+ if(strlen(%q),%q,
+ [if(%q,[u(FUN`AFF`ENTER,%0,%q,dec(%q))][u(FUN`ENC`PATCH,%0,json(object,aff,json(object,%q,json(object,reduced,1))))]%q's %q goes back to stage [dec(%q)].%b)][
+ if(%q,
+ [setqm(ctr_face,die(1,20),ctr_mod,add(%q,mul(min(2,%q),5)))][
+ setq(ctr_degree,u({{core}}/FUN`DEGREE`OF`CHECK,add(%q,%q),%q,%q))][
+ setq(ctr_max,extract([dec(%q)] [dec(%q)] [add(%q,1)] [add(%q,3)],inc(%q),1))][
+ setq(ctr_ok,cand(gt(%q,0),lte(%q,%q)))][
+ Counteract %q on %q (rank %q, DC %q): 1d20\[%q\] [if(lt(%q,0),-,+)] [abs(%q)] = [add(%q,%q)], [lcstr(u(FUN`ACT`DEGREE,%q))]. [switch(1,
+ %q,[switch(1,t(strlen(%q)),u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%q,null))),t(strlen(%q)),u(FUN`AFF`END,%0,%q),u(FUN`ENC`PATCH,%0,json(object,conds,json(object,%q,null),dur,json(object,%q,null))))][capstr(%q)] ends.,
+ cand(strlen(%q),gt(%q,0),lte(sub(%q,2),%q)),[u(FUN`CAST`SUPPRESS,%0,u(FUN`ENC`C,%q,k))][capstr(%q)] is suppressed until the start of [u(FUN`ENC`C,%q,name)]'s next turn.,
+ [capstr(%q)] stays.)]])])]
+ flags: [funsyntax]
+ # Suppression until the start of key %1's next turn (FUN`TURN`TICK lifts it): an effect is marked supp and gives
+ # nothing meanwhile; a condition no effect grants moves to supc, value~key.
+ FUN`CAST`SUPPRESS:
+ value: |-
+ @@(%0 a target's index, %1 the caster's key; ctr_key or ctr_cond)[
+ if(strlen(%q),
+ u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%q,json(object,supp,json(string,%1))))),
+ [setq(sup_value,json_query(firstof(u(FUN`ENC`C,%0,conds),json(object)),extract,$\["%q"\]))][
+ u(FUN`ENC`PATCH,%0,json(object,conds,json(object,%q,null),supc,json(object,%q,json(string,firstof(%q,true)~%1))))])]
+ flags: [funsyntax]
+ # The keys of effects %0 (a combatant's fx) that are not suppressed.
+ FUN`FX`LIVE:
+ value: |-
+ @@(%0 a combatant's fx)[
+ squish(iter(json_map(%!/FUN`JSON`KEY,%0,%b),if(strlen(json_query(%0,extract,$\["%i0"\].supp)),,%i0)))]
+ flags: [funsyntax]
# The conditions the spell's text gives the target for its degree of success (its save, or the spell attack roll
# against it) when the spell brings no effect: each condition linked in that degree's paragraph, its value from the
# link's label (Frightened 2); one without a value lasts N rounds, a minute, or until the start or end of the caster's
@@ -6913,7 +6993,7 @@ objects:
t(strlen(%q)),[setqm(dmg_parts,%q,dmg_raw,%q,dmg_total,%q)][u(FUN`ACT`IWR,%0)][u(FUN`CAST`SBMARK,%0,0)][u(FUN`ACT`HARM,%0,%q,0)]%q[u(FUN`ACT`IWR`TEXT)].,
))][
switch(1,
- not(strlen(%q)),if(cor(%q,strlen(%q)),setq(on_line,trim(%q [u(FUN`CAST`TEXTCONDS,%0)]))),
+ not(strlen(%q)),[if(cor(%q,strlen(%q)),setq(on_line,trim(%q [u(FUN`CAST`TEXTCONDS,%0)])))][if(cand(strlen(%q),strmatch(json_query(u({{core}}/FUN`ITEM`GET,spells,%q),extract,$.system.counteraction),true)),setq(on_line,trim(%q [u(FUN`CAST`COUNTER,%0)])))],
cand(strlen(%q),cor(%q,strlen(%q))),if(member(rest(%q,~),setr(on_deg,extract(critical-failure failure success critical-success,inc(%q),1))),setq(on_line,trim(%q [u(FUN`FX`ADD,%0,first(%q,~),rest(%q,~),%q,json(object,first(%q,~),json(string,%q)),u(FUN`ENC`C,%q,k))]))),
cor(%q,not(cor(%q,strlen(%q)))),setq(on_line,trim(%q [u(FUN`FX`ADD,%0,first(%q,~),rest(%q,~),%q,%q,u(FUN`ENC`C,%q,k))])))]%q
flags: [funsyntax]
@@ -6968,7 +7048,7 @@ objects:
if(strmatch(%q,*"parent:*),u(FUN`FX`AUTOCHOICE,%0,%1,%2))][
setq(fxa_old,firstof(u(FUN`ENC`C,%0,fx),json(object)))][
null(iter(json_map(%!/FUN`JSON`KEY,%q,%b),if(cor(strmatch(%i0,%2),cand(member(json_query(%q,extract,$.unapplied),BattleForm),member(json_query(get(u({{core}}/DATA`PACK`[edit(json_query(%q,extract,$\["%i0"\].pack),",)])/ITEM`%i0`PREP),extract,$.unapplied),BattleForm)),cand(strmatch(%q,stance-*),strmatch(json_query(get(u({{core}}/DATA`PACK`[edit(json_query(%q,extract,$\["%i0"\].pack),",)])/ITEM`%i0`PREP),extract,$.slug),stance-*))),u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%i0,null))))))][
- u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%2,json(object,pack,json(string,%1),lvl,firstof(%3,json_query(%q,extract,$.level),1),ch,%q,badge,firstof(%q,null),end,if(gt(%q,0),json(string,%5~%q),null),sus,if(strlen(%q),json(string,%q),null),susn,if(strlen(%q),2,null)))))][
+ u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%2,json(object,pack,json(string,%1),lvl,firstof(%3,json_query(%q,extract,$.level),1),ch,%q,badge,firstof(%q,null),end,if(gt(%q,0),json(string,%5~%q),null),sus,if(strlen(%q),json(string,%q),null),susn,if(strlen(%q),2,null),dc,if(isint(%q),%q,null)))))][
if(isint(%q),if(neq(%q,setr(fxa_kept,firstof(u(FUN`FX`BADGE`CLAMP,%0,%1,%2,%q),1))),[setq(fxa_badge,%q)][u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%2,json(object,badge,%q))))]))][
u(FUN`ENC`PREPARE,%0)][
setq(fxa_temp,max(firstof(u({{core}}/FUN`CHECK`FORM`GET,tempHP),0),u(FUN`FX`TEMPHP,%q)))][
@@ -7810,6 +7890,10 @@ objects:
FUN`TURN`TICK:
value: |-
@@(%0 a combatant's index, %1 the key whose turn starts)[
+ setq(tick_fx,firstof(u(FUN`ENC`C,%0,fx),json(object)))][
+ null(iter(json_map(%!/FUN`JSON`KEY,%q,%b),if(strmatch(edit(json_query(%q,extract,$\["%i0"\].supp),",),%1),u(FUN`ENC`PATCH,%0,json(object,fx,json(object,%i0,json(object,supp,null))))))))][
+ setq(tick_supc,firstof(u(FUN`ENC`C,%0,supc),json(object)))][
+ null(iter(json_map(%!/FUN`JSON`KEY,%q,%b),if(strmatch(rest(setr(tick_value,edit(json_query(%q,extract,$\["%i0"\]),",)),~),%1),u(FUN`ENC`PATCH,%0,json(object,supc,json(object,%i0,null),conds,json(object,%i0,first(%q,~)))))))][
setq(tick_dur,u(FUN`ENC`C,%0,dur))][
null(iter(json_map(%!/FUN`JSON`KEY,%q,%b),
if(cand(strmatch(first(setr(tick_value,json_query(%q,extract,$\["%i0"\])),~),%1),not(strmatch(last(%q,~),end))),
@@ -8014,7 +8098,7 @@ objects:
@@(%0 a combatant's index: their conditions and persistent damage, as a list)[
setqm(show_conds,u(FUN`ENC`C,%0,conds),show_pers,u(FUN`ENC`C,%0,pers))][
setq(show_fx,firstof(u(FUN`ENC`C,%0,fx),json(object)))][
- itemize(squish([if(t(u(FUN`ENC`C,%0,raised)),shield raised|)][iter(json_map(%!/FUN`JSON`KEY,%q,%b),[u(FUN`FX`NAME,setr(show_fxpack,edit(json_query(%q,extract,$\["%i0"\].pack),",)),%i0)][u(FUN`FX`BADGE`SHOW,%q,%i0,json_query(%q,extract,$\["%i0"\].badge))],%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,%q,%b),%i0[if(json_query(%q,extract,$.%i0),%b[json_query(%q,extract,$.%i0)])],%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,%q,%b),persistent [json_query(%q,extract,$.%i0)] %i0,%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,setr(show_aff,firstof(u(FUN`ENC`C,%0,aff),json(object))),%b),[json_query(%q,extract,$\["%i0"\].name)] [if(json_query(%q,extract,$\["%i0"\].stage),stage [json_query(%q,extract,$\["%i0"\].stage)],onset)],%b,|)],|),|)]
+ itemize(squish([if(t(u(FUN`ENC`C,%0,raised)),shield raised|)][iter(json_map(%!/FUN`JSON`KEY,%q,%b),[u(FUN`FX`NAME,setr(show_fxpack,edit(json_query(%q,extract,$\["%i0"\].pack),",)),%i0)][u(FUN`FX`BADGE`SHOW,%q,%i0,json_query(%q,extract,$\["%i0"\].badge))][if(strlen(json_query(%q,extract,$\["%i0"\].supp)),%b%(suppressed%))],%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,%q,%b),%i0[if(json_query(%q,extract,$.%i0),%b[json_query(%q,extract,$.%i0)])],%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,setr(show_supc,firstof(u(FUN`ENC`C,%0,supc),json(object))),%b),%i0[if(isint(setr(show_sv,first(edit(json_query(%q,extract,$\["%i0"\]),",),~))),%b%q)] %(suppressed%),%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,%q,%b),persistent [json_query(%q,extract,$.%i0)] %i0,%b,|)]|[iter(json_map(%!/FUN`JSON`KEY,setr(show_aff,firstof(u(FUN`ENC`C,%0,aff),json(object))),%b),[json_query(%q,extract,$\["%i0"\].name)] [if(json_query(%q,extract,$\["%i0"\].stage),stage [json_query(%q,extract,$\["%i0"\].stage)],onset)],%b,|)],|),|)]
flags: [funsyntax]
FUN`SHOW`LOOK:
value: |-
@@ -8528,7 +8612,7 @@ objects:
- A spell attack rolls against each target's AC with your multiple attack penalty; a save is rolled for each target against your spell DC, with the damage of a basic save.
- The damage is rolled once for every target, with what your feats and effects add to spell damage, such as a status bonus to damage.
- Heal and Harm heal allies and harm foes. Name targets with commas, or `foes`, `characters` or `everyone`.
- - A spell that brings an effect, such as Animal Form, Mystic Armor or Bless, gives it to an ally you name, or you. Name the form when there are several: `+cast animal form as ape`. A spell on a weapon, armor or shield, such as Runic Weapon or Precious Metals, goes on the target's item you name, or on the only one that fits: `+cast precious metals as silver on longsword=Amiri`. A battle form gives its Strikes, AC, skills and Speed until it ends. A spell whose effect depends on the target's save or the spell attack roll, such as Leaden Steps or Tangle Vine, gives each target the effect for its own result; the conditions an effect brings, such as encumbered, come and go with it. A spell that brings no effect gives the target the conditions its text names for the result: Fear makes a target that fails frightened 2.
+ - A spell that brings an effect, such as Animal Form, Mystic Armor or Bless, gives it to an ally you name, or you. Name the form when there are several: `+cast animal form as ape`. A spell on a weapon, armor or shield, such as Runic Weapon or Precious Metals, goes on the target's item you name, or on the only one that fits: `+cast precious metals as silver on longsword=Amiri`. A battle form gives its Strikes, AC, skills and Speed until it ends. A spell whose effect depends on the target's save or the spell attack roll, such as Leaden Steps or Tangle Vine, gives each target the effect for its own result; the conditions an effect brings, such as encumbered, come and go with it. A spell that brings no effect gives the target the conditions its text names for the result: Fear makes a target that fails frightened 2. A spell that counteracts names what: `+cast dispel magic on leaden steps=` rolls the counteract check against that effect, affliction or condition and ends it when the check beats its rank. A condition no effect grants takes the DC of what caused it: `+cast clear mind on frightened vs 20=`.
- A sustained spell's effect lasts until the end of your next turn. `+act sustain` (one action, once a turn, not on the turn you cast) keeps each of yours going to the end of your next turn; one not sustained ends.
- Outside an encounter `+cast` spends from your sheet's day and heals the characters you name.