Skip to content

Instantly share code, notes, and snippets.

@kjaegers
Last active April 15, 2021 23:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kjaegers/d73e276e3a5f5b56e197abba441dc0d2 to your computer and use it in GitHub Desktop.
Save kjaegers/d73e276e3a5f5b56e197abba441dc0d2 to your computer and use it in GitHub Desktop.
PowerCards Automated Macro System
// PCMHelper - A utility script for PowerCards creates attributes to facilitate PowerCard template and
// replacements style cards. Will monitor creation of objects and changes to characters to
// try to keep the attributes updated so there is no additional work involved on the DMs
// part to set up new creatures or character abilities.
//
// The following attributes are created on characters (PCs and/or NPCs) as appropriate:
// attacklist = list of PC Attacks (center of the character sheet). ONLY those marked as attacks.
// npcactionlist = list of repeating_npcaction entries (under the "Actions" heading on the sheet)
// npclegendaryactions = list of repeating_npcaction-l entries
// cantriplist = list of known cantrips
// l1_spell_list thru l9_spell_list = list of known spells.
//
// Supported Commands:
// !pcm Runs the attribute evaluation for any selected tokens.
// !pcmeverybody Runs the attribute evaluation for ALL characters in the game. Good for adding the system
// to an existing game without needing to select each character. Might take a while to run
// on large campaigns (and might even fail).
// !pcmqueue Processes the current queue (if any) - should never be needed.
// !pcmsetup Create (or recreate) the Replacements, Templates, and Macros used by PCMHelper
//
// Latest Changes:
//
// V 1.0.11b Requires PowerCards 3.8.17 or higher. Utilizes the SPELLSOUND, SPELLVFX, ATTACKSOUND, and ATTACKVFX
// replacement variables added by that version of PowerCards to play sounds and visual effects if they
// are defined in the PowerCard Sounds and PowerCard Visual Effects handouts.
//
// Cleaned up the spellcasting code to reduce sandbox crashes
//
// Removed ! commands that couldn't be utilized anyway (because everything gets toLower'd)
//
// Refactored event handler code to move all event handlers inside the on ready event
//
// Added the !pcmformats command to generate a formats handout for all of your player characters
//
var PCMHelper = PCMHelper || (function() {
var PCMHelper_Author = "Kurt Jaegers";
var PCMHelper_Version = "1.0.13";
var PCMHelper_LastUpdated = "2021-04-15";
var color_code_list = [
"#913f92", "#d84242", "#187173", "#7e3f14", "#ff8100", "#618157", "#56859c", "#00154d", "#75716e",
"#83929f","#ea6a47","#ac3e31","#6ab187", "#613318","#816c5b", "#a9a18c", "#855723","#d57500","#404f24","#4e6172",
"#816c5b", "#a9a18c", "#855723","#d57500","#404f24","#4e6172","#83929f","#ea6a47","#ac3e31","#6ab187", "#613318",
"#816c5b", "#a9a18c", "#855723","#d57500","#404f24","#4e6172","#83929f","#ea6a47","#ac3e31","#6ab187", "#613318",
"#816c5b", "#a9a18c", "#855723","#d57500","#404f24","#4e6172","#83929f","#ea6a47","#ac3e31","#6ab187", "#613318"
];
// Text that gets entered into the PowerCard Replacements PCMHelper handout
var pc_replacements = `Advantage:{{query=1}} {{normal=1}} {{r2=[[0d20|1d20;{{query=1}} {{advantage=1}} {{r2=[[1d20|2d20kh1;{{query=1}} {{disadvantage=1}} {{r2=[[1d20|2d20kl1`;
// Text that gets entered into the PowerCard Templates PCMHelper handout
var pc_templates = `Basics: --tokenid|~0! --target_list|~1! --['~6!' -ne '/w gm ']emote|~S-TN$ ~2! against ~T-TN$ --format|~S-CN$ --name|~3! --leftsub|~4! --rightsub|~5!<br>
PCAttack: --['~1!' -eq '/w gm ']whisper|gm --['~2!' -eq '']Attack *1|[#[ [$Atk] ~0! + ~PCA-ATKBONUS$ [Attack Bonus] ]#] vs **AC** [#[~T-AC$]#] --['~2!' -ne '']Attack *2|[#[ [$Atk] ~0! + ~PCA-ATKBONUS$ [Attack Bonus] + ~2! [Bless] ]#] vs **AC** [#[~T-AC$]#] --?? $Atk.base == 1 ?? Fumble|The attack went horribly wrong! --?? $Atk.base <> 1 AND $Atk.base <> 20 AND $Atk.total < ~T-AC$ ?? Miss *1|~S-CN$ missed. --["~PCA-DMG2DICE$" -eq "none" -and "~3!" -eq "0"]?? $Atk.base <> 20 AND $Atk.total >= ~T-AC$ ?? Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1DICE$ ]] ~PCA-DMG1TYPE$ damage --["~PCA-DMG2DICE$" -ne "none" -and "~3!" -eq "0"]?? $Atk.base <> 20 AND $Atk.total >= ~T-AC$ ?? Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1DICE$ ]] ~PCA-DMG1TYPE$ damage and [[ [$Dmg2] ~PCA-DMG2DICE$ ]] ~PCA-DMG2TYPE$ damage --["~PCA-DMG2DICE$" -eq "none" -and "~3!" -ne "0"]?? $Atk.base <> 20 AND $Atk.total >= ~T-AC$ ?? Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1DICE$ ]] ~PCA-DMG1TYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --["~PCA-DMG2DICE$" -ne "none" -and "~3!" -ne "0"]?? $Atk.base <> 20 AND $Atk.total >= ~T-AC$ ?? Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1DICE$ ]] ~PCA-DMG1TYPE$ damage, [[ [$GDmg] ~3! ]] ~4! damage and [[ [$Dmg2] ~PCA-DMG2DICE$ ]] ~PCA-DMG2TYPE$ damage --["~PCA-DMG2DICE$" -eq "none" -and "~3!" -eq "0"]?? $Atk.base == 20 AND $Atk.total >= ~T-AC$ ?? Critical Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1CRIT$ ]] ~PCA-DMG1TYPE$ damage --["~PCA-DMG2DICE$" -ne "none" -and "~3!" -eq "0"]?? $Atk.base == 20 AND $Atk.total >= ~T-AC$ ?? Critical Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1CRIT$ ]] ~PCA-DMG1TYPE$ damage and [[ [$Dmg2] ~PCA-DMG2CRIT$ ]] ~PCA-DMG2TYPE$ damage --["~PCA-DMG2DICE$" -eq "none" -and "~3!" -ne "0"]?? $Atk.base == 20 AND $Atk.total >= ~T-AC$ ?? Critical Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1CRIT$ ]] ~PCA-DMG1TYPE$ damage and [[ [$GDmg] ~5! ]] ~4! damage --["~PCA-DMG2DICE$" -ne "none" -and "~3!" -ne "0"]?? $Atk.base == 20 AND $Atk.total >= ~T-AC$ ?? Critical Hit|~S-CN$ hits ~T-CN$ for [#[ [$Dmg] ~PCA-DMG1CRIT$ ]] ~PCA-DMG1TYPE$ damage [[ [$GDmg] ~5! ]] ~4! damage and [[ [$Dmg2] ~PCA-DMG2CRIT$ ]] ~PCA-DMG2TYPE$ damage --["~PCA-SAVE$" -eq "true"]?? $Atk.base == 20 OR $Atk.total >= ~T-AC$ ?? Save|~T-CN$ can attempt a **DC ~PCA-SAVEDC$** ~PCA-SAVEATTR$ saving throw for ~PCA-SAVEEFFECT$ --["~PCA-SAVE$" -eq "true"]?? $Atk.base == 20 OR $Atk.total >= ~T-AC$ ?? Save|~T-CN$ can attempt a **DC ~PCA-SAVEDC$** ~PCA-SAVEATTR$ saving throw for ~PCA-SAVEEFFECT$ --["~PCA-DESC$" -ne "none"]Description|~PCA-DESC$<br>
NPCBasics: --tokenid|~0! --target_list|~1! --emote|~S-TN$ ~2! against ~T-TN$ --format|badguys --name|~3! --['~NPCA-TYPE$' -eq 'ATTACK']leftsub|~4! --['~NPCA-RANGE$' -eq 'ATTACK']rightsub|~5!<br>
NPCAttack: --["~NPCA-TYPE$" -eq "ATTACK"]Attack:|[#[ [$Atk] ~0! + ~NPCA-TOHIT$ [Attack Bonus] ]#] vs **AC** [#[~T-AC$]#] --["~NPCA-TYPE$" -eq "ATTACK"]?? $Atk < ~T-AC$ ?? !Missed|**The ~NPCA-NAME$ attack missed!** --["~NPCA-TYPE$" -eq "ATTACK" -and "~NPCA-DAMAGETYPE2$" -eq ""]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] ~NPCA-DAMAGE$ ]#] ~NPCA-DAMAGETYPE$ damage --["~NPCA-TYPE$" -eq "ATTACK" -and "~NPCA-DAMAGETYPE2$" -ne ""]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] ~NPCA-DAMAGE$ ]#] ~NPCA-DAMAGETYPE$ damage and [#[ [$Dmg2] ~NPCA-DAMAGE2$ ]#] ~NPCA-DAMAGETYPE2$ damage --["~NPCA-TYPE$" -eq "ATTACK" -and "~NPCA-DAMAGETYPE2$" -eq ""]?? $Atk.base == 20 ?? Hit:|[#[ [$Dmg] ~NPCA-CRIT$ ]#] ~NPCA-DAMAGETYPE$ damage --["~NPCA-TYPE$" -eq "ATTACK" -and "~NPCA-DAMAGETYPE2$" -ne ""]?? $Atk.base == 20 ?? Hit:|[#[ [$Dmg] ~NPCA-CRIT$ ]#] ~NPCA-DAMAGETYPE$ damage and [#[ [$Dmg2] ~NPCA-CRIT2$ ]#] ~NPCA-DAMAGETYPE2$ damage --["~NPCA-TYPE$" -eq "ATTACK"]?? $Atk.base == 1 ?? Fumble|The attack goes horribly wrong! --["~NPCA-DESCRIPTION$" -ne "" ]Description|~NPCA-DESCRIPTION$<br>
CantripAttack: --["~1!" -eq "/w gm"]whisper|gm --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and '~2!' -eq '']Attack: *1|[#[ [$Atk] ~0! + ~S-SAB$ [Spell Attack] ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and '~2!' -ne '']Attack: *2|[#[ [$Atk] ~0! + ~S-SAB$ [Spell Attack] ~2! [Bless] ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '']?? $Atk < ~T-AC$ ?? !Missed|**You missed!** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 0]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~S-L$ -lt 4 -and ~SP-MORECANTRIPDAMAGE$ -eq 1]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 4 -and ~S-L$ -lt 12]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 11 -and ~S-L$ -lt 17]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 16 ]?? $Atk -ge ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ~SP-DAMAGETYPE$ ]#] damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 0]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~S-L$ -lt 4 -and ~SP-MORECANTRIPDAMAGE$ -eq 1]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 4 -and ~S-L$ -lt 12]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 11 -and ~S-L$ -lt 17]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 16 ]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 0]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~S-L$ -lt 4 -and ~SP-MORECANTRIPDAMAGE$ -eq 1]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 4 -and ~S-L$ -lt 12]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 11 -and ~S-L$ -lt 17]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 16 ]?? $Atk -ge ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ~SP-DAMAGETYPE$ ]#] damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 0]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage and [[ [$GDmg] ~5! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~S-L$ -lt 4 -and ~SP-MORECANTRIPDAMAGE$ -eq 1]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage and [[ [$GDmg] ~5! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 4 -and ~S-L$ -lt 12]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage and [[ [$GDmg] ~5! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 11 -and ~S-L$ -lt 17]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage and [[ [$GDmg] ~5! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 16 ]?? $Atk.base == 20 ?? Critical Hit:|[#[ [$CritDmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Crit] ]#] ~SP-DAMAGETYPE$ Damage and [[ [$GDmg] ~5! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq '']?? $Atk.base == 1 ?? !|**Fumble:** Spell goes horribly wrong! --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Strength']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBSTR$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Dexterity']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBDEX$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Constitution']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBCON$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Intelligence']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBINT$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Wisdom']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBWIS$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Charisma']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBCHA$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -eq "0" -and ~S-L$ -lt 4 -and ~SP-MORECANTRIPDAMAGE$ -ne 0]?? $Save < ~S-SSDC$ ?? Save Failed|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 0]?? $Save < ~S-SSDC$ ?? Save Failed|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 4 -and ~S-L$ -lt 12]?? $Save < ~S-SSDC$ ?? Save Failed:|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 11 -and ~S-L$ -lt 17]?? $Save < ~S-SSDC$ ?? Save Failed:|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -eq "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 16 ]?? $Save < ~S-SSDC$ ?? Save Failed:|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -ne "0" -and ~S-L$ -lt 4 -and ~SP-MORECANTRIPDAMAGE$ -ne 0]?? $Save < ~S-SSDC$ ?? Save Failed|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 0]?? $Save < ~S-SSDC$ ?? Save Failed|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 4 -and ~S-L$ -lt 12]?? $Save < ~S-SSDC$ ?? Save Failed:|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 11 -and ~S-L$ -lt 17]?? $Save < ~S-SSDC$ ?? Save Failed:|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and "~3!" -ne "0" -and ~SP-MORECANTRIPDAMAGE$ -eq 1 -and ~S-L$ -gt 16 ]?? $Save < ~S-SSDC$ ?? Save Failed:|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) + (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '']?? $Save >= ~S-SSDC$ ?? Save Succeded|~T-CN$ avoids the effect of the ~SP-NAME$ --Description|~SP-DESCRIPTION$<br>
SpellCast: --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-ATTACK$' -ne 'None']Attack:|[#[ [$Atk] ~0! + ~S-SAB$ [Spell Attack] ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-ATTACK$' -eq 'None']hroll|[#[ [$Atk] 1d10 + 500 ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK']?? $Atk < ~T-AC$ ?? !Missed|**You missed!** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE$' -ne '' -and '~SP-DAMAGE2$' -eq '']?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE$' -ne '' -and '~SP-DAMAGE2$' -eq '']?? $Atk.base == 20 ?? Critical Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HLCrit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE$' -ne '' -and '~SP-DAMAGE2$' -ne '']?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] ~SP-DAMAGETYPE$ damage and [#[ [$Dmg2] (~SP-DAMAGE2$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE2$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE$' -ne '' -and '~SP-DAMAGE2$' -ne '']?? $Atk.base == 20 ?? Critical Hit:|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HLCrit] ]#] ~SP-DAMAGETYPE$ Damage and [#[ [$Dmg2] (~SP-DAMAGE2$) [Base] (~SP-DAMAGE2$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE2$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Strength']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBSTR$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Dexterity']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBDEX$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Constitution']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBCON$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Intelligence']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBINT$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Wisdom']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBWIS$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Charisma']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBCHA$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '']?? Save < ~S-SSDC$ ?? Save Failed|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '']?? $Save >= ~S-SSDC$ ?? Save Succeded|~T-CN$ saves for ~SP-SAVESUCCESS$ --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-HEALING$' -ne '']Healing:|[#[ [$Heal] (~SP-HEALING$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] --Description|~SP-DESCRIPTION$<br>
`;
// Base PCMHelper Formats Text
var pc_formats = `atwill: --txcolor|#000000 --bgcolor|#004400<br>
charinfo: --txcolor|#ffff00 --bgcolor|#000000 --titlefontshadow|#0000cc --corners|10 --orowbg|#cec7b6 --erowbg|#cec7b6<br>
badguys: --txcolor|#ffff00 --bgcolor|#000000 --titlefontshadow|#0000cc --corners|10 --emotefont|font-family: Arial; font-weight: bold;<br>
bigbad: --txcolor|#ffff00 --bgcolor|#000000 --titlefontshadow|#0000cc --corners|10<br>`;
var format_template = ' --txcolor|#ffff00 --titlefontshadow|#0000cc --corners|10<br>';
//SpellCast: --["~1!" -eq "/w gm"]whisper|gm --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-ATTACK$' -ne 'None' -and '~SP-DAMAGE$' -ne '' -and '~2!' -eq '']Attack: *1|[#[ [$Atk] ~0! + ~S-SAB$ [Spell Attack] ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-ATTACK$' -ne 'None' -and '~SP-DAMAGE$' -ne '' -and '~2!' -ne '']Attack: *2|[#[ [$Atk] ~0! + ~S-SAB$ [Spell Attack] + ~2! [Bless] ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-ATTACK$' -eq 'None' -and '~SP-DAMAGE$' -ne '']hroll|[#[ [$Atk] 1d10 + 500 ]#] vs **AC** [#[~T-AC$]#] --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE$' -ne '']?? $Atk < ~T-AC$ ?? !Missed|**You missed!** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -eq '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -eq "0"]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit: *1|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -eq '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -eq "0"]?? $Atk.base == 20 ?? Critical Hit: *1|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HLCrit] ]#] ~SP-DAMAGETYPE$ Damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -ne '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -eq "0"]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit: *2|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] ~SP-DAMAGETYPE$ damage and [#[ [$Dmg2] (~SP-DAMAGE2$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE2$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -ne '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -eq "0"]?? $Atk.base == 20 ?? Critical Hit: *2|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HLCrit] ]#] ~SP-DAMAGETYPE$ Damage and [#[ [$Dmg2] (~SP-DAMAGE2$) [Base] (~SP-DAMAGE2$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE2$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -eq '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -ne "0"]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit: *3|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -eq '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -ne "0"]?? $Atk.base == 20 ?? Critical Hit: *3|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HLCrit] ]#] ~SP-DAMAGETYPE$ Damage and [[ [$GDmg] ~5! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -ne '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -ne "0"]?? $Atk >= ~T-AC$ AND $Atk.base <> 20 ?? Hit: *4|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] ~SP-DAMAGETYPE$ damage, [[ [$GDmg] ~3! ]] ~4! damage and [#[ [$Dmg2] (~SP-DAMAGE2$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE2$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-DAMAGE2$' -ne '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -ne "0"]?? $Atk.base == 20 ?? Critical Hit: *4|[#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~SP-DAMAGE$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HLCrit] ]#] ~SP-DAMAGETYPE$ Damage, [[ [$GDmg] ~5! ]] ~4! damage and [#[ [$Dmg2] (~SP-DAMAGE2$) [Base] (~SP-DAMAGE2$) [Crit] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE2$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Strength' -and '~SP-DAMAGE$' -ne '']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBSTR$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Dexterity' -and '~SP-DAMAGE$' -ne '']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBDEX$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Constitution' -and '~SP-DAMAGE$' -ne '']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBCON$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Intelligence' -and '~SP-DAMAGE$' -ne '']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBINT$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Wisdom' -and '~SP-DAMAGE$' -ne '']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBWIS$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -eq 'Charisma' -and '~SP-DAMAGE$' -ne '']Save|~T-CN$ rolls [[ [$Save] 1d20 + ~T-SBCHA$ ]] on a ~SP-SAVE$ save vs **DC ~S-SSDC$** --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -eq "0"]?? Save < ~S-SSDC$ ?? Save Failed *1|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and '~SP-DAMAGE$' -ne '' -and "~3!" -ne "0"]?? Save < ~S-SSDC$ ?? Save Failed *2|~T-CN$ takes [#[ [$Dmg] (~SP-DAMAGE$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] ]#] ~SP-DAMAGETYPE$ damage and [[ [$GDmg] ~3! ]] ~4! damage --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-SAVE$' -ne '' -and '~SP-DAMAGE$' -ne '']?? $Save >= ~S-SSDC$ ?? Save Succeded|~T-CN$ saves for ~SP-SAVESUCCESS$ --['~SP-OUTPUT$' -eq 'ATTACK' -and '~SP-HEALING$' -ne '']Healing:|[#[ [$Heal] (~SP-HEALING$) [Base] + (~S-SAM$ * ~SP-ADDABILITY$) [Ability] + (~SP-HLDICE$*~SSL$)~SP-HLDIETYPE$~SP-HLBONUS$ [HigherLevel] ]#] --Description|~SP-DESCRIPTION$<br>
// Text of the PCMHelper Macros that will be added to your game by running !pcmsetup
var pc_npcaction = `!power {{
--replacenpcaction|@{selected|character_id}|?{Select action to use|@{selected|npcactionlist}}
--replacement|Advantage
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--soundfx|_audio,play,nomenu|~ATTACKSOUND$
--vfx_opt|~ATTACKVFX$
--template|NPCBasics|@{selected|token_id};@{target|token_id};uses ~NPCA-NAME$;~NPCA-NAME$;~NPCA-ATYPE$;~NPCA-RANGE$
--template|NPCAttack|~@{selected|rtype}$
}}`;
var pc_pcattack = `!power {{
--replacepcattack|@{selected|character_id}|?{Select attack to use|@{selected|attacklist}}
--replacement|Advantage
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--soundfx|_audio,play,nomenu|~ATTACKSOUND$
--vfx_opt|~ATTACKVFX$
--template|Basics|@{selected|token_id};@{target|token_id};uses ~PCA-NAME$;~PCA-NAME$;~PCA-ATYPE$;~PCA-RANGE$;@{selected|whispertoggle}
--template|PCAttack|~@{selected|rtype}$;@{selected|whispertoggle};@{selected|global_attack_mod};@{selected|global_damage_mod_roll};@{selected|global_damage_mod_type};@{selected|global_damage_mod_crit}
}}`;
var pc_legendary = `!power {{
--replacenpcaction|@{selected|character_id}|?{Select action to use|@{selected|legendaryactionlist}}
--replacement|Advantage
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--soundfx|_audio,play,nomenu|~ATTACKSOUND$
--vfx_opt|~ATTACKVFX$
--template|NPCBasics|@{selected|token_id};@{target|token_id};uses ~NPCA-NAME$;~NPCA-NAME$;~NPCA-ATYPE$;~NPCA-RANGE$
--template|NPCAttack|~@{selected|rtype}$
}}`;
var pc_cantrip = `!power {{
--replacespell|@{selected|character_id}|?{Cantrip to cast|@{selected|cantrip_list}}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Cantrip;~SP-RANGE$;@{selected|whispertoggle}
--template|CantripAttack|~@{selected|rtype}$;@{selected|whispertoggle};@{selected|global_attack_mod};@{selected|global_damage_mod_roll};@{selected|global_damage_mod_type};@{selected|global_damage_mod_crit}
}}`;
var pc_level1 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l1_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|1,0|2,1|3,2|4,3|5,4|6,5|7,6|8,7|9,8}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level2 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l2_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|2,0|3,1|4,2|5,3|6,4|7,5|8,6|9,7}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level3 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l3_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|3,0|4,1|5,2|6,3|7,4|8,5|9,6}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level4 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l4_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|4,0|5,1|6,2|7,3|8,4|9,5}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level5 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l5_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|5,0|6,1|7,2|8,3|9,4}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level6 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l6_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|6,0|7,1|8,2|9,3}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level7 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l7_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|7,0|8,1|9,2}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level8 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l8_spell_list}}
--inlinereplace|SSL|?{Spell Slot Level?|8,0|9,1}
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
var pc_level9 = `!power {{
--replacespell|@{selected|character_id}|?{Spell to Cast|@{selected|l9_spell_list}}
--inlinereplace|SSL|0
--replaceattrs|S-|@{selected|character_id}|@{selected|token_id}
--replaceattrs|T-|@{target|character_id}|@{target|token_id}
--replacement|Advantage
--soundfx|_audio,play,nomenu|~SPELLSOUND$
--vfx_opt|~SPELLVFX$
--template|Basics|@{selected|token_id};@{target|token_id};casts ~SP-NAME$;~SP-NAME$;Save DC ~S-SSDC$;~SP-RANGE$;@{selected|whispertoggle}
--template|SpellCast|~@{selected|rtype}$;@{selected|whispertoggle}
}}`;
// API COMMAND HANDLER
on("ready", function() {
on("chat:message", function(msg) {
if (msg.type !== "api") {
return;
}
switch (msg.content.split(" ", 1)[0].toLowerCase()) {
// The basic !pcm command runs the evaluator for the selected tokens and creates the required attributes on each
// token, including the spell lists, attack lists, action list, and legendary action list
case "!pcmhelper":
case "!pcm":
case "!pcmh":
var player_obj = getObj("player", msg.playerid);
msg.who = msg.who.replace(" (GM)", "");
msg.content = msg.content.replace(/<br\/>\n/g, ' ').replace(/({{)(.*)((\}\}))/, " $2 ").replace(/\[#\[/g,"[[").replace(/\]#\]/g,"]]");
getAttackInfo(msg, player_obj);
getNPCActionInfo(msg, player_obj);
getSpellInfo(msg, player_obj);
break;
// Running !pcmsetup removes and recreates the PCMHelper related macros
case "!pcmsetup":
log("Running PCMSetup - installing macros for version " + PCMHelper_Version);
createHandouts();
createPCMacros(getObj("player", msg.playerid));
state.PCMHelper.currentVersion = PCMHelper_Version;
var html = "<table border=2 width=100%><tr><td bgcolor=goldenrod colspan=1 align=center><font color=black>PCMHelper</font></td></tr>";
html += "<tr><td colspan=1>Your PCMHelper macros and handouts have been updated to version <strong>" + PCMHelper_Version + "</strong></td></tr>";
html += "</table>";
sendChat("PCMHelper:",html);
break;
// Debugging command. Sets your version information to an old version number
case "!pcmoldversion":
state.PCMHelper.currentVersion = "1.0.1"
break;
// Outputs to the log the items remaining in the processing queue
case "!pcmshowqueue":
log(state.PCMHelper.Queue);
break;
// Queues ALL characters in your game for !pcm processing. Queues are processed by a worker to leave the game available and keep the sandbox
// from timing out.
case "!pcmeverybody":
var chars = findObjs({ _type: "character"});
_.each(chars, function(obj) {
AddQueueItem(obj.id);
});
log(`Queue length is ${state.PCMHelper.Queue.length}`);
break;
case '!pcmformats':
generatePlayerFormats();
break;
case '!pcmremove':
removePCMMacros();
sendChat("PCMHelper", "PCMHelper Macros Removed");
break;
// Output the current version information for PCMHelper
case "!pcm_version":
sendChat("", "/w " + msg.who + " You are using version " + PCMHelper_Version + " of PCMHelper, authored by " + PCMHelper_Author + ", which was last updated on: " + PCMHelper_LastUpdated + ".");
break;
}
});
// Monitor attribute changes on characters and queue them for !pcm updates if what changed is an attack, action, or spell
on("change:attribute", function(obj) {
if (obj.get("name").endsWith("_rollbase")) {
AddQueueItem(obj.get("_characterid"));
}
if (obj.get("name").endsWith("_hasattack")) {
AddQueueItem(obj.get("_characterid"));
}
if (obj.get("name").endsWith("_spellname")) {
AddQueueItem(obj.get("_characterid"));
}
});
// When an attribute is removed (spell removed) rerun !pcm on the character
on("destroy:attribute", function(obj) {
if(obj.get("name").endsWith("_spellname")) {
AddQueueItem(obj.get("_characterid"));
}
});
if (!state.PCMHelper) state.PCMHelper = { currentVersion:"Unknown", Queue:[] } ;
state.PCMHelper.Queue = [];
var existingMacroVersion = state.PCMHelper.currentVersion;
if (existingMacroVersion !== PCMHelper_Version) {
var html = "<table border=2 width=100%><tr><td bgcolor=goldenrod colspan=2 align=center><font color=black>PCMHelper</font></td></tr>";
html += "<tr><td colspan=2>Your PCMHelper macros are outdated</td></tr>";
html += "<tr><td>Installed Ver</td><td>" + existingMacroVersion + "</td></tr>";
html += "<tr><td>Available Ver</td><td>" + PCMHelper_Version + "</td></tr>";
html += "<tr><td colspan=2>Please consider running <strong>!pcmsetup</strong> to install the latest version of the macros</tr></tr></table>"
sendChat("PCMHelper:",html);
}
log("-=> PCMHelper v" + PCMHelper_Version + " <=- [" + PCMHelper_LastUpdated + "]");
handleQueue();
});
function handleQueue() {
queueProcessor = setInterval(function(){
processQueue();
},5000);
}
function processQueue() {
if (state.PCMHelper.Queue !== undefined && state.PCMHelper.Queue.length > 0 ) {
var procLength = (20 >= state.PCMHelper.Queue.Length ? state.PCMHelper.Queue.Length : 20)
for (var x=0; x<procLength; x++) {
if (state.PCMHelper.Queue.length > 0){
var thisChar = findObjs({type:"character", id:state.PCMHelper.Queue[0]})[0];
log(`Processing character ${state.PCMHelper.Queue[0]} for ${thisChar.get("name")};`);
processCharacter(state.PCMHelper.Queue[0]);
processNPC(state.PCMHelper.Queue[0]);
processSpells(state.PCMHelper.Queue[0]);
state.PCMHelper.Queue.shift();
}
}
log(`PCMHelper : Queue Length is now ${state.PCMHelper.Queue.length}`);
}
}
function AddQueueItem(charID) {
if (!state.PCMHelper.Queue.includes(charID)) {
state.PCMHelper.Queue.push(charID);
}
}
function IsInQueue(charID) {
var found = false;
if (state.PCMHelper.Queue == undefined) {
state.PCMHelper.Queue = "";
found = false;
}
if (state.PCMHelper.Queue.indexOf(charID) !== -1) {
found = true;
}
return found;
}
function processCharacter(charID)
{
// Only run on tokens that represent characters (PCs or NPCs)
var atklist = "";
var attrCount = 0;
var attrs = getRepeatingSectionAttrs(charID, "repeating_attack");
var attrLen = 0;
if (attrs !== undefined) {
attrLen = attrs[0].length;
}
if (attrLen > 0) {
do {
var key="repeating_attack_$" + attrCount + "_atkname";
thisAttr = getAttrByName(charID, "repeating_attack_$" + attrCount + "_atkname");
var isAttack = getAttrByName(charID, "repeating_attack_$" + attrCount + "_atkflag");
if (isAttack !== "0") {
if (thisAttr !== "") {
atklist += thisAttr + "|";
}
}
attrCount += 1;
} while (thisAttr !== "" && attrCount < attrLen);
}
oldAttrs = findObjs({ _type:"attribute", _characterid:charID, name: "attacklist"});
if (oldAttrs.length > 0) {
oldAttrs.forEach(function(element) { element.remove(); });
}
if (atklist !== "") {
atklist = atklist.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "attacklist", current: atklist });
}
}
function getAttackInfo(msg, player_obj) {
// Run through all selected tokens
msg.selected.forEach(function(selected){
var tokenID;
var graphicObj;
var charObj;
var charID;
// Retrieve information about what this token represents
tokenID = selected._id;
if (tokenID !== undefined) {
graphicObj = getObj("graphic", tokenID);
}
if (graphicObj !== undefined) {
charObj = getObj("character", graphicObj.get("represents"));
}
if (charObj !== undefined) {
charID = charObj.get("_id");
}
if (charID !== undefined) {
processCharacter(charID);
}
});
}
function processNPC(charID)
{
// Only run on tokens that represent characters (PCs or NPCs)
var attrCount = 0;
var actionList = "";
var legendaryList = "";
var attrs = getRepeatingSectionAttrs(charID, "repeating_npcaction");
var lattrs = getRepeatingSectionAttrs(charID, "repeating_npcaction-l");
var attrLen = 0;
var lattrLen = 0;
if (attrs !== undefined) {
attrLen = attrs[0].length;
}
if (lattrs !== undefined) {
lattrLen = lattrs[0].length;
}
if (attrLen > 0) {
do {
var key="repeating_npcaction_$" + attrCount + "_atkname";
thisAttr = getAttrByName(charID, "repeating_npcaction_$" + attrCount + "_name");
if (thisAttr !== "") {
actionList += thisAttr + "|";
}
attrCount += 1;
} while (thisAttr !== "" && attrCount < attrLen);
}
var attrCount = 0;
if (lattrLen > 0) {
do {
var key="repeating_npcaction-l_$" + attrCount + "_atkname";
thisAttr = getAttrByName(charID, "repeating_npcaction-l_$" + attrCount + "_name");
if (thisAttr !== "") {
legendaryList += thisAttr + "|";
}
attrCount += 1;
} while (thisAttr !== "" && attrCount < lattrLen);
}
oldAttrs = findObjs({ _type:"attribute", _characterid:charID, name: "npcactionlist"});
if (oldAttrs.length > 0) {
oldAttrs.forEach(function(element) { element.remove(); });
}
oldAttrs = findObjs({ _type:"attribute", _characterid:charID, name: "legendaryactionlist"});
if (oldAttrs.length > 0) {
oldAttrs.forEach(function(element) { element.remove(); });
}
if (actionList !== "") {
actionList = actionList.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "npcactionlist", current: actionList });
}
if (legendaryList !== "") {
legendaryList = legendaryList.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "legendaryactionlist", current: legendaryList });
}
}
function generatePlayerFormats()
{
var chars = findObjs({
_type: 'character'
});
var playerChars = [];
for (var x=0; x<chars.length; x++) {
if (chars[x].get("controlledby").startsWith("-")) {
playerChars.push(chars[x].id);
}
}
var colorCount = 0;
var formatOutput = pc_formats + '\n';
for (var x=0; x<chars.length; x++) {
var thisChar = getObj("character", playerChars[x]);
if (thisChar !== undefined) {
log(thisChar);
var thisFormat = `${thisChar.get("name")}: --bgcolor|${color_code_list[x]} ${format_template}\n`;
formatOutput += thisFormat;
}
}
var Handouts = findObjs({
_type : "handout",
});
Handouts.forEach(function (handout) {
if (handout.get("name").startsWith("PowerCard Formats PCMHelper")) {
handout.remove();
};
});
// Create the handouts. Note the because of an API bug, the Notes cannot be set
// during creation and if an attempt is made to do that, they are bugged and can't
// be set after creation either, so create them empty.
createObj("handout", { name:"PowerCard Formats PCMHelper"});
// Now loop through the handouts again and set the notes for them.
Handouts = findObjs({
_type : "handout",
});
Handouts.forEach(function (handout) {
if (handout.get("name").startsWith("PowerCard Formats PCMHelper")) {
handout.set("notes", formatOutput);
};
});
}
function processSpells(charID) {
try {
var spell_list = filterObjs(function(z) { return (z.get("characterid") == charID && z.get("name").endsWith("spellname")); });
var cantrips = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-cantrip")), "current");
var L1Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-1")), "current");
var L2Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-2")), "current");
var L3Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-3")), "current");
var L4Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-4")), "current");
var L5Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-5")), "current");
var L6Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-6")), "current");
var L7Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-7")), "current");
var L8Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-8")), "current");
var L9Spells = sortByKey(spell_list.filter(s => s.get("name").startsWith("repeating_spell-9")), "current");
nameList = "cantrip_list|l1_spell_list|l2_spell_list|l3_spell_list|l4_spell_list|l5_spell_list|l6_spell_list|l7_spell_list|l8_spell_list|l9_spell_list";
var attrNames = nameList.split("|");
attrNames.forEach(function(attrName) {
oldAttrs = findObjs({ _type:"attribute", _characterid:charID, name: attrName} );
if (oldAttrs.length > 0)
{
oldAttrs.forEach(function(element) { element.remove(); });
}
});
var attrText = "";
if (cantrips.length > 0) {
cantrips.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "cantrip_list", current: attrText });
}
attrText = "";
if (L1Spells.length > 0) {
L1Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l1_spell_list", current: attrText });
}
attrText = "";
if (L2Spells.length > 0) {
L2Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l2_spell_list", current: attrText });
}
attrText = "";
if (L3Spells.length > 0) {
L3Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l3_spell_list", current: attrText });
}
attrText = "";
if (L4Spells.length > 0) {
L4Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l4_spell_list", current: attrText });
}
attrText = "";
if (L5Spells.length > 0) {
L5Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l5_spell_list", current: attrText });
}
attrText = "";
if (L6Spells.length > 0) {
L6Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l6_spell_list", current: attrText });
}
attrText = "";
if (L7Spells.length > 0) {
L7Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l7_spell_list", current: attrText });
}
attrText = "";
if (L8Spells.length > 0) {
L8Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l8_spell_list", current: attrText });
}
attrText = "";
if (L9Spells.length > 0) {
L9Spells.forEach(function(s) { attrText += s.get("current") + "|" });
attrText = attrText.slice(0,-1);
createObj("attribute", { _characterid: charID, name: "l9_spell_list", current: attrText });
}
} catch { }
}
function getNPCActionInfo(msg, player_obj) {
// Run through all selected tokens
msg.selected.forEach(function(selected){
var tokenID;
var graphicObj;
var charObj;
var charID;
// Retrieve information about what this token represents
tokenID = selected._id;
if (tokenID !== undefined) {
graphicObj = getObj("graphic", tokenID);
}
if (graphicObj !== undefined) {
charObj = getObj("character", graphicObj.get("represents"));
}
if (charObj !== undefined) {
charID = charObj.get("_id");
}
if (charID !== undefined) {
processNPC(charID);
}
});
}
function getSpellInfo(msg, player_obj) {
msg.selected.forEach(function(selected){
var tokenID;
var graphicObj;
var charObj;
var charID;
tokenID = selected._id;
if (tokenID !== undefined) {
graphicObj = getObj("graphic", tokenID);
}
if (graphicObj !== undefined) {
charObj = getObj("character", graphicObj.get("represents"));
}
if (charObj !== undefined) {
charID = charObj.get("_id");
}
if (charID !== undefined) {
processSpells(charID);
}
});
}
function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a.get(key);
var y = b.get(key);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
const getRepeatingSectionAttrs = function (charid, prefix) {
// Input
// charid: character id
// prefix: repeating section name, e.g. 'repeating_weapons'
// Output
// repRowIds: array containing all repeating section IDs for the given prefix, ordered in the same way that the rows appear on the sheet
// repeatingAttrs: object containing all repeating attributes that exist for this section, indexed by their name
const repeatingAttrs = {},
regExp = new RegExp(`^${prefix}_(-[-A-Za-z0-9]+?|\\d+)_`);
let repOrder;
// Get attributes
findObjs({
_type: 'attribute',
_characterid: charid
}).forEach(o => {
const attrName = o.get('name');
if (attrName.search(regExp) === 0) repeatingAttrs[attrName] = o;
else if (attrName === `_reporder_${prefix}`) repOrder = o.get('current').split(',');
});
if (!repOrder) repOrder = [];
// Get list of repeating row ids by prefix from repeatingAttrs
const unorderedIds = [...new Set(Object.keys(repeatingAttrs)
.map(n => n.match(regExp))
.filter(x => !!x)
.map(a => a[1]))];
const repRowIds = [...new Set(repOrder.filter(x => unorderedIds.includes(x)).concat(unorderedIds))];
return [repRowIds, repeatingAttrs];
}
function createHandouts() {
// Start by removing existing handouts if they are in the game
var Handouts = findObjs({
_type : "handout",
});
Handouts.forEach(function (handout) {
if (handout.get("name").startsWith("PowerCard Replacements PCMHelper")) {
handout.remove();
};
if (handout.get("name").startsWith("PowerCard Templates PCMHelper")) {
handout.remove();
};
});
// Create the handouts. Note the because of an API bug, the Notes cannot be set
// during creation and if an attempt is made to do that, they are bugged and can't
// be set after creation either, so create them empty.
createObj("handout", { name:"PowerCard Replacements PCMHelper"});
createObj("handout", { name:"PowerCard Templates PCMHelper"});
// Now loop through the handouts again and set the notes for them.
Handouts = findObjs({
_type : "handout",
});
Handouts.forEach(function (handout) {
if (handout.get("name").startsWith("PowerCard Replacements PCMHelper")) {
handout.set("notes", pc_replacements);
};
if (handout.get("name").startsWith("PowerCard Templates PCMHelper")) {
handout.set("notes", pc_templates);
};
});
}
function removePCMMacros() {
var Macros = findObjs({
_type : "macro",
});
Macros.forEach(function (macro) {
if (macro.get("name") === "NPC-Action") {
macro.remove();
}
if (macro.get("name") === "NPC-Legendary") {
macro.remove();
}
if (macro.get("name") === "PC-Attack") {
macro.remove();
}
if (macro.get("name") === "Cast-Cantrip") {
macro.remove();
}
if (macro.get("name") === "Cast-L1") {
macro.remove();
}
if (macro.get("name") === "Cast-L2") {
macro.remove();
}
if (macro.get("name") === "Cast-L3") {
macro.remove();
}
if (macro.get("name") === "Cast-L4") {
macro.remove();
}
if (macro.get("name") === "Cast-L5") {
macro.remove();
}
if (macro.get("name") === "Cast-L6") {
macro.remove();
}
if (macro.get("name") === "Cast-L7") {
macro.remove();
}
if (macro.get("name") === "Cast-L8") {
macro.remove();
}
if (macro.get("name") === "Cast-L9") {
macro.remove();
}
});
}
function createPCMacros(player) {
var pid = player.get("id");
var Macros = findObjs({
_type : "macro",
});
Macros.forEach(function (macro) {
if (macro.get("name") === "NPC-Action") {
macro.remove();
}
if (macro.get("name") === "NPC-Legendary") {
macro.remove();
}
if (macro.get("name") === "PC-Attack") {
macro.remove();
}
if (macro.get("name") === "Cast-Cantrip") {
macro.remove();
}
if (macro.get("name") === "Cast-L1") {
macro.remove();
}
if (macro.get("name") === "Cast-L2") {
macro.remove();
}
if (macro.get("name") === "Cast-L3") {
macro.remove();
}
if (macro.get("name") === "Cast-L4") {
macro.remove();
}
if (macro.get("name") === "Cast-L5") {
macro.remove();
}
if (macro.get("name") === "Cast-L6") {
macro.remove();
}
if (macro.get("name") === "Cast-L7") {
macro.remove();
}
if (macro.get("name") === "Cast-L8") {
macro.remove();
}
if (macro.get("name") === "Cast-L9") {
macro.remove();
}
});
createObj("macro", { name:"NPC-Action", playerid:pid });
createObj("macro", { name:"NPC-Legendary", playerid:pid });
createObj("macro", { name:"PC-Attack", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-Cantrip", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L1", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L2", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L3", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L4", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L5", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L6", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L7", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L8", playerid:pid, visibleto:"all", istokenaction:true });
createObj("macro", { name:"Cast-L9", playerid:pid, visibleto:"all", istokenaction:true });
var Macros = findObjs({
_type : "macro",
});
Macros.forEach(function (macro) {
if (macro.get("name") === "NPC-Action") {
macro.set("action", pc_npcaction);
}
if (macro.get("name") === "NPC-Legendary") {
macro.set("action", pc_legendary);
}
if (macro.get("name") === "PC-Attack") {
macro.set("action", pc_pcattack);
}
if (macro.get("name") === "Cast-Cantrip") {
macro.set("action", pc_cantrip);
}
if (macro.get("name") === "Cast-L1") {
macro.set("action", pc_level1);
}
if (macro.get("name") === "Cast-L2") {
macro.set("action", pc_level2);
}
if (macro.get("name") === "Cast-L3") {
macro.set("action", pc_level3);
}
if (macro.get("name") === "Cast-L4") {
macro.set("action", pc_level4);
}
if (macro.get("name") === "Cast-L5") {
macro.set("action", pc_level5);
}
if (macro.get("name") === "Cast-L6") {
macro.set("action", pc_level6);
}
if (macro.get("name") === "Cast-L7") {
macro.set("action", pc_level7);
}
if (macro.get("name") === "Cast-L8") {
macro.set("action", pc_level8);
}
if (macro.get("name") === "Cast-L9") {
macro.set("action", pc_level9);
}
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment