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.