Files
roll20-character-sheets/dragonbane/dragonbane.html
T
2024-06-03 13:15:14 -04:00

4625 lines
319 KiB
HTML

<input name="attr_sheet_version" value="0" type="hidden" title="@{sheet_version}"/>
<input name="attr_sheet_state" value="settings" type="hidden" title="@{sheet_state}"/>
<input name="attr_collapsed" value="" type="hidden" title="@{collapsed}"/>
<button name="act_push" hidden="" type="action">
</button>
<div class="compendium-drop-target npcs slp">
<input name="attr_drop_name" accept="Name" value="" type="hidden" title="@{drop_name}"/>
<input name="attr_drop_data" accept="data" value="" type="hidden" title="@{drop_data}"/>
<main id="main"><!-- sectionName:dragonbane -->
<input name="attr_dragonbane_tab" value="nav-tabs-dragonbane--settings" type="hidden" title="@{dragonbane_tab}"/>
<div class="tabs tabs--dragonbane">
<nav class="tabs__header tabs--dragonbane__header">
<div class="bane-boon-entry flex-box tiny-gap">
<input class="display-control" name="attr_have_lightning_fast" value="1" hidden="" type="checkbox" title="@{have_lightning_fast}"/>
<label class="input-label marble-header marble-header--full-left marble-header--full-right controlled-display">
<h3 class="marble-header__title" data-i18n="use lightning fast"></h3>
<input type="checkbox" name="attr_lightning_fast" value="1" title="@{lightning_fast}"/>
</label>
<div class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="boons"></h3>
<label class="--parchment">
<input name="attr_boons" type="number" min="0" value="0" title="@{boons}"/>
</label>
</div>
<div class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="banes"></h3>
<label class="--parchment">
<input name="attr_banes" type="number" min="0" value="0" title="@{banes}"/>
</label>
</div>
<button class="round-button" name="act_reset-modifiers" type="action">restart_alt
</button>
</div>
<ul class="tabs__nav-list">
<li class="tabs__nav-item">
<button class="tabs__button tabs--dragonbane__button tabs--dragonbane__button--settings round-button" name="act_nav-tabs-dragonbane--settings" data-container-button="dragonbane" data-button="settings" type="action" data-container-tab="dragonbane" data-tab="settings">settings
</button>
</li>
<li class="tabs__nav-item">
<button class="tabs__button tabs--dragonbane__button tabs--dragonbane__button--pc round-button" name="act_nav-tabs-dragonbane--pc" data-container-button="dragonbane" data-button="pc" type="action" data-container-tab="dragonbane" data-tab="pc">person
</button>
</li>
<li class="tabs__nav-item">
<button class="tabs__button tabs--dragonbane__button tabs--dragonbane__button--monster round-button" name="act_nav-tabs-dragonbane--monster" data-container-button="dragonbane" data-button="monster" type="action" data-container-tab="dragonbane" data-tab="monster">person
</button>
</li>
<li class="tabs__nav-item">
<button class="tabs__button tabs--dragonbane__button tabs--dragonbane__button--party round-button" name="act_nav-tabs-dragonbane--party" data-container-button="dragonbane" data-button="party" type="action" data-container-tab="dragonbane" data-tab="party">groups
</button>
</li>
</ul>
</nav>
<div class="tabs__body tabs--dragonbane__body">
<article class="tabs__container tabs--dragonbane__container tabs--dragonbane__container--settings flex-box flex-wrap half-gap" data-container-tab="dragonbane" data-tab="settings">
<input name="attr_sheet_type" value="pc" type="hidden" title="@{sheet_type}"/>
<input class="display-control--inverted" name="attr_sheet_type" hidden="" value="party" type="checkbox" title="@{sheet_type}"/>
<input name="attr_bar_1" type="hidden" title="@{bar_1}"/>
<input name="attr_custom_bar_1" type="hidden" title="@{custom_bar_1}"/>
<input name="attr_bar_2" type="hidden" title="@{bar_2}"/>
<input name="attr_custom_bar_2" type="hidden" title="@{custom_bar_2}"/>
<input name="attr_bar_3" type="hidden" title="@{bar_3}"/>
<input name="attr_custom_bar_3" type="hidden" title="@{custom_bar_3}"/>
<section class="flex-box flex-wrap half-gap controlled-display" aria-labelledby="optional-header">
<h2 data-i18n="optional rules" id="optional-header"></h2>
<label class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="use magical mishaps"></h3>
<input type="checkbox" name="attr_magical_mishaps" value="1" checked="" title="@{magical_mishaps}"/>
</label>
<label class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="Allow pushing"></h3>
<input type="checkbox" name="attr_allow_push" value="1" checked="" title="@{allow_push}"/>
</label>
<label class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="have lightning fast"></h3>
<input type="checkbox" name="attr_have_lightning_fast" value="1" title="@{have_lightning_fast}"/>
</label>
</section>
<section class="flex-box flex-wrap half-gap" aria-labelledby="behavior-header">
<h2 data-i18n="sheet behavior" id="behavior-header"></h2>
<div class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="whisper rolls"></h3>
<label class="--parchment">
<select name="attr_whisper" title="@{whisper}">
<option value="" data-i18n="never" selected="">
</option>
<option value="/w gm " data-i18n="always">
</option>
</select>
</label>
</div>
<div class="input-label marble-header marble-header--full-left marble-header--full-right">
<h3 class="marble-header__title" data-i18n="sheet type"></h3>
<label class="--parchment">
<select name="attr_sheet_type" title="@{sheet_type}">
<option value="pc" data-i18n="pc/npc" selected="">
</option>
<option value="monster" data-i18n="monster">
</option>
<option value="party" data-i18n="party/gm">
</option>
</select>
</label>
</div>
<input class="display-control" name="attr_sheet_type" hidden="" value="party" type="checkbox" title="@{sheet_type}"/>
<div class="input-label marble-header marble-header--full-left marble-header--full-right controlled-display">
<h3 class="marble-header__title" data-i18n="use roll20 initiative"></h3>
<label class="--parchment">
<select name="attr_use_roll20_initiative" title="@{use_roll20_initiative}">
<option value="0" data-i18n="no" selected="">
</option>
<option value="1" data-i18n="always">
</option>
</select>
</label>
</div>
<input class="display-control" name="attr_sheet_type" checked="" hidden="" value="pc" type="checkbox" title="@{sheet_type}"/>
<div class="input-label marble-header marble-header--full-left marble-header--full-right controlled-display">
<h3 class="marble-header__title" data-i18n="Bonus WP"></h3>
<label class="--parchment">
<input name="attr_willpower_points_bonus" type="number" title="@{willpower_points_bonus}"/>
</label>
</div>
<input class="display-control" name="attr_sheet_type" checked="" hidden="" value="pc" type="checkbox" title="@{sheet_type}"/>
<div class="input-label marble-header marble-header--full-left marble-header--full-right controlled-display">
<h3 class="marble-header__title" data-i18n="Bonus HP"></h3>
<label class="--parchment">
<input name="attr_hit_points_bonus" type="number" title="@{hit_points_bonus}"/>
</label>
</div>
</section>
</article>
<article class="tabs__container tabs--dragonbane__container tabs--dragonbane__container--pc" data-container-tab="dragonbane" data-tab="pc">
<header class="flex-box flex-wrap normal-gap-x half-gap-y">
<div class="character-details flex-box half-gap flex-wrap">
<label class="input-label stacked"><span class="input-label__text" data-i18n="character name" role="heading" aria-level="3"></span>
<input class="underline input-label__input" name="attr_character_name" type="text" title="@{character_name}"/>
</label>
<label class="input-label stacked"><span class="input-label__text" data-i18n="player name" role="heading" aria-level="3"></span>
<input class="underline input-label__input" name="attr_player_name" type="text" title="@{player_name}"/>
</label>
</div>
<h1 class="logo" data-i18n="dragon bane"></h1>
<div class="character-details flex-box half-gap flex-wrap">
<div class="flex-box half-gap align-items-end">
<label class="input-label stacked"><span class="input-label__text" data-i18n="kin & movement" role="heading" aria-level="3"></span>
<input class="underline input-label__input" name="attr_kin" type="text" title="@{kin}"/>
</label>
<input class="underline" name="attr_kin_movement" type="number" title="@{kin_movement}"/>
</div>
<label class="input-label stacked" style="flex:1;"><span class="input-label__text" data-i18n="age" role="heading" aria-level="3"></span>
<input class="underline input-label__input" name="attr_age" type="text" title="@{age}"/>
</label>
<label class="input-label stacked" style="flex:1;"><span class="input-label__text" data-i18n="profession" role="heading" aria-level="3"></span>
<input class="underline input-label__input" name="attr_profession" type="text" title="@{profession}"/>
</label>
</div>
<div class="descriptions flex-box flex-wrap half-gap">
<label class="input-desc weakness"><span class="capitalize input-label" data-i18n="weakness" role="heading" aria-level="3"></span>
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_weakness" title="@{weakness}"></span>
<textarea class="underline adaptive--text__textarea" name="attr_weakness" title="@{weakness}"></textarea>
</div>
</label>
<label class="input-desc appearance"><span class="capitalize input-label" data-i18n="appearance" role="heading" aria-level="3"></span>
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_appearance" title="@{appearance}"></span>
<textarea class="underline adaptive--text__textarea" name="attr_appearance" title="@{appearance}"></textarea>
</div>
</label>
</div>
</header>
<div class="section--attributes">
<div class="section--attributes__deco section--attributes__deco--left"> </div>
<div class="section--attributes__deco section--attributes__deco--right"></div>
<div class="attribute">
<button class="attribute__button roller" name="roll_strength" role="heading" aria-level="3" data-i18n="strength-abbreviation" value="@{strength_action}" type="roll">
</button>
<button name="act_strength-action" hidden="" type="action">
</button>
<input name="attr_strength_action" type="hidden" title="@{strength_action}"/>
<input class="attribute__value" name="attr_strength" value="0" type="number" title="@{strength}"/>
<label class="attribute__condition"> <span class="attribute__condition__background border--marble-green"></span>
<input class="attribute__condition__checkbox --outset" name="attr_exhausted" value="1" type="checkbox" title="@{exhausted}"/>
<div class="input-label marble-header attribute__condition__label marble-header--min">
<h3 class="marble-header__title" data-i18n="exhausted"></h3>
</div>
</label>
</div>
<div class="attribute">
<button class="attribute__button roller" name="roll_constitution" role="heading" aria-level="3" data-i18n="constitution-abbreviation" value="@{constitution_action}" type="roll">
</button>
<button name="act_constitution-action" hidden="" type="action">
</button>
<input name="attr_constitution_action" type="hidden" title="@{constitution_action}"/>
<input class="attribute__value" name="attr_constitution" value="0" type="number" title="@{constitution}"/>
<label class="attribute__condition"> <span class="attribute__condition__background border--marble-green"></span>
<input class="attribute__condition__checkbox --outset" name="attr_sickly" value="1" type="checkbox" title="@{sickly}"/>
<div class="input-label marble-header attribute__condition__label marble-header--min">
<h3 class="marble-header__title" data-i18n="sickly"></h3>
</div>
</label>
</div>
<div class="attribute">
<button class="attribute__button roller" name="roll_agility" role="heading" aria-level="3" data-i18n="agility-abbreviation" value="@{agility_action}" type="roll">
</button>
<button name="act_agility-action" hidden="" type="action">
</button>
<input name="attr_agility_action" type="hidden" title="@{agility_action}"/>
<input class="attribute__value" name="attr_agility" value="0" type="number" title="@{agility}"/>
<label class="attribute__condition"> <span class="attribute__condition__background border--marble-green"></span>
<input class="attribute__condition__checkbox --outset" name="attr_dazed" value="1" type="checkbox" title="@{dazed}"/>
<div class="input-label marble-header attribute__condition__label marble-header--min">
<h3 class="marble-header__title" data-i18n="dazed"></h3>
</div>
</label>
</div>
<div class="attribute">
<button class="attribute__button roller" name="roll_intelligence" role="heading" aria-level="3" data-i18n="intelligence-abbreviation" value="@{intelligence_action}" type="roll">
</button>
<button name="act_intelligence-action" hidden="" type="action">
</button>
<input name="attr_intelligence_action" type="hidden" title="@{intelligence_action}"/>
<input class="attribute__value" name="attr_intelligence" value="0" type="number" title="@{intelligence}"/>
<label class="attribute__condition"> <span class="attribute__condition__background border--marble-green"></span>
<input class="attribute__condition__checkbox --outset" name="attr_angry" value="1" type="checkbox" title="@{angry}"/>
<div class="input-label marble-header attribute__condition__label marble-header--min">
<h3 class="marble-header__title" data-i18n="angry"></h3>
</div>
</label>
</div>
<div class="attribute">
<button class="attribute__button roller" name="roll_willpower" role="heading" aria-level="3" data-i18n="willpower-abbreviation" value="@{willpower_action}" type="roll">
</button>
<button name="act_willpower-action" hidden="" type="action">
</button>
<input name="attr_willpower_action" type="hidden" title="@{willpower_action}"/>
<input class="attribute__value" name="attr_willpower" value="0" type="number" title="@{willpower}"/>
<label class="attribute__condition"> <span class="attribute__condition__background border--marble-green"></span>
<input class="attribute__condition__checkbox --outset" name="attr_scared" value="1" type="checkbox" title="@{scared}"/>
<div class="input-label marble-header attribute__condition__label marble-header--min">
<h3 class="marble-header__title" data-i18n="scared"></h3>
</div>
</label>
</div>
<div class="attribute">
<button class="attribute__button roller" name="roll_charisma" role="heading" aria-level="3" data-i18n="charisma-abbreviation" value="@{charisma_action}" type="roll">
</button>
<button name="act_charisma-action" hidden="" type="action">
</button>
<input name="attr_charisma_action" type="hidden" title="@{charisma_action}"/>
<input class="attribute__value" name="attr_charisma" value="0" type="number" title="@{charisma}"/>
<label class="attribute__condition"> <span class="attribute__condition__background border--marble-green"></span>
<input class="attribute__condition__checkbox --outset" name="attr_disheartened" value="1" type="checkbox" title="@{disheartened}"/>
<div class="input-label marble-header attribute__condition__label marble-header--min">
<h3 class="marble-header__title" data-i18n="disheartened"></h3>
</div>
</label>
</div>
</div>
<div class="section--attributes_secondaries flex-wrap justify-space-around">
<div class="input-label marble-header section--attributes-secondaries__header marble-header--full-left marble-header--full-right">
<h2 class="marble-header__title" data-i18n="Damage Bon. Str"></h2>
<label class="--parchment"><span class="uppercase" name="attr_damage_bonus_strength" value="—" title="@{damage_bonus_strength}"></span>
</label>
</div>
<div class="input-label marble-header section--attributes-secondaries__header marble-header--full-left marble-header--full-right">
<h2 class="marble-header__title" data-i18n="Damage Bon. AGL"></h2>
<label class="--parchment"><span class="uppercase" name="attr_damage_bonus_agility" value="—" title="@{damage_bonus_agility}"></span>
</label>
</div>
<div class="input-label marble-header section--attributes-secondaries__header marble-header--full-left marble-header--full-right">
<h2 class="marble-header__title" data-i18n="movement"></h2>
<label class="--parchment">
<input name="attr_movement" value="0" type="number" title="@{movement}"/>
</label>
</div>
</div>
<div class="section--skills --parchment">
<div class="input-label marble-header marble-header--full-left marble-header--full-right section--skills__header --boxtitle offset-box">
<h2 class="marble-header__title" data-i18n="Skills"></h2>
</div>
<button class="section--skills__button--advance" name="act_advance" id="advancement-checkbox" type="action">upgrade
</button>
<div class="--parchment__trim --top"> </div>
<div class="--parchment__trim --bottom --lg"></div>
<input name="attr_strength_base_chance" value="0" type="hidden" title="@{strength_base_chance}"/>
<input name="attr_constitution_base_chance" value="0" type="hidden" title="@{constitution_base_chance}"/>
<input name="attr_agility_base_chance" value="0" type="hidden" title="@{agility_base_chance}"/>
<input name="attr_intelligence_base_chance" value="0" type="hidden" title="@{intelligence_base_chance}"/>
<input name="attr_willpower_base_chance" value="0" type="hidden" title="@{willpower_base_chance}"/>
<input name="attr_charisma_base_chance" value="0" type="hidden" title="@{charisma_base_chance}"/>
<div class="section--skills__list--base" data-i18n-list="base-skill-order">
<div class="section--skills__row" data-i18n-list-item="acrobatics">
<input class="section--skills__row__checkbox" name="attr_acrobatics_advancement" value="1" type="checkbox" title="@{acrobatics_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_acrobatics_levels" value="0" type="number" title="@{acrobatics_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_acrobatics" readonly="" value="0" type="number" title="@{acrobatics}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_acrobatics" data-i18n="acrobatics" value="@{acrobatics_action}" type="roll">
</button>
<button name="act_acrobatics-action" hidden="" type="action">
</button>
<input name="attr_acrobatics_action" type="hidden" title="@{acrobatics_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="awareness">
<input class="section--skills__row__checkbox" name="attr_awareness_advancement" value="1" type="checkbox" title="@{awareness_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_awareness_levels" value="0" type="number" title="@{awareness_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_awareness" readonly="" value="0" type="number" title="@{awareness}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_awareness" data-i18n="awareness" value="@{awareness_action}" type="roll">
</button>
<button name="act_awareness-action" hidden="" type="action">
</button>
<input name="attr_awareness_action" type="hidden" title="@{awareness_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="bartering">
<input class="section--skills__row__checkbox" name="attr_bartering_advancement" value="1" type="checkbox" title="@{bartering_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_bartering_levels" value="0" type="number" title="@{bartering_levels}"/><span class="section--skills__row__field--base_chance" name="attr_charisma_base_chance" title="@{charisma_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_bartering" readonly="" value="0" type="number" title="@{bartering}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_bartering" data-i18n="bartering" value="@{bartering_action}" type="roll">
</button>
<button name="act_bartering-action" hidden="" type="action">
</button>
<input name="attr_bartering_action" type="hidden" title="@{bartering_action}"/><span data-i18n="charisma-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="beast lore">
<input class="section--skills__row__checkbox" name="attr_beast_lore_advancement" value="1" type="checkbox" title="@{beast_lore_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_beast_lore_levels" value="0" type="number" title="@{beast_lore_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_beast_lore" readonly="" value="0" type="number" title="@{beast_lore}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_beast_lore" data-i18n="beast lore" value="@{beast_lore_action}" type="roll">
</button>
<button name="act_beast-lore-action" hidden="" type="action">
</button>
<input name="attr_beast_lore_action" type="hidden" title="@{beast_lore_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="bluffing">
<input class="section--skills__row__checkbox" name="attr_bluffing_advancement" value="1" type="checkbox" title="@{bluffing_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_bluffing_levels" value="0" type="number" title="@{bluffing_levels}"/><span class="section--skills__row__field--base_chance" name="attr_charisma_base_chance" title="@{charisma_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_bluffing" readonly="" value="0" type="number" title="@{bluffing}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_bluffing" data-i18n="bluffing" value="@{bluffing_action}" type="roll">
</button>
<button name="act_bluffing-action" hidden="" type="action">
</button>
<input name="attr_bluffing_action" type="hidden" title="@{bluffing_action}"/><span data-i18n="charisma-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="bushcraft">
<input class="section--skills__row__checkbox" name="attr_bushcraft_advancement" value="1" type="checkbox" title="@{bushcraft_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_bushcraft_levels" value="0" type="number" title="@{bushcraft_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_bushcraft" readonly="" value="0" type="number" title="@{bushcraft}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_bushcraft" data-i18n="bushcraft" value="@{bushcraft_action}" type="roll">
</button>
<button name="act_bushcraft-action" hidden="" type="action">
</button>
<input name="attr_bushcraft_action" type="hidden" title="@{bushcraft_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="crafting">
<input class="section--skills__row__checkbox" name="attr_crafting_advancement" value="1" type="checkbox" title="@{crafting_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_crafting_levels" value="0" type="number" title="@{crafting_levels}"/><span class="section--skills__row__field--base_chance" name="attr_strength_base_chance" title="@{strength_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_crafting" readonly="" value="0" type="number" title="@{crafting}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_crafting" data-i18n="crafting" value="@{crafting_action}" type="roll">
</button>
<button name="act_crafting-action" hidden="" type="action">
</button>
<input name="attr_crafting_action" type="hidden" title="@{crafting_action}"/><span data-i18n="strength-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="evade">
<input class="section--skills__row__checkbox" name="attr_evade_advancement" value="1" type="checkbox" title="@{evade_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_evade_levels" value="0" type="number" title="@{evade_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_evade" readonly="" value="0" type="number" title="@{evade}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_evade" data-i18n="evade" value="@{evade_action}" type="roll">
</button>
<button name="act_evade-action" hidden="" type="action">
</button>
<input name="attr_evade_action" type="hidden" title="@{evade_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="healing">
<input class="section--skills__row__checkbox" name="attr_healing_advancement" value="1" type="checkbox" title="@{healing_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_healing_levels" value="0" type="number" title="@{healing_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_healing" readonly="" value="0" type="number" title="@{healing}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_healing" data-i18n="healing" value="@{healing_action}" type="roll">
</button>
<button name="act_healing-action" hidden="" type="action">
</button>
<input name="attr_healing_action" type="hidden" title="@{healing_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="hunting &amp; fishing">
<input class="section--skills__row__checkbox" name="attr_hunting_&_fishing_advancement" value="1" type="checkbox" title="@{hunting_&_fishing_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_hunting_&_fishing_levels" value="0" type="number" title="@{hunting_&_fishing_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_hunting_&_fishing" readonly="" value="0" type="number" title="@{hunting_&_fishing}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_hunting_&_fishing" data-i18n="hunting & fishing" value="@{hunting_&_fishing_action}" type="roll">
</button>
<button name="act_hunting-&-fishing-action" hidden="" type="action">
</button>
<input name="attr_hunting_&_fishing_action" type="hidden" title="@{hunting_&_fishing_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="languages">
<input class="section--skills__row__checkbox" name="attr_languages_advancement" value="1" type="checkbox" title="@{languages_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_languages_levels" value="0" type="number" title="@{languages_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_languages" readonly="" value="0" type="number" title="@{languages}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_languages" data-i18n="languages" value="@{languages_action}" type="roll">
</button>
<button name="act_languages-action" hidden="" type="action">
</button>
<input name="attr_languages_action" type="hidden" title="@{languages_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="myths &amp; legends">
<input class="section--skills__row__checkbox" name="attr_myths_&_legends_advancement" value="1" type="checkbox" title="@{myths_&_legends_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_myths_&_legends_levels" value="0" type="number" title="@{myths_&_legends_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_myths_&_legends" readonly="" value="0" type="number" title="@{myths_&_legends}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_myths_&_legends" data-i18n="myths & legends" value="@{myths_&_legends_action}" type="roll">
</button>
<button name="act_myths-&-legends-action" hidden="" type="action">
</button>
<input name="attr_myths_&_legends_action" type="hidden" title="@{myths_&_legends_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="performance">
<input class="section--skills__row__checkbox" name="attr_performance_advancement" value="1" type="checkbox" title="@{performance_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_performance_levels" value="0" type="number" title="@{performance_levels}"/><span class="section--skills__row__field--base_chance" name="attr_charisma_base_chance" title="@{charisma_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_performance" readonly="" value="0" type="number" title="@{performance}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_performance" data-i18n="performance" value="@{performance_action}" type="roll">
</button>
<button name="act_performance-action" hidden="" type="action">
</button>
<input name="attr_performance_action" type="hidden" title="@{performance_action}"/><span data-i18n="charisma-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="persuasion">
<input class="section--skills__row__checkbox" name="attr_persuasion_advancement" value="1" type="checkbox" title="@{persuasion_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_persuasion_levels" value="0" type="number" title="@{persuasion_levels}"/><span class="section--skills__row__field--base_chance" name="attr_charisma_base_chance" title="@{charisma_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_persuasion" readonly="" value="0" type="number" title="@{persuasion}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_persuasion" data-i18n="persuasion" value="@{persuasion_action}" type="roll">
</button>
<button name="act_persuasion-action" hidden="" type="action">
</button>
<input name="attr_persuasion_action" type="hidden" title="@{persuasion_action}"/><span data-i18n="charisma-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="riding">
<input class="section--skills__row__checkbox" name="attr_riding_advancement" value="1" type="checkbox" title="@{riding_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_riding_levels" value="0" type="number" title="@{riding_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_riding" readonly="" value="0" type="number" title="@{riding}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_riding" data-i18n="riding" value="@{riding_action}" type="roll">
</button>
<button name="act_riding-action" hidden="" type="action">
</button>
<input name="attr_riding_action" type="hidden" title="@{riding_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="seamanship">
<input class="section--skills__row__checkbox" name="attr_seamanship_advancement" value="1" type="checkbox" title="@{seamanship_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_seamanship_levels" value="0" type="number" title="@{seamanship_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_seamanship" readonly="" value="0" type="number" title="@{seamanship}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_seamanship" data-i18n="seamanship" value="@{seamanship_action}" type="roll">
</button>
<button name="act_seamanship-action" hidden="" type="action">
</button>
<input name="attr_seamanship_action" type="hidden" title="@{seamanship_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="sleight of hand">
<input class="section--skills__row__checkbox" name="attr_sleight_of_hand_advancement" value="1" type="checkbox" title="@{sleight_of_hand_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_sleight_of_hand_levels" value="0" type="number" title="@{sleight_of_hand_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_sleight_of_hand" readonly="" value="0" type="number" title="@{sleight_of_hand}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_sleight_of_hand" data-i18n="sleight of hand" value="@{sleight_of_hand_action}" type="roll">
</button>
<button name="act_sleight-of-hand-action" hidden="" type="action">
</button>
<input name="attr_sleight_of_hand_action" type="hidden" title="@{sleight_of_hand_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="sneaking">
<input class="section--skills__row__checkbox" name="attr_sneaking_advancement" value="1" type="checkbox" title="@{sneaking_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_sneaking_levels" value="0" type="number" title="@{sneaking_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_sneaking" readonly="" value="0" type="number" title="@{sneaking}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_sneaking" data-i18n="sneaking" value="@{sneaking_action}" type="roll">
</button>
<button name="act_sneaking-action" hidden="" type="action">
</button>
<input name="attr_sneaking_action" type="hidden" title="@{sneaking_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="spot hidden">
<input class="section--skills__row__checkbox" name="attr_spot_hidden_advancement" value="1" type="checkbox" title="@{spot_hidden_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_spot_hidden_levels" value="0" type="number" title="@{spot_hidden_levels}"/><span class="section--skills__row__field--base_chance" name="attr_intelligence_base_chance" title="@{intelligence_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_spot_hidden" readonly="" value="0" type="number" title="@{spot_hidden}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_spot_hidden" data-i18n="spot hidden" value="@{spot_hidden_action}" type="roll">
</button>
<button name="act_spot-hidden-action" hidden="" type="action">
</button>
<input name="attr_spot_hidden_action" type="hidden" title="@{spot_hidden_action}"/><span data-i18n="intelligence-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="swimming">
<input class="section--skills__row__checkbox" name="attr_swimming_advancement" value="1" type="checkbox" title="@{swimming_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_swimming_levels" value="0" type="number" title="@{swimming_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_swimming" readonly="" value="0" type="number" title="@{swimming}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_swimming" data-i18n="swimming" value="@{swimming_action}" type="roll">
</button>
<button name="act_swimming-action" hidden="" type="action">
</button>
<input name="attr_swimming_action" type="hidden" title="@{swimming_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
</div>
<div class="section--skills__list--weapon" data-i18n-list="weapon-skill-order">
<h2 data-i18n="Weapon Skills">Weapon Skills</h2>
<div class="section--skills__row" data-i18n-list-item="axes">
<input class="section--skills__row__checkbox" name="attr_axes_advancement" value="1" type="checkbox" title="@{axes_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_axes_levels" value="0" type="number" title="@{axes_levels}"/><span class="section--skills__row__field--base_chance" name="attr_strength_base_chance" title="@{strength_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_axes" readonly="" value="0" type="number" title="@{axes}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_axes" data-i18n="axes" value="@{axes_action}" type="roll">
</button>
<button name="act_axes-action" hidden="" type="action">
</button>
<input name="attr_axes_action" type="hidden" title="@{axes_action}"/><span data-i18n="strength-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="bows">
<input class="section--skills__row__checkbox" name="attr_bows_advancement" value="1" type="checkbox" title="@{bows_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_bows_levels" value="0" type="number" title="@{bows_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_bows" readonly="" value="0" type="number" title="@{bows}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_bows" data-i18n="bows" value="@{bows_action}" type="roll">
</button>
<button name="act_bows-action" hidden="" type="action">
</button>
<input name="attr_bows_action" type="hidden" title="@{bows_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="brawling">
<input class="section--skills__row__checkbox" name="attr_brawling_advancement" value="1" type="checkbox" title="@{brawling_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_brawling_levels" value="0" type="number" title="@{brawling_levels}"/><span class="section--skills__row__field--base_chance" name="attr_strength_base_chance" title="@{strength_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_brawling" readonly="" value="0" type="number" title="@{brawling}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_brawling" data-i18n="brawling" value="@{brawling_action}" type="roll">
</button>
<button name="act_brawling-action" hidden="" type="action">
</button>
<input name="attr_brawling_action" type="hidden" title="@{brawling_action}"/><span data-i18n="strength-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="crossbows">
<input class="section--skills__row__checkbox" name="attr_crossbows_advancement" value="1" type="checkbox" title="@{crossbows_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_crossbows_levels" value="0" type="number" title="@{crossbows_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_crossbows" readonly="" value="0" type="number" title="@{crossbows}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_crossbows" data-i18n="crossbows" value="@{crossbows_action}" type="roll">
</button>
<button name="act_crossbows-action" hidden="" type="action">
</button>
<input name="attr_crossbows_action" type="hidden" title="@{crossbows_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="hammers">
<input class="section--skills__row__checkbox" name="attr_hammers_advancement" value="1" type="checkbox" title="@{hammers_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_hammers_levels" value="0" type="number" title="@{hammers_levels}"/><span class="section--skills__row__field--base_chance" name="attr_strength_base_chance" title="@{strength_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_hammers" readonly="" value="0" type="number" title="@{hammers}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_hammers" data-i18n="hammers" value="@{hammers_action}" type="roll">
</button>
<button name="act_hammers-action" hidden="" type="action">
</button>
<input name="attr_hammers_action" type="hidden" title="@{hammers_action}"/><span data-i18n="strength-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="knives">
<input class="section--skills__row__checkbox" name="attr_knives_advancement" value="1" type="checkbox" title="@{knives_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_knives_levels" value="0" type="number" title="@{knives_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_knives" readonly="" value="0" type="number" title="@{knives}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_knives" data-i18n="knives" value="@{knives_action}" type="roll">
</button>
<button name="act_knives-action" hidden="" type="action">
</button>
<input name="attr_knives_action" type="hidden" title="@{knives_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="slings">
<input class="section--skills__row__checkbox" name="attr_slings_advancement" value="1" type="checkbox" title="@{slings_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_slings_levels" value="0" type="number" title="@{slings_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_slings" readonly="" value="0" type="number" title="@{slings}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_slings" data-i18n="slings" value="@{slings_action}" type="roll">
</button>
<button name="act_slings-action" hidden="" type="action">
</button>
<input name="attr_slings_action" type="hidden" title="@{slings_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="spears">
<input class="section--skills__row__checkbox" name="attr_spears_advancement" value="1" type="checkbox" title="@{spears_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_spears_levels" value="0" type="number" title="@{spears_levels}"/><span class="section--skills__row__field--base_chance" name="attr_strength_base_chance" title="@{strength_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_spears" readonly="" value="0" type="number" title="@{spears}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_spears" data-i18n="spears" value="@{spears_action}" type="roll">
</button>
<button name="act_spears-action" hidden="" type="action">
</button>
<input name="attr_spears_action" type="hidden" title="@{spears_action}"/><span data-i18n="strength-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="staves">
<input class="section--skills__row__checkbox" name="attr_staves_advancement" value="1" type="checkbox" title="@{staves_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_staves_levels" value="0" type="number" title="@{staves_levels}"/><span class="section--skills__row__field--base_chance" name="attr_agility_base_chance" title="@{agility_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_staves" readonly="" value="0" type="number" title="@{staves}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_staves" data-i18n="staves" value="@{staves_action}" type="roll">
</button>
<button name="act_staves-action" hidden="" type="action">
</button>
<input name="attr_staves_action" type="hidden" title="@{staves_action}"/><span data-i18n="agility-abbreviation"></span>
</label>
</div>
<div class="section--skills__row" data-i18n-list-item="swords">
<input class="section--skills__row__checkbox" name="attr_swords_advancement" value="1" type="checkbox" title="@{swords_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_swords_levels" value="0" type="number" title="@{swords_levels}"/><span class="section--skills__row__field--base_chance" name="attr_strength_base_chance" title="@{strength_base_chance}"></span>
<input class="section--skills__row__field--total" name="attr_swords" readonly="" value="0" type="number" title="@{swords}"/>
</div>
<label>
<button class="section--skills__button capitalize roller" name="roll_swords" data-i18n="swords" value="@{swords_action}" type="roll">
</button>
<button name="act_swords-action" hidden="" type="action">
</button>
<input name="attr_swords_action" type="hidden" title="@{swords_action}"/><span data-i18n="strength-abbreviation"></span>
</label>
</div>
</div>
<div class="section--skills__list--secondary repeating-section-container">
<h2 data-i18n="Secondary Skills">Secondary Skills</h2>
<button class="repcontrol-button repcontrol-button--add" name="act_add-secondary-skills" type="action">
</button><span class="section--skills__list--secondary" hidden=""></span>
<fieldset class="repeating_secondary-skills">
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_secondary-skills_$X_collapse}"/>
<div class="collapsed section--skills__row">
<input class="section--skills__checkbox" name="attr_advancement" value="1" type="checkbox" title="@{repeating_secondary-skills_$X_advancement}"/>
<div class="inputFold">
<input class="section--skills__row__field--skill_levels" name="attr_levels" value="0" type="number" title="@{repeating_secondary-skills_$X_levels}"/>
<input class="section--skills__row__field--total" name="attr_total" readonly="" value="0" type="number" title="@{repeating_secondary-skills_$X_total}"/>
</div>
<label>
<button class="section--skills__button roller" name="roll_roll" value="@{action}" type="roll">
</button>
<button name="act_action" hidden="" type="action">
</button>
<input name="attr_action" type="hidden" title="@{repeating_secondary-skills_$X_action}"/><span class="section--skills__list--secondary__skill_name" name="attr_name" value="New Skill" title="@{repeating_secondary-skills_$X_name}"></span>
<input name="attr_attribute_abbreviation" value="intelligence-abbreviation" type="hidden" title="@{repeating_secondary-skills_$X_attribute_abbreviation}"/><span class="parentheses uppercase" name="attr_attribute_abbreviation" data-i18n-dynamic="" title="@{repeating_secondary-skills_$X_attribute_abbreviation}">intelligence-abbreviation</span>
</label>
</div>
<div class="expanded">
<input class="section--skills__list--secondary__skill_name --edit --parchment" name="attr_name" value="New Skill" type="text" title="@{repeating_secondary-skills_$X_name}"/>
<select class="section--skills__list--secondary__skill_attribute --edit --parchment" name="attr_attribute_select" value="intelligence" title="@{repeating_secondary-skills_$X_attribute_select}">
<option value="strength" data-i18n="strength">
</option>
<option value="constitution" data-i18n="constitution">
</option>
<option value="agility" data-i18n="agility">
</option>
<option value="intelligence" data-i18n="intelligence" selected="selected">
</option>
<option value="willpower" data-i18n="willpower">
</option>
<option value="charisma" data-i18n="charisma">
</option>
</select>
</div>
</fieldset>
</div>
</div>
<div class="section--inventory repeating-section-container">
<div class="input-label marble-header section--inventory__header marble-header--full-right">
<h2 class="marble-header__title" data-i18n="Inventory"></h2>
<label class="--parchment">
<div class="flex-box" style="align-items:center;--invWidth:2rem;">
<input name="attr_encumbrance" value="0" style="width:var(--invWidth)" type="number" title="@{encumbrance}"/><span class="slash">/</span>
<input name="attr_encumbrance_max" value="0" readonly="" style="width:var(--invWidth)" type="number" title="@{encumbrance|max}"/>
</div>
</label>
</div>
<label style="display: flex; justify-content: space-around">
<h3 data-i18n="backpack"></h3>
<input class="section--inventory__backpack" name="attr_backpack" value="2" type="checkbox" title="@{backpack}"/>
</label>
<button class="repcontrol-button repcontrol-button--add" name="act_add-gear" type="action">
</button>
<fieldset class="repeating_gear">
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_gear_$X_collapse}"/>
<label class="input-label section--inventory__quantity--wrapper"><span data-i18n="x"></span>
<input class="section--inventory__quantity input-label__input" name="attr_quantity" type="number" value="1" title="@{repeating_gear_$X_quantity}"/>
</label>
<input class="section--inventory__name underline" name="attr_name" placeholder="New item" type="text" title="@{repeating_gear_$X_name}"/>
<input class="section--inventory__weight underline" name="attr_weight" type="number" title="@{repeating_gear_$X_weight}"/>
<div class="adaptive adaptive--text expanded section--inventory__description"><span class="adaptive--text__span" name="attr_description" title="@{repeating_gear_$X_description}"></span>
<textarea class="adaptive--text__textarea" name="attr_description" placeholder="Description" title="@{repeating_gear_$X_description}"></textarea>
</div>
</fieldset>
<div class="subsection--memento --parchment">
<div class="--parchment__trim --bottom"></div>
<h3 data-i18n="memento"></h3>
<textarea class="section--inventory__memento" name="attr_memento" title="@{memento}"></textarea>
</div>
<div class="subsection--tinyitems --parchment">
<div class="--parchment__trim --bottom"></div>
<h3 data-i18n="tiny items"></h3>
<textarea class="section--inventory__tinylist" name="attr_tiny_list" title="@{tiny_list}"></textarea>
</div>
</div>
<div class="section--abilities repeating-section-container">
<div class="input-label marble-header section--abilities__header marble-header--full-left">
<h2 class="marble-header__title" data-i18n="Abilities &amp; Spells"></h2>
</div>
<button class="repcontrol-button repcontrol-button--add" name="act_add-abilities" type="action">
</button><span class="bullet-point-section" hidden=""></span>
<fieldset class="repeating_abilities">
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_abilities_$X_collapse}"/>
<div class="collapsed">
<button class="round-button" name="roll_describe" type="roll" value="@{template_start} {{label=@{name}}} {{description=@{description}}} {{rank=@{rank}}} {{requirement=@{requirement}}} {{casting_time=@{casting_time}}} {{range=@{range}}} {{duration=@{duration}}} {{spell=@{spell}}}">mode_comment
</button>
<div class="flex-box underline half-gap">
<input class="collapse" name="attr_spell" value="1" type="checkbox" title="@{repeating_abilities_$X_spell}" hidden="hidden"/>
<input class="collapsed" name="attr_prepared" value="1" type="checkbox" title="@{repeating_abilities_$X_prepared}"/>
<button class="roller" name="roll_cast" value="@{cast_action}" type="roll"><span class="section--abilities__name--display" name="attr_name" title="@{repeating_abilities_$X_name}"></span>
</button>
<button name="act_cast-action" hidden="" type="action">
</button>
<input name="attr_cast_action" type="hidden" title="@{repeating_abilities_$X_cast_action}"/><span class="section--abilities__cost--display" name="attr_cost" title="@{repeating_abilities_$X_cost}"></span>
</div>
</div>
<div class="expanded">
<ul>
<li>
<label class="input-label"><span data-i18n="Name:"></span>
<input class="input-label__input" name="attr_name" type="text" data-i18n-placeholder="New Ability" title="@{repeating_abilities_$X_name}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Cost:"></span>
<input class="input-label__input" name="attr_cost" type="text" data-i18n-placeholder="1" title="@{repeating_abilities_$X_cost}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Requirements:"></span>
<input class="input-label__input" name="attr_requirement" type="text" data-i18n-placeholder="Gesture" title="@{repeating_abilities_$X_requirement}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Spell?"></span>
<input class="input-label__input" name="attr_spell" type="checkbox" value="1" title="@{repeating_abilities_$X_spell}"/>
</label>
</li>
</ul>
<input class="--spellReveal" name="attr_spell" hidden="" value="1" type="checkbox" title="@{repeating_abilities_$X_spell}"/>
<ul class="section--abilities__spell_details">
<li>
<label class="input-label"><span class="input-label__text" data-i18n="skill:"></span>
<select class="magic-select input-label__input" name="attr_skill" title="@{repeating_abilities_$X_skill}">
<option value="magic trick" data-i18n="magic trick">
</option>
<option value="general spell" data-i18n="general spell" selected="selected">
</option>
</select>
</label>
</li>
<li>
<label class="input-label"><span class="question input-label__text" data-i18n="dynamic power"></span>
<input class="input-label__input" name="attr_spell_power" type="checkbox" value="1" checked="" title="@{repeating_abilities_$X_spell_power}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Rank:"></span>
<input class="input-label__input" name="attr_rank" type="number" data-i18n-placeholder="1" title="@{repeating_abilities_$X_rank}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Casting Time:"></span>
<input class="input-label__input" name="attr_casting_time" type="text" data-i18n-placeholder="Instant" title="@{repeating_abilities_$X_casting_time}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Range:"></span>
<input class="input-label__input" name="attr_range" type="text" data-i18n-placeholder="Touch" title="@{repeating_abilities_$X_range}"/>
</label>
</li>
<li>
<label class="input-label"><span data-i18n="Duration:"></span>
<input class="input-label__input" name="attr_duration" type="text" data-i18n-placeholder="Instant" title="@{repeating_abilities_$X_duration}"/>
</label>
</li>
</ul>
<div class="adaptive adaptive--text section--abilities__description"><span class="adaptive--text__span" name="attr_description" title="@{repeating_abilities_$X_description}"></span>
<textarea class="adaptive--text__textarea" name="attr_description" data-i18n-placeholder="Description" title="@{repeating_abilities_$X_description}"></textarea>
</div>
</div>
</fieldset>
</div>
<div class="section--wealth">
<div class="input-label marble-header section--wealth__header ">
<h2 class="marble-header__title" data-i18n="Gold"></h2>
<label class="--parchment">
<input class="section--wealth__header__input" name="attr_gold" type="number" value="0" title="@{gold}"/>
</label>
</div>
<div class="input-label marble-header section--wealth__header ">
<h2 class="marble-header__title" data-i18n="Silver"></h2>
<label class="--parchment">
<input class="section--wealth__header__input" name="attr_silver" type="number" value="0" title="@{silver}"/>
</label>
</div>
<div class="input-label marble-header section--wealth__header ">
<h2 class="marble-header__title" data-i18n="Copper"></h2>
<label class="--parchment">
<input class="section--wealth__header__input" name="attr_copper" type="number" value="0" title="@{copper}"/>
</label>
</div>
</div>
<div class="bottom">
<section class="armor" data-i18n-aria-label="armor">
<div class="input-label marble-header marble-header--full-left marble-header--full-right grid-span-all">
<h2 class="marble-header__title" data-i18n="armor rating"></h2>
<label class="--parchment">
<input name="attr_armor_rating_total" type="number" readonly="" title="@{armor_rating_total}"/>
</label>
</div>
<div class="armor__row">
<h3 data-i18n="armor"></h3>
<label class="image-container"><img src="https://files.d20.io/images/346041944/S5Qsjcp3Fj_VnKlLShv-hw/original.png"/>
<input name="attr_armor_rating" type="number" title="@{armor_rating}"/>
</label>
<label class="--cap --parchment">
<input name="attr_armor_name" value="" type="text" title="@{armor_name}"/>
</label>
<h4 class="bane-label" data-i18n="banes on"></h4>
<div class="banes flex-box flex-wrap half-gap">
<label class="input-label"><span class="input-label__text" data-i18n="sneaking"></span>
<input class="input-label__input" name="attr_armor_sneaking_bane" type="checkbox" value="1" title="@{armor_sneaking_bane}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="evade"></span>
<input class="input-label__input" name="attr_armor_evade_bane" type="checkbox" value="1" title="@{armor_evade_bane}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="acrobatics"></span>
<input class="input-label__input" name="attr_armor_acrobatics_bane" type="checkbox" value="1" title="@{armor_acrobatics_bane}"/>
</label>
</div>
</div>
<div class="armor__row">
<h3 data-i18n="helmet"></h3>
<label class="image-container"><img src="https://files.d20.io/images/346049175/Uv09LQO-CzNxChMNqF6gOA/original.png"/>
<input name="attr_helmet_rating" type="number" title="@{helmet_rating}"/>
</label>
<label class="--cap --parchment">
<input name="attr_helmet_name" value="" type="text" title="@{helmet_name}"/>
</label>
<h4 class="bane-label" data-i18n="banes on"></h4>
<div class="banes flex-box flex-wrap half-gap">
<label class="input-label"><span class="input-label__text" data-i18n="awareness"></span>
<input class="input-label__input" name="attr_helmet_awareness_bane" type="checkbox" value="1" title="@{helmet_awareness_bane}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="ranged attacks"></span>
<input class="input-label__input" name="attr_helmet_ranged_attacks_bane" type="checkbox" value="1" title="@{helmet_ranged_attacks_bane}"/>
</label>
</div>
</div>
</section>
<div class="section--points">
<div class="section--rest grid-span-all">
<h2 class="colon" data-i18n="rest"></h2>
<label>
<h3 data-i18n="round"></h3>
<input class="round-rest" name="attr_round_rest" value="1" type="checkbox" title="@{round_rest}"/>
</label>
<label>
<h3 data-i18n="stretch"></h3>
<input class="stretch-rest" name="attr_stretch_rest" value="1" type="checkbox" title="@{stretch_rest}"/>
</label>
<button class="roller" name="roll_shift_rest" data-i18n="shift" role="heading" aria-level="3" value="@{shift_rest_action}" type="roll">
</button>
<button name="act_shift-rest-action" hidden="" type="action">
</button>
<input name="attr_shift_rest_action" type="hidden" title="@{shift_rest_action}"/>
</div>
<div class="section-willpower">
<div class="plate--willpower">
<h3 data-i18n="willpower points">Willpower Points</h3>
<div class="scores">
<input class="willpower-points" name="attr_willpower_points" value="0" type="number" title="@{willpower_points}"/>
<input class="willpower-points" name="attr_willpower_points_max" value="0" readonly="" type="number" title="@{willpower_points|max}"/>
</div>
<input name="attr_willpower_points_max" value="0" type="hidden" title="@{willpower_points|max}"/>
<div class="fill-left">
<input class="fill-left__radio" name="attr_willpower_points" value="0" type="hidden" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="1" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="2" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="3" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="4" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="5" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="6" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="7" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="8" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="9" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="10" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="11" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="12" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="13" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="14" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="15" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="16" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="17" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="18" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="19" type="checkbox" title="@{willpower_points}"/>
<input class="fill-left__radio" name="attr_willpower_points" value="20" type="checkbox" title="@{willpower_points}"/>
</div>
</div>
</div>
<div class="section-health">
<div class="plate--health">
<h3 data-i18n="hit points">Hit Points</h3>
<div class="scores">
<input class="hit-points" name="attr_hit_points" value="0" type="number" title="@{hit_points}"/>
<input class="hit-points" name="attr_hit_points_max" value="0" readonly="" type="number" title="@{hit_points|max}"/>
</div>
<input name="attr_hit_points_max" value="0" type="hidden" title="@{hit_points|max}"/>
<div class="fill-left">
<input class="fill-left__radio" name="attr_hit_points" value="0" type="hidden" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="1" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="2" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="3" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="4" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="5" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="6" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="7" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="8" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="9" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="10" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="11" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="12" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="13" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="14" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="15" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="16" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="17" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="18" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="19" type="checkbox" title="@{hit_points}"/>
<input class="fill-left__radio" name="attr_hit_points" value="20" type="checkbox" title="@{hit_points}"/>
</div>
</div>
<div class="death-saves">
<button class="death-saves__button roller" name="roll_death_saves" value="@{death_saves_action}" type="roll">
<h3 data-i18n="Death Rolls">Death Rolls</h3>
</button>
<button name="act_death-saves-action" hidden="" type="action">
</button>
<input name="attr_death_saves_action" type="hidden" title="@{death_saves_action}"/>
<div class="death-saves--successes">
<h4 data-i18n="Successes">Successes</h4>
<div class="fill-left">
<input class="diamond fill-left__radio" name="attr_death_saves_successes" value="0" type="hidden" title="@{death_saves_successes}"/>
<input class="diamond fill-left__radio" name="attr_death_saves_successes" value="1" type="checkbox" title="@{death_saves_successes}"/>
<input class="diamond fill-left__radio" name="attr_death_saves_successes" value="2" type="checkbox" title="@{death_saves_successes}"/>
<input class="diamond fill-left__radio" name="attr_death_saves_successes" value="3" type="checkbox" title="@{death_saves_successes}"/>
</div>
</div>
<div class="death-saves--failures">
<h4 data-i18n="Failures">Failures</h4>
<div class="fill-left">
<input class="diamond fill-left__radio" name="attr_death_saves_failures" value="0" type="hidden" title="@{death_saves_failures}"/>
<input class="diamond fill-left__radio" name="attr_death_saves_failures" value="1" type="checkbox" title="@{death_saves_failures}"/>
<input class="diamond fill-left__radio" name="attr_death_saves_failures" value="2" type="checkbox" title="@{death_saves_failures}"/>
<input class="diamond fill-left__radio" name="attr_death_saves_failures" value="3" type="checkbox" title="@{death_saves_failures}"/>
</div>
</div>
</div>
</div>
</div>
<section class="weapons repeating-section-container" data-i18n-aria-label="weapons">
<div class="input-label marble-header marble-header--full-left marble-header--full-right">
<h2 class="marble-header__title" data-i18n="weapons"></h2>
</div>
<button class="repcontrol-button repcontrol-button--add" name="act_add-weapons" type="action">
</button><span class="bullet-point-section column-section" hidden=""></span>
<fieldset class="repeating_weapons">
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_weapons_$X_collapse}"/>
<div class="collapsed flex-box underline justify-space-between">
<button class="roller" name="roll_roll" value="@{action}" type="roll"><span name="attr_name" title="@{repeating_weapons_$X_name}"></span>
</button>
<button name="act_action" hidden="" type="action">
</button>
<input name="attr_action" type="hidden" title="@{repeating_weapons_$X_action}"/><span name="attr_damage" title="@{repeating_weapons_$X_damage}"></span>
<input name="attr_durability" value="0" type="number" title="@{repeating_weapons_$X_durability}"/>
</div>
<div class="expanded">
<ul>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="name"></span>
<input class="input-label__input" name="attr_name" type="text" data-i18n-placeholder="New Weapon" title="@{repeating_weapons_$X_name}"/>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="type"></span>
<select class="input-label__input" name="attr_type" data-i18n-list="weapon-section-type-order" title="@{repeating_weapons_$X_type}">
<option value="-" selected="" data-i18n-list-item="-">-
</option>
<option data-i18n="melee" value="melee" data-i18n-list-item="melee">
</option>
<option data-i18n="ranged" value="ranged" data-i18n-list-item="ranged">
</option>
</select>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="skill"></span>
<select class="input-label__input" name="attr_skill" data-i18n-list="weapon-section-skill-order" title="@{repeating_weapons_$X_skill}">
<option value="-" selected="" data-i18n-list-item="-">-
</option>
<option value="axes" data-i18n="axes" data-i18n-list-item="axes">
</option>
<option value="bows" data-i18n="bows" data-i18n-list-item="bows">
</option>
<option value="brawling" data-i18n="brawling" data-i18n-list-item="brawling">
</option>
<option value="crossbows" data-i18n="crossbows" data-i18n-list-item="crossbows">
</option>
<option value="hammers" data-i18n="hammers" data-i18n-list-item="hammers">
</option>
<option value="knives" data-i18n="knives" data-i18n-list-item="knives">
</option>
<option value="slings" data-i18n="slings" data-i18n-list-item="slings">
</option>
<option value="spears" data-i18n="spears" data-i18n-list-item="spears">
</option>
<option value="staves" data-i18n="staves" data-i18n-list-item="staves">
</option>
<option value="swords" data-i18n="swords" data-i18n-list-item="swords">
</option>
</select>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="damage bonus"></span>
<input class="input-label__input" name="attr_use_bonus" type="checkbox" value="1" checked="" title="@{repeating_weapons_$X_use_bonus}"/>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="grip"></span>
<select class="uppercase input-label__input" name="attr_grip" data-i18n-list="weapon-section-grip-order" title="@{repeating_weapons_$X_grip}">
<option value="-" selected="" data-i18n-list-item="-">-
</option>
<option data-i18n="1h-abbreviation" value="1" data-i18n-list-item="1">
</option>
<option data-i18n="2h-abbreviation" value="2" data-i18n-list-item="2">
</option>
</select>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="strength-abbreviation"></span>
<input class="input-label__input" name="attr_strength_requirement" type="number" placeholder="-" title="@{repeating_weapons_$X_strength_requirement}"/>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="range"></span>
<input class="input-label__input" name="attr_range" type="text" placeholder="-" title="@{repeating_weapons_$X_range}"/>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="damage"></span>
<input class="input-label__input" name="attr_damage" type="text" title="@{repeating_weapons_$X_damage}"/>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="durability"></span>
<input class="input-label__input" name="attr_durability_max" type="number" placeholder="-" title="@{repeating_weapons_$X_durability|max}"/>
</label>
</li>
<li>
<label class="input-label"><span class="input-label__text" data-i18n="features"></span>
<input class="input-label__input" name="attr_properties" type="text" title="@{repeating_weapons_$X_properties}"/>
</label>
</li>
</ul>
<textarea name="attr_description" title="@{repeating_weapons_$X_description}"></textarea>
</div>
</fieldset>
</section>
</div>
</article>
<article class="tabs__container tabs--dragonbane__container tabs--dragonbane__container--monster" data-container-tab="dragonbane" data-tab="monster">
<section class="section--monster-stats --parchment collapse-container" data-i18n-aria-label="monster stats">
<input class="collapse" name="attr_monster_view" value="1" type="checkbox" title="@{monster_view}"/>
<div class="--parchment__trim --bottom"></div>
<input name="attr_character_name" value="" role="heading" aria-level="2" type="text" title="@{character_name}"/>
<div class="stat-container">
<div class="flex-box stat-row flex-wrap half-gap">
<label class="input-label"><span class="input-label__text" data-i18n="ferocity"></span>
<input class="underline input-label__input" name="attr_ferocity" type="number" title="@{ferocity}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="size"></span>
<select class="underline input-label__input" name="attr_size" title="@{size}">
<option value="small" data-i18n="small">
</option>
<option value="normal" data-i18n="normal" selected="">
</option>
<option value="large" data-i18n="large">
</option>
<option value="huge" data-i18n="huge">
</option>
</select>
</label>
<label class="input-label tiny-gap"><span class="input-label__text" data-i18n="swarm"></span>
<input class="input-label__input" name="attr_swarm" type="checkbox" value="1" title="@{swarm}"/>
</label>
</div>
<div class="flex-box stat-row flex-wrap half-gap">
<label class="input-label"><span class="input-label__text" data-i18n="movement"></span>
<input class="underline input-label__input" name="attr_movement" type="number" title="@{movement}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="armor"></span>
<input class="underline input-label__input" name="attr_armor_rating_total" type="number" title="@{armor_rating_total}"/>
</label>
<label class="input-label"><span class="uppercase input-label__text" data-i18n="hp"></span>
<input class="underline input-label__input" name="attr_hit_points" type="number" title="@{hit_points}"/>
</label>
</div>
</div>
<div class="stat-container expanded flex-box flex-wrap justify-space-between tiny-gap">
<label class="input-label"><span class="input-label__text" data-i18n="acrobatics"></span>
<input class="underline input-label__input" name="attr_acrobatics_levels" type="number" title="@{acrobatics_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="awareness"></span>
<input class="underline input-label__input" name="attr_awareness_levels" type="number" title="@{awareness_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="bartering"></span>
<input class="underline input-label__input" name="attr_bartering_levels" type="number" title="@{bartering_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="beast lore"></span>
<input class="underline input-label__input" name="attr_beast_lore_levels" type="number" title="@{beast_lore_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="bluffing"></span>
<input class="underline input-label__input" name="attr_bluffing_levels" type="number" title="@{bluffing_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="bushcraft"></span>
<input class="underline input-label__input" name="attr_bushcraft_levels" type="number" title="@{bushcraft_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="crafting"></span>
<input class="underline input-label__input" name="attr_crafting_levels" type="number" title="@{crafting_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="evade"></span>
<input class="underline input-label__input" name="attr_evade_levels" type="number" title="@{evade_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="healing"></span>
<input class="underline input-label__input" name="attr_healing_levels" type="number" title="@{healing_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="hunting & fishing"></span>
<input class="underline input-label__input" name="attr_hunting_&_fishing_levels" type="number" title="@{hunting_&_fishing_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="languages"></span>
<input class="underline input-label__input" name="attr_languages_levels" type="number" title="@{languages_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="myths & legends"></span>
<input class="underline input-label__input" name="attr_myths_&_legends_levels" type="number" title="@{myths_&_legends_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="performance"></span>
<input class="underline input-label__input" name="attr_performance_levels" type="number" title="@{performance_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="persuasion"></span>
<input class="underline input-label__input" name="attr_persuasion_levels" type="number" title="@{persuasion_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="riding"></span>
<input class="underline input-label__input" name="attr_riding_levels" type="number" title="@{riding_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="seamanship"></span>
<input class="underline input-label__input" name="attr_seamanship_levels" type="number" title="@{seamanship_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="sleight of hand"></span>
<input class="underline input-label__input" name="attr_sleight_of_hand_levels" type="number" title="@{sleight_of_hand_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="sneaking"></span>
<input class="underline input-label__input" name="attr_sneaking_levels" type="number" title="@{sneaking_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="spot hidden"></span>
<input class="underline input-label__input" name="attr_spot_hidden_levels" type="number" title="@{spot_hidden_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="swimming"></span>
<input class="underline input-label__input" name="attr_swimming_levels" type="number" title="@{swimming_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="axes"></span>
<input class="underline input-label__input" name="attr_axes_levels" type="number" title="@{axes_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="bows"></span>
<input class="underline input-label__input" name="attr_bows_levels" type="number" title="@{bows_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="brawling"></span>
<input class="underline input-label__input" name="attr_brawling_levels" type="number" title="@{brawling_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="crossbows"></span>
<input class="underline input-label__input" name="attr_crossbows_levels" type="number" title="@{crossbows_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="hammers"></span>
<input class="underline input-label__input" name="attr_hammers_levels" type="number" title="@{hammers_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="knives"></span>
<input class="underline input-label__input" name="attr_knives_levels" type="number" title="@{knives_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="slings"></span>
<input class="underline input-label__input" name="attr_slings_levels" type="number" title="@{slings_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="spears"></span>
<input class="underline input-label__input" name="attr_spears_levels" type="number" title="@{spears_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="staves"></span>
<input class="underline input-label__input" name="attr_staves_levels" type="number" title="@{staves_levels}"/>
</label>
<label class="input-label"><span class="input-label__text" data-i18n="swords"></span>
<input class="underline input-label__input" name="attr_swords_levels" type="number" title="@{swords_levels}"/>
</label>
</div>
<div class="stat-container collapsed flex-box flex-wrap half-gap" style="--input-label-gap:var(--tiny-gap)">
<div class="input-label input-label--button">
<button class="capitalize roller" data-i18n="base skills" name="roll_base_skills" value="@{base_skills_action}" type="roll">
</button>
<button name="act_base-skills-action" hidden="" type="action">
</button>
<input name="attr_base_skills_action" type="hidden" title="@{base_skills_action}"/><span class="input-label__input" name="attr_base_skills" type="number" value="15" title="@{base_skills}">15</span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_acrobatics_levels" value="0" type="hidden" title="@{acrobatics_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="acrobatics" name="roll_acrobatics" value="@{acrobatics_action}" type="roll">
</button><span name="attr_acrobatics" type="number" title="@{acrobatics}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_awareness_levels" value="0" type="hidden" title="@{awareness_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="awareness" name="roll_awareness" value="@{awareness_action}" type="roll">
</button><span name="attr_awareness" type="number" title="@{awareness}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_bartering_levels" value="0" type="hidden" title="@{bartering_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="bartering" name="roll_bartering" value="@{bartering_action}" type="roll">
</button><span name="attr_bartering" type="number" title="@{bartering}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_beast_lore_levels" value="0" type="hidden" title="@{beast_lore_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="beast lore" name="roll_beast_lore" value="@{beast_lore_action}" type="roll">
</button><span name="attr_beast_lore" type="number" title="@{beast_lore}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_bluffing_levels" value="0" type="hidden" title="@{bluffing_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="bluffing" name="roll_bluffing" value="@{bluffing_action}" type="roll">
</button><span name="attr_bluffing" type="number" title="@{bluffing}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_bushcraft_levels" value="0" type="hidden" title="@{bushcraft_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="bushcraft" name="roll_bushcraft" value="@{bushcraft_action}" type="roll">
</button><span name="attr_bushcraft" type="number" title="@{bushcraft}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_crafting_levels" value="0" type="hidden" title="@{crafting_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="crafting" name="roll_crafting" value="@{crafting_action}" type="roll">
</button><span name="attr_crafting" type="number" title="@{crafting}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_evade_levels" value="0" type="hidden" title="@{evade_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="evade" name="roll_evade" value="@{evade_action}" type="roll">
</button><span name="attr_evade" type="number" title="@{evade}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_healing_levels" value="0" type="hidden" title="@{healing_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="healing" name="roll_healing" value="@{healing_action}" type="roll">
</button><span name="attr_healing" type="number" title="@{healing}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_hunting_&_fishing_levels" value="0" type="hidden" title="@{hunting_&_fishing_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="hunting & fishing" name="roll_hunting_&_fishing" value="@{hunting_&_fishing_action}" type="roll">
</button><span name="attr_hunting_&_fishing" type="number" title="@{hunting_&_fishing}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_languages_levels" value="0" type="hidden" title="@{languages_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="languages" name="roll_languages" value="@{languages_action}" type="roll">
</button><span name="attr_languages" type="number" title="@{languages}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_myths_&_legends_levels" value="0" type="hidden" title="@{myths_&_legends_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="myths & legends" name="roll_myths_&_legends" value="@{myths_&_legends_action}" type="roll">
</button><span name="attr_myths_&_legends" type="number" title="@{myths_&_legends}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_performance_levels" value="0" type="hidden" title="@{performance_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="performance" name="roll_performance" value="@{performance_action}" type="roll">
</button><span name="attr_performance" type="number" title="@{performance}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_persuasion_levels" value="0" type="hidden" title="@{persuasion_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="persuasion" name="roll_persuasion" value="@{persuasion_action}" type="roll">
</button><span name="attr_persuasion" type="number" title="@{persuasion}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_riding_levels" value="0" type="hidden" title="@{riding_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="riding" name="roll_riding" value="@{riding_action}" type="roll">
</button><span name="attr_riding" type="number" title="@{riding}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_seamanship_levels" value="0" type="hidden" title="@{seamanship_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="seamanship" name="roll_seamanship" value="@{seamanship_action}" type="roll">
</button><span name="attr_seamanship" type="number" title="@{seamanship}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_sleight_of_hand_levels" value="0" type="hidden" title="@{sleight_of_hand_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="sleight of hand" name="roll_sleight_of_hand" value="@{sleight_of_hand_action}" type="roll">
</button><span name="attr_sleight_of_hand" type="number" title="@{sleight_of_hand}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_sneaking_levels" value="0" type="hidden" title="@{sneaking_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="sneaking" name="roll_sneaking" value="@{sneaking_action}" type="roll">
</button><span name="attr_sneaking" type="number" title="@{sneaking}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_spot_hidden_levels" value="0" type="hidden" title="@{spot_hidden_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="spot hidden" name="roll_spot_hidden" value="@{spot_hidden_action}" type="roll">
</button><span name="attr_spot_hidden" type="number" title="@{spot_hidden}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_swimming_levels" value="0" type="hidden" title="@{swimming_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="swimming" name="roll_swimming" value="@{swimming_action}" type="roll">
</button><span name="attr_swimming" type="number" title="@{swimming}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_axes_levels" value="0" type="hidden" title="@{axes_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="axes" name="roll_axes" value="@{axes_action}" type="roll">
</button><span name="attr_axes" type="number" title="@{axes}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_bows_levels" value="0" type="hidden" title="@{bows_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="bows" name="roll_bows" value="@{bows_action}" type="roll">
</button><span name="attr_bows" type="number" title="@{bows}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_brawling_levels" value="0" type="hidden" title="@{brawling_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="brawling" name="roll_brawling" value="@{brawling_action}" type="roll">
</button><span name="attr_brawling" type="number" title="@{brawling}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_crossbows_levels" value="0" type="hidden" title="@{crossbows_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="crossbows" name="roll_crossbows" value="@{crossbows_action}" type="roll">
</button><span name="attr_crossbows" type="number" title="@{crossbows}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_hammers_levels" value="0" type="hidden" title="@{hammers_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="hammers" name="roll_hammers" value="@{hammers_action}" type="roll">
</button><span name="attr_hammers" type="number" title="@{hammers}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_knives_levels" value="0" type="hidden" title="@{knives_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="knives" name="roll_knives" value="@{knives_action}" type="roll">
</button><span name="attr_knives" type="number" title="@{knives}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_slings_levels" value="0" type="hidden" title="@{slings_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="slings" name="roll_slings" value="@{slings_action}" type="roll">
</button><span name="attr_slings" type="number" title="@{slings}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_spears_levels" value="0" type="hidden" title="@{spears_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="spears" name="roll_spears" value="@{spears_action}" type="roll">
</button><span name="attr_spears" type="number" title="@{spears}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_staves_levels" value="0" type="hidden" title="@{staves_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="staves" name="roll_staves" value="@{staves_action}" type="roll">
</button><span name="attr_staves" type="number" title="@{staves}"></span>
</div>
<input class="display-control--custom display-control--non-zero" name="attr_swords_levels" value="0" type="hidden" title="@{swords_levels}"/>
<div class="input-label input-label--button controlled-display">
<button class="capitalize" data-i18n="swords" name="roll_swords" value="@{swords_action}" type="roll">
</button><span name="attr_swords" type="number" title="@{swords}"></span>
</div>
</div>
<div class="repeating-section-container">
<button class="repcontrol-button repcontrol-button--add" name="act_add-abilities" type="action">
</button><span class="bullet-point-section" hidden=""></span>
<fieldset class="repeating_abilities">
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_abilities_$X_collapse}"/>
<div class="collapsed">
<button class="label roller" name="roll_describe" type="roll" value="&{template:dragonbane} {{name=@{character_name}}} {{label=@{name}}} {{description=@{description}}}"><span class="section--abilities__name--display" name="attr_name" title="@{repeating_abilities_$X_name}"></span>
</button><span class="monster-description-span" name="attr_description" title="@{repeating_abilities_$X_description}"></span>
</div>
<div class="expanded">
<ul>
<li>
<label class="input-label"><span data-i18n="Name:"></span>
<input class="input-label__input" name="attr_name" type="text" data-i18n-placeholder="New Ability" title="@{repeating_abilities_$X_name}"/>
</label>
</li>
</ul>
<div class="adaptive adaptive--text section--abilities__description"><span class="adaptive--text__span" name="attr_description" title="@{repeating_abilities_$X_description}"></span>
<textarea class="adaptive--text__textarea" name="attr_description" data-i18n-placeholder="Description" title="@{repeating_abilities_$X_description}"></textarea>
</div>
</div>
</fieldset>
</div>
</section>
<section class="section--monster-attacks repeating-section-container" data-i18n-aria-label="monster attacks" style="position:relative;">
<div class="input-label marble-header marble-header--full-left marble-header--full-right section--monster-attacks__header --boxtitle offset-box">
<hundefined class="marble-header__title" data-i18n="Monster Attacks"></hundefined>
<div class="marble-header__title">
<button class="roller" name="roll_monster_attacks" role="heading" aria-level="2" data-i18n="attacks" value="@{monster_attacks_action}" type="roll">
</button>
<button name="act_monster-attacks-action" hidden="" type="action">
</button>
<input name="attr_monster_attacks_action" type="hidden" title="@{monster_attacks_action}"/>
</div>
</div>
<div class="--parchment__trim --top"> </div>
<div class="--parchment__trim --bottom --lg"></div>
<button class="repcontrol-button repcontrol-button--add" name="act_add-attacks" type="action">
</button><span class="bullet-point-section" hidden=""></span>
<fieldset class="repeating_attacks">
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_attacks_$X_collapse}"/>
<div class="collapsed"><span class="colon" name="attr_result" title="@{repeating_attacks_$X_result}"></span>
<button class="label roller" name="roll_roll" value="@{action}" type="roll"><span name="attr_name" title="@{repeating_attacks_$X_name}"></span>
</button>
<button name="act_action" hidden="" type="action">
</button>
<input name="attr_action" type="hidden" title="@{repeating_attacks_$X_action}"/><span class="monster-description-span" name="attr_description" title="@{repeating_attacks_$X_description}"></span>
<input class="collapse" name="attr_subtable" value="1" type="checkbox" title="@{repeating_attacks_$X_subtable}" hidden="hidden" checked="checked"/>
<ul class="subtable-list expanded">
<li class="subtable-row"><span class="colon" name="attr_subtable_result_1" title="@{repeating_attacks_$X_subtable_result_1}"></span><span class="label" name="attr_subtable_name_1" title="@{repeating_attacks_$X_subtable_name_1}"></span><span class="monster-description-span" name="attr_subtable_description_1" title="@{repeating_attacks_$X_subtable_description_1}"></span>
</li>
<li class="subtable-row"><span class="colon" name="attr_subtable_result_2" title="@{repeating_attacks_$X_subtable_result_2}"></span><span class="label" name="attr_subtable_name_2" title="@{repeating_attacks_$X_subtable_name_2}"></span><span class="monster-description-span" name="attr_subtable_description_2" title="@{repeating_attacks_$X_subtable_description_2}"></span>
</li>
<li class="subtable-row"><span class="colon" name="attr_subtable_result_3" title="@{repeating_attacks_$X_subtable_result_3}"></span><span class="label" name="attr_subtable_name_3" title="@{repeating_attacks_$X_subtable_name_3}"></span><span class="monster-description-span" name="attr_subtable_description_3" title="@{repeating_attacks_$X_subtable_description_3}"></span>
</li>
<li class="subtable-row"><span class="colon" name="attr_subtable_result_4" title="@{repeating_attacks_$X_subtable_result_4}"></span><span class="label" name="attr_subtable_name_4" title="@{repeating_attacks_$X_subtable_name_4}"></span><span class="monster-description-span" name="attr_subtable_description_4" title="@{repeating_attacks_$X_subtable_description_4}"></span>
</li>
<li class="subtable-row"><span class="colon" name="attr_subtable_result_5" title="@{repeating_attacks_$X_subtable_result_5}"></span><span class="label" name="attr_subtable_name_5" title="@{repeating_attacks_$X_subtable_name_5}"></span><span class="monster-description-span" name="attr_subtable_description_5" title="@{repeating_attacks_$X_subtable_description_5}"></span>
</li>
<li class="subtable-row"><span class="colon" name="attr_subtable_result_6" title="@{repeating_attacks_$X_subtable_result_6}"></span><span class="label" name="attr_subtable_name_6" title="@{repeating_attacks_$X_subtable_name_6}"></span><span class="monster-description-span" name="attr_subtable_description_6" title="@{repeating_attacks_$X_subtable_description_6}"></span>
</li>
</ul>
</div>
<div class="expanded">
<ul>
<li class="subtable-row">
<input name="attr_weight" value="1" type="hidden" title="@{repeating_attacks_$X_weight}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="number input-label__input" name="attr_result" type="text" title="@{repeating_attacks_$X_result}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="input-label__input" name="attr_name" type="text" data-i18n-placeholder="New Attack" title="@{repeating_attacks_$X_name}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="input-label__input" name="attr_damage" type="text" title="@{repeating_attacks_$X_damage}"/>
</label>
</li>
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_attacks_$X_description}"></span>
<textarea class="section--monster-attacks__description adaptive--text__textarea" name="attr_description" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_description}"></textarea>
</div>
<input class="collapse check-highlight" name="attr_subtable" value="1" type="checkbox" title="@{repeating_attacks_$X_subtable}" hidden="hidden" checked="checked"/>
<label class="input-label hover-cursor"><span data-i18n="add table"></span>
<input class="input-label__input" name="attr_subtable" type="checkbox" value="1" checked="" hidden="" title="@{repeating_attacks_$X_subtable}"/>
</label>
<ul class="subtable-list expanded">
<li class="subtable-row">
<input name="attr_subtable_weight_1" value="1" type="hidden" title="@{repeating_attacks_$X_subtable_weight_1}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="underline number input-label__input" name="attr_subtable_result_1" type="text" title="@{repeating_attacks_$X_subtable_result_1}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="underline input-label__input" name="attr_subtable_name_1" type="text" data-i18n-placeholder="Attack Sub-option" title="@{repeating_attacks_$X_subtable_name_1}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="underline input-label__input" name="attr_subtable_damage_1" type="text" title="@{repeating_attacks_$X_subtable_damage_1}"/>
</label>
<div class="adaptive adaptive--text section--monster-sub-attacks__description"><span class="adaptive--text__span" name="attr_subtable_description_1" title="@{repeating_attacks_$X_subtable_description_1}"></span>
<textarea class="adaptive--text__textarea" name="attr_subtable_description_1" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_subtable_description_1}"></textarea>
</div>
</li>
<li class="subtable-row">
<input name="attr_subtable_weight_2" value="1" type="hidden" title="@{repeating_attacks_$X_subtable_weight_2}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="underline number input-label__input" name="attr_subtable_result_2" type="text" title="@{repeating_attacks_$X_subtable_result_2}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="underline input-label__input" name="attr_subtable_name_2" type="text" data-i18n-placeholder="Attack Sub-option" title="@{repeating_attacks_$X_subtable_name_2}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="underline input-label__input" name="attr_subtable_damage_2" type="text" title="@{repeating_attacks_$X_subtable_damage_2}"/>
</label>
<div class="adaptive adaptive--text section--monster-sub-attacks__description"><span class="adaptive--text__span" name="attr_subtable_description_2" title="@{repeating_attacks_$X_subtable_description_2}"></span>
<textarea class="adaptive--text__textarea" name="attr_subtable_description_2" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_subtable_description_2}"></textarea>
</div>
</li>
<li class="subtable-row">
<input name="attr_subtable_weight_3" value="1" type="hidden" title="@{repeating_attacks_$X_subtable_weight_3}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="underline number input-label__input" name="attr_subtable_result_3" type="text" title="@{repeating_attacks_$X_subtable_result_3}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="underline input-label__input" name="attr_subtable_name_3" type="text" data-i18n-placeholder="Attack Sub-option" title="@{repeating_attacks_$X_subtable_name_3}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="underline input-label__input" name="attr_subtable_damage_3" type="text" title="@{repeating_attacks_$X_subtable_damage_3}"/>
</label>
<div class="adaptive adaptive--text section--monster-sub-attacks__description"><span class="adaptive--text__span" name="attr_subtable_description_3" title="@{repeating_attacks_$X_subtable_description_3}"></span>
<textarea class="adaptive--text__textarea" name="attr_subtable_description_3" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_subtable_description_3}"></textarea>
</div>
</li>
<li class="subtable-row">
<input name="attr_subtable_weight_4" value="1" type="hidden" title="@{repeating_attacks_$X_subtable_weight_4}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="underline number input-label__input" name="attr_subtable_result_4" type="text" title="@{repeating_attacks_$X_subtable_result_4}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="underline input-label__input" name="attr_subtable_name_4" type="text" data-i18n-placeholder="Attack Sub-option" title="@{repeating_attacks_$X_subtable_name_4}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="underline input-label__input" name="attr_subtable_damage_4" type="text" title="@{repeating_attacks_$X_subtable_damage_4}"/>
</label>
<div class="adaptive adaptive--text section--monster-sub-attacks__description"><span class="adaptive--text__span" name="attr_subtable_description_4" title="@{repeating_attacks_$X_subtable_description_4}"></span>
<textarea class="adaptive--text__textarea" name="attr_subtable_description_4" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_subtable_description_4}"></textarea>
</div>
</li>
<li class="subtable-row">
<input name="attr_subtable_weight_5" value="1" type="hidden" title="@{repeating_attacks_$X_subtable_weight_5}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="underline number input-label__input" name="attr_subtable_result_5" type="text" title="@{repeating_attacks_$X_subtable_result_5}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="underline input-label__input" name="attr_subtable_name_5" type="text" data-i18n-placeholder="Attack Sub-option" title="@{repeating_attacks_$X_subtable_name_5}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="underline input-label__input" name="attr_subtable_damage_5" type="text" title="@{repeating_attacks_$X_subtable_damage_5}"/>
</label>
<div class="adaptive adaptive--text section--monster-sub-attacks__description"><span class="adaptive--text__span" name="attr_subtable_description_5" title="@{repeating_attacks_$X_subtable_description_5}"></span>
<textarea class="adaptive--text__textarea" name="attr_subtable_description_5" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_subtable_description_5}"></textarea>
</div>
</li>
<li class="subtable-row">
<input name="attr_subtable_weight_6" value="1" type="hidden" title="@{repeating_attacks_$X_subtable_weight_6}"/>
<label class="input-label"><span data-i18n="result"></span>
<input class="underline number input-label__input" name="attr_subtable_result_6" type="text" title="@{repeating_attacks_$X_subtable_result_6}"/>
</label>
<label class="input-label"><span data-i18n="name"></span>
<input class="underline input-label__input" name="attr_subtable_name_6" type="text" data-i18n-placeholder="Attack Sub-option" title="@{repeating_attacks_$X_subtable_name_6}"/>
</label>
<label class="input-label"><span data-i18n="damage"></span>
<input class="underline input-label__input" name="attr_subtable_damage_6" type="text" title="@{repeating_attacks_$X_subtable_damage_6}"/>
</label>
<div class="adaptive adaptive--text section--monster-sub-attacks__description"><span class="adaptive--text__span" name="attr_subtable_description_6" title="@{repeating_attacks_$X_subtable_description_6}"></span>
<textarea class="adaptive--text__textarea" name="attr_subtable_description_6" data-i18n-placeholder="Description" title="@{repeating_attacks_$X_subtable_description_6}"></textarea>
</div>
</li>
</ul>
</ul>
</div>
</fieldset>
</section>
</article>
<article class="tabs__container tabs--dragonbane__container tabs--dragonbane__container--party" data-container-tab="dragonbane" data-tab="party">
<section class="section--gm --parchment" data-i18n-aria-label="gm sheet">
<input name="attr_cards" hidden="" value="1,2,3,4,5,6,7,8,9,10" type="text" title="@{cards}"/>
<input name="attr_deck_size" value="10" hidden="" type="number" title="@{deck_size}"/>
<button class="round-button initiative-control draw round-button--symbol roller" name="roll_initiative" data-i18n-title="Draw Initiative" value="@{initiative_action}" type="roll">playing_cards
</button>
<button name="act_initiative-action" hidden="" type="action">
</button>
<input name="attr_initiative_action" type="hidden" title="@{initiative_action}"/>
<button class="round-button initiative-control reset roller" name="roll_reset" data-i18n-title="Reset Initiative Order" value="@{reset_action}" type="roll">restart_alt
</button>
<button name="act_reset-action" hidden="" type="action">
</button>
<input name="attr_reset_action" type="hidden" title="@{reset_action}"/>
<div class="input-label marble-header marble-header--full-left marble-header--full-right --boxtitle offset-box">
<h2 class="marble-header__title" data-i18n="initiative"></h2>
</div>
<div class="--parchment__trim --top"></div>
<div class="--parchment__trim --bottom --lg"></div>
<ul class="list"><span class="bullet-point-section" hidden=""></span>
<fieldset class="repeating_initiative">
<li class="subtable-row flex-box half-gap">
<input class="visually-hidden fade-control" name="attr_used" value="1" type="checkbox" title="@{repeating_initiative_$X_used}"/>
<div class="fade-overlay"></div>
<button class="round-button round-button-symbol" name="act_use" data-i18n-title="Use your initiative" type="action">task_alt
</button>
<input class="card" name="attr_card" readonly="" role="heading" aria-level="3" type="number" title="@{repeating_initiative_$X_card}"/>
<input name="attr_name" readonly="" type="text" data-i18n-placeholder="Name" title="@{repeating_initiative_$X_name}"/>
<label class="input-label stacked center flex-column-reverse hold"><span class="input-label__text" data-i18n="hold"></span>
<input class="input-label__input" name="attr_hold" type="checkbox" value="1" title="@{repeating_initiative_$X_hold}"/>
</label>
<button class="round-button round-button--symbol" name="act_remove" data-i18n-title="Remove" type="action">close
</button>
<button class="round-button round-button-symbol" name="act_switch" data-i18n-title="Swap Initiative" type="action">autorenew
</button>
</li>
</fieldset>
</ul>
<button class="deck flex-column roller" name="roll_initiative" data-i18n-title="Draw Initiative" value="@{initiative_action}" type="roll"><span name="attr_deck_size" title="@{deck_size}">10</span>
<h4 data-i18n="initiative"></h4>
</button>
<button name="act_initiative-action" hidden="" type="action">
</button>
<input name="attr_initiative_action" type="hidden" title="@{initiative_action}"/>
</section>
</article>
</div>
</div>
</main>
</div>
<input name="attr_template_start" value="@{whisper}&{template:dragonbane} {{character_name=@{character_name}}} {{character_id=@{character_id}}}" type="hidden" title="@{template_start}"/>
<rolltemplate class="sheet-rolltemplate-dragonbane">
<div class="sheet-container">
<div class="sheet-marble-header">{{#character_name}}{{#character_id}}
<h2 class="character_name sheet-marble-header__title">[{{character_name}}](http://journal.roll20.net/character/{{character_id}})</h2>{{/character_id}}{{^character_id}}
<h2 class="character_name sheet-marble-header__title">{{character_name}}</h2>{{/character_id}}{{/character_name}}
</div>
<div class="sheet-label">{{#label}}
<h2>{{label}}</h2>{{/label}}{{#roll1}}{{^label}}
<h2 data-i18n="roll"></h2>{{/label}}
<div class="sheet-result">{{computed::roll1}}</div>{{/roll1}}
</div>{{#damage}}
<div class="sheet-label">{{#damage_label}}
<h3>{{damage_label}}</h3>{{/damage_label}}{{^damage_label}}
<h3 data-i18n="damage"></h3>{{/damage_label}}
<div class="sheet-result">{{damage}}</div>
</div>{{/damage}}{{#spell}}
<div class="sheet-spell">{{#rank}}
<div class="sheet-spell__rank">
<dt>Rank</dt>
<dd>{{rank}}</dd>
</div>{{/rank}}{{#requirement}}
<div class="sheet-spell__requirement">
<dt>Requirement</dt>
<dd>{{requirement}}</dd>
</div>{{/requirement}}{{#casting_time}}
<div class="sheet-spell__casting_time">
<dt>Casting Time</dt>
<dd>{{casting_time}}</dd>
</div>{{/casting_time}}{{#range}}
<div class="sheet-spell__range">
<dt>Range</dt>
<dd>{{range}}</dd>
</div>{{/range}}{{#duration}}
<div class="sheet-spell__duration">
<dt>Duration</dt>
<dd>{{duration}}</dd>
</div>{{/duration}}
</div>{{/spell}}
{{#description}}
<div class="description">{{#rollGreater() computed::dragonResult 0}}<span data-i18n="dragon-result-instructions"></span>
<ul>
<li><span data-i18n="dragon-spell-1"></span></li>
<li><span data-i18n="dragon-spell-2"></span></li>
<li><span data-i18n="dragon-spell-3"></span></li>
</ul>{{/rollGreater() computed::dragonResult 0}}{{description}}
</div>{{/description}}{{^description}}{{#rollGreater() computed::dragonResult 0}}
<div class="description"><span data-i18n="dragon-result-instructions"></span>
<ul>
<li><span data-i18n="dragon-spell-1"></span></li>
<li><span data-i18n="dragon-spell-2"></span></li>
<li><span data-i18n="dragon-spell-3"></span></li>
</ul>
</div>{{/rollGreater() computed::dragonResult 0}}{{/description}}{{#character_name}}{{#^rollTotal() computed::push_through 0}}{{#roll1}}
<div class="sheet-result sheet-push">[update](~{{character_name}}|push||{{computed::push_through}})</div>{{/roll1}}{{/^rollTotal() computed::push_through 0}}{{/character_name}}{{#test}}
<div class="sheet-result sheet-check">{{test}}</div>{{/test}}
</div>
</rolltemplate>
<script type="text/worker">//# sourceURL=dragonbane.js
const k = (function(){
const kFuncs = {};
const cascades = {"attr_character_name":{"name":"character_name","type":"text","defaultValue":"","affects":[],"triggeredFuncs":["setActionCalls"],"listenerFunc":"accessSheet","listener":"change:character_name"},"attr_sheet_version":{"name":"sheet_version","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_sheet_state":{"name":"sheet_state","type":"hidden","defaultValue":"settings","triggeredFuncs":[],"affects":[]},"attr_collapsed":{"name":"collapsed","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_push":{"triggeredFuncs":["pushRoll"],"name":"push","listener":"clicked:push","listenerFunc":"accessSheet","type":"action"},"attr_drop_name":{"triggeredFuncs":["handleCompendiumDrop"],"name":"drop_name","listener":"change:drop_name","listenerFunc":"accessSheet","type":"hidden","defaultValue":"","affects":[]},"attr_drop_data":{"name":"drop_data","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_dragonbane_tab":{"name":"dragonbane_tab","type":"hidden","defaultValue":"nav-tabs-dragonbane--settings","triggeredFuncs":[],"affects":[]},"attr_have_lightning_fast":{"name":"have_lightning_fast","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_lightning_fast":{"name":"lightning_fast","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_boons":{"name":"boons","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_banes":{"name":"banes","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_reset-modifiers":{"triggeredFuncs":["resetModifiers"],"name":"reset-modifiers","listener":"clicked:reset-modifiers","listenerFunc":"accessSheet","type":"action"},"act_nav-tabs-dragonbane--settings":{"triggeredFuncs":["kSwitchTab","toggleNavButtons"],"name":"nav-tabs-dragonbane--settings","listener":"clicked:nav-tabs-dragonbane--settings","listenerFunc":"accessSheet","type":"action"},"act_nav-tabs-dragonbane--pc":{"triggeredFuncs":["kSwitchTab","toggleNavButtons"],"name":"nav-tabs-dragonbane--pc","listener":"clicked:nav-tabs-dragonbane--pc","listenerFunc":"accessSheet","type":"action"},"act_nav-tabs-dragonbane--monster":{"triggeredFuncs":["kSwitchTab","toggleNavButtons"],"name":"nav-tabs-dragonbane--monster","listener":"clicked:nav-tabs-dragonbane--monster","listenerFunc":"accessSheet","type":"action"},"act_nav-tabs-dragonbane--party":{"triggeredFuncs":["kSwitchTab","toggleNavButtons"],"name":"nav-tabs-dragonbane--party","listener":"clicked:nav-tabs-dragonbane--party","listenerFunc":"accessSheet","type":"action"},"attr_sheet_type":{"type":"hidden","name":"sheet_type","defaultValue":"pc","triggeredFuncs":["hideInactiveNavButtons"],"affects":[],"listener":"change:sheet_type","listenerFunc":"accessSheet"},"attr_bar_1":{"name":"bar_1","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_custom_bar_1":{"name":"custom_bar_1","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_bar_2":{"name":"bar_2","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_custom_bar_2":{"name":"custom_bar_2","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_bar_3":{"name":"bar_3","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_custom_bar_3":{"name":"custom_bar_3","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_magical_mishaps":{"name":"magical_mishaps","type":"checkbox","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_allow_push":{"name":"allow_push","type":"checkbox","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_whisper":{"name":"whisper","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_use_roll20_initiative":{"type":"select","name":"use_roll20_initiative","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_willpower_points_bonus":{"affects":["willpower_points_max"],"name":"willpower_points_bonus","listener":"change:willpower_points_bonus","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_hit_points_bonus":{"affects":["hit_points_max"],"name":"hit_points_bonus","listener":"change:hit_points_bonus","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_player_name":{"name":"player_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_kin":{"name":"kin","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_kin_movement":{"affects":["movement"],"name":"kin_movement","listener":"change:kin_movement","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_age":{"name":"age","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_profession":{"name":"profession","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_weakness":{"name":"weakness","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_appearance":{"name":"appearance","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_strength-action":{"triggeredFuncs":["rollAttribute"],"name":"strength-action","listener":"clicked:strength-action","listenerFunc":"accessSheet","type":"action"},"attr_strength_action":{"name":"strength_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_strength":{"affects":["damage_bonus_strength","strength_base_chance","axes","brawling","crafting","hammers","spears","swords","repeating_secondary-skills_$X_skill_total","encumbrance_max"],"name":"strength","listener":"change:strength","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]},"attr_exhausted":{"name":"exhausted","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_constitution-action":{"triggeredFuncs":["rollAttribute"],"name":"constitution-action","listener":"clicked:constitution-action","listenerFunc":"accessSheet","type":"action"},"attr_constitution_action":{"name":"constitution_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_constitution":{"affects":["constitution_base_chance","repeating_secondary-skills_$X_skill_total","hit_points_max"],"name":"constitution","listener":"change:constitution","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]},"attr_sickly":{"name":"sickly","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_agility-action":{"triggeredFuncs":["rollAttribute"],"name":"agility-action","listener":"clicked:agility-action","listenerFunc":"accessSheet","type":"action"},"attr_agility_action":{"name":"agility_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_agility":{"affects":["damage_bonus_agility","agility_base_chance","movement","acrobatics","bows","crossbows","evade","hunting_&_fishing","knives","riding","sleight_of_hand","knives","riding","sleight_of_hand","slings","sneaking","staves","swimming","repeating_secondary-skills_$X_skill_total"],"name":"agility","listener":"change:agility","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]},"attr_dazed":{"name":"dazed","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_intelligence-action":{"triggeredFuncs":["rollAttribute"],"name":"intelligence-action","listener":"clicked:intelligence-action","listenerFunc":"accessSheet","type":"action"},"attr_intelligence_action":{"name":"intelligence_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_intelligence":{"affects":["intelligence_base_chance","awareness","beast_lore","bushcraft","healing","languages","myths_&_legends","seamanship","spot_hidden","repeating_secondary-skills_$X_skill_total"],"name":"intelligence","listener":"change:intelligence","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]},"attr_angry":{"name":"angry","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_willpower-action":{"triggeredFuncs":["rollAttribute"],"name":"willpower-action","listener":"clicked:willpower-action","listenerFunc":"accessSheet","type":"action"},"attr_willpower_action":{"name":"willpower_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_willpower":{"affects":["willpower_base_chance","willpower_points_max","repeating_secondary-skills_$X_skill_total"],"name":"willpower","listener":"change:willpower","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]},"attr_scared":{"name":"scared","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_charisma-action":{"triggeredFuncs":["rollAttribute"],"name":"charisma-action","listener":"clicked:charisma-action","listenerFunc":"accessSheet","type":"action"},"attr_charisma_action":{"name":"charisma_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_charisma":{"affects":["charisma_base_chance","bluffing","bartering","performance","persuasion","repeating_secondary-skills_$X_skill_total"],"name":"charisma","listener":"change:charisma","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]},"attr_disheartened":{"name":"disheartened","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_damage_bonus_strength":{"calculation":"calcDamageBonus","name":"damage_bonus_strength","type":"span","defaultValue":"—","triggeredFuncs":[],"affects":[]},"attr_damage_bonus_agility":{"calculation":"calcDamageBonus","name":"damage_bonus_agility","type":"span","defaultValue":"—","triggeredFuncs":[],"affects":[]},"attr_movement":{"calculation":"calcMovement","name":"movement","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_advance":{"triggeredFuncs":["advanceSkills"],"name":"advance","listener":"clicked:advance","listenerFunc":"accessSheet","type":"action"},"attr_strength_base_chance":{"calculation":"calcSkillBase","name":"strength_base_chance","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_constitution_base_chance":{"calculation":"calcSkillBase","name":"constitution_base_chance","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_agility_base_chance":{"calculation":"calcSkillBase","name":"agility_base_chance","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_intelligence_base_chance":{"calculation":"calcSkillBase","name":"intelligence_base_chance","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_willpower_base_chance":{"calculation":"calcSkillBase","name":"willpower_base_chance","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_charisma_base_chance":{"calculation":"calcSkillBase","name":"charisma_base_chance","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_acrobatics_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"acrobatics_advancement","listener":"change:acrobatics_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_acrobatics_levels":{"affects":["acrobatics"],"name":"acrobatics_levels","listener":"change:acrobatics_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_acrobatics":{"calculation":"calcSkill","name":"acrobatics","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_acrobatics-action":{"triggeredFuncs":["rollSkill"],"name":"acrobatics-action","listener":"clicked:acrobatics-action","listenerFunc":"accessSheet","type":"action"},"attr_acrobatics_action":{"name":"acrobatics_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_awareness_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"awareness_advancement","listener":"change:awareness_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_awareness_levels":{"affects":["awareness"],"name":"awareness_levels","listener":"change:awareness_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_awareness":{"calculation":"calcSkill","name":"awareness","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_awareness-action":{"triggeredFuncs":["rollSkill"],"name":"awareness-action","listener":"clicked:awareness-action","listenerFunc":"accessSheet","type":"action"},"attr_awareness_action":{"name":"awareness_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_bartering_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"bartering_advancement","listener":"change:bartering_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_bartering_levels":{"affects":["bartering"],"name":"bartering_levels","listener":"change:bartering_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_bartering":{"calculation":"calcSkill","name":"bartering","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_bartering-action":{"triggeredFuncs":["rollSkill"],"name":"bartering-action","listener":"clicked:bartering-action","listenerFunc":"accessSheet","type":"action"},"attr_bartering_action":{"name":"bartering_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_beast_lore_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"beast_lore_advancement","listener":"change:beast_lore_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_beast_lore_levels":{"affects":["beast_lore"],"name":"beast_lore_levels","listener":"change:beast_lore_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_beast_lore":{"calculation":"calcSkill","name":"beast_lore","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_beast-lore-action":{"triggeredFuncs":["rollSkill"],"name":"beast-lore-action","listener":"clicked:beast-lore-action","listenerFunc":"accessSheet","type":"action"},"attr_beast_lore_action":{"name":"beast_lore_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_bluffing_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"bluffing_advancement","listener":"change:bluffing_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_bluffing_levels":{"affects":["bluffing"],"name":"bluffing_levels","listener":"change:bluffing_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_bluffing":{"calculation":"calcSkill","name":"bluffing","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_bluffing-action":{"triggeredFuncs":["rollSkill"],"name":"bluffing-action","listener":"clicked:bluffing-action","listenerFunc":"accessSheet","type":"action"},"attr_bluffing_action":{"name":"bluffing_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_bushcraft_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"bushcraft_advancement","listener":"change:bushcraft_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_bushcraft_levels":{"affects":["bushcraft"],"name":"bushcraft_levels","listener":"change:bushcraft_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_bushcraft":{"calculation":"calcSkill","name":"bushcraft","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_bushcraft-action":{"triggeredFuncs":["rollSkill"],"name":"bushcraft-action","listener":"clicked:bushcraft-action","listenerFunc":"accessSheet","type":"action"},"attr_bushcraft_action":{"name":"bushcraft_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_crafting_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"crafting_advancement","listener":"change:crafting_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_crafting_levels":{"affects":["crafting"],"name":"crafting_levels","listener":"change:crafting_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_crafting":{"calculation":"calcSkill","name":"crafting","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_crafting-action":{"triggeredFuncs":["rollSkill"],"name":"crafting-action","listener":"clicked:crafting-action","listenerFunc":"accessSheet","type":"action"},"attr_crafting_action":{"name":"crafting_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_evade_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"evade_advancement","listener":"change:evade_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_evade_levels":{"affects":["evade"],"name":"evade_levels","listener":"change:evade_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_evade":{"calculation":"calcSkill","name":"evade","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_evade-action":{"triggeredFuncs":["rollSkill"],"name":"evade-action","listener":"clicked:evade-action","listenerFunc":"accessSheet","type":"action"},"attr_evade_action":{"name":"evade_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_healing_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"healing_advancement","listener":"change:healing_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_healing_levels":{"affects":["healing"],"name":"healing_levels","listener":"change:healing_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_healing":{"calculation":"calcSkill","name":"healing","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_healing-action":{"triggeredFuncs":["rollSkill"],"name":"healing-action","listener":"clicked:healing-action","listenerFunc":"accessSheet","type":"action"},"attr_healing_action":{"name":"healing_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_hunting_&_fishing_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"hunting_&_fishing_advancement","listener":"change:hunting_&_fishing_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_hunting_&_fishing_levels":{"affects":["hunting_&_fishing"],"name":"hunting_&_fishing_levels","listener":"change:hunting_&_fishing_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_hunting_&_fishing":{"calculation":"calcSkill","name":"hunting_&_fishing","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_hunting-&-fishing-action":{"triggeredFuncs":["rollSkill"],"name":"hunting-&-fishing-action","listener":"clicked:hunting-&-fishing-action","listenerFunc":"accessSheet","type":"action"},"attr_hunting_&_fishing_action":{"name":"hunting_&_fishing_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_languages_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"languages_advancement","listener":"change:languages_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_languages_levels":{"affects":["languages"],"name":"languages_levels","listener":"change:languages_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_languages":{"calculation":"calcSkill","name":"languages","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_languages-action":{"triggeredFuncs":["rollSkill"],"name":"languages-action","listener":"clicked:languages-action","listenerFunc":"accessSheet","type":"action"},"attr_languages_action":{"name":"languages_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_myths_&_legends_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"myths_&_legends_advancement","listener":"change:myths_&_legends_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_myths_&_legends_levels":{"affects":["myths_&_legends"],"name":"myths_&_legends_levels","listener":"change:myths_&_legends_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_myths_&_legends":{"calculation":"calcSkill","name":"myths_&_legends","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_myths-&-legends-action":{"triggeredFuncs":["rollSkill"],"name":"myths-&-legends-action","listener":"clicked:myths-&-legends-action","listenerFunc":"accessSheet","type":"action"},"attr_myths_&_legends_action":{"name":"myths_&_legends_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_performance_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"performance_advancement","listener":"change:performance_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_performance_levels":{"affects":["performance"],"name":"performance_levels","listener":"change:performance_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_performance":{"calculation":"calcSkill","name":"performance","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_performance-action":{"triggeredFuncs":["rollSkill"],"name":"performance-action","listener":"clicked:performance-action","listenerFunc":"accessSheet","type":"action"},"attr_performance_action":{"name":"performance_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_persuasion_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"persuasion_advancement","listener":"change:persuasion_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_persuasion_levels":{"affects":["persuasion"],"name":"persuasion_levels","listener":"change:persuasion_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_persuasion":{"calculation":"calcSkill","name":"persuasion","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_persuasion-action":{"triggeredFuncs":["rollSkill"],"name":"persuasion-action","listener":"clicked:persuasion-action","listenerFunc":"accessSheet","type":"action"},"attr_persuasion_action":{"name":"persuasion_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_riding_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"riding_advancement","listener":"change:riding_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_riding_levels":{"affects":["riding"],"name":"riding_levels","listener":"change:riding_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_riding":{"calculation":"calcSkill","name":"riding","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_riding-action":{"triggeredFuncs":["rollSkill"],"name":"riding-action","listener":"clicked:riding-action","listenerFunc":"accessSheet","type":"action"},"attr_riding_action":{"name":"riding_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_seamanship_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"seamanship_advancement","listener":"change:seamanship_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_seamanship_levels":{"affects":["seamanship"],"name":"seamanship_levels","listener":"change:seamanship_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_seamanship":{"calculation":"calcSkill","name":"seamanship","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_seamanship-action":{"triggeredFuncs":["rollSkill"],"name":"seamanship-action","listener":"clicked:seamanship-action","listenerFunc":"accessSheet","type":"action"},"attr_seamanship_action":{"name":"seamanship_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_sleight_of_hand_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"sleight_of_hand_advancement","listener":"change:sleight_of_hand_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_sleight_of_hand_levels":{"affects":["sleight_of_hand"],"name":"sleight_of_hand_levels","listener":"change:sleight_of_hand_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_sleight_of_hand":{"calculation":"calcSkill","name":"sleight_of_hand","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_sleight-of-hand-action":{"triggeredFuncs":["rollSkill"],"name":"sleight-of-hand-action","listener":"clicked:sleight-of-hand-action","listenerFunc":"accessSheet","type":"action"},"attr_sleight_of_hand_action":{"name":"sleight_of_hand_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_sneaking_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"sneaking_advancement","listener":"change:sneaking_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_sneaking_levels":{"affects":["sneaking"],"name":"sneaking_levels","listener":"change:sneaking_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_sneaking":{"calculation":"calcSkill","name":"sneaking","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_sneaking-action":{"triggeredFuncs":["rollSkill"],"name":"sneaking-action","listener":"clicked:sneaking-action","listenerFunc":"accessSheet","type":"action"},"attr_sneaking_action":{"name":"sneaking_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_spot_hidden_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"spot_hidden_advancement","listener":"change:spot_hidden_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_spot_hidden_levels":{"affects":["spot_hidden"],"name":"spot_hidden_levels","listener":"change:spot_hidden_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_spot_hidden":{"calculation":"calcSkill","name":"spot_hidden","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_spot-hidden-action":{"triggeredFuncs":["rollSkill"],"name":"spot-hidden-action","listener":"clicked:spot-hidden-action","listenerFunc":"accessSheet","type":"action"},"attr_spot_hidden_action":{"name":"spot_hidden_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_swimming_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"swimming_advancement","listener":"change:swimming_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_swimming_levels":{"affects":["swimming"],"name":"swimming_levels","listener":"change:swimming_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_swimming":{"calculation":"calcSkill","name":"swimming","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_swimming-action":{"triggeredFuncs":["rollSkill"],"name":"swimming-action","listener":"clicked:swimming-action","listenerFunc":"accessSheet","type":"action"},"attr_swimming_action":{"name":"swimming_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_axes_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"axes_advancement","listener":"change:axes_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_axes_levels":{"affects":["axes"],"name":"axes_levels","listener":"change:axes_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_axes":{"calculation":"calcSkill","name":"axes","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_axes-action":{"triggeredFuncs":["rollSkill"],"name":"axes-action","listener":"clicked:axes-action","listenerFunc":"accessSheet","type":"action"},"attr_axes_action":{"name":"axes_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_bows_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"bows_advancement","listener":"change:bows_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_bows_levels":{"affects":["bows"],"name":"bows_levels","listener":"change:bows_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_bows":{"calculation":"calcSkill","name":"bows","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_bows-action":{"triggeredFuncs":["rollSkill"],"name":"bows-action","listener":"clicked:bows-action","listenerFunc":"accessSheet","type":"action"},"attr_bows_action":{"name":"bows_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_brawling_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"brawling_advancement","listener":"change:brawling_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_brawling_levels":{"affects":["brawling"],"name":"brawling_levels","listener":"change:brawling_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_brawling":{"calculation":"calcSkill","name":"brawling","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_brawling-action":{"triggeredFuncs":["rollSkill"],"name":"brawling-action","listener":"clicked:brawling-action","listenerFunc":"accessSheet","type":"action"},"attr_brawling_action":{"name":"brawling_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_crossbows_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"crossbows_advancement","listener":"change:crossbows_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_crossbows_levels":{"affects":["crossbows"],"name":"crossbows_levels","listener":"change:crossbows_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_crossbows":{"calculation":"calcSkill","name":"crossbows","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_crossbows-action":{"triggeredFuncs":["rollSkill"],"name":"crossbows-action","listener":"clicked:crossbows-action","listenerFunc":"accessSheet","type":"action"},"attr_crossbows_action":{"name":"crossbows_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_hammers_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"hammers_advancement","listener":"change:hammers_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_hammers_levels":{"affects":["hammers"],"name":"hammers_levels","listener":"change:hammers_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_hammers":{"calculation":"calcSkill","name":"hammers","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_hammers-action":{"triggeredFuncs":["rollSkill"],"name":"hammers-action","listener":"clicked:hammers-action","listenerFunc":"accessSheet","type":"action"},"attr_hammers_action":{"name":"hammers_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_knives_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"knives_advancement","listener":"change:knives_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_knives_levels":{"affects":["knives"],"name":"knives_levels","listener":"change:knives_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_knives":{"calculation":"calcSkill","name":"knives","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_knives-action":{"triggeredFuncs":["rollSkill"],"name":"knives-action","listener":"clicked:knives-action","listenerFunc":"accessSheet","type":"action"},"attr_knives_action":{"name":"knives_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_slings_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"slings_advancement","listener":"change:slings_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_slings_levels":{"affects":["slings"],"name":"slings_levels","listener":"change:slings_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_slings":{"calculation":"calcSkill","name":"slings","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_slings-action":{"triggeredFuncs":["rollSkill"],"name":"slings-action","listener":"clicked:slings-action","listenerFunc":"accessSheet","type":"action"},"attr_slings_action":{"name":"slings_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_spears_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"spears_advancement","listener":"change:spears_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_spears_levels":{"affects":["spears"],"name":"spears_levels","listener":"change:spears_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_spears":{"calculation":"calcSkill","name":"spears","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_spears-action":{"triggeredFuncs":["rollSkill"],"name":"spears-action","listener":"clicked:spears-action","listenerFunc":"accessSheet","type":"action"},"attr_spears_action":{"name":"spears_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_staves_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"staves_advancement","listener":"change:staves_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_staves_levels":{"affects":["staves"],"name":"staves_levels","listener":"change:staves_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_staves":{"calculation":"calcSkill","name":"staves","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_staves-action":{"triggeredFuncs":["rollSkill"],"name":"staves-action","listener":"clicked:staves-action","listenerFunc":"accessSheet","type":"action"},"attr_staves_action":{"name":"staves_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_swords_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"swords_advancement","listener":"change:swords_advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_swords_levels":{"affects":["swords"],"name":"swords_levels","listener":"change:swords_levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_swords":{"calculation":"calcSkill","name":"swords","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_swords-action":{"triggeredFuncs":["rollSkill"],"name":"swords-action","listener":"clicked:swords-action","listenerFunc":"accessSheet","type":"action"},"attr_swords_action":{"name":"swords_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-secondary-skills":{"listenerFunc":"addItem","name":"add-secondary-skills","listener":"clicked:add-secondary-skills","type":"action"},"fieldset_repeating_secondary-skills":{"addFuncs":["initializeSkill","setupMagicSelect","setActionCalls"],"triggeredFuncs":["setupMagicSelect"],"name":"repeating_secondary-skills","listener":"remove:repeating_secondary-skills","listenerFunc":"accessSheet","type":"fieldset"},"attr_repeating_secondary-skills_$X_collapse":{"name":"repeating_secondary-skills_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_secondary-skills_$X_advancement":{"triggeredFuncs":["displayUpgrade"],"name":"repeating_secondary-skills_$X_advancement","listener":"change:repeating_secondary-skills:advancement","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_repeating_secondary-skills_$X_levels":{"affects":["repeating_secondary-skills_$X_total"],"name":"repeating_secondary-skills_$X_levels","listener":"change:repeating_secondary-skills:levels","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_repeating_secondary-skills_$X_total":{"calculation":"calcSkill","name":"repeating_secondary-skills_$X_total","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_repeating_secondary-skills_$X_action":{"triggeredFuncs":["rollSkill"],"name":"repeating_secondary-skills_$X_action","listener":"clicked:repeating_secondary-skills:action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_secondary-skills_$X_action":{"name":"repeating_secondary-skills_$X_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_secondary-skills_$X_name":{"name":"repeating_secondary-skills_$X_name","type":"span","defaultValue":"New Skill","triggeredFuncs":["setupMagicSelect"],"affects":[],"listener":"change:repeating_secondary-skills:name","listenerFunc":"accessSheet"},"attr_repeating_secondary-skills_$X_attribute_abbreviation":{"name":"repeating_secondary-skills_$X_attribute_abbreviation","type":"hidden","defaultValue":"intelligence-abbreviation","triggeredFuncs":[],"affects":[],"calculation":"convertAbbreviation"},"attr_repeating_secondary-skills_$X_attribute_select":{"affects":["repeating_secondary-skills_$X_total","repeating_secondary-skills_$X_attribute_abbreviation"],"name":"repeating_secondary-skills_$X_attribute_select","listener":"change:repeating_secondary-skills:attribute_select","listenerFunc":"accessSheet","type":"select","defaultValue":"intelligence","triggeredFuncs":[]},"attr_encumbrance":{"calculation":"calcEncumbrance","name":"encumbrance","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_encumbrance_max":{"calculation":"calcEncumbranceMax","name":"encumbrance_max","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_backpack":{"affects":["encumbrance_max"],"name":"backpack","listener":"change:backpack","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"triggeredFuncs":[]},"act_add-gear":{"listenerFunc":"addItem","name":"add-gear","listener":"clicked:add-gear","type":"action"},"fieldset_repeating_gear":{"affects":["encumbrance"],"name":"repeating_gear","listener":"remove:repeating_gear","listenerFunc":"accessSheet","type":"fieldset"},"attr_repeating_gear_$X_collapse":{"name":"repeating_gear_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_gear_$X_quantity":{"affects":["encumbrance"],"name":"repeating_gear_$X_quantity","listener":"change:repeating_gear:quantity","listenerFunc":"accessSheet","type":"number","defaultValue":"1","triggeredFuncs":[]},"attr_repeating_gear_$X_name":{"name":"repeating_gear_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_gear_$X_weight":{"affects":["encumbrance"],"name":"repeating_gear_$X_weight","listener":"change:repeating_gear:weight","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_repeating_gear_$X_description":{"name":"repeating_gear_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_memento":{"name":"memento","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_tiny_list":{"name":"tiny_list","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-abilities":{"listenerFunc":"addItem","name":"add-abilities","listener":"clicked:add-abilities","type":"action"},"fieldset_repeating_abilities":{"addFuncs":["setActionCalls"],"name":"repeating_abilities","type":"fieldset"},"attr_repeating_abilities_$X_collapse":{"name":"repeating_abilities_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_spell":{"name":"repeating_abilities_$X_spell","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":["repeating_abilities_$X_cost"],"listener":"change:repeating_abilities:spell","listenerFunc":"accessSheet"},"attr_repeating_abilities_$X_prepared":{"name":"repeating_abilities_$X_prepared","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_name":{"name":"repeating_abilities_$X_name","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_abilities_$X_cast-action":{"triggeredFuncs":["castSpell"],"name":"repeating_abilities_$X_cast-action","listener":"clicked:repeating_abilities:cast-action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_abilities_$X_cast_action":{"name":"repeating_abilities_$X_cast_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_cost":{"name":"repeating_abilities_$X_cost","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[],"calculation":"calcCost"},"attr_repeating_abilities_$X_requirement":{"name":"repeating_abilities_$X_requirement","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_skill":{"affects":["repeating_abilities_$X_cost"],"name":"repeating_abilities_$X_skill","listener":"change:repeating_abilities:skill","listenerFunc":"accessSheet","type":"select","defaultValue":"","triggeredFuncs":[]},"attr_repeating_abilities_$X_spell_power":{"name":"repeating_abilities_$X_spell_power","type":"checkbox","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_rank":{"name":"repeating_abilities_$X_rank","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_casting_time":{"name":"repeating_abilities_$X_casting_time","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_range":{"name":"repeating_abilities_$X_range","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_duration":{"name":"repeating_abilities_$X_duration","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_abilities_$X_description":{"name":"repeating_abilities_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_gold":{"affects":["encumbrance"],"name":"gold","listener":"change:gold","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_silver":{"affects":["encumbrance"],"name":"silver","listener":"change:silver","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_copper":{"affects":["encumbrance"],"name":"copper","listener":"change:copper","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_armor_rating_total":{"calculation":"calcArmorTotal","name":"armor_rating_total","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_armor_rating":{"affects":["armor_rating_total"],"name":"armor_rating","listener":"change:armor_rating","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_armor_name":{"name":"armor_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_armor_sneaking_bane":{"name":"armor_sneaking_bane","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_armor_evade_bane":{"name":"armor_evade_bane","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_armor_acrobatics_bane":{"name":"armor_acrobatics_bane","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_helmet_rating":{"affects":["armor_rating_total"],"name":"helmet_rating","listener":"change:helmet_rating","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_helmet_name":{"name":"helmet_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_helmet_awareness_bane":{"name":"helmet_awareness_bane","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_helmet_ranged_attacks_bane":{"name":"helmet_ranged_attacks_bane","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_round_rest":{"triggeredFuncs":["useRest"],"name":"round_rest","listener":"change:round_rest","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_stretch_rest":{"triggeredFuncs":["useRest"],"name":"stretch_rest","listener":"change:stretch_rest","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"act_shift-rest-action":{"triggeredFuncs":["useRest"],"name":"shift-rest-action","listener":"clicked:shift-rest-action","listenerFunc":"accessSheet","type":"action"},"attr_shift_rest_action":{"name":"shift_rest_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_willpower_points":{"name":"willpower_points","type":"number","defaultValue":"0","triggeredFuncs":[],"affects":[]},"attr_willpower_points_max":{"calculation":"calcPoints","name":"willpower_points_max","type":"number","defaultValue":"0","triggeredFuncs":[],"affects":[]},"attr_hit_points":{"name":"hit_points","type":"number","defaultValue":"0","triggeredFuncs":[],"affects":[]},"attr_hit_points_max":{"calculation":"calcPoints","name":"hit_points_max","type":"number","defaultValue":"0","triggeredFuncs":[],"affects":[]},"act_death-saves-action":{"triggeredFuncs":["rollDeath"],"name":"death-saves-action","listener":"clicked:death-saves-action","listenerFunc":"accessSheet","type":"action"},"attr_death_saves_action":{"name":"death_saves_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_death_saves_successes":{"triggeredFuncs":["addSuccessHP"],"name":"death_saves_successes","listener":"change:death_saves_successes","listenerFunc":"accessSheet","type":"hidden","defaultValue":0,"affects":[]},"attr_death_saves_failures":{"name":"death_saves_failures","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_add-weapons":{"listenerFunc":"addItem","name":"add-weapons","listener":"clicked:add-weapons","type":"action"},"fieldset_repeating_weapons":{"addFuncs":["setActionCalls"],"name":"repeating_weapons","type":"fieldset"},"attr_repeating_weapons_$X_collapse":{"name":"repeating_weapons_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_name":{"name":"repeating_weapons_$X_name","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_weapons_$X_action":{"triggeredFuncs":["rollAttack"],"name":"repeating_weapons_$X_action","listener":"clicked:repeating_weapons:action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_weapons_$X_action":{"name":"repeating_weapons_$X_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_damage":{"name":"repeating_weapons_$X_damage","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_durability":{"calculation":"setDurability","name":"repeating_weapons_$X_durability","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_type":{"name":"repeating_weapons_$X_type","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_skill":{"name":"repeating_weapons_$X_skill","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_use_bonus":{"name":"repeating_weapons_$X_use_bonus","type":"checkbox","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_grip":{"name":"repeating_weapons_$X_grip","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_strength_requirement":{"name":"repeating_weapons_$X_strength_requirement","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_range":{"name":"repeating_weapons_$X_range","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_durability_max":{"affects":["repeating_weapons_$X_durability"],"name":"repeating_weapons_$X_durability_max","listener":"change:repeating_weapons:durability_max","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"attr_repeating_weapons_$X_properties":{"name":"repeating_weapons_$X_properties","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_weapons_$X_description":{"name":"repeating_weapons_$X_description","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_monster_view":{"name":"monster_view","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_ferocity":{"name":"ferocity","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_size":{"name":"size","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_swarm":{"name":"swarm","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_base-skills-action":{"triggeredFuncs":["rollSkill"],"name":"base-skills-action","listener":"clicked:base-skills-action","listenerFunc":"accessSheet","type":"action"},"attr_base_skills_action":{"name":"base_skills_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_base_skills":{"name":"base_skills","type":"span","defaultValue":15,"triggeredFuncs":[],"affects":[]},"act_monster-attacks-action":{"triggeredFuncs":["rollRandomAttack"],"name":"monster-attacks-action","listener":"clicked:monster-attacks-action","listenerFunc":"accessSheet","type":"action"},"attr_monster_attacks_action":{"name":"monster_attacks_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-attacks":{"listenerFunc":"addItem","name":"add-attacks","listener":"clicked:add-attacks","type":"action"},"fieldset_repeating_attacks":{"addFuncs":["setActionCalls"],"name":"repeating_attacks","type":"fieldset"},"attr_repeating_attacks_$X_collapse":{"name":"repeating_attacks_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_result":{"name":"repeating_attacks_$X_result","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_weight"],"listener":"change:repeating_attacks:result","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_name":{"name":"repeating_attacks_$X_name","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_attacks_$X_action":{"triggeredFuncs":["rollMonsterAttack"],"name":"repeating_attacks_$X_action","listener":"clicked:repeating_attacks:action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_attacks_$X_action":{"name":"repeating_attacks_$X_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_description":{"name":"repeating_attacks_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable":{"name":"repeating_attacks_$X_subtable","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_result_1":{"name":"repeating_attacks_$X_subtable_result_1","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_subtable_weight_1"],"listener":"change:repeating_attacks:subtable_result_1","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_subtable_name_1":{"name":"repeating_attacks_$X_subtable_name_1","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_description_1":{"name":"repeating_attacks_$X_subtable_description_1","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_result_2":{"name":"repeating_attacks_$X_subtable_result_2","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_subtable_weight_2"],"listener":"change:repeating_attacks:subtable_result_2","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_subtable_name_2":{"name":"repeating_attacks_$X_subtable_name_2","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_description_2":{"name":"repeating_attacks_$X_subtable_description_2","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_result_3":{"name":"repeating_attacks_$X_subtable_result_3","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_subtable_weight_3"],"listener":"change:repeating_attacks:subtable_result_3","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_subtable_name_3":{"name":"repeating_attacks_$X_subtable_name_3","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_description_3":{"name":"repeating_attacks_$X_subtable_description_3","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_result_4":{"name":"repeating_attacks_$X_subtable_result_4","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_subtable_weight_4"],"listener":"change:repeating_attacks:subtable_result_4","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_subtable_name_4":{"name":"repeating_attacks_$X_subtable_name_4","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_description_4":{"name":"repeating_attacks_$X_subtable_description_4","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_result_5":{"name":"repeating_attacks_$X_subtable_result_5","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_subtable_weight_5"],"listener":"change:repeating_attacks:subtable_result_5","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_subtable_name_5":{"name":"repeating_attacks_$X_subtable_name_5","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_description_5":{"name":"repeating_attacks_$X_subtable_description_5","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_result_6":{"name":"repeating_attacks_$X_subtable_result_6","type":"span","defaultValue":"","triggeredFuncs":[],"affects":["repeating_attacks_$X_subtable_weight_6"],"listener":"change:repeating_attacks:subtable_result_6","listenerFunc":"accessSheet"},"attr_repeating_attacks_$X_subtable_name_6":{"name":"repeating_attacks_$X_subtable_name_6","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_description_6":{"name":"repeating_attacks_$X_subtable_description_6","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_weight":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_weight","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_damage":{"name":"repeating_attacks_$X_damage","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_weight_1":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_subtable_weight_1","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_damage_1":{"name":"repeating_attacks_$X_subtable_damage_1","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_weight_2":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_subtable_weight_2","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_damage_2":{"name":"repeating_attacks_$X_subtable_damage_2","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_weight_3":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_subtable_weight_3","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_damage_3":{"name":"repeating_attacks_$X_subtable_damage_3","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_weight_4":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_subtable_weight_4","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_damage_4":{"name":"repeating_attacks_$X_subtable_damage_4","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_weight_5":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_subtable_weight_5","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_damage_5":{"name":"repeating_attacks_$X_subtable_damage_5","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_weight_6":{"calculation":"calcDieWeight","name":"repeating_attacks_$X_subtable_weight_6","type":"hidden","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_attacks_$X_subtable_damage_6":{"name":"repeating_attacks_$X_subtable_damage_6","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_cards":{"calculation":"calcInitiativeDeck","affects":["deck_size"],"name":"cards","listener":"change:cards","listenerFunc":"accessSheet","type":"text","defaultValue":"1,2,3,4,5,6,7,8,9,10","triggeredFuncs":[]},"attr_deck_size":{"calculation":"calcDeckSize","name":"deck_size","type":"number","defaultValue":10,"triggeredFuncs":[],"affects":[]},"act_initiative-action":{"triggeredFuncs":["rollInitiative"],"name":"initiative-action","listener":"clicked:initiative-action","listenerFunc":"accessSheet","type":"action"},"attr_initiative_action":{"name":"initiative_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_reset-action":{"triggeredFuncs":["resetInitiative"],"affects":["cards"],"name":"reset-action","listener":"clicked:reset-action","listenerFunc":"accessSheet","type":"action"},"attr_reset_action":{"name":"reset_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_initiative_$X_used":{"name":"repeating_initiative_$X_used","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_repeating_initiative_$X_use":{"triggeredFuncs":["useInitiative"],"name":"repeating_initiative_$X_use","listener":"clicked:repeating_initiative:use","listenerFunc":"accessSheet","type":"action"},"attr_repeating_initiative_$X_card":{"name":"repeating_initiative_$X_card","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_initiative_$X_name":{"name":"repeating_initiative_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_initiative_$X_hold":{"name":"repeating_initiative_$X_hold","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_repeating_initiative_$X_remove":{"triggeredFuncs":["removeInitiative"],"affects":"cards","name":"repeating_initiative_$X_remove","listener":"clicked:repeating_initiative:remove","listenerFunc":"accessSheet","type":"action"},"act_repeating_initiative_$X_switch":{"triggeredFuncs":["switchInitiative"],"name":"repeating_initiative_$X_switch","listener":"clicked:repeating_initiative:switch","listenerFunc":"accessSheet","type":"action"},"attr_template_start":{"name":"template_start","type":"hidden","defaultValue":"@{whisper}&{template:dragonbane} {{character_name=@{character_name}}} {{character_id=@{character_id}}}","triggeredFuncs":[],"affects":[]}};
kFuncs.cascades = cascades;
const repeatingSectionDetails = [{"section":"repeating_secondary-skills","fields":["collapse","advancement","levels","total","action","name","attribute_abbreviation","attribute_select"]},{"section":"repeating_gear","fields":["collapse","quantity","name","weight","description"]},{"section":"repeating_abilities","fields":["collapse","spell","prepared","name","cast_action","cost","requirement","skill","spell_power","rank","casting_time","range","duration","description"]},{"section":"repeating_weapons","fields":["collapse","name","action","damage","durability","type","skill","use_bonus","grip","strength_requirement","range","durability_max","properties","description"]},{"section":"repeating_attacks","fields":["collapse","result","name","action","description","subtable","subtable_result_1","subtable_name_1","subtable_description_1","subtable_result_2","subtable_name_2","subtable_description_2","subtable_result_3","subtable_name_3","subtable_description_3","subtable_result_4","subtable_name_4","subtable_description_4","subtable_result_5","subtable_name_5","subtable_description_5","subtable_result_6","subtable_name_6","subtable_description_6","weight","damage","subtable_weight_1","subtable_damage_1","subtable_weight_2","subtable_damage_2","subtable_weight_3","subtable_damage_3","subtable_weight_4","subtable_damage_4","subtable_weight_5","subtable_damage_5","subtable_weight_6","subtable_damage_6"]},{"section":"repeating_initiative","fields":["used","card","name","hold"]}];
kFuncs.repeatingSectionDetails = repeatingSectionDetails;
const persistentTabs = ["dragonbane_tab"];
kFuncs.persistentTabs = persistentTabs;
/**
* The K-scaffold provides several variables to allow your scripts to tap into its information flow.
* @namespace Sheetworkers.Variables
*/
/**
* This stores the name of your sheet for use in the logging functions {@link log} and {@link debug}. Accessible by `k.sheetName`
* @memberof Variables
* @var
* @type {string}
*/
let sheetName = 'kScaffold Powered Sheet';
kFuncs.sheetName = sheetName;
/**
* This stores the version of your sheet for use in the logging functions{@link log} and {@link debug}. It is also stored in the sheet_version attribute on your character sheet. Accessible via `k.version`
* @memberof Variables
* @var
* @type {number}
*/
let version = 0;
kFuncs.version = version;
/**
* A boolean flag that tells the script whether to enable or disable {@link debug} calls. If the version of the sheet is `0`, or an attribute named `debug_mode` is found on opening this is set to true for your entire session. Otherwise, it remains false.
* @memberof Variables
* @var
* @type {boolean}
*/
let debugMode = false;
kFuncs.debugMode = debugMode;
const funcs = {};
kFuncs.funcs = funcs;
const updateHandlers = {};
const openHandlers = {};
const initialSetups = {};
const allHandlers = {};
const addFuncs = {};
const kscaffoldJSVersion = '1.0.0';
const kscaffoldPUGVersion = '1.0.0';
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
/**
* These are utility functions that are not directly related to Roll20 systems. They provide easy methods for everything from processing text and numbers to querying the user for input.
* @namespace Sheetworkers.Utilities
* @alias Utilities
*/
/**
* Replaces problem characters to use a string as a regex
* @memberof Utilities
* @param {string} text - The text to replace characters in
* @returns {string}
* @example
* const textForRegex = k.sanitizeForRegex('.some thing[with characters]');
* console.log(textForRegex);// => "\.some thing\[with characters\]"
*/
const sanitizeForRegex = function(text){
return text.replace(/\.|\||\(|\)|\[|\]|\-|\+|\?|\/|\{|\}|\^|\$|\*/g,'\\$&');
};
kFuncs.sanitizeForRegex = sanitizeForRegex;
/**
* Converts a value to a number, it\'s default value, or `0` if no default value passed.
* @memberof Utilities
* @param {string|number} val - Value to convert to a number
* @param {number} def - The default value, uses 0 if not passed
* @returns {number|undefined}
* @example
* const num = k.value('100');
* console.log(num);// => 100
*/
const value = function(val,def){
const convertVal = +val;
if(def !== undefined && isNaN(def)){
throw(`K-scaffold Error: invalid default for value(). Default: ${def}`);
}
return convertVal === 0 ?
convertVal :
(+val||def||0);
};
kFuncs.value = value;
/**
* Extracts the section (e.g. `repeating_equipment`), rowID (e.g `-;lkj098J:LKj`), and field name (e.g. `bulk`) from a repeating attribute name.
* @memberof Utilities
* @param {string} string - The string to parse
* @returns {array} - Array of matches. Index 0: the section name, e.g. repeating_equipment | Index 1:the row ID | index 2: The name of the attribute
* @returns {string[]}
* @example
* //Extract info from a full repeating name
* const [section,rowID,attrName] = k.parseRepeatName('repeating_equipment_-8908asdflkjZlkj23_name');
* console.log(section);// => "repeating_equipment"
* console.log(rowID);// => "-8908asdflkjZlkj23"
* console.log(attrName);// => "name"
*
* //Extract info from just a row name
* const [section,rowID,attrName] = k.parseRepeatName('repeating_equipment_-8908asdflkjZlkj23');
* console.log(section);// => "repeating_equipment"
* console.log(rowID);// => "-8908asdflkjZlkj23"
* console.log(attrName);// => undefined
*/
const parseRepeatName = function(string){
let match = string.match(/(repeating_[^_]+)_([^_]+)(?:_(.+))?/);
match.shift();
return match;
};
kFuncs.parseRepeatName = parseRepeatName;
/**
* Parses out the components of a trigger name similar to [parseRepeatName](#parserepeatname). Aliases: parseClickTrigger.
*
* Aliases: `k.parseClickTrigger`
* @memberof Utilities
* @param {string} string The triggerName property of the
* @returns {array} - For a repeating button named `repeating_equipment_-LKJhpoi98;lj_roll`, the array will be `['repeating_equipment','-LKJhpoi98;lj','roll']`. For a non repeating button named `roll`, the array will be `[undefined,undefined,'roll']`
* @returns {string[]}
* @example
* //Parse a non repeating trigger
* const [section,rowID,attrName] = k.parseTriggerName('clicked:some-button');
* console.log(section);// => undefined
* console.log(rowID);// => undefined
* console.log(attrName);// => "some-button"
*
* //Parse a repeating trigger
* const [section,rowID,attrName] = k.parseTriggerName('clicked:repeating_attack_-234lkjpd8fu8usadf_some-button');
* console.log(section);// => "repeating_attack"
* console.log(rowID);// => "-234lkjpd8fu8usadf"
* console.log(attrName);// => "some-button"
*
* //Parse a repeating name
* const [section,rowID,attrName] = k.parseTriggerName('repeating_attack_-234lkjpd8fu8usadf_some-button');
* console.log(section);// => "repeating_attack"
* console.log(rowID);// => "-234lkjpd8fu8usadf"
* console.log(attrName);// => "some-button"
*/
const parseTriggerName = function(string){
let match = string.replace(/^clicked:/,'').match(/(?:(repeating_[^_]+)_([^_]+)_)?(.+)/);
match.shift();
return match;
};
kFuncs.parseTriggerName = parseTriggerName;
const parseClickTrigger = parseTriggerName;
kFuncs.parseClickTrigger = parseClickTrigger;
/**
* Parses out the attribute name from the htmlattribute name.
* @memberof Utilities
* @param {string} string - The triggerName property of the [event](https://wiki.roll20.net/Sheet_Worker_Scripts#eventInfo_Object).
* @returns {string}
* @example
* //Parse a name
* const attrName = k.parseHtmlName('attr_attribute_1');
* console.log(attrName);// => "attribute_1"
*/
const parseHTMLName = function(string){
let match = string.match(/(?:attr|act|roll)_(.+)/);
match.shift();
return match[0];
};
kFuncs.parseHTMLName = parseHTMLName;
/**
* Capitalize each word in a string
* @memberof Utilities
* @param {string} string - The string to capitalize
* @returns {string}
* @example
* const capitalized = k.capitalize('a word');
* console.log(capitalized);// => "A Word"
*/
const capitalize = function(string){
return string.replace(/(?:^|\s+|\/)[a-z]/ig,(letter)=>letter.toUpperCase());
};
kFuncs.capitalize = capitalize;
/**
* Extracts a roll query result for use in later functions. Must be awaited as per [startRoll documentation](https://wiki.roll20.net/Sheet_Worker_Scripts#Roll_Parsing.28NEW.29). Stolen from [Oosh\'s Adventures with Startroll thread](https://app.roll20.net/forum/post/10346883/adventures-with-startroll).
* @memberof Utilities
* @param {string} query - The query should be just the text as the `?{` and `}` at the start/end of the query are added by the function.
* @returns {Promise} - Resolves to the selected value from the roll query
* @example
* const rollFunction = async function(){
* //Get the result of a choose from list query
* const queryResult = await extractQueryResult('Prompt Text Here|Option 1|Option 2');
* console.log(queryResult);//=> "Option 1" or "Option 2" depending on what the user selects
*
* //Get free form input from the user
* const freeResult = await extractQueryResult('Prompt Text Here');
* consoel.log(freeResult);// => Whatever the user entered
* }
*/
const extractQueryResult = async function(query){
debug('entering extractQueryResult');
let queryRoll = await startRoll(`!{{query=[[0[response=?{${query}}]]]}}`);
finishRoll(queryRoll.rollId);
return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,'');
};
kFuncs.extractQueryResult = extractQueryResult;
/**
* Simulates a query for ensuring that async/await works correctly in the sheetworker environment when doing conditional startRolls. E.g. if you have an if/else and only one of the conditions results in `startRoll` being called (and thus an `await`), the sheetworker environment would normally crash. Awaiting this in the condition that does not actually need to call `startRoll` will keep the environment in sync.
* @memberof Utilities
* @param {string|number} [value] - The value to return. Optional.
* @returns {Promise} - Resolves to the value passed to the function
* @example
* const rollFunction = async function(){
* //Get the result of a choose from list query
* const queryResult = await pseudoQuery('a value');
* console.log(queryResult);//=> "a value"
* }
*/
const pseudoQuery = async function(value){
debug('entering pseudoQuery');
let queryRoll = await startRoll(`!{{query=[[0[response=${value}]]]}}`);
finishRoll(queryRoll.rollId);
return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,'');
};
kFuncs.pseudoQuery = pseudoQuery;
/**
* An alias for console.log.
* @memberof Utilities
* @param {any} msg - The message can be a straight string, an object, or an array. If it is an object or array, the object will be broken down so that each key is used as a label to output followed by the value of that key. If the value of the key is an object or array, it will be output via `console.table`.
*/
const log = function(msg){
if(typeof msg === 'string'){
console.log(`%c${kFuncs.sheetName} log| ${msg}`,"background-color:#159ccf");
}else if(typeof msg === 'object'){
Object.keys(msg).forEach((m)=>{
if(typeof msg[m] === 'string'){
console.log(`%c${kFuncs.sheetName} log| ${m}: ${msg[m]}`,"background-color:#159ccf");
}else{
console.log(`%c${kFuncs.sheetName} log| ${typeof msg[m]} ${m}`,"background-color:#159ccf");
console.table(msg[m]);
}
});
}
};
kFuncs.log = log;
/**
* Alias for console.log that only triggers when debug mode is enabled or when the sheet\'s version is `0`. Useful for entering test logs that will not pollute the console on the live sheet.
* @memberof Utilities
* @param {any} msg - 'See {@link k.log}
* @param {boolean} force - Pass as a truthy value to force the debug output to be output to the console regardless of debug mode.
* @returns {void}
*/
const debug = function(msg,force){
if(!kFuncs.debugMode && !force && kFuncs.version > 0) return;
if(typeof msg === 'string'){
console.warn(`%c${kFuncs.sheetName} DEBUG| ${msg}`,"background-color:tan;color:red;");
}else if(typeof msg === 'object'){
Object.keys(msg).forEach((m)=>{
if(typeof msg[m] === 'string'){
console.warn(`%c${kFuncs.sheetName} DEBUG| ${m}: ${msg[m]}`,"background-color:tan;color:red;");
}else{
console.warn(`%c${kFuncs.sheetName} DEBUG| ${typeof msg[m]} ${m}`,"background-color:tan;color:red;font-weight:bold;");
console.table(msg[m]);
}
});
}
};
kFuncs.debug = debug;
/**
* Orders the section id arrays for all sections in the `sections` object to match the repOrder attribute.
* @memberof Utilities
* @param {attributesProxy} attributes - The attributes object that must have a value for the reporder for each section.
* @param {object[]} sections - Object containing the IDs for the repeating sections, indexed by repeating section name.
*/
const orderSections = function(attributes,sections){
Object.keys(sections).forEach((section)=>{
attributes.attributes[`_reporder_${section}`] = commaArray(attributes[`_reporder_${section}`]);
sections[section] = orderSection(attributes.attributes[`_reporder_${section}`],sections[section]);
});
};
kFuncs.orderSections = orderSections;
/**
* Orders a single ID array.
* @memberof Utilities
* @param {string[]} repOrder - Array of IDs in the order they are in on the sheet.
* @param {string[]} IDs - Array of IDs to be ordered. Aka the default ID Array passed to the getSectionIDs callback
* @returns {string[]} - The ordered id array
*/
const orderSection = function(repOrder,IDs=[]){
const idArr = [...repOrder.filter(v => v),...IDs.filter(id => !repOrder.includes(id.toLowerCase()))];
return idArr;
};
kFuncs.orderSection = orderSection;
/**
* Splits a comma delimited string into an array
* @memberof Utilities
* @param {string} string - The string to split.
* @returns {array} - The string segments of the comma delimited list.
*/
const commaArray = function(string=''){
return string.toLowerCase().split(/\s*,\s*/);
};
kFuncs.commaArray = commaArray;
// Roll escape functions for passing data in action button calls. Base64 encodes/decodes the data.
const RE = {
chars: {
'"': '%quot;',
',': '%comma;',
':': '%colon;',
'}': '%rcub;',
'{': '%lcub;',
},
escape(data) {
return typeof data === 'object' ?
`KDATA${btoa(JSON.stringify(data))}` :
`KSTRING${btoa(data)}`;
},
unescape(string) {
const isData = typeof string === 'string' &&
(
string.startsWith('KDATA') ||
string.startsWith('KSTRING')
);
return isData ?
(
string.startsWith('KDATA') ?
JSON.parse(atob(string.replace(/^KDATA/,''))) :
atob(string.replace(/^KSTRING/,''))
) :
string;
}
};
/**
* Encodes data in Base64. This is useful for passing roll information to action buttons called from roll buttons.
* @function
* @param {string|object|any[]} data - The data that you want to Base64 encode
* @returns {string} - The encoded data
* @memberof! Utilities
*/
const escape = RE.escape;
/**
* Decodes Base64 encoded strings that were created by the K-scaffold
* @function
* @param {string|object|any[]} string - The string of encoded data to decode. If this is not a string, or is not a string that was encoded by the K-scaffold, it will be returned as is.
* @returns {string|object|any[]}
* @memberof! Utilities
*/
const unescape = RE.unescape;
Object.assign(kFuncs,{escape,unescape});/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
//# Attribute Obj Proxy handler
const createAttrProxy = function(attrs,sections,casc){
//creates a proxy for the attributes object so that values can be worked with more easily.
const getCascObj = function(event){
const eventName = event.triggerName || event.sourceAttribute;
let typePrefix = eventName.startsWith('clicked:') ?
'act_' :
event.removedInfo ?
'fieldset_' :
'attr_';
let cascName = `${typePrefix}${eventName.replace(/(?:removed?|clicked):/,'')}`;
let cascObj = casc[cascName];
k.debug({[cascName]:cascObj});
if(event && cascObj){
if(event.previousValue){
cascObj.previousValue = event.previousValue;
}else if(event.originalRollId){
cascObj.originalRollId = event.originalRollId;
cascObj.rollData = RE.unescape(event.originalRollId);
}
}
return cascObj || {};
};
const triggerFunctions = function(obj){
if(obj.triggeredFuncs && obj.triggeredFuncs.length){
debug(`triggering functions for ${obj.name}`);
obj.triggeredFuncs && obj.triggeredFuncs.forEach(func=>funcs[func] ?
funcs[func]({trigger:obj,attributes,sections,casc}) :
debug(`!!!Warning!!! no function named ${func} found. Triggered function not called for ${obj.name}`,true));
}
};
const initialFunction = function(obj){
if(obj.initialFunc){
debug(`initial functions for ${obj.name}`);
funcs[obj.initialFunc] ?
funcs[obj.initialFunc]({trigger:obj,attributes,sections}) :
debug(`!!!Warning!!! no function named ${obj.initialFunc} found. Initial function not called for ${obj.name}`,true);
}
};
const alwaysFunctions = function(trigger){
Object.values(allHandlers).forEach((handler)=>{
handler({trigger,attributes,sections,casc});
});
};
const processChange = function({event,trigger}){
if(event && !trigger){
debug(`${event.sourceAttribute} change detected. No trigger found`);
return;
}
if(!attributes || !sections || !casc){
debug(`!!! Insufficient arguments || attributes > ${!!attributes} | sections > ${!!sections} | casc > ${!!casc} !!!`);
return;
}
debug({trigger});
if(event){
debug('checking for initial & always functions');
if(Array.isArray(trigger.affects)){
attributes.queue.push(...trigger.affects);
}
alwaysFunctions(trigger,attributes,sections,casc);//Functions that should be run for all events.
initialFunction(trigger,attributes,sections,casc);//functions that should only be run if the attribute was the thing changed by the user
}
if(trigger){
debug(`processing ${trigger.name}`);
triggerFunctions(trigger,attributes,sections,casc);
if(!event && trigger.calculation && funcs[trigger.calculation]){
attributes[trigger.name] = funcs[trigger.calculation]({trigger,attributes,sections,casc});
}else if(trigger.calculation && !funcs[trigger.calculation]){
debug(`K-Scaffold Error: No function named ${trigger.calculation} found`);
}
}
attributes.set();
};
const attrTarget = {
updates:{},
attributes:{...attrs},
repOrders:{},
queue: [],
casc:{},
alwaysFunctions,
processChange,
triggerFunctions,
initialFunction,
getCascObj
};
const attrHandler = {
get:function(obj,prop){//gets the most value of the attribute.
//If it is a repeating order, returns the array, otherwise returns the update value or the original value
if(prop === 'set'){
return function(){
let {callback,vocal} = arguments[0] ? arguments[0] : {};
if(sections && casc && attributes.queue.length){
const triggerName = attributes.queue.shift();
const trigger = getCascObj({sourceAttribute:triggerName});
processChange({trigger,attributes,sections,casc});
}else{
debug({updates:obj.updates});
const trueCallback = Object.keys(obj.repOrders).length ?
function(){
Object.entries(obj.repOrders).forEach(([section,order])=>{
_setSectionOrder(section,order)
});
callback && callback();
}:
callback;
Object.keys(obj.updates).forEach((key)=>obj.attributes[key] = obj.updates[key]);
const update = obj.updates;
obj.updates = {};
set(update,vocal,trueCallback);
}
}
}else if(Object.keys(obj).some(key=>key===prop)){
return Reflect.get(...arguments)
}else{
let retValue;
switch(true){
case obj.repOrders.hasOwnProperty(prop):
retValue = obj.repOrders[prop];
break;
case obj.updates.hasOwnProperty(prop):
retValue = obj.updates[prop];
break;
default:
retValue = obj.attributes[prop];
break;
}
let cascRef = `attr_${prop.replace(/(repeating_[^_]+_)[^_]+/,'$1\$X')}`;
let numRetVal = +retValue;
if(!Number.isNaN(numRetVal) && retValue !== ''){
retValue = numRetVal;
}else if(cascades[cascRef] && (typeof cascades[cascRef].defaultValue === 'number' || cascades[cascRef].type === 'number')){
retValue = cascades[cascRef].defaultValue;
}
return retValue;
}
},
set:function(obj,prop,value){
//Sets the value. Also verifies that the value is a valid attribute value
//e.g. not undefined, null, or NaN
if(value || value===0 || value===''){
if(/reporder|^repeating_[^_]+$/.test(prop)){
let section = prop.replace(/_reporder_/,'');
obj.repOrders[section] = value;
}else if(`${obj.attributes}` !== `${value}` ||
(obj.updates[prop] && `${obj.updates}` !== `${value}`)
){
if(sections && casc){
const trigger = getCascObj({sourceAttribute:prop});
if(Array.isArray(trigger.affects)){
attributes.queue.push(...trigger.affects);
}
}
obj.updates[prop] = value;
}
}else{
debug(`!!!Warning: Attempted to set ${prop} to an invalid value:${value}; value not stored!!!`);
}
return true;
},
deleteProperty(obj,prop){
//removes the property from the original attributes, updates, and the reporders
Object.keys(obj).forEach((key)=>{
delete obj[key][prop.toLowerCase()];
});
}
};
const attributes = new Proxy(attrTarget,attrHandler);
return attributes;
};
/**
* Function that registers a function for being called via the funcs object. Returns true if the function was successfully registered, and false if it could not be registered for any reason.
* @memberof Utilities
* @param {object} funcObj - Object with keys that are names to register functions under and values that are functions.
* @param {object} optionsObj - Object that contains options to use for this registration.
* @param {string[]} optionsObj.type - Array that contains the types of specialized functions that apply to the functions being registered. Valid types are `"opener"`, `"updater"`, and `"default"`. `"default"` is always used, and never needs to be passed.
* @returns {boolean} - True if the registration succeeded, false if it failed.
* @example
* //Basic Registration
* const myFunc = function({trigger,attributes,sections,casc}){};
* k.registerFuncs({myFunc});
*
* //Register a function to run on sheet open
* const openFunc = function({trigger,attributes,sections,casc}){};
* k.registerFuncs({openFunc},{type:['opener']})
*
* //Register a function to run on all events
* const allFunc = function({trigger,attributes,sections,casc}){};
* k.registerFuncs({allFunc},{type:['all']})
*/
const registerFuncs = function(funcObj,optionsObj = {}){
if(typeof funcObj !== 'object' || typeof optionsObj !== 'object'){
debug(`!!!! K-scaffold error: Improper arguments to register functions !!!!`);
return false;
}
const typeArr = optionsObj.type ? ['default',...optionsObj.type] : ['default'];
const typeSwitch = {
'opener':openHandlers,
'updater':updateHandlers,
'new':initialSetups,
'all':allHandlers,
'default':funcs
};
let setState;
Object.entries(funcObj).map(([prop,value])=>{
typeArr.forEach((type)=>{
if(typeSwitch[type][prop]){
debug(`!!! Duplicate function name for ${prop} as ${type}!!!`);
setState = false;
}else if(typeof value === 'function'){
typeSwitch[type][prop] = value;
setState = setState !== false ? true : false;
}else{
debug(`!!! K-scaffold error: Function registration requires a function. Invalid value to register as ${type} !!!`);
setState = false;
}
});
});
return setState;
};
kFuncs.registerFuncs = registerFuncs;
/**
* Function that sets up the action calls used in the roller mixin.
* @memberof Sheetworkers
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
*/
const setActionCalls = function({attributes,sections}){
actionAttributes.forEach((base)=>{
let [section,,field] = k.parseTriggerName(base);
let fieldAction = field.replace(/_/g,'-');
if(section){
sections[section].forEach((id)=>{
attributes[`${section}_${id}_${field}`] = `%{${attributes.character_name}|${section}_${id}_${fieldAction}}`;
});
}else{
attributes[`${field}`] = `%{${attributes.character_name}|${fieldAction}}`;
}
});
};
funcs.setActionCalls = setActionCalls;
kFuncs.setActionCalls = setActionCalls;
/**
* Function to call a function previously registered to the funcs object. May not be used that much in actual sheets, but very useful when writing unit tests for your sheet. Either returns the function or null if no function exists.
* @memberof Sheetworkers
* @param {string} funcName - The name of the function to invoke.
* @param {...any} args - The arguments to call the function with.
* @returns {function|null}
* @example
* //Call myFunc with two arguments
* k.callFunc('myFunc','an argument','another argument');
*/
const callFunc = function(funcName,...args){
if(funcs[funcName]){
debug(`calling ${funcName}`);
return funcs[funcName](...args);
}else{
debug(`Invalid function name: ${funcName}`);
return null;
}
};
kFuncs.callFunc = callFunc;/**@namespace Sheetworkers */
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
//Sheet Updaters and styling functions
const updateSheet = function(){
log('updating sheet');
getAllAttrs({props:['debug_mode',...baseGet],callback:(attributes,sections,casc)=>{
kFuncs.debugMode = kFuncs.debugMode || !!attributes.debug_mode;
debug({sheet_version:attributes.sheet_version});
if(!attributes.sheet_version){
Object.entries(initialSetups).forEach(([funcName,handler])=>{
if(typeof funcs[funcName] === 'function'){
debug(`running ${funcName}`);
funcs[funcName]({attributes,sections,casc});
}else{
debug(`!!!Warning!!! no function named ${funcName} found. Initial sheet setup not performed.`);
}
});
}else{
Object.entries(updateHandlers).forEach(([ver,handler])=>{
if(attributes.sheet_version < +ver){
handler({attributes,sections,casc});
}
});
}
k.debug({openHandlers});
Object.entries(openHandlers).forEach(([funcName,func])=>{
if(typeof funcs[funcName] === 'function'){
debug(`running ${funcName}`);
funcs[funcName]({attributes,sections,casc});
}else{
debug(`!!!Warning!!! no function named ${funcName} found. Sheet open handling not performed.`);
}
});
setActionCalls({attributes,sections});
attributes.sheet_version = kFuncs.version;
log(`Sheet Update applied. Current Sheet Version ${kFuncs.version}`);
attributes.set();
log('Sheet ready for use');
}});
};
const initialSetup = function(attributes,sections){
debug('Initial sheet setup');
};
/**
* This is the default listener function for attributes that the K-Scaffold uses. It utilizes the `triggerFuncs`, `listenerFunc`, `calculation`, and `affects` properties of the K-scaffold trigger object (see the Pug section of the scaffold for more details).
* @memberof Sheetworkers
* @param {Roll20Event} event - The Roll20 event object
* @returns {void}
* @example
* //Call from an attribute change
* on('change:an_attribute',k.accessSheet);
*/
const accessSheet = function(event){
debug({funcs:Object.keys(funcs)});
debug({event});
getAllAttrs({callback:(attributes,sections,casc)=>{
let trigger = attributes.getCascObj(event,casc);
attributes.processChange({event,trigger,attributes,sections,casc});
}});
};
funcs.accessSheet = accessSheet;/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
/*
Cascade Expansion functions
*/
//Expands the repeating section templates in cascades to reflect the rows actually available
const expandCascade = function(cascade,sections){
return _.keys(cascade).reduce((memo,key)=>{//iterate through cascades and replace references to repeating attributes with correct row ids.
if(/^(?:act|attr)_repeating_/.test(key)){//If the attribute is a repeating attribute, do special logic
expandRepeating(memo,key,cascade,sections);
}else if(key){//for non repeating attributes do this logic
expandNormal(memo,key,cascade,sections);
}
return memo;
},{});
};
const expandRepeating = function(memo,key,cascade,sections){
key.replace(/((?:attr|act)_)(repeating_[^_]+)_[^_]+?_(.+)/,(match,type,section,field)=>{
(sections[section]||[]).forEach((id)=>{
memo[`${type}${section}_${id}_${field}`]=_.clone(cascade[key]);//clone the details so that each row's attributes have correct ids
memo[`${type}${section}_${id}_${field}`].name = `${section}_${id}_${field}`;
if(key.startsWith('attr_')){
memo[`${type}${section}_${id}_${field}`].affects = memo[`${type}${section}_${id}_${field}`].affects.reduce((m,affected)=>{
if(section === affected){//otherwise if the affected attribute is in the same section, simply set the affected attribute to have the same row id.
m.push(applyID(affected,id));
}else if(/repeating/.test(affected)){//If the affected attribute isn't in the same repeating section but is still a repeating attribute, add all the rows of that section
addAllRows(affected,m,sections);
}else{//otherwise the affected attribute is a non repeating attribute. Simply add it to the computed affected array
m.push(affected);
}
return m;
},[]);
}
});
});
};
const applyID = function(affected,id){
return affected.replace(/(repeating_[^_]+_)[^_]+(.+)/,`$1${id}$2`);
};
const expandNormal = function(memo,key,cascade,sections){
memo[key] = _.clone(cascade[key]);
if(key.startsWith('attr_')){
memo[key].affects = memo[key].affects || [];
memo[key].affects = memo[key].affects.reduce((m,a)=>{
if(/^repeating/.test(a)){
addAllRows(a,m,sections);
}else{
m.push(a);
}
return m;
},[]);
}
};
const addAllRows = function(affected,memo,sections){
affected.replace(/(repeating_[^_]+?)_[^_]+?_(.+)/,(match,section,field)=>{
sections[section].forEach(id=>memo.push(`${section}_${id}_${field}`));
});
};/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
/**
* These are functions that provide K-scaffold aliases for the basic Roll20 sheetworker functions. These functions also provide many additional features on top of the standard Roll20 sheetworkers.
* @namespace Sheetworkers.Sheetworker Aliases
*/
/**
* Alias for [setSectionOrder()](https://wiki.roll20.net/Sheet_Worker_Scripts#setSectionOrder.28.3CRepeating_Section_Name.3E.2C_.3CSection_Array.3E.2C_.3CCallback.3E.29) that allows you to use the section name in either `repeating_section` or `section` formats. Note that the Roll20 sheetworker [setSectionOrder](https://wiki.roll20.net/Sheet_Worker_Scripts#setSectionOrder.28.3CRepeating_Section_Name.3E.2C_.3CSection_Array.3E.2C_.3CCallback.3E.29) currently causes some display issues on sheets.
* @memberof Sheetworker Aliases
* @name setSectionOrder
* @param {string} section - The name of the section, with or without `repeating_`
* @param {string[]} order - Array of ids describing the desired order of the section.
* @returns {void}
* @example
* //Set the order of a repeating_weapon section
* k.setSectionOrder('repeating_equipment',['id1','id2','id3']);
* //Can also specify the section name without the repeating_ prefix
* k.setSectionOrder('equipment',['id1','id2','id3']);
*/
const _setSectionOrder = function(section,order){
let trueSection = section.replace(/repeating_/,'');
setSectionOrder(trueSection,order);
};
kFuncs.setSectionOrder = _setSectionOrder;
/**
* Alias for [removeRepeatingRow](https://wiki.roll20.net/Sheet_Worker_Scripts#removeRepeatingRow.28_RowID_.29) that also removes the row from the current object of attribute values and array of section IDs to ensure that erroneous updates are not issued.
* @memberof Sheetworker Aliases
* @name removeRepeatingRow
* @param {string} row - The row id to be removed
* @param {attributesProxy} attributes - The attribute values currently in memory
* @param {object} sections - Object that contains arrays of all the IDs in sections on the sheet indexed by repeating name.
* @returns {void}
* @example
* //Remove a repeating Row
* k.getAllAttrs({
* callback:(attributes,sections)=>{
* const rowID = sections.repeating_equipment[0];
* k.removeRepeatingRow(`repeating_equipment_${rowID}`,attributes,sections);
* console.log(sections.repeating_equipment); // => rowID no longer exists in the array.
* console.log(attributes[`repeating_equipment_${rowID}_name`]); // => undefined
* }
* })
*/
const _removeRepeatingRow = function(row,attributes,sections){
debug(`removing ${row}`);
Object.keys(attributes.attributes).forEach((key)=>{
if(key.startsWith(row)){
delete attributes[key];
}
});
let [,section,rowID] = row.match(/(repeating_[^_]+)_(.+)/,'');
sections[section] = sections[section].filter((id)=>id!==rowID);
removeRepeatingRow(row);
};
kFuncs.removeRepeatingRow = _removeRepeatingRow;
/**
* Alias for [getAttrs()](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29) that converts the default object of attribute values into an {@link attributesProxy} and passes that back to the callback function.
* @memberof Sheetworker Aliases
* @name getAttrs
* @param {string[]} [props=baseGet] - Array of attribute names to get the value of. Defaults to {@link baseGet} if not passed.
* @param {function(attributesProxy)} callback - The function to call after the attribute values have been gotten. An {@link attributesProxy} is passed to the callback.
* @example
* //Gets the attributes named in props.
* k.getAttrs({
* props:['attribute_1','attribute_2'],
* callback:(attributes)=>{
* //Work with the attributes as you would in a normal getAttrs, or use the superpowers of the K-scaffold attributes object like so:
* attributes.attribute_1 = 'new value';
* attributes.set();
* }
* })
*/
const _getAttrs = function({props=baseGet,callback}){
getAttrs(props,(values)=>{
const attributes = createAttrProxy(values);
callback(attributes);
});
};
kFuncs.getAttrs = _getAttrs;
/**
* Alias for [getAttrs()](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29) and [getSectionIDs](https://wiki.roll20.net/Sheet_Worker_Scripts#getSectionIDs.28section_name.2Ccallback.29) that combines the actions of both sheetworker functions and converts the default object of attribute values into an {@link attributesProxy}. Also gets the details on how to handle all attributes from the master {@link cascades} object and.
* @memberof Sheetworker Aliases
* @param {Object} args
* @param {string[]} [args.props=baseGet] - Array of attribute names to get the value of. Defaults to {@link baseGet} if not passed.
* @param {repeatingSectionDetails} sectionDetails - Array of details about a section to get the IDs for and attributes that need to be gotten.
* @param {function(attributesProxy,sectionObj,expandedCascade):void} args.callback - The function to call after the attribute values have been gotten. An {@link attributesProxy} is passed to the callback along with a {@link sectionObj} and {@link expandedCascade}.
* @example
* //Get every K-scaffold linked attribute on the sheet
* k.getAllAttrs({
* callback:(attributes,sections,casc)=>{
* //Work with the attributes as you please.
* attributes.some_attribute = 'a value';
* attributes.set();//Apply our change
* }
* })
*/
const getAllAttrs = function({props=baseGet,sectionDetails=repeatingSectionDetails,callback}){
getSections(sectionDetails,(repeats,sections)=>{
getAttrs([...props,...repeats],(values)=>{
const casc = expandCascade(cascades,sections);
const attributes = createAttrProxy(values,sections,casc);
orderSections(attributes,sections);
callback(attributes,sections,casc);
})
});
};
kFuncs.getAllAttrs = getAllAttrs;
/**
* Alias for [getSectionIDs()](https://wiki.roll20.net/Sheet_Worker_Scripts#getSectionIDs.28section_name.2Ccallback.29) that allows you to iterate through several functions at once. Also assembles an array of repeating attributes to get.
* @memberof Sheetworker Aliases
* @param {object[]} sectionDetails - Array of details about a section to get the IDs for and attributes that need to be gotten.
* @param {string} sectionDetails.section - The full name of the repeating section including the `repeating_` prefix.
* @param {string[]} sectionDetails.fields - Array of field names that need to be gotten from the repeating section
* @param {function(string[],sectionObj)} callback - The function to call once all IDs have been gotten and the array of repating attributes to get has been assembled. The callback is passed the array of repating attributes to get and a {@link sectionObj}.
* @example
* // Get some section details
* const sectionDetails = {
* {section:'repeating_equipment',fields:['name','weight','cost']},
* {section:'repeating_weapon',fields:['name','attack','damage']}
* };
* k.getSections(sectionDetails,(attributeNames,sections)=>{
* console.log(attributeNames);// => Array containing all row specific attribute names
* console.log(sections);// => Object with arrays containing the row ids. Indexed by section name (e.g. repeating_eqiupment)
* })
*/
const getSections = function(sectionDetails,callback){
let queueClone = _.clone(sectionDetails);
const worker = (queue,repeatAttrs=[],sections={})=>{
let detail = queue.shift();
getSectionIDs(detail.section,(IDs)=>{
sections[detail.section] = IDs;
IDs.forEach((id)=>{
detail.fields.forEach((f)=>{
repeatAttrs.push(`${detail.section}_${id}_${f}`);
});
});
repeatAttrs.push(`_reporder_${detail.section}`);
if(queue.length){
worker(queue,repeatAttrs,sections);
}else{
callback(repeatAttrs,sections);
}
});
};
if(!queueClone[0]){
callback([],{});
}else{
worker(queueClone);
}
};
kFuncs.getSections = getSections;
// Sets the attributes while always calling with {silent:true}
// Can be awaited to get the values returned from _setAttrs
/**
* Alias for [setAttrs()](https://wiki.roll20.net/Sheet_Worker_Scripts#setAttrs.28values.2Coptions.2Ccallback.29) that sets silently by default.
* @memberof Sheetworker Aliases
* @param {object} obj - The object containting attributes to set
* @param {boolean} [vocal=false] - Whether to set silently (default value) or not.
* @param {function()} [callback] - The callback function to invoke after the setting has been completed. No arguments are passed to the callback function.
* @example
* //Set some attributes silently
* k.setAttrs({attribute_1:'new value'})
* //Set some attributes and triggers listeners
* k.setAttrs({attribute_1:'new value',true})
* //Set some attributes and call a callback function
* k.setAttrs({attribute_1:'new value'},null,()=>{
* //Do something after the attribute is set
* })
*/
const set = function(obj,vocal=false,callback){
setAttrs(obj,{silent:!vocal},callback);
};
kFuncs.setAttrs = set;
const generateCustomID = function(string){
if(!string.startsWith('-')){
string = `-${string}`;
}
rowID = generateRowID();
let re = new RegExp(`^.{${string.length}}`);
return `${string}${rowID.replace(re,'')}`;
};
/**
* Alias for generateRowID that adds the new id to the {@link sectionObj}. Also allows for creation of custom IDs that conform to the section ID requirements.
* @memberof Sheetworker Aliases
* @name generateRowID
* @param {sectionObj} sections
* @param {string} [customText] - Custom text to start the ID with. This text should not be longer than the standard repeating section ID format.
* @returns {string} - The created ID
* @example
* k.getAllAttrs({
* callback:(attributes,sections,casc)=>{
* //Create a new row ID
* const rowID = k.generateRowID('repeating_equipment',sections);
* console.log(rowID);// => -p8rg908ug0suzz
* //Create a custom row ID
* const customID = k.generateRowID('repeating_equipment',sections,'custom');
* console.log(customID);// => -custom98uadj89kj
* }
* });
*/
const _generateRowID = function(section,sections,customText){
let rowID = customText ?
generateCustomID(customText) :
generateRowID();
section = section.match(/^repeating_[^_]+$/) ?
section :
`repeating_${section}`;
sections[section] = sections[section] || [];
sections[section].push(rowID);
return `${section}_${rowID}`;
};
kFuncs.generateRowID = _generateRowID;/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
const listeners = {};
/**
* The array of attribute names that the k-scaffold gets by default. Does not incude repeating attributes.
* @memberof Variables
* @var
* @type {array}
*/
const baseGet = Object.entries(cascades).reduce((memo,[attrName,detailObj])=>{
if(!/repeating/.test(attrName) && detailObj.type !== 'action'){
memo.push(detailObj.name);
}
if(detailObj.listener){
listeners[detailObj.listener] = detailObj.listenerFunc;
}
return memo;
},[]);
kFuncs.baseGet = baseGet;
const registerEventHandlers = function(){
on('sheet:opened',updateSheet);
debug({funcKeys:Object.keys(funcs),funcs});
//Roll20 change and click listeners
Object.entries(listeners).forEach(([event,funcName])=>{
if(funcs[funcName]){
on(event,funcs[funcName]);
}else{
debug(`!!!Warning!!! no function named ${funcName} found. No listener created for ${event}`,true);
}
});
log(`kScaffold Loaded`);
};
setTimeout(registerEventHandlers,0);//Delay the execution of event registration to ensure all event properties are present.
/**
* Function to add a repeating section when the add button of a customControlFieldset or inlineFieldset is clicked.
* @memberof Sheetworkers
* @param {object} event - The R20 event object
*/
const addItem = function(event){
let [,,section] = parseClickTrigger(event.triggerName);
section = section.replace(/add-/,'');
getAllAttrs({
callback:(attributes,sections,casc) => {
let row = _generateRowID(section,sections);
debug({row});
attributes[`${row}_name`] = '';
setActionCalls({attributes,sections});
const trigger = cascades[`fieldset_repeating_${section}`];
if(trigger){
if(trigger.addFuncs){
trigger.addFuncs.forEach((funcName) => {
if(funcs[funcName]){
funcs[funcName]({attributes,sections,casc,trigger});
}
});
}
if(Array.isArray(trigger.affects)){
attributes.queue.push(...trigger.affects);
}
}
attributes.set({attributes,sections,casc});
}
});
};
funcs.addItem = addItem;/**
* The default tab navigation function of the K-scaffold. Courtesy of Riernar. It will add `k-active-tab` to the active tab-container and `k-active-button` to the active button. You can either write your own CSS to control display of these, or use the default CSS included in `scaffold/_k.scss`. Note that `k-active-button` has no default CSS as it is assumed that you will want to style the active button to match your system.
* @memberof Sheetworkers
* @param {Object} trigger - The trigger object
* @param {object} attributes - The attribute values of the character
*/
const kSwitchTab = function ({ trigger, attributes }) {
const [container, tab] = (
trigger.name.match(/nav-tabs-(.+)--(.+)/) ||
[]
).slice(1);
$20(`[data-container-tab="${container}"]`).removeClass('k-active-tab');
$20(`[data-container-tab="${container}"][data-tab="${tab}"]`).addClass('k-active-tab');
$20(`[data-container-button="${container}"]`).removeClass('k-active-button');
$20(`[data-container-button="${container}"][data-button="${tab}"]`).addClass('k-active-button');
const tabInputName = `${container.replace(/\-/g,'_')}_tab`;
if(persistentTabs.indexOf(tabInputName) > -1){
attributes[tabInputName] = trigger.name;
}
}
registerFuncs({ kSwitchTab });
/**
* Sets persistent tabs to their last active state
* @memberof Sheetworkers
* @param {object} attributes - The attribute values of the character
*/
const kTabOnOpen = function({trigger,attributes,sections,casc}){
if(typeof persistentTabs === 'undefined') return;
persistentTabs.forEach((tabInput) => {
const pseudoTrigger = {name:attributes[tabInput]};
kSwitchTab({trigger:pseudoTrigger, attributes});
});
};
registerFuncs({ kTabOnOpen },{type:['opener']});
return kFuncs;
}());
const actionAttributes = ["strength_action","constitution_action","agility_action","intelligence_action","willpower_action","charisma_action","acrobatics_action","awareness_action","bartering_action","beast_lore_action","bluffing_action","bushcraft_action","crafting_action","evade_action","healing_action","hunting_&_fishing_action","languages_action","myths_&_legends_action","performance_action","persuasion_action","riding_action","seamanship_action","sleight_of_hand_action","sneaking_action","spot_hidden_action","swimming_action","axes_action","bows_action","brawling_action","crossbows_action","hammers_action","knives_action","slings_action","spears_action","staves_action","swords_action","repeating_secondary-skills_$X_action","repeating_abilities_$X_cast_action","shift_rest_action","death_saves_action","repeating_weapons_$X_action","base_skills_action","monster_attacks_action","repeating_attacks_$X_action","initiative_action","reset_action"];const characteristics = [{"name":"strength","label":"STR","condition":"exhausted","sheetworker":{"affects":["damage_bonus_strength","strength_base_chance","axes","brawling","crafting","hammers","spears","swords","repeating_secondary-skills_$X_skill_total","encumbrance_max"],"name":"strength","listener":"change:strength","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]}},{"name":"constitution","label":"CON","condition":"sickly","sheetworker":{"affects":["constitution_base_chance","repeating_secondary-skills_$X_skill_total","hit_points_max"],"name":"constitution","listener":"change:constitution","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]}},{"name":"agility","label":"AGL","condition":"dazed","sheetworker":{"affects":["damage_bonus_agility","agility_base_chance","movement","acrobatics","bows","crossbows","evade","hunting_&_fishing","knives","riding","sleight_of_hand","knives","riding","sleight_of_hand","slings","sneaking","staves","swimming","repeating_secondary-skills_$X_skill_total"],"name":"agility","listener":"change:agility","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]}},{"name":"intelligence","label":"INT","condition":"angry","sheetworker":{"affects":["intelligence_base_chance","awareness","beast_lore","bushcraft","healing","languages","myths_&_legends","seamanship","spot_hidden","repeating_secondary-skills_$X_skill_total"],"name":"intelligence","listener":"change:intelligence","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]}},{"name":"willpower","label":"WIL","condition":"scared","sheetworker":{"affects":["willpower_base_chance","willpower_points_max","repeating_secondary-skills_$X_skill_total"],"name":"willpower","listener":"change:willpower","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]}},{"name":"charisma","label":"CHA","condition":"disheartened","sheetworker":{"affects":["charisma_base_chance","bluffing","bartering","performance","persuasion","repeating_secondary-skills_$X_skill_total"],"name":"charisma","listener":"change:charisma","listenerFunc":"accessSheet","type":"number","defaultValue":"0","triggeredFuncs":[]}}];const conditions = ["exhausted","sickly","dazed","angry","scared","disheartened"];const attribute_secondaries = [{"name":"damage bonus strength","label":"Damage Bon. Str","span":{"name":"attr_damage_bonus_strength","class":"uppercase","value":"—","trigger":{"calculation":"calcDamageBonus","name":"damage_bonus_strength","type":"span","defaultValue":"—","triggeredFuncs":[],"affects":[]},"title":"@{damage_bonus_strength}","type":"span"}},{"name":"damage bonus agility","label":"Damage Bon. AGL","span":{"name":"attr_damage_bonus_agility","class":"uppercase","value":"—","trigger":{"calculation":"calcDamageBonus","name":"damage_bonus_agility","type":"span","defaultValue":"—","triggeredFuncs":[],"affects":[]},"title":"@{damage_bonus_agility}","type":"span"}}];const skills = [{"name":"acrobatics","label":"acrobatics","attr":"agl","attribute":"agility"},{"name":"awareness","label":"awareness","attr":"int","attribute":"intelligence"},{"name":"bartering","label":"bartering","attr":"cha","attribute":"charisma"},{"name":"beast lore","label":"beast_lore","attr":"int","attribute":"intelligence"},{"name":"bluffing","label":"bluffing","attr":"cha","attribute":"charisma"},{"name":"bushcraft","label":"bushcraft","attr":"int","attribute":"intelligence"},{"name":"crafting","label":"crafting","attr":"str","attribute":"strength"},{"name":"evade","label":"evade","attr":"agl","attribute":"agility"},{"name":"healing","label":"healing","attr":"int","attribute":"intelligence"},{"name":"hunting & fishing","label":"hunting_&_fishing","attr":"agl","attribute":"agility"},{"name":"languages","label":"languages","attr":"int","attribute":"intelligence"},{"name":"myths & legends","label":"myths_&_legends","attr":"int","attribute":"intelligence"},{"name":"performance","label":"performance","attr":"cha","attribute":"charisma"},{"name":"persuasion","label":"persuasion","attr":"cha","attribute":"charisma"},{"name":"riding","label":"riding","attr":"agl","attribute":"agility"},{"name":"seamanship","label":"seamanship","attr":"int","attribute":"intelligence"},{"name":"sleight of hand","label":"sleight_of_hand","attr":"agl","attribute":"agility"},{"name":"sneaking","label":"sneaking","attr":"agl","attribute":"agility"},{"name":"spot hidden","label":"spot_hidden","attr":"int","attribute":"intelligence"},{"name":"swimming","label":"swimming","attr":"agl","attribute":"agility"}];const weapon_skills = [{"name":"axes","attr":"str","attribute":"strength"},{"name":"bows","attr":"agl","attribute":"agility"},{"name":"brawling","attr":"str","attribute":"strength"},{"name":"crossbows","attr":"agl","attribute":"agility"},{"name":"hammers","attr":"str","attribute":"strength"},{"name":"knives","attr":"agl","attribute":"agility"},{"name":"slings","attr":"agl","attribute":"agility"},{"name":"spears","attr":"str","attribute":"strength"},{"name":"staves","attr":"agl","attribute":"agility"},{"name":"swords","attr":"str","attribute":"strength"}];const armor = [{"name":"armor","banes":["sneaking","evade","acrobatics"],"image":"https://files.d20.io/images/346041944/S5Qsjcp3Fj_VnKlLShv-hw/original.png"},{"name":"helmet","banes":["awareness","ranged attacks"],"image":"https://files.d20.io/images/346049175/Uv09LQO-CzNxChMNqF6gOA/original.png"}];const weapons = {"expanded":[{"type":"input","labelObj":{"inputObj":{"name":"attr_name","type":"text","data-i18n-placeholder":"New Weapon","class":"input-label__input","title":"@{repeating_weapons_$X_name}"},"spanObj":{"data-i18n":"name","class":"input-label__text"}}},{"type":"select","labelObj":{"inputObj":{"name":"attr_type","data-i18n-list":"weapon-section-type-order","class":"input-label__input","title":"@{repeating_weapons_$X_type}"},"spanObj":{"data-i18n":"type","class":"input-label__text"}},"options":[{"value":"-","selected":"","content":"-"},{"data-i18n":"melee","value":"melee"},{"data-i18n":"ranged","value":"ranged"}]},{"type":"select","labelObj":{"inputObj":{"name":"attr_skill","data-i18n-list":"weapon-section-skill-order","class":"input-label__input","title":"@{repeating_weapons_$X_skill}"},"spanObj":{"data-i18n":"skill","class":"input-label__text"}},"options":[{"value":"-","selected":"","content":"-"},{"value":"axes","data-i18n":"axes"},{"value":"bows","data-i18n":"bows"},{"value":"brawling","data-i18n":"brawling"},{"value":"crossbows","data-i18n":"crossbows"},{"value":"hammers","data-i18n":"hammers"},{"value":"knives","data-i18n":"knives"},{"value":"slings","data-i18n":"slings"},{"value":"spears","data-i18n":"spears"},{"value":"staves","data-i18n":"staves"},{"value":"swords","data-i18n":"swords"}]},{"type":"input","labelObj":{"inputObj":{"name":"attr_use_bonus","type":"checkbox","value":1,"checked":"","class":"input-label__input","title":"@{repeating_weapons_$X_use_bonus}"},"spanObj":{"data-i18n":"damage bonus","class":"input-label__text"}}},{"type":"select","labelObj":{"inputObj":{"name":"attr_grip","class":"uppercase input-label__input","data-i18n-list":"weapon-section-grip-order","title":"@{repeating_weapons_$X_grip}"},"spanObj":{"data-i18n":"grip","class":"input-label__text"}},"options":[{"value":"-","selected":"","content":"-"},{"data-i18n":"1h-abbreviation","value":1},{"data-i18n":"2h-abbreviation","value":2}]},{"type":"input","labelObj":{"inputObj":{"name":"attr_strength_requirement","type":"number","placeholder":"-","class":"input-label__input","title":"@{repeating_weapons_$X_strength_requirement}"},"spanObj":{"data-i18n":"strength-abbreviation","class":"input-label__text"}}},{"type":"input","labelObj":{"inputObj":{"name":"attr_range","type":"text","placeholder":"-","class":"input-label__input","title":"@{repeating_weapons_$X_range}"},"spanObj":{"data-i18n":"range","class":"input-label__text"}}},{"type":"input","labelObj":{"inputObj":{"name":"attr_damage","type":"text","class":"input-label__input","title":"@{repeating_weapons_$X_damage}"},"spanObj":{"data-i18n":"damage","class":"input-label__text"}}},{"type":"input","labelObj":{"inputObj":{"name":"attr_durability_max","type":"number","placeholder":"-","trigger":{"affects":["repeating_weapons_$X_durability"],"name":"repeating_weapons_$X_durability_max","listener":"change:repeating_weapons:durability_max","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"class":"input-label__input","title":"@{repeating_weapons_$X_durability|max}"},"spanObj":{"data-i18n":"durability","class":"input-label__text"}}},{"type":"input","labelObj":{"inputObj":{"name":"attr_properties","type":"text","class":"input-label__input","title":"@{repeating_weapons_$X_properties}"},"spanObj":{"data-i18n":"features","class":"input-label__text"}}}]};const specialCategories = {"Abilities":"Abilities (Förmågor)","abilities":"Abilities (Förmågor)","Armor":"Armor (Rustningar)","armor":"Armor (Rustningar)","Gear":"Gear (Utrustning)","gear":"Gear (Utrustning)","NPCs":"NPCs (SLP)","npcs":"NPCs (SLP)","Spells":"Spells (Besvärjelser)","spells":"Spells (Besvärjelser)","Weapons":"Weapons (Vapen)","weapons":"Weapons (Vapen)"};const itemCategories = ["Abilities","Armor","Gear","NPCs","Spells","Weapons"];const maxAttr = ["hit_points","willpower_points"];const sectionLookup = {"Internal":"internal-modules"};const coins = ["gold","silver","copper"];k.sheetName = 'Dragonbane';
k.version = 1.93;
/**
* Assembles the roll string from the roll object
* @param {object} rollObj - object describing the roll
* @param {string} [rollStart = '@{template_start}'] - The string to start the roll with.
* @returns {string}
*/
const assembleRoll = (rollObj, rollStart = "@{template_start}") => {
return Object.entries(rollObj).reduce((str, [field, content]) => {
return (str += content ? ` {{${field}=${content}}}` : "");
}, `${rollStart}`);
};
/**
* Executes the roll. Uses a callback if any computations are required.
* @param {object} rollObj - Object describing the roll fields to be used
* @param {object} attributes - The character attributes
* @param {object[]} sections - The sections array
* @returns {Promise<object[]>} - Resolves to array with index 0 being the roll results object and index 1 being the computeObj with success/panics precalculated.
*/
const executeRoll = async ({ rollObj, attributes,customString }) => {
const rollString = assembleRoll(rollObj, customString);
const roll = await startRoll(rollString);
const computeObj = {};
computeObj.push_through = assemblePushData(roll,attributes,rollObj);
return [roll, computeObj];
};
/**
* Assembles the d20 roll taking into account all banes/boons.
* @param {AttributesProxy} attributes - the attributs object from the K-scaffold
* @param {string} attribute - The attribute being rolled for.
* @param {string[]} [rollTypes = []] - additional roll types that describe this roll (e.g. 'ranged attack')
*/
const assembleD20 = ({attributes,characteristic,attribute,rollTypes = []}) => {
const bbSources = ['armor_sneaking_bane','armor_evade_bane','armor_acrobatics_bane','helmet_awareness_bane','helmet_ranged_attacks_bane'].reduce((acc,name) => {
if(
name.includes(attribute) ||
rollTypes.some(t => name.includes(t))
){
acc.push(name);
}
return acc;
},[]);
let boonBane = [...bbSources,'boons','banes'].reduce((total,source) => {
if(/bane/.test(source)){
total -= attributes[source];
}else{
total += attributes[source];
}
return total;
},0);
if(characteristic){
const charObj = characteristics.find(o => o.name === characteristic);
if(charObj){
boonBane -= attributes[charObj.condition];
}
}
const diceNum = 1 + Math.abs(boonBane);
const keep = boonBane ?
(
boonBane > 0 ?
'kl1' :
'kh1'
) :
'';
return `[[${diceNum}d20${keep}cs<1cf>20]]`;
};/**
* Processes the push information and constructs the roll to be pushed.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const pushRoll = async function({trigger,attributes,sections,casc}){
if(!trigger.originalRollId) return;
k.debug('pushing');
attributes.stress_level = Math.min(attributes.stress_level + 1, 10);
const pushData = k.unescape(trigger.originalRollId);
const [roll,computeObj] = await executeRoll({rollObj:pushData});
finishRoll(roll.rollId,computeObj);
};
k.registerFuncs({pushRoll});/**
* Assembles and encodes the push data.
* @param {object} results - The results details
* @param {object} rollObj - The object detailing the roll that was sent.
*/
const assemblePushData = (results,attributes,rollObj) => {
if(
rollObj.no_push ||
!attributes ||
(results && results.results && results.results && results.results.roll1 && results.results.roll1.result === 20) ||
!attributes.allow_push ||
conditions.every(c => attributes[c])
){
// If attributes argument wasn't passed, no push can be calculated
// if the roll was a demon, no push allowed
// If pushes are disabled, no push allowed
// If all conditions are checked, no push is allowed.
return 0;
}
const pushObj = Object.entries(rollObj).reduce((memo,[key,val]) => {
if(key !== 'push_through'){
memo[key] = val;
}
return memo;
},{});
const pushString = k.escape(pushObj);
return pushString;
};const possibleQueryTransKeys = ['power level'];
const assembleDamage = async (damage) => {
const dynamicRx = /(d\d+)\/([a-z\s]+)/;
const [,die,prompt] = damage.match(dynamicRx) || [];
const transPartialKey = prompt ?
possibleQueryTransKeys.find(k => k === prompt.toLowerCase()) :
undefined;
const translation = transPartialKey ?
getTranslationByKey(`power level prompt`) :
prompt ?
prompt :
undefined;
const dynamicResult = await (translation ?
k.extractQueryResult(translation) :
k.pseudoQuery(''));
return dynamicResult ?
`[[${damage.replace(dynamicRx,`${dynamicResult}${die}`)}]]` :
`[[${damage}]]`;
};/**
* Applies advancement checkmarks for rolled skills on a Dragon/Demon.
* @param {string} skillName - The skill attribute name (e.g. acrobatics)
* @param {object} rollObj - The object describing the results of the roll
* @param {AttributesProxy} attributes - The K-scaffold Attributes object.
*/
const markForAdvance = (skillName,rollObj,attributes) => {
if(
rollObj.roll1.result === 1 ||
rollObj.roll1.result === 20
){
attributes[`${skillName}_advancement`] = 1;
}
}/**
* Rolls death saves and sets the success/failure checkboxes
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollDeath = async function({trigger,attributes,sections,casc}){
const rollObj = {
label:'^{death roll}',
roll1:'[[1d20cs1cf20]]',
roll2:'[[1d20cs1cf20]]',
test:'[[@{constitution}]]'
};
const [deathRoll] = await executeRoll({rollObj});
finishRoll(deathRoll.rollId);
const deathProg = deathRoll.results.roll1.result === 1 ||
deathRoll.results.roll1.result === 20 ?
2 :
1;
if(deathRoll.results.roll1.result <= attributes.constitution){
attributes.death_saves_successes = Math.min(attributes.death_saves_successes + deathProg, 3);
}else{
attributes.death_saves_failures = Math.min(attributes.death_saves_failures + deathProg, 3);
}
attributes.set({callback(){
addSuccessHP({attributes});
}});
};
k.registerFuncs({rollDeath});/**
* Casts a spell or sends an ability's info to chat. Also handles rolling on effect tables for demon rolls on spell cast rolls.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const castSpell = async function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
const rollObj = {
label:attributes[`${row}_name`],
rank:attributes[`${row}_rank`],
cost:attributes[`${row}_cost`],
description:attributes[`${row}_description`],
push_through:'[[0[computed value]]]'
};
let spellCost;
if(attributes[`${row}_skill`] === 'magic trick'){
spellCost = await k.pseudoQuery(attributes[`${row}_cost`] || 1);
}else if(attributes[`${row}_spell`]){
const spellPower = await(
attributes[`${row}_spell_power`] ?
k.extractQueryResult(`${k.capitalize(getTranslationByKey('what power are you casting at'))}|1|2|3`) :
k.pseudoQuery(1)
);
spellCost = spellPower * attributes[`${row}_cost`];
}else{
spellCost = await k.pseudoQuery(attributes[`${row}_cost`]);
}
// Check if there is enough willpower to cast
const newWillpower = attributes.willpower_points - spellCost;
let skillRow
if(newWillpower < 0){
rollObj.label = `${rollObj.label}\n^{insufficient will}`;
}else{
attributes.willPower_points = newWillpower;
if(attributes[`${row}_spell`]){
['rank','requirement','casting_time','range','duration'].forEach(attr => rollObj[attr.replace(/_/g,' ')] = attributes[`${row}_${attr}`]);
if(attributes[`${row}_skill`] !== 'magic trick'){
// add test for casting spell
const skillID = attributes[`${row}_skill`] === 'general spell' ?
sections['repeating_secondary-skills'].reduce((highID,id) => {
const idRow = `repeating_secondary-skills_${id}`;
const highRow = `repeating_secondary-skills_${id}`;
if(attributes[`${idRow}_total`] > attributes[`${highRow}_total`]){
highID = id;
}
return highID;
}) :
attributes[`${row}_skill`];
skillRow = `repeating_secondary-skills_${skillID}`;
rollObj.roll1 = assembleD20({attributes,characteristic:attributes[`${skillRow}_attribute_select`],attribute:row});
rollObj.test = `[[${attributes[`${skillRow}_total`]}]]`;
rollObj.dragonResult = `[[0[computed result]]]`
}
}
}
const [spellRoll,computeObj] = await executeRoll({rollObj,attributes});
if(rollObj.roll1){
computeObj.dragonResult = spellRoll.results.roll1.result === 1 ?
1 :
0;
}
finishRoll(spellRoll.rollId,computeObj);
if(rollObj.roll1){
// handle the spell cast roll result
const result = spellRoll.results.roll1.result;
markForAdvance(skillRow,spellRoll.results,attributes);
if(result === 1){
// Dragon handling
await k.pseudoQuery();//These pseudoQueries are here to ensure that we always await a roll on either side of logic. If we don't do this, the character sheet will disconnect from the roll20 setup.
}else if(result === 20){
// Demon Handling
if(attributes.magical_mishaps){
// magical mishap handling
await rollMishap({row,attributes,sections,casc});
}else{
await k.pseudoQuery();
}
}
}else{
await k.pseudoQuery();
}
attributes.set();
};
k.registerFuncs({castSpell});
/**
* Rolls on the magical mishap table (pg 60) when a demon is rolled when casting a spell.
* @param {string} row - The row string for the spell that was cast
* @param {AttributesProxy} attributes - the k-scaffold attributes object
* @param {object} sections - the k-scaffold sections object
* @param {object} casc - the k-scaffold expanded cascade object
*/
const rollMishap = async ({row,attributes,sections,casc}) => {
const tableRoll = await startRoll('!{{table=[[1d20]]}}');
finishRoll(tableRoll.rollId);
const tableResult = tableRoll.results.table.result;
const complexResults = {
'7':mishap7,
'8':mishap8,
'9':mishap9,
'10':mishap10,
'17':mishap17
};
const description = await (complexResults[tableResult] ?
complexResults[tableResult](row,attributes) :
k.pseudoQuery(`^{mishap-${tableResult}}`)
);
const rollObj = {
label:`${attributes[`${row}_name`]} - ^{mishap}`,
roll1:`[[${tableResult}[computed result]]]`,
description
};
const [mishapRoll] = await executeRoll({rollObj});
finishRoll(mishapRoll.rollId);
};
// Complex mishap handlers
const mishap7 = async (row,attributes) => {
const mishapRoll = await startRoll(`!{{roll=[[${attributes[`${row}_rank`]}d6]]}}`);
finishRoll(mishapRoll.rollId);
attributes.hit_points = Math.max(attributes.hit_points - mishapRoll.results.roll.result, 0);
return `^{mishap-7}: [[${mishapRoll.results.roll.result}]]`;
};
const mishap8 = async (row,attributes) => {
const mishapRoll = await startRoll(`!{{roll=[[${attributes[`${row}_rank`]}d6]]}}`);
finishRoll(mishapRoll.rollId);
attributes.willpower_points = Math.max(attributes.willpower_points - mishapRoll.results.roll.result, 0);
return `^{mishap-8}: [[-${mishapRoll.results.roll.result}]]`;
};
const mishap9 = async (row,attributes) => {
const mishapRoll = await startRoll(`!{{roll=[[3d6]]}}`);
finishRoll(mishapRoll.rollId);
return `^{mishap-9}: [[${mishapRoll.results.roll.result}]]`;
};
const mishap10 = async (row,attributes,sections) => {
const spells = sections.repeating_abilities.reduce((arr,id) => {
const spellRow = `repeating_abilities_${id}`;
if(attributes[`${spellRow}_spell`]){
arr.push(id);
}
return arr;
},[]);
const mishapRoll = await startRoll(`!{{roll=[[1d${spells.length}]]}}`);
finishRoll(mishapRoll.rollId);
const randomRow = `repeating_abilities_${spells[mishapRoll.results.roll.result]}`;
return `^{mishap-10}: [${attributes[`${randomRow}_name`]}](~${attributes.character_name}|${randomRow}_describe)`;
};
const mishap17 = async (row,attributes) => {
const mishapRoll = await startRoll(`!{{roll=[[1d6 - 1]]}}`);
finishRoll(mishapRoll.rollId);
const animals = ['cat','fox','goat','wolf','deer','bear'];
return `^{mishap-17}: ^{${animals[mishapRoll.results.roll.result]}}`;
};/**
* Rolls an attack roll for a PC/NPCs weapon.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollAttack = async function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
const skillName = attributes[`${row}_skill`];
const weaponSkillObj = weapon_skills.find(o => o.name === skillName);
const weaponAttribute = weaponSkillObj.attribute;
const rollObj = {
label:attributes[`${row}_name`],
roll1:assembleD20({attributes,characteristic:weaponAttribute,attribute:row,rollTypes:[attributes[`${row}_type`],attributes[`${row}_skill`]]}),
description:attributes[`${row}_description`],
push_through:'[[0[computed value]]]'
};
rollObj.test = skillName ?
attributes[skillName] :
0;
if(attributes[`${row}_damage`]){
const damageBonus =
attributes[`${row}_use_bonus`] && attributes[`damage_bonus_${weaponAttribute}`] && attributes[`damage_bonus_${weaponAttribute}`].startsWith('d') ?
`+ ${attributes[`damage_bonus_${weaponAttribute}`]}` :
'';
rollObj.damage = await assembleDamage(`${attributes[`${row}_damage`]}${damageBonus}`);
}
const [attackRoll,computeObj] = await executeRoll({rollObj,attributes});
finishRoll(attackRoll.rollId,computeObj);
markForAdvance(skillName,attackRoll.results,attributes);
attributes.set();
};
k.registerFuncs({rollAttack});/**
* Rolls skill checks
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollSkill = async function({trigger,attributes,sections,casc}){
const [section,rowID,base] = k.parseTriggerName(trigger.name);
const row = section ?
`${section}_${rowID}_` :
'';
const skillName = section ?
attributes[`${row}name`] :
base.replace(/-/g,' ').replace(/ action/,'');
const skillObj = section ?
{attribute:attributes[`${row}attribute_select`] } :
[...skills,...weapon_skills].find(o => o.name === skillName);
const rollObj = {
label:section ? skillName : `^{${skillName}}`,
roll1:skillObj ?
assembleD20({attributes,characteristic:skillObj.attribute,attribute:skillName.replace(/ /g,'_')}) :
assembleD20({attributes,attribute:skillName}),
test: section ?
attributes[`${row}total`] :
attributes[skillName.replace(/ /g,'_')],
push_through:'[[0[computed value]]]'
};
const [skillRoll,computeObj] = await executeRoll({rollObj,attributes});
finishRoll(skillRoll.rollId,computeObj);
const advanceName = row ?
row.replace(/_$/,'') :
skillName.replace(/ /g,'_');
markForAdvance(advanceName,skillRoll.results,attributes);
attributes.set();
};
k.registerFuncs({rollSkill});/**
* Rolls a specific monster attack
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollMonsterAttack = async function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
const subTableRoll = !attributes[`${row}_subtable`] ?
Math.ceil(Math.random() * 6) :
0;
const tablePossibles = [1,2,3,4,5,6].reduce((arr,n,i) => {
const weight = attributes[`${row}_subtable_weight_${n}`];
if(weight){
Array.from({length: weight}, (_, i) => i + 1).forEach(n => arr.push(i + 1));
}
return arr;
},[]);
const subTableRow = subTableRoll ?
(tablePossibles.find((n,i) => {
return subTableRoll <= (i + 1);
}) || 0) :
0;
const rollObj = {
label:attributes[`${row}_name`],
damage: await (attributes[`${row}_damage`] ?
(
subTableRow ?
(
attributes[`${row}_subtable_damage_${subTableRow}`] ?
assembleDamage(`${attributes[`${row}_subtable_damage_${subTableRow}`]}`) :
(
attributes[`${row}_damage`] ?
assembleDamage(`${attributes[`${row}_damage`]}`) :
k.pseudoQuery()
)
) :
assembleDamage(`${attributes[`${row}_damage`]}`)
) :
k.pseudoQuery('')),
description:`${attributes[`${row}_description`]}${subTableRow ? `\n\n**${attributes[`${row}_subtable_name_${subTableRow}`]}:** ${attributes[`${row}_subtable_description_${subTableRow}`]}` : ''}`
};
const [attackRoll] = await executeRoll({rollObj});
finishRoll(attackRoll.rollId);
};
k.registerFuncs({rollMonsterAttack});/**
* Rolls a random monster attack
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollRandomAttack = function({trigger,attributes,sections,casc}){
const attacks = sections.repeating_attacks.reduce((arr,id,i) => {
const weight = attributes[`repeating_attacks_${id}_weight`];
if(weight){
Array.from({length: weight}, (_, i) => i + 1).forEach(n => arr.push(id));
}
return arr;
},[]);
const randIndex = Math.floor(Math.random() * attacks.length);
const attackTrigger = {name:`repeating_attacks_${attacks[randIndex]}_action`};
rollMonsterAttack({trigger:attackTrigger,attributes,sections,casc});
};
k.registerFuncs({rollRandomAttack});/**
* "rolls" the initiative for a given token
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollInitiative = async function({trigger,attributes,sections,casc}){
debugger;
const availableCards = `${attributes.cards}`.trim().split(/\s*,\s*/);
const rollObj = {
label:'^{initiative}',
character_name:`@{selected|character_name}`,
character_id:`@{selected|character_id}`,
no_push:1
};
const { ferocity,character_name,lightning_fast:lightningFast } = await extractAttributes({cName:'selected',attributeNames:['ferocity','character_name','lightning_fast']});
if(
typeof ferocity !== 'number' ||
/^selected\|character_name/.test(character_name)
){
return;
}
const ferArr = [...Array(ferocity || 1).keys()];
if(availableCards.length >= ferArr.length){
rollObj.roll1 = `[[0[computed roll]]]`;
ferArr.forEach(i => {
rollObj[`initiative${i}`] = `[[${lightningFast + 1}d${availableCards.length - i}]]`;
})
}else{
rollObj.description = `^{no more cards}\n[^{reset initiative}](~${attributes.character_name}|reset)`;
}
const [attackRoll,computeObj] = await executeRoll({rollObj,attributes});
if(rollObj.roll1){
const cards = [];
let lighningUsed = false;
await Promise.all(
ferArr.map(async i => {
let rolledI;
const iRoll = attackRoll.results[`initiative${i}`];
const indices = iRoll.dice.map(d => d - 1);
if(indices.length > 1 && !lighningUsed){
rolledI = Math.min(...indices);
lightningUsed = true;
}else{
rolledI = await k.pseudoQuery(indices[0]);
}
cards.push(availableCards.splice(rolledI,1));
})
);
computeObj.roll1 = cards.join('/');
attributes.cards = availableCards.length ?
availableCards.join(',') :
' ';
addToInitiative(attributes,cards,character_name,sections,casc);
}
finishRoll(attackRoll.rollId,computeObj);
};
k.registerFuncs({rollInitiative});
// Adds the drawn initiative to the tracker and sorts the tracker.
const addToInitiative = async (attributes,cards,character_name,sections,casc) => {
// sort the cards
cards.sort((a,b) => a - b);
sections.repeating_initiative.forEach(id => {
if(attributes[`repeating_initiative_${id}_name`] === character_name){
k.removeRepeatingRow(`repeating_initiative_${id}`,attributes,sections);
}
});
sortInitiative({sections,attributes,character_name,cards});
filterInitiativeDeck(attributes,sections);
if(attributes.use_roll20_initiative){
startRoll(`!{{initiative=[[${cards[0]}&{tracker}]]}}`,r=>finishRoll(r.rollId));
}
attributes.set();
};
/**
*
* @param {string} [cName] - The name of the character to extract attributes from. pass 'selected' if you want to get attributes from a currently selected token. Pass 'target` if you want to get attributes from a targeted token. Attribute values are coerced to numbers if they are not NaN.
* @param {string[]} attributeNames - An array of attribute names to get.
* @param {string[]} rollValues - Array of rolls to make and extract the value of.
* @returns {Promise<object>} - Promise that resolves to an object of attribute names similar to the attributes object of the K-scaffold, but it is static.
*/
const extractAttributes = async ({cName,attributeNames,rollValues = []}) => {
const rollString = attributeNames.reduce((str,name,i) => {
str += rollValues[i] ?
`{{${name}=[[${rollValues[i]}]]}}` :
`{{${name}=[[0[response=@{${cName ? `${cName}|`:''}${name}}]]]}}`;
return str
},'!');
const r = await startRoll(rollString);
finishRoll(r.rollId);
const results = r.results;
const resReturn = Object.entries(results).reduce((obj,[key,resObj]) => {
const keyI = attributeNames.indexOf(key);
obj[key] = rollValues[keyI] ?
resObj.result :
resObj.expression.replace(/^.+?response=|\]$/g,'');
if(!isNaN(obj[key])){
obj[key] = +obj[key];
}
return obj;
},{});
return resReturn;
};/**
* Rolls attribute checks
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const rollAttribute = async function({trigger,attributes,sections,casc}){
const attributeName = trigger.name.replace(/-/g,' ').replace(/ action/,'');
const rollObj = {
label:`^{${attributeName}}`,
roll1: assembleD20({attributes,characteristic:attributeName}),
test: attributes[attributeName.replace(/ /g,'_')],
push_through:'[[0[computed value]]]'
};
const [attributeRoll,computeObj] = await executeRoll({rollObj,attributes});
finishRoll(attributeRoll.rollId,computeObj);
};
k.registerFuncs({rollAttribute});
/**
* Upgrades the sheet to version 1.1
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const v1x1 = function({trigger,attributes,sections,casc}){
// update willpower
['willpower_points','hit_points'].forEach(name => {
const oValue =attributes[`${name}_max`];
attributes[`${name}_max`] = calcPoints({trigger:{name:`${name}_max`},attributes,sections,casc});
const valDiff = oValue - attributes[`${name}_max`];
if(valDiff){
attributes[`${name}_bonus`] = valDiff;
}
attributes[`${name}_max`] = oValue;
});
// update encumbrance
attributes.encumbrance = calcEncumbrance({trigger,attributes,sections});
// update weapon skills
// Using getAttrs to get the old weapon skill attribute names
const v1WeaponSkills = weapon_skills.map(o => `${o.name}_skill_levels`);
k.getAttrs({
props:v1WeaponSkills,
callback(v1Attrs){
weapon_skills.forEach(o =>{
attributes[`${o.name}_levels`] = v1Attrs[`${o.name}_skill_levels`];
});
// Set the attributes using the attributes object from the main thread. This will cause the calculations dependent on these changes to fire.
attributes.set();
}
})
};
k.registerFuncs({'1.1':v1x1},{type:['updater']});/**
* Upgrades the sheet to v1.2 from v1.1
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const v1x3 = function({trigger,attributes,sections,casc}){
attributes.damage_bonus_agility = calcDamageBonus({trigger:{name:'damage_bonus_agility'},attributes,sections,casc});
attributes.damage_bonus_strength = calcDamageBonus({trigger:{name:'damage_bonus_strength'},attributes,sections,casc});
attributes.deck_size = calcDeckSize({attributes,sections,casc});
};
k.registerFuncs({'1.3':v1x3},{type:['updater']});/**
*
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const v1x5 = function({trigger,attributes,sections,casc}){
attributes.encumbrance_max = calcEncumbranceMax({attributes,sections,casc});
k.getAttrs({
props:['apperance'],
callback(v){
if(v.appearance){
attributes.appearance = `${attributes.appearance}\n${v.appearance}`;
}
attributes.set();
}})
};
k.registerFuncs({'1.5':v1x5},{type:['updater']});/**
* Updates to version 1.9. Converts weights to die rolls for monster attacks.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const v1x9 = function({trigger,attributes,sections,casc}){
if(!sections.repeating_attacks.length) return;
let lastResult = 0;
sections.repeating_attacks.forEach(id => {
const row =`repeating_attacks_${id}`;
[attributes[`${row}_result`],lastResult] = calcDieResults(attributes[`${row}_weight`],lastResult);
let subtableLastResult = 0;
[1,2,3,4,5,6].forEach(n => {
[attributes[`${row}_subtable_result_${n}`],subtableLastResult] = calcDieResults(attributes[`${row}_subtable_weight_${n}`],subtableLastResult);
});
});
};
// registered as updater and new because previously dropped npcs did not get their sheet version assigned correctly.
k.registerFuncs({'1.9':v1x9},{type:['updater','new']});
/**
* Calculates die results based on their weight
* @param {number} weight - The existing weight for the object
* @param {number} lastResult - What the last die result was
* @returns {array} - [dieResults,newLastResult]
*/
const calcDieResults = (weight,lastResult) => {
const resultStart = lastResult + 1;
const resultEnd = resultStart + weight - 1;
const newEnd = resultEnd;
const resultString = resultEnd !== resultStart ?
`${resultStart} - ${resultEnd}` :
`${resultStart}`;
return [resultString,newEnd];
};
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
const handleCompendiumDrop = function(event){
k.debug({event});
k.getAllAttrs({
callback:async (attributes,sections,casc)=>{
clearDropAttributes();
let data = await parseDropData(attributes.drop_data,attributes,sections,casc);
if(!data) return;
k.debug({data});
compendiumLookup({
origBlock:data,
attributes,sections,casc,
callback:async (lookupObj)=>{
k.debug({'threat data':data});
await processDropData({data:lookupObj,attributes,sections,casc});
k.debug('Drop processing complete');
// Handle spell association with secondary skill
const spellSchools = ['animism','elementalism','mentalism'];
sections.repeating_abilities.forEach(id => {
const row = `repeating_abilities_${id}`;
if(
attributes.updates[`${row}_spell`] &&
attributes[`${row}_skill`] &&
attributes[`${row}_skill`] !== 'magic trick' &&
attributes[`${row}_skill`] !== 'general spell'
){
const expectedName =
getTranslationByKey(attributes[`${row}_skill`]) ?
attributes[`${row}_skill`] :
spellSchools.find(school => getTranslationByKey(school).toLowerCase() ===attributes[`${row}_skill`].toLowerCase());
attributes[`${row}_skill`] = sections['repeating_secondary-skills'].find(skillID => {
const skillRow = `repeating_secondary-skills_${skillID}`;
return attributes[`${skillRow}_name`].toLowerCase() === getTranslationByKey(expectedName).toLowerCase();
});
attributes[`${row}_skill`] = attributes[`${row}_skill`].toLowerCase();
}
})
// Ensure that dropped values don't get reset by other calculations
const updateKeys = Object.keys(lookupObj);
const iterateQueue = [...attributes.queue];
iterateQueue.forEach((q,i) =>{
if(updateKeys.includes(`data-cs-${q}`)){
const qI = attributes.queue.indexOf(q);
attributes.queue.splice(qI,1);
}
});
k.callFunc('setupMagicSelect',{attributes,sections,casc});
k.callFunc('setActionCalls',{attributes,sections,casc});
attributes.sheet_version = k.version;
attributes.set();
}
});
}
});
};
k.registerFuncs({handleCompendiumDrop});
const parseDropData = function(drop_data,attributes,sections,casc){
k.debug('parsing drop data');
k.debug({drop_data:`"${drop_data}"`});
try{
let data = JSON.parse(drop_data);
data = Object.entries(data)
.reduce((memo,[key,val])=>{
if(val){
if(typeof val === 'string' && val.startsWith('[{')){
val = JSON.parse(val);
}
memo[key] = val;
}
return memo;
},{});
return processSpecialCategories(data,attributes,sections,casc);
}catch(err){
k.debug({'Invalid Drop Data! Drop aborted. Error:':err,drop_data},true);
return false;
}
};
const clearSheet = function(attributes,sections,casc){
Object.entries(sections).forEach(([section,idArray])=>{
idArray.forEach((id)=>{
k.removeRepeatingRow(`${section}_${id}`,attributes,sections);
});
});
Object.keys(attributes.attributes).forEach((attr)=>{
if(casc[`attr_${attr}`] && !/^(?:custom_)?bar_\d$/.test(attr)){
attributes[attr] = casc[`attr_${attr}`].hasOwnProperty('defaultValue') ?
casc[`attr_${attr}`].defaultValue :
'';
}
})
};
const clearDropAttributes = function(){
k.setAttrs({drop_name:'',drop_data:''});
};
const processDropData = function({data, attributes, sections, casc,section=''}){
section = section ? `${section}_` : '';
const worker = async (queue) => {
let [key,val] = queue.shift();
try{
let setKey = key.replace(/^(?:data-)?cs(?:list)?-/,'');
if(typeof val === 'string' && val.startsWith('[{')){
val = JSON.parse(val);
}
if(!Array.isArray(val) && (key.startsWith('cs-') || key.startsWith('data-cs-'))){
await k.pseudoQuery();
attributes[`${section}${setKey}`] = val;
if(maxAttr.includes(setKey)){
attributes[`${section}${setKey}_max`] = val;
}
}else if(Array.isArray(val) && key.startsWith('data-')){
let lookupKey = key.replace(/data-(?:cs(?:list)?-)?/,'');
if(repeatProcessors[lookupKey]){
k.debug(`processing ${lookupKey}`);
await repeatProcessors[lookupKey](lookupKey,val,attributes,sections,casc);
}else if(key.startsWith('data-cslist-')){
await k.pseudoQuery();
attributes[`${section}${setKey}`] = val.map((o)=>o.name).join(', ');
}else if(key === 'data-content'){
await k.pseudoQuery();
attributes[`${section}description`] = val.reduce((textArr,content)=>{
if(content.heading){
textArr.push(content.heading);
}
if(content.content){
let text = /list/.test(content.type) ? `• ${content.content}` : content.content;
textArr.push(text);
}
return textArr;
},[]).join('\n')
.replace(/\n{2,}/,'\n')
.replace(/\n+$/,'');
}
}
}catch(err){
k.debug({[`Invalid JSON entered for ${key} on ${data.display_name}`]:err,JSON:val});
}
if(queue.length){
return worker(queue);
}else{
return true;
}
};
return worker(Object.entries(data));
};
/**
* Does the basic prepwork for repeating section drops by creating the rowID and grabbing the item to work on. Passes the selected itemObj and the created section details to the callback function
* @param {string} lookupKey
* @param {array} arr
* @param {object} sections
* @param {function} callback
*/
const repeatWorker = async function(lookupKey,arr,sections,casc,callback){
const type = sectionLookup[lookupKey] || lookupKey.toLowerCase();
const worker = async (queue)=>{
const itemObj = queue.shift();
itemObj['data-cs-collapse'] = 1;
const section = k.generateRowID(type,sections);
addRowToCasc(section,casc);
await callback(itemObj,section);
if(queue.length){
return worker(queue);
}else{
return true;
}
};
return await worker([...arr]);
}
/**
* Adds the cascade objects for the indicated row to the casc object.
* @param {string} section - The row information (repeating section, and rowID)
* @param {object} casc - The cascade object for this particular character
* @param {number|string} [previousValue] - What to set the previous value to
*/
const addRowToCasc = function(section,casc,previousValue){
k.debug(`Adding ${section} to cascades`);
const match = section.match(/(.+?_.+?)_(.+)/);
match.shift();
const [repSection,rowID] = match;
k.debug({repSection,rowID});
Object
.entries(k.cascades)
.forEach(([key,obj]) => {
if(key.startsWith(`attr_${repSection}`)){
const newObj = {...obj};
newObj.name = newObj.name.replace(/\$X/,rowID)
const newKey = key.replace(/\$X/,rowID);
newObj.previousValue = previousValue === undefined ?
newObj.defaultValue :
previousValue;
newObj.affects = newObj.affects.map(a => a.replace(/\$X/,rowID));
casc[newKey] = newObj;
k.debug({[`casc[${newKey}]`]:casc[newKey]});
}
});
};/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
/*jshint -W014,-W084,-W030,-W033*/
//Initiate a compendium lookup
//Start of the actual compendium lookup functions
//Function to initiate the lookup. Parses the statblock to figure out what needs to be looked up in the compendium, and what attribute should be filtered for based on the category.
//ARGUMENTS
//statblock (object): base object dropped from the compendium
//callback (function): A function that will use the parsed compendium lookup data to finish the drag and drop of the item
//The callback function receives the parsed statblock as an argument
const compendiumLookup = function({queue, callback, origBlock, attributes, sections, casc, pass = 0}) {
pass++;
origBlock = origBlock || queue[0];
queue = queue || [origBlock];
let searchArray = [];
queue.forEach((statblock)=>{
searchArray = itemCategories.reduce((m, type) => {//Construct an array of items to search for.
let searchType = specialCategories[type] || type;
if (statblock[`data-${type.toLowerCase()}`]){
let searchNames = statblock[`data-${type.toLowerCase()}`].map((obj) => obj.name || obj['data-cs-name'] || '')
.join('|')
.replace(/\|{2,}/g,'')
.replace(/\|$/,'');
if(searchNames.length > 0){
let searchString = `Category:${searchType} data-cs-name:${searchNames}`;
m.push(searchString);
}
}
return m;
}, searchArray);
k.debug({searchArray});
if(searchArray.length){
lookupBurndown(statblock, searchArray, callback, origBlock, attributes, sections, casc,pass);
}else{
callback(origBlock);
}
});
};
//Actually queries the compendium to get details on the items in each category using the searchArray assembled in compendiumLookup
//ARGUMENTS
//statblock (object): the original object dropped from the compendium
//callback (function): A function that will use the parsed compendium lookup data to finish the drag and drop of the item
//The callback function receives the parsed statblock as an argument
const lookupBurndown = function(statblock, searchArray, callback, origBlock, attributes, sections, casc,pass) {
getCompendiumQuery(searchArray, (dataArr) => {
k.debug({dataArr});
const expansionIDs = dataArr
.reduce( (arr,obj)=>{
arr.push(k.value(obj.data.Expansion));
return arr;
},[])
.sort((a,b) => b - a);
itemCategories.forEach((oCategory) => {
const category = statblock[`data-${oCategory}`] ?
oCategory :
oCategory.toLowerCase();
if (statblock[`data-${category}`]) {
origBlock[`data-${category}`] = statblock[`data-${category}`].map((obj) => {
const fullItem = getItemDetails(obj, dataArr, expansionIDs);
fullItem['data-cs-name'] = fullItem['data-cs-name'] || fullItem.name;
return fullItem;
});
}
});
const queue = additionalLookups(statblock,origBlock);
if(queue.length /*&& pass < 2*/){
compendiumLookup({queue,callback,origBlock, attributes, sections, casc,pass});
}else{
callback(origBlock);
}
});
};
const additionalLookups = function(statblock,origBlock){
return Object.entries(statblock).reduce((memo,[prop,arr])=>{
if(prop.startsWith('data-') && Array.isArray(arr)){
let nestedData = arr.reduce((m,obj)=>{
Object.entries(obj).forEach(([nProp,nVal])=>{
/*commented code shouldn't be needed
if(
nProp.startsWith('data-') &&
typeof nVal === 'string' &&
nVal.startsWith('[{')
){
try{
let jArr = JSON.parse(nVal);
if(Array.isArray(jArr)){
jArr = jArr.map((o)=>{
o.datasource = obj['cs-name'] || obj.Category;
if(!o.datasource){
delete o.datasource;
}
return o;
});
origBlock[nProp] = origBlock[nProp] ?
[...origBlock[nProp],...jArr] :
[...jArr];
m.data[nProp] = jArr;
m.nested = true;
}
}catch(err){
//if the parse failed, do nothing
}
}else */
if(nProp === 'data-features'){
try{
if(typeof nVal === 'string'){
k.debug('string data-feature detected');
nVal = JSON.parse(nVal);
}
nVal.forEach((feature)=>{
if(!origBlock[`data-${feature.category}`] || origBlock[`data-${feature.category}`].every((o)=>o['data-cs-name'].toLowerCase() !== feature.name.toLowerCase())){
m.nested = true;
m.data[`data-${feature.category}`] = m.data[`data-${feature.category}`] || [];
m.data[`data-${feature.category}`].push({'data-cs-name':feature.name});
}
});
}catch(err){
k.debug({[`Invalid data-feature on ${obj['data-cs-name']}`]:err,'data-feature':nVal},true);
}
}
});
return m;
},{data:{},nested:false});
if(nestedData && nestedData.nested){
memo.push(nestedData.data);
}
}
return memo;
},[]);
};
//Finds the compendium item that most precisely matches the needs of the compendium item based on expansion ID and name property.
//If nothing matches based on expansion ID, simply returns the first item with appropriate name property.
//ARGUMENTS
//itemObj (object): the data on the Item to return that is included in the base statblock
//dataArr (array): The compendium items that were returned from getCompendiumQuery
const getItemDetails = function(itemObj, dataArr, expansionIDs) {
let objName = itemObj['data-cs-name'] || itemObj.name;
let compendiumObj;
expansionIDs.find((id) => {
compendiumObj = dataArr.find((dataObj) => k.value(dataObj.data.Expansion) === id &&
dataObj.data['data-cs-name'] === objName);
if (compendiumObj) {
return true;
} else {
return false;
}
});
if (!compendiumObj) { //If we didn't find an object matching the expansion pathways and the object name, just find the first item with a matching name
compendiumObj = dataArr.find((dataObj) =>
dataObj.data['data-cs-name'] === objName);
if (!compendiumObj) { //If there still isn't a matching compendium object, return the original Item
return itemObj;
}
}
Object.keys(compendiumObj.data).forEach((key) => {
itemObj[key] = itemObj[key] || compendiumObj.data[key];
});
return itemObj;
};/**
* Handles dropping of repeating section items that need no special handling. Provided as part of the compendium infrastructure as it is useful for nearly any project and can serve as a template for more specific drop functions.
* @param {string} lookupKey - The section name
* @param {object[]} arr - Array of data to parse
* @param {attributesProxy} attributes - The attributes for the character
* @param {object} sections - The object with keys equal to repeating section names and values of arrays of repeating ids
* @param {object} casc - The cascade object
* @param {array} sectionsToQuery - sections that need further user input before drop completes
*/
const basicDrop = (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
return repeatWorker(lookupKey,arr,sections,casc,async (itemObj,section)=>{
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
});
};/**
* Does all the generic handling for NPC type dropped items (e.g. Antagonists in Scion and Threats in TCF)
* @param {object} data - the data received from the drop
* @param {AttributesProxy} attributes - The attributes object from the K-scaffold
* @param {object} sections - The sections object form the k-scaffold
* @param {object} casc - The cascade object form the k-scaffold
*/
const npcHandler = (data,attributes,sections,casc) => {
clearSheet(attributes,sections,casc);
attributes.sheet_type = data['data-cs-sheet_type'] || 'pc';
attributes.allow_push = 0;
const tokenObj = {
width:70,
height:70,
};
// token bar association
const barNums = [1,2,3];
const barAttrs = ['hit_points','willpower_points'];
barAttrs.forEach(attr => {
const dataAttr = `data-cs-${attr}`;
if(data[dataAttr]){
const bar = barNums.find(n => attributes[`bar_${n}`] === attr);
tokenObj[`bar${bar}_value`] = data[dataAttr];
tokenObj[`bar${bar}_max`] = data[dataAttr];
data[`data-cs-${bar}_max`] = data[`data-cs-${bar}`];
}
});
[...skills,...weapon_skills].forEach(obj => {
attributes[`${obj.name.replace(/ /g,'_')}_levels`] = attributes.sheet_type === 'pc' ?
5 :
15;
if(
attributes.sheet_type === 'pc' &&
data.hasOwnProperty(`data-cs-${obj.name.replace(/ /g,'_')}`)
){
data[`data-cs-${obj.name.replace(/ /g,'_')}_levels`] = data[`data-cs-${obj.name.replace(/ /g,'_')}`];
delete data[`data-cs-${obj.name.replace(/ /g,'_')}`];
}
});
if(attributes.sheet_type === 'monster'){
attributes.monster_view = 1;
}
setDefaultToken(tokenObj);
k.callFunc('kSwitchTab',{trigger:{name:`nav-tabs-dragonbane--${attributes.sheet_type}`},attributes});
toggleNavButtons({attributes});
};
/**
* Processes abilities and spells for dropping to create an ability repeating item.
* @param {string} lookupKey - The section name
* @param {object[]} arr - Array of data to parse
* @param {attributesProxy} attributes - The attributes for the character
* @param {object} sections - The object with keys equal to repeating section names and values of arrays of repeating ids
* @param {object} casc - The cascade object
* @param {array} sectionsToQuery - sections that need further user input before drop completes
*/
const abilitySpellDrop = (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
return repeatWorker('Abilities',arr,sections,casc,async (itemObj,section)=>{
if(/spells/i.test(lookupKey)){
itemObj['data-cs-spell'] = 1;
if(
itemObj['data-cs-rank'] &&
/magic trick/i.test(itemObj['data-cs-rank'])
){
itemObj['data-cs-skill'] = 'magic trick';
}else{
itemObj['data-cs-skill'] = itemObj.school === 'general magic' ?
'general spell' :
itemObj.school;
}
}
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
});
};/**
* Handles dropping of armor and helmets.
* @param {string} lookupKey - The section name
* @param {object[]} arr - Array of data to parse
* @param {attributesProxy} attributes - The attributes for the character
* @param {object} sections - The object with keys equal to repeating section names and values of arrays of repeating ids
* @param {object} casc - The cascade object
* @param {array} sectionsToQuery - sections that need further user input before drop completes
*/
const armorDrop = async (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
const proms = arr.map(async itemObj => {
const prefix = itemObj['data-type'];
['rating','name','evade_bane','sneaking_bane','awareness_bane','acrobatics_bane','ranged_attacks_bane'].forEach(key => {
if(itemObj[`data-cs-${key}`]){
itemObj[`data-cs-${prefix}_${key}`] = itemObj[`data-cs-${key}`];
}
delete itemObj[`data-cs-${key}`];
});
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery});
});
await Promise.all(proms);
};/**
* function to handle dropping monster attacks
* @param {string} lookupKey - The section name
* @param {object[]} arr - Array of data to parse
* @param {attributesProxy} attributes - The attributes for the character
* @param {object} sections - The object with keys equal to repeating section names and values of arrays of repeating ids
* @param {object} casc - The cascade object
* @param {array} sectionsToQuery - sections that need further user input before drop completes
*/
const weaponDrop = (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
return repeatWorker(lookupKey,arr,sections,casc,async (itemObj,section)=>{
if(itemObj['data-cs-durability']){
itemObj['data-cs-durability_max'] = itemObj['data-cs-durability'];
}
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
});
};/**
* function to handle dropping monster attacks
* @param {string} lookupKey - The section name
* @param {object[]} arr - Array of data to parse
* @param {attributesProxy} attributes - The attributes for the character
* @param {object} sections - The object with keys equal to repeating section names and values of arrays of repeating ids
* @param {object} casc - The cascade object
* @param {array} sectionsToQuery - sections that need further user input before drop completes
*/
const attackDrop = (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
return repeatWorker(lookupKey,arr,sections,casc,async (itemObj,section)=>{
if(itemObj['data-cs-subtable_weight_1']){
itemObj['data-cs-subtable'] = 0;
}
if(itemObj['data-result']){
itemObj['data-cs-result'] = itemObj['data-result'];
}
const subtableRows = [1,2,3,4,5,6].reduce((m,n) => {
if(itemObj[`data-cs-subtable_weight_${n}`]){
m.push(n);
}
return m;
},[]);
let subTableLastResult = 0;
subtableRows.forEach((n,i,arr) => {
[
itemObj[`data-cs-subtable_result_${n}`],
subTableLastResult
] = calcDieResults(
k.value(itemObj[`data-cs-subtable_weight_${n}`]),
subTableLastResult
);
});
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
});
};/**
* Lookup for what specific drop function to use for a given drop type. Note that the key is the part after `data-` if it is in another compendium item (e)g. in a Monster), or is the same as the Compendium category (minus)anything after a space).
* @var
*/
const repeatProcessors = {
Spells:abilitySpellDrop,
'Besvärjelser':abilitySpellDrop,
spells:abilitySpellDrop,
'besvärjelser':abilitySpellDrop,
Abilities:abilitySpellDrop,
'Förmågor':abilitySpellDrop,
abilities:abilitySpellDrop,
'förmågor':abilitySpellDrop,
Armor:armorDrop,
'Rustningar':armorDrop,
armor:armorDrop,
'rustningar':armorDrop,
Gear:basicDrop,
'Utrustning':basicDrop,
gear:basicDrop,
'utrustning':basicDrop,
Weapons:weaponDrop,
'Vapen':weaponDrop,
weapons:weaponDrop,
'vapen':weaponDrop,
Attacks:attackDrop,
attacks:attackDrop,
'Secondary-skills':basicDrop,
'secondary-skills':basicDrop
};/**
* Does the system specific handling for specialized drop categories.
* @param {object} data - the data received from the drop
* @param {AttributesProxy} attributes - The attributes object from the K-scaffold
* @param {object} sections - The sections object form the k-scaffold
* @param {object} casc - The cascade object form the k-scaffold
* @returns {object|[]} - The manipulated data object
*/
const processSpecialCategories = async (data,attributes,sections,casc) => {
if(!/npcs|slp/i.test(data.Category)){
let category = data.Category.replace(/\s.+/,'');
data = {[`data-${category}`]:[data]};
if(data[`data-${category}`]['data-features']){
data[category]['data-features'].forEach((feature)=>{
let cat = k.capitalize(feature.category);
data[`data-${cat}`] = data[`data-${cat}`] || [];
data[`data-${cat}`].push({name:feature.name});
});
}
await k.pseudoQuery('');
}else{
if(data['data-cs-size'] === 'swarm'){
const queryTrans = getTranslationByKey('swarm drop query {{creature name}}')
.replace(/\{\{0\}\}/,data['data-cs-character_name']);
const creatureNum = await k.extractQueryResult(queryTrans);
['hit_points','ferocity'].forEach(attr => {
data[`data-cs-${attr}`] = data[`data-cs-${attr}`]
.trim()
.replace(/(\d+)\/.+/,(match,num) => num * creatureNum);
});
}else{
await k.pseudoQuery('');
}
// Handle summon hp
if(/\//.test(data['data-cs-hit_points'])){
const [,value,basis] = data['data-cs-hit_points']
.trim()
.match(/(.+?)\/(.+)/);
const queryTrans = getTranslationByKey(`dynamic spell level drop query {{monster name}}`)
.replace(/\{\{0\}\}/,data['data-cs-character_name']);
const total = await k.extractQueryResult(queryTrans);
data['data-cs-hit_points'] = value * total;
}else{
await k.pseudoQuery();
}
npcHandler(data,attributes,sections,casc);
}
return data;
};const calcDamageBonus = function({trigger, attributes}) {
const attrName = trigger.name.replace(/damage_bonus_/,'');
const attrBonus = attributes[attrName];
return attrBonus >= 17 ?
'd6' :
attrBonus >= 13 ?
'd4' :
'—';//Note this is an em-dash
}
k.registerFuncs({calcDamageBonus});
const calcSkillBase = function({trigger, attributes}) {
const attrName = trigger.name.replace(/_base_chance/,'');
const attrBonus = attributes[attrName];
return attrBonus >= 16 ? 7 :
attrBonus >= 13 ? 6 :
attrBonus >= 9 ? 5 :
attrBonus >= 6 ? 4 :
attrBonus >= 1 ? 3 : 0;
}
k.registerFuncs({calcSkillBase});const calcSkill = function({trigger, attributes}) {
const [section,rowID,name] = k.parseTriggerName(trigger.name);
const row = section ?
`${section}_${rowID}` :
'';
const skillLevel = row ?
attributes[`${row}_levels`] :
attributes[`${trigger.name}_levels`] ;
let attrName = row ?
attributes[`${row}_attribute_select`] :
skills.find(skill => skill.name === trigger.name.replace(/_/g, ' '))?.attribute;
if (!attrName) {
attrName = weapon_skills.find(skill => skill.name === trigger.name.replace(/_/g, ' '))?.attribute;
}
const attrBonus = attributes[attrName + '_base_chance'] || 0;
return skillLevel + attrBonus;
}
k.registerFuncs({calcSkill});
const advanceSkills = async function ({ trigger, attributes, sections,casc }) {
// iterate through the arrays: skills, weapon_skills, and rows of secondary_skills, using k.getSection
// For each skill, check if it's <skill>_advancement checkbox is checked
// If it is, then use custom roll parsing to roll 1d20, if the result is higher than the current skill level, then increase the skill level by 1
// Finally, regardless of result, uncheck the checkbox
k.debug("Advancing skills...");
const secondary_skills = sections['repeating_secondary-skills'].map(id => ({name:`repeating_secondary-skills_${id}_name`}));
// Collect all the promises generated from the async runs into an array. We'll wait on the array of promises further on.
const rollPromises = [...skills, ...weapon_skills, ...secondary_skills].map(async skill => {
// Get the skill name, advance checkbox, skill level, and skill total
// Secondary skills are repeating section, needs special handling due to different naming convention
const skillAttr = skill.name.endsWith('_name') ?
skill.name :
skill.name.replace(/\s+/g, '_');
const skillName = skill.name.endsWith('_name') ?
attributes[skillAttr] :
skill.name;
const skillAdvance = skill.name.endsWith('_name') ?
skill.name.replace('_name', '_advancement') :
skill.name.replace(/\s+/g, '_') + '_advancement';
const skillLevels = skill.name.endsWith('_name') ?
skill.name.replace('_name', '_levels') :
skill.name.replace(/\s+/g, '_') + '_levels';
const skillTotal = skill.name.endsWith('_name') ?
skill.name.replace('_name', '_total') :
skill.name.replace(/\s+/g, '_');
// Check if the checkbox is 'on'
if (attributes[skillAdvance] == "1" && attributes[skillTotal] < 18) {
k.debug("Advancing " + skillAttr + "...");
// Wait on the roll result
const results = await startRoll(`/w gm &{template:dragonbane} {{name=@{character_name}}} {{label=^{Advance}: ^{${skillName}} }} {{roll1=[[1d20]]}} {{test=[[${attributes[skillTotal]}]]}}`);
// Finisht the roll immediately since we aren't doing any changes to the roll display
finishRoll(results.rollId);
//k.debug(`roll: ${JSON.stringify(results)}`);
//k.debug(`The ${skillName} skill level is ${attributes[skillLevels]} with total ${attributes[skillTotal]} and the roll was ${results.results.roll1.result}`);
if (results.results.roll1.result > attributes[skillTotal]) {
// If the roll is higher than the current skill level, increase the skill level by 1 and the skill total by 1
// NB: The total isn't at the time of writing updating automatically when skill level increase.
newlvl = attributes[skillLevels] += 1;
newtot = attributes[skillTotal] += 1;
// Assign the new values
attributes[`${skillLevels}`] = newlvl;
attributes[`${skillTotal}`] = newtot;
k.debug(skillName + " level increased by 1 to " + attributes[skillLevels] + " for a total of " + attributes[skillName]);
} else {
k.debug(skillName + " level did not increase");
}
// Uncheck the checkbox
//attributes[skillAdvance] = ''; // Direct assignment to attributes does not work?
attributes[`${skillAdvance}`] = '';
}else{
// We have to await on both sides of the logic or the sheet loses connection
await k.pseudoQuery();
}
/* else {
k.debug(skillName + " did not advance!");
} */
});
// Wait for all the rolls to be done
await Promise.all(rollPromises);
// Use the set method of `attributes` to reconnect to the k-scaffold's pseudo cascade so that we can do all the reactions to these changes without needing to do another getAttrs.
attributes.set()
};
k.registerFuncs({ advanceSkills });const calcEncumbranceMax = function({trigger, attributes,sections}) {
return Math.ceil(attributes.strength / 2) + attributes.backpack;
}
k.registerFuncs({calcEncumbranceMax});/**
* Calculates the total encumbrance used
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcEncumbrance = function({trigger,attributes,sections,casc}){
const coinWeight = Math.floor(
coins.reduce((qty,coin) => {
return qty + attributes[coin];
},0)
/ 100
);
return sections.repeating_gear
.filter(n => n)
.reduce((total,id) => {
const row = `repeating_gear_${id}`;
return total + attributes[`${row}_quantity`] * attributes[`${row}_weight`];
},coinWeight);
};
k.registerFuncs({calcEncumbrance});const getAdvanceName = skillArray => skillArray.map(skillObject => ({name:`${skillObject.name} advancement`.replace(/\s+/g,'_')}));
/**
* Toggles the hidden class on the upgrade button so that it is displayed or not based on whether a skill has been marked for upgrading. Is run in response to upgrade checkbox changes as well as at sheet open.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const displayUpgrade = function({trigger,attributes,sections,casc}){
const skillAttrs = sections['repeating_secondary-skills']
.filter(id => id)
.map(id => ({name:`repeating_secondary-skills_${id}_advancement`}));
skillAttrs.push(...getAdvanceName(skills), ...getAdvanceName(weapon_skills));
const isUpgrade = skillAttrs.some(({name}) => attributes[name])
const jAction = isUpgrade ?
'removeClass' :
'addClass';
$20('#advancement-checkbox')[jAction]('hidden');
};
k.registerFuncs({displayUpgrade},{type:['opener']});
/**
* Adds the d6 of hp for getting a 3rd successful death roll.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const addSuccessHP = async function({trigger,attributes,sections,casc}){
if(attributes.death_saves_successes < 3) return;
const hpRoll = await startRoll('!{{hp=[[1d6]]}}');
finishRoll(hpRoll.rollId);
attributes.hit_points = Math.min(attributes.hit_points + hpRoll.results.hp.result,attributes['hit_points_max']);
attributes.death_saves_successes = 0;
attributes.set();
};
k.registerFuncs({addSuccessHP});/**
* Adds the custom skills to the selects for selecting which magic skill to use. Runs when an ability is created, when a secondary skill name is updated, or when a secondary skill is removed.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const setupMagicSelect = function({trigger,attributes,sections,casc}){
// assemble the options.
const optionsArray = sections['repeating_secondary-skills']
.filter(id => id)
.reduce((arr,id) => {
arr.push({value:id.toLowerCase(),label:attributes[`repeating_secondary-skills_${id}_name`] || k.capitalize(getTranslationByKey('new skill'))});
return arr;
},[{value:'magic trick'},{value:'general spell'}]);
populateListOptions({elemSelector:'.magic-select',optionsArray});
// iterate over all abilities and either leave them as they are or reset them to the default if their selected skill is no longer present.
sections.repeating_abilities
.filter(id => id)
.forEach(id => {
const row = `repeating_abilities_${id}`;
attributes[`${row}_skill`] = optionsArray.some(obj => obj.value === attributes[`${row}_skill`]) ?
attributes[`${row}_skill`] :
'general spell';
});
};
k.registerFuncs({setupMagicSelect},{type:['opener']});/**
* Calculates the total armor value.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcArmorTotal = function({trigger,attributes,sections,casc}){
return attributes.armor_rating + attributes.helmet_rating;
};
k.registerFuncs({calcArmorTotal});/**
* Sets the current durability to the max durability
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const setDurability = function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
return attributes[`${section}_${rowID}_durability_max`];
};
k.registerFuncs({setDurability});/**
* Resets the boon/banes
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const resetModifiers = function({trigger,attributes,sections,casc}){
attributes.boons = 0;
attributes.banes = 0;
};
k.registerFuncs({resetModifiers});/**
* Converts values to their abbreviation i18n key.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const convertAbbreviation = function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
return `${attributes[`${section}_${rowID}_attribute_select`]}-abbreviation`;
};
k.registerFuncs({convertAbbreviation});/**
* Toggles the displayed nav buttons so that only the nav button for the inactive sheet view is present.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const toggleNavButtons = function({trigger,attributes,sections,casc}){
$20(`.tabs--dragonbane__button:not([name$="${attributes.dragonbane_tab}"])`).removeClass('toggle-disabled');
$20(`.tabs--dragonbane__button[name$="${attributes.dragonbane_tab}"]`).addClass('toggle-disabled');
};
k.registerFuncs({toggleNavButtons},{type:['opener']});/**
* Hides the nav buttons that don't match the active sheet type.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const hideInactiveNavButtons = function({trigger,attributes,sections,casc}){
$20(`.tabs--dragonbane__button:not([name$="settings"],[name$="${attributes.sheet_type}"])`).addClass('disabled');
$20(`.tabs--dragonbane__button[name$="${attributes.sheet_type}"]`).removeClass('disabled');
};
k.registerFuncs({hideInactiveNavButtons},{type:['opener']});/**
* calculates your total movement rating
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcMovement = function({trigger,attributes,sections,casc}){
if(attributes.sheet_type === 'monster') return;
const moveMod = attributes.agility <= 6 ?
-4 :
attributes.agility <= 9 ?
-2 :
attributes.agility <= 12 ?
0 :
attributes.agility <= 15 ?
2 :
4;
return attributes.kin_movement + moveMod;
};
k.registerFuncs({calcMovement});/**
* Resets the intiative tracker on the character sheet
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const resetInitiative = function({trigger,attributes,sections,casc}){
debugger;
sections.repeating_initiative.forEach(id => {
if(!attributes[`repeating_initiative_${id}_hold`]){
k.removeRepeatingRow(`repeating_initiative_${id}`,attributes,sections);
}
});
filterInitiativeDeck(attributes,sections);
};
k.registerFuncs({resetInitiative});
const filterInitiativeDeck = (attributes,sections) => {
const heldCards = sections.repeating_initiative.map(id => attributes[`repeating_initiative_${id}_card`]);
attributes.cards = `1,2,3,4,5,6,7,8,9,10`
.split(',')
.filter(n => !heldCards.includes(+n));
}/**
* Initializes a newly created skill.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const initializeSkill = function({trigger,attributes,sections,casc}){
const newID = sections['repeating_secondary-skills'][sections['repeating_secondary-skills'].length -1];
const toCalc = [];
Object
.entries(k.cascades)
.filter(([key,obj]) => /attr_repeating_secondary-skills/.test(key) && !/name|action/.test(key))
.forEach(([key,obj]) => {
attributes[key.replace(/\$X/,newID).replace(/^attr_/,'')] = obj.defaultValue || '';
if(obj.calculation){
toCalc.push(obj);
}
});
toCalc.forEach(obj => {
attributes[obj.name.replace(/\$X/,newID).replace(/^attr_/,'')] = k.callFunc(obj.calculation,{trigger:{name:obj.name.replace(/\$X/,newID).replace(/^attr_/,'')},attributes,sections,casc})
});
};
k.registerFuncs({initializeSkill});/**
* calculates the maximum points for hp/wp
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcPoints = function({trigger,attributes,sections,casc}){
const basePointName = trigger.name.replace(/_max/,'');
const attributeObj = characteristics.find(o => o.sheetworker && o.sheetworker.affects && o.sheetworker.affects.includes(trigger.name));
return attributes[attributeObj.name] + attributes[`${basePointName}_bonus`];
};
k.registerFuncs({calcPoints});/**
* Handles the resting for the character
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const useRest = function({trigger,attributes,sections,casc}){
const [duration] = trigger.name.match(/^[a-z]+/i);
const durationSwitch = {
round:roundRest,
stretch:roundRest,
shift:shiftRest
};
if(durationSwitch[duration]){
durationSwitch[duration](duration,attributes);
}
};
k.registerFuncs({useRest});
const roundRest = async (duration,attributes) =>{
if(!attributes[`${duration}_rest`]) return;
const rollObj = {
character_name:`${attributes.character_name} - ^{${duration} rest}`,
label:'^{willpower points}',
roll1:'[[1d6]]'
};
if(duration === 'stretch'){
rollObj.damage = `[[?{${k.capitalize(getTranslationByKey('are you being cared for'))}|${k.capitalize(getTranslationByKey('no'))},1|${k.capitalize(getTranslationByKey('yes'))},2}d6]]`;
rollObj.damage_label = '^{hit points}';
rollObj.description = `^{Heal a condition of your choice}`;
}
[roll] = await executeRoll({rollObj});
finishRoll(roll.rollId);
attributes.willpower_points = Math.min(attributes.willpower_points + roll.results.roll1.result,attributes.willpower_points_max);
if(rollObj.damage){
attributes.hit_points = Math.min(attributes.hit_points + roll.results.damage.result,attributes.hit_points_max);
}
attributes.set();
}
const shiftRest = (duration,attributes) => {
attributes.willpower_points = attributes.willpower_points_max;
attributes.hit_points = attributes.hit_points_max;
characteristics.forEach(obj => attributes[obj.condition] = 0);
['round','stretch'].forEach(attr => attributes[`${attr}_rest`] = 0);
};/**
* Calculates the cost of a spell
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcCost = function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
if(!attributes[`${row}_spell`]) return;
return attributes[`${row}_skill`] === 'magic trick' ?
1 :
2;
};
k.registerFuncs({calcCost});/**
* Calculates the size of the deck remaining
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcDeckSize = function({trigger,attributes,sections,casc}){
return `${attributes.cards}`.split(',').length;
};
k.registerFuncs({calcDeckSize});/**
* Starts the process of swapping initiative
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const switchInitiative = async function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
const options = sections.repeating_initiative.reduce((arr,id) => {
if(
attributes[`repeating_initiative_${id}_name`] !== attributes[`${row}_name`] &&
!attributes[`repeating_initiative_${id}_used`]
){
arr.push(`${attributes[`repeating_initiative_${id}_name`]} - ${attributes[`repeating_initiative_${id}_card`]},${id}`)
}
return arr;
},[]);
const swapID = await k.extractQueryResult(`${k.capitalize(getTranslationByKey('swap query'))}|${options.join('|')}`);
const swapRow = `${section}_${swapID}`;
const swapCard = attributes[`${swapRow}_card`];
const sourceCard = attributes[`${row}_card`];
attributes[`${row}_card`] = swapCard;
attributes[`${swapRow}_card`] = sourceCard;
sortInitiative({sections,attributes})
attributes.set()
};
k.registerFuncs({switchInitiative});
/**
*
* @param {object} attributes - The attribute values of the character
* @param {object} sections - All the repeating section IDs
* @param {array} [cards=[]] - an array of card values to add for the given character.
* @param {string} [character_name] - the name of the character currently being worked on. REQUIRED IF cards is provided
*/
const sortInitiative = ({sections,attributes,cards=[],character_name}) => {
sections.repeating_initiative.reduce((arr,id) => {
const row = `repeating_initiative_${id}`;
arr.push({name:attributes[`${row}_name`],card:attributes[`${row}_card`],row,hold:attributes[`${row}_hold`]})
return arr;
},cards.map(card => ({name:character_name,card})))
.sort((a,b) => a.card - b.card)
.forEach(obj => {
if(obj.row){
k.removeRepeatingRow(obj.row,attributes,sections);
}
const row = k.generateRowID('repeating_initiative',sections);
attributes[`${row}_name`] = obj.name;
attributes[`${row}_card`] = obj.card;
attributes[`${row}_hold`] = obj.hold;
});
}/**
* Sets an initiative row to be used (the character has used their actions)
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const useInitiative = function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
attributes[`${row}_used`] = (attributes[`${row}_used`] - 1) * -1;//Flip the use state of the row
};
k.registerFuncs({useInitiative});/**
* Removes a specific initiative row.
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const removeInitiative = function({trigger,attributes,sections,casc}){
const [section,rowID] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
k.removeRepeatingRow(row,attributes,sections);
filterInitiativeDeck(attributes,sections);
};
k.registerFuncs({removeInitiative});/**
* Calculates the die weight of a given monster attack
* @param {object} trigger - The trigger that caused the function to be called
* @param {object} attributes - The attribute values of the character
* @param {object[]} sections - All the repeating section IDs
* @param {object} casc - Expanded cascade object
*/
const calcDieWeight = function({trigger,attributes,sections,casc}){
const [section,rowID,attr] = k.parseTriggerName(trigger.name);
const row = `${section}_${rowID}`;
const resultAttr = attr.replace(/weight/,'result');
const result = attributes[`${row}_${resultAttr}`];
const resultArr = `${result}`.split(/\D+/);
const weight = k.value(resultArr[resultArr.length - 1]) - k.value(resultArr[0]) + 1;
return weight;
};
k.registerFuncs({calcDieWeight});
</script>