mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-08-30 11:42:29 +00:00
7022 lines
529 KiB
HTML
7022 lines
529 KiB
HTML
|
|
<button name="act_k-network-call" hidden="" type="action">
|
|
</button><!-- Inserted fonts:"Material+Icons+Outlined" --><!-- Inserted fonts:"El+Messiri" --><!-- Inserted fonts:"IM+Fell+Double+Pica" -->
|
|
<input name="attr_character_id" type="hidden" title="@{character_id}"/>
|
|
<input name="attr_script_character_name" type="hidden" title="@{script_character_name}"/>
|
|
<input name="attr_sheet_version" value="0" type="hidden" title="@{sheet_version}"/>
|
|
<button name="act_push" hidden="" type="action">
|
|
</button>
|
|
<div class="compendium-drop-target npcs">
|
|
<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}"/>
|
|
<div class="sheet-toggle section">
|
|
<div class="section-container">
|
|
<div class="layout layout--flex"><span data-i18n="disable-roll-options"></span>
|
|
<div class="on-off on-off--rollmodal-disabled">
|
|
<input name="attr_rollmodal_disabled" value="1" type="checkbox" title="@{rollmodal_disabled}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section-container">
|
|
<div class="layout layout--flex"><span data-i18n="npc-sheet"></span>
|
|
<div class="on-off on-off--is-npc">
|
|
<input name="attr_is_npc" value="1" type="checkbox" title="@{is_npc}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section-container compendium-dependent-content disabled">
|
|
<div class="layout layout--flex">
|
|
<button name="act_open-table" data-i18n="rollable tables" type="action">
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="section-container compendium-dependent-content disabled">
|
|
<div class="layout layout--flex">
|
|
<button class="material-icons" name="act_refresh-mancer" data-i18n-title="Restart the character builder" style="font-size:inherit;" type="action">refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="kmodal kmodal--mancer kmodal__checkbox kmodal--mancer__checkbox" value="1" id="kmodal-mancer" name="attr_kmodal-mancer" type="checkbox" title="@{kmodal-mancer}"/>
|
|
<div class="kmodal kmodal__outer kmodal--mancer kmodal--mancer__outer">
|
|
<label class="kmodal kmodal__background kmodal--mancer kmodal--mancer__background" for="kmodal-mancer"></label>
|
|
<div class="kmodal kmodal__inner kmodal--mancer kmodal--mancer__inner">
|
|
<label class="kmodal kmodal__close kmodal--mancer kmodal--mancer__close" for="kmodal-mancer"></label>
|
|
<div class="kmodal kmodal__content kmodal--mancer kmodal--mancer__content">
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="refresh" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-refresh controlled-display mancer-startup fade-transition tiny-gap">
|
|
<input name="attr_mancer_confirm_wipe" value="0" type="hidden" title="@{mancer_confirm_wipe}"/><span data-i18n="mancer refresh dialog"></span>
|
|
<div class="flex-box justify-space-between">
|
|
<button class="capitalize rollable modal-button modal-button--thick" name="act_mancer-toggle" data-i18n="cancel" type="action">
|
|
</button>
|
|
<button class="warning capitalize rollable modal-button modal-button--thick" name="act_mancer-wipe" type="action">
|
|
<input name="attr_mancer_wipe_button_text" value="wipe character data" type="hidden" title="@{mancer_wipe_button_text}"/><span name="attr_mancer_wipe_button_text" data-i18n-dynamic="" title="@{mancer_wipe_button_text}"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="startup" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-startup controlled-display mancer-startup fade-transition tiny-gap"><span data-i18n="mancer startup dialog"></span>
|
|
<div class="flex-box justify-space-between">
|
|
<button class="capitalize rollable modal-button modal-button--thick" name="act_mancer-toggle" data-i18n="manually edit" type="action">
|
|
</button>
|
|
<button class="capitalize rollable modal-button modal-button--thick" name="act_mancer-create" data-i18n="use character guide" type="action">
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="create" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-create controlled-display mancer-startup fade-transition layout--grid half-gap"><span data-i18n="character creation dialog"></span><span>
|
|
<button class="capitalize modal-button" name="act_mancer-randomize-new" data-i18n="randomize all" type="action">
|
|
</button> <span data-i18n="or follow the generation steps"></span>.</span>
|
|
<ol class="layout--grid tiny-gap">
|
|
<li>
|
|
<div class="layout--grid tiny-gap">
|
|
<button class="rollable modal-button modal-button--thin modal-button--content" name="act_mancer-roll-ability-scores" data-i18n="roll ability scores" type="action">
|
|
</button>
|
|
<div class="flex-box flex-wrap flex-justify-center tiny-gap">
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--strength">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-strength" type="action"><span class="labelled-edit__label" data-i18n="strength"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--strength-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_strength_modifier_mod" type="hidden" title="@{strength_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_strength_modifier" type="hidden" title="@{strength_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_strength_modifier" aria-hidden="true" title="@{strength_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_strength_diff" hidden="" value="1" type="checkbox" title="@{strength_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_strength_total" type="hidden" title="@{strength_total}"/>
|
|
<input name="attr_strength_mod" type="hidden" title="@{strength_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_strength" type="hidden" title="@{strength}"/><span class="labelled-edit__display" name="attr_strength_total" aria-hidden="true" title="@{strength_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_strength" placeholder="0" type="number" title="@{strength}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_strength_max" type="number" title="@{strength|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--agility">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-agility" type="action"><span class="labelled-edit__label" data-i18n="agility"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--agility-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_agility_modifier_mod" type="hidden" title="@{agility_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_agility_modifier" type="hidden" title="@{agility_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_agility_modifier" aria-hidden="true" title="@{agility_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_agility_diff" hidden="" value="1" type="checkbox" title="@{agility_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_agility_total" type="hidden" title="@{agility_total}"/>
|
|
<input name="attr_agility_mod" type="hidden" title="@{agility_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_agility" type="hidden" title="@{agility}"/><span class="labelled-edit__display" name="attr_agility_total" aria-hidden="true" title="@{agility_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_agility" placeholder="0" type="number" title="@{agility}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_agility_max" type="number" title="@{agility|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--stamina">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-stamina" type="action"><span class="labelled-edit__label" data-i18n="stamina"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--stamina-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_stamina_modifier_mod" type="hidden" title="@{stamina_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_stamina_modifier" type="hidden" title="@{stamina_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_stamina_modifier" aria-hidden="true" title="@{stamina_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_stamina_diff" hidden="" value="1" type="checkbox" title="@{stamina_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_stamina_total" type="hidden" title="@{stamina_total}"/>
|
|
<input name="attr_stamina_mod" type="hidden" title="@{stamina_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_stamina" type="hidden" title="@{stamina}"/><span class="labelled-edit__display" name="attr_stamina_total" aria-hidden="true" title="@{stamina_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_stamina" placeholder="0" type="number" title="@{stamina}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_stamina_max" type="number" title="@{stamina|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--personality">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-personality" type="action"><span class="labelled-edit__label" data-i18n="personality"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--personality-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_personality_modifier_mod" type="hidden" title="@{personality_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_personality_modifier" type="hidden" title="@{personality_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_personality_modifier" aria-hidden="true" title="@{personality_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_personality_diff" hidden="" value="1" type="checkbox" title="@{personality_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_personality_total" type="hidden" title="@{personality_total}"/>
|
|
<input name="attr_personality_mod" type="hidden" title="@{personality_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_personality" type="hidden" title="@{personality}"/><span class="labelled-edit__display" name="attr_personality_total" aria-hidden="true" title="@{personality_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_personality" placeholder="0" type="number" title="@{personality}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_personality_max" type="number" title="@{personality|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--luck">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-luck" type="action"><span class="labelled-edit__label" data-i18n="luck"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--luck-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_luck_modifier_mod" type="hidden" title="@{luck_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_luck_modifier" type="hidden" title="@{luck_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_luck_modifier" aria-hidden="true" title="@{luck_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_luck_diff" hidden="" value="1" type="checkbox" title="@{luck_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_luck_total" type="hidden" title="@{luck_total}"/>
|
|
<input name="attr_luck_mod" type="hidden" title="@{luck_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_luck" type="hidden" title="@{luck}"/><span class="labelled-edit__display" name="attr_luck_total" aria-hidden="true" title="@{luck_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_luck" placeholder="0" type="number" title="@{luck}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_luck_max" type="number" title="@{luck|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--intelligence">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-intelligence" type="action"><span class="labelled-edit__label" data-i18n="intelligence"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--intelligence-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_intelligence_modifier_mod" type="hidden" title="@{intelligence_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_intelligence_modifier" type="hidden" title="@{intelligence_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_intelligence_modifier" aria-hidden="true" title="@{intelligence_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_intelligence_diff" hidden="" value="1" type="checkbox" title="@{intelligence_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_intelligence_total" type="hidden" title="@{intelligence_total}"/>
|
|
<input name="attr_intelligence_mod" type="hidden" title="@{intelligence_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_intelligence" type="hidden" title="@{intelligence}"/><span class="labelled-edit__display" name="attr_intelligence_total" aria-hidden="true" title="@{intelligence_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_intelligence" placeholder="0" type="number" title="@{intelligence}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_intelligence_max" type="number" title="@{intelligence|max}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex-box tiny-gap">
|
|
<button class="rollable modal-button modal-button--thin modal-button--content" name="act_mancer-roll-birth-augur" data-i18n="birth augur" type="action">
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--augur labelled-edit--string"><span class="labelled-edit__label" data-i18n="augur"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_mancer_augur_mod" type="hidden" title="@{mancer_augur_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_mancer_augur" type="hidden" title="@{mancer_augur}"/><span class="labelled-edit__display" name="attr_mancer_augur" aria-hidden="true" title="@{mancer_augur}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
<input class="labelled-edit__value" name="attr_mancer_augur" data-i18n-placeholder="-" type="text" title="@{mancer_augur}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="flex-box tiny-gap">
|
|
<button class="rollable modal-button modal-button--thin modal-button--content" name="act_mancer-roll-hp" data-i18n=" roll hp" type="action">
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--hp labelled-edit--string"><span class="labelled-edit__label" data-i18n="hp"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_mancer_hp_mod" type="hidden" title="@{mancer_hp_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_mancer_hp" type="hidden" title="@{mancer_hp}"/><span class="labelled-edit__display" name="attr_mancer_hp" aria-hidden="true" title="@{mancer_hp}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="1d4"></span>
|
|
<input class="labelled-edit__value" name="attr_mancer_hp" data-i18n-placeholder="1d4" type="text" title="@{mancer_hp}"/>
|
|
</div>
|
|
</div><span class="capitalize" data-i18n="+ stamina" style="align-self:center;"></span>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="layout--grid tiny-gap">
|
|
<button class="rollable modal-button modal-button--thin modal-button--content" name="act_mancer-determine-occupation" data-i18n="determine occupation" type="action">
|
|
</button>
|
|
<div class="flex-box tiny-gap flex-wrap">
|
|
<div class="labelled-edit labelled-edit--occupation labelled-edit--string"><span class="labelled-edit__label" data-i18n="occupation"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_mancer_occupation_mod" type="hidden" title="@{mancer_occupation_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_mancer_occupation" type="hidden" title="@{mancer_occupation}"/><span class="labelled-edit__display" name="attr_mancer_occupation" aria-hidden="true" title="@{mancer_occupation}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="occupation"></span>
|
|
<input class="labelled-edit__value" name="attr_mancer_occupation" data-i18n-placeholder="occupation" type="text" title="@{mancer_occupation}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--weapon labelled-edit--string"><span class="labelled-edit__label" data-i18n="weapon"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_mancer_weapon_mod" type="hidden" title="@{mancer_weapon_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_mancer_weapon" type="hidden" title="@{mancer_weapon}"/><span class="labelled-edit__display" name="attr_mancer_weapon" aria-hidden="true" title="@{mancer_weapon}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="weapon"></span>
|
|
<input class="labelled-edit__value" name="attr_mancer_weapon" data-i18n-placeholder="weapon" type="text" title="@{mancer_weapon}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--trade-goods labelled-edit--string"><span class="labelled-edit__label" data-i18n="trade-goods"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_mancer_trade_goods_mod" type="hidden" title="@{mancer_trade_goods_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_mancer_trade_goods" type="hidden" title="@{mancer_trade_goods}"/><span class="labelled-edit__display" name="attr_mancer_trade_goods" aria-hidden="true" title="@{mancer_trade_goods}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="trade-goods"></span>
|
|
<input class="labelled-edit__value" name="attr_mancer_trade_goods" data-i18n-placeholder="trade-goods" type="text" title="@{mancer_trade_goods}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="layout--grid tiny-gap"><span class="capitalize" data-i18n="choose an alignment"></span>
|
|
<div class="labelled-edit labelled-edit--alignment labelled-edit--object"><span class="labelled-edit__label" data-i18n="alignment"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_alignment_mod" type="hidden" title="@{alignment_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_alignment" type="hidden" title="@{alignment}"/><span class="labelled-edit__display" name="attr_alignment" aria-hidden="true" title="@{alignment}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="choose"></span>
|
|
<select class="labelled-edit__value" name="attr_alignment">
|
|
<option value="" data-i18n="choose"></option>
|
|
<option value="lawful" data-i18n="lawful"></option>
|
|
<option value="chaotic" data-i18n="chaotic"></option>
|
|
<option value="neutral" data-i18n="neutral"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="layout--grid tiny-gap">
|
|
<button class="rollable modal-button modal-button--thin modal-button--content" name="act_mancer-roll-coinage" data-i18n="roll for starting coin" type="action">
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--starting-coin labelled-edit--number"><span class="labelled-edit__label" data-i18n="starting-coin"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_mancer_starting_coin_mod" type="hidden" title="@{mancer_starting_coin_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_mancer_starting_coin" type="hidden" title="@{mancer_starting_coin}"/><span class="labelled-edit__display" name="attr_mancer_starting_coin" aria-hidden="true" title="@{mancer_starting_coin}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">cp</span>
|
|
<input class="labelled-edit__value" name="attr_mancer_starting_coin" placeholder="cp" type="number" title="@{mancer_starting_coin}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="layout--grid tiny-gap"><span data-i18n="new mancer finish dialog"></span>
|
|
<button class="rollable modal-button modal-button--thick modal-button--content" name="act_mancer-new-finish" data-i18n="create character" type="action">
|
|
</button>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="class" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-class controlled-display mancer-startup fade-transition layout--grid half-gap">
|
|
<label class="input-label"><span class="capitalize input-label__text" data-i18n="choose your class"></span>
|
|
<select class="class-select input-label__input" name="attr_mancer_class" title="@{mancer_class}">
|
|
<option value="" data-i18n="none" selected="">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<input class="display-control--non-zero--inverted" name="attr_mancer_class" value="" type="hidden" title="@{mancer_class}"/>
|
|
<div class="controlled-display class-details-display"><span class="locked" hidden=""></span>
|
|
<fieldset class="repeating_mancer-class-options">
|
|
<input name="attr_ability_map" value="" type="hidden" title="@{repeating_mancer-class-options_$X_ability_map}"/>
|
|
<input name="attr_name" value="" type="hidden" title="@{repeating_mancer-class-options_$X_name}"/>
|
|
<input name="attr_description" value="" type="hidden" title="@{repeating_mancer-class-options_$X_description}"/>
|
|
<input name="attr_row_id" type="hidden" title="@{repeating_mancer-class-options_$X_row_id}"/>
|
|
<input class="display-control" name="attr_mancer_sub_field_control" hidden="" value="generic_ability" type="checkbox" title="@{repeating_mancer-class-options_$X_mancer_sub_field_control}"/>
|
|
<div class="mancer-subfield controlled-display">
|
|
<div class="mancer-inline-display"><span class="labelled-edit__label" name="attr_name" title="@{repeating_mancer-class-options_$X_name}"></span><span class="preserve-whitespace" name="attr_description" title="@{repeating_mancer-class-options_$X_description}"></span>
|
|
</div>
|
|
</div>
|
|
<input class="display-control" name="attr_mancer_sub_field_control" hidden="" value="sub_ability" type="checkbox" title="@{repeating_mancer-class-options_$X_mancer_sub_field_control}"/>
|
|
<div class="mancer-subfield controlled-display">
|
|
<div class="labelled-edit labelled-edit--string"><span class="italics" name="attr_name" title="@{repeating_mancer-class-options_$X_name}"></span>
|
|
<div class="labelled-edit__container"><span class="labelled-edit__display preserve-whitespace" name="attr_description" title="@{repeating_mancer-class-options_$X_description}"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="display-control" name="attr_mancer_sub_field_control" hidden="" value="select" type="checkbox" title="@{repeating_mancer-class-options_$X_mancer_sub_field_control}"/>
|
|
<div class="mancer-subfield controlled-display">
|
|
<div class="flex-box tiny-gap"><span class="colon" name="attr_name" title="@{repeating_mancer-class-options_$X_name}"></span>
|
|
<select class="mancer-select" name="attr_select" value="" title="@{repeating_mancer-class-options_$X_select}">
|
|
<option value="" data-i18n="loading content">
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<input class="display-control" name="attr_mancer_sub_field_control" hidden="" value="labelled-text" type="checkbox" title="@{repeating_mancer-class-options_$X_mancer_sub_field_control}"/>
|
|
<div class="mancer-subfield controlled-display">
|
|
<div class="flex-box tiny-gap"><span class="colon" name="attr_name" title="@{repeating_mancer-class-options_$X_name}"></span><span class="preserve-whitespace" name="attr_description" title="@{repeating_mancer-class-options_$X_description}"></span>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<h3 data-i18n="class table"></h3>
|
|
<div class="class-table"><span class="material-icons level-progress-indicator disabled">arrow_downward</span><span class="capitalize header" data-i18n="level"></span><span class="row-1 row-content">1</span><span class="row-2 row-content">2</span><span class="row-3 row-content">3</span><span class="row-4 row-content">4</span><span class="row-5 row-content">5</span><span class="row-6 row-content">6</span><span class="row-7 row-content">7</span><span class="row-8 row-content">8</span><span class="row-9 row-content">9</span><span class="row-10 row-content">10</span><span class="locked" hidden=""></span>
|
|
<fieldset class="repeating_mancer-class-table">
|
|
<input name="attr_row_id" value="" type="hidden" title="@{repeating_mancer-class-table_$X_row_id}"/>
|
|
<input name="attr_ability_map" value="" type="hidden" title="@{repeating_mancer-class-table_$X_ability_map}"/><span class="capitalize header" name="attr_name" title="@{repeating_mancer-class-table_$X_name}"></span><span class="row-1" name="attr_value_1" title="@{repeating_mancer-class-table_$X_value_1}"></span><span class="row-2" name="attr_value_2" title="@{repeating_mancer-class-table_$X_value_2}"></span><span class="row-3" name="attr_value_3" title="@{repeating_mancer-class-table_$X_value_3}"></span><span class="row-4" name="attr_value_4" title="@{repeating_mancer-class-table_$X_value_4}"></span><span class="row-5" name="attr_value_5" title="@{repeating_mancer-class-table_$X_value_5}"></span><span class="row-6" name="attr_value_6" title="@{repeating_mancer-class-table_$X_value_6}"></span><span class="row-7" name="attr_value_7" title="@{repeating_mancer-class-table_$X_value_7}"></span><span class="row-8" name="attr_value_8" title="@{repeating_mancer-class-table_$X_value_8}"></span><span class="row-9" name="attr_value_9" title="@{repeating_mancer-class-table_$X_value_9}"></span><span class="row-10" name="attr_value_10" title="@{repeating_mancer-class-table_$X_value_10}"></span>
|
|
</fieldset>
|
|
</div>
|
|
<button class="rollable modal-button modal-button--thick modal-button--content sticky-corner corner-right" name="act_mancer-class-finish" data-i18n="Select Class" type="action">
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="level" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-level controlled-display mancer-startup fade-transition layout--grid half-gap">
|
|
<div class="flex-box half-gap">
|
|
<div class="labelled-edit labelled-edit--level labelled-edit--readyonly labelled-edit--string"><span class="labelled-edit__label" data-i18n="level"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_level_mod" type="hidden" title="@{level_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_level" type="hidden" title="@{level}"/><span class="labelled-edit__display" name="attr_level" aria-hidden="true" title="@{level}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">false</span>
|
|
</div>
|
|
</div><span class="material-icons">arrow_forward</span>
|
|
<input name="attr_mancer_level" type="number" title="@{mancer_level}"/>
|
|
</div>
|
|
<div class="flex-box half-gap">
|
|
<div class="labelled-edit labelled-edit--hit-points-max labelled-edit--readyonly labelled-edit--string"><span class="labelled-edit__label" data-i18n="hit points"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_hit_points_max_mod" type="hidden" title="@{hit_points_max_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_hit_points_max" type="hidden" title="@{hit_points|max}"/><span class="labelled-edit__display" name="attr_hit_points_max" aria-hidden="true" title="@{hit_points|max}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">false</span>
|
|
</div>
|
|
</div><span class="material-icons">add</span>
|
|
<input name="attr_mancer_hp" value="0" type="number" title="@{mancer_hp}"/>
|
|
</div>
|
|
<h3 data-i18n="class table"></h3>
|
|
<div class="class-table"><span class="material-icons level-progress-indicator disabled">arrow_downward</span><span class="capitalize header" data-i18n="level"></span><span class="row-1 row-content">1</span><span class="row-2 row-content">2</span><span class="row-3 row-content">3</span><span class="row-4 row-content">4</span><span class="row-5 row-content">5</span><span class="row-6 row-content">6</span><span class="row-7 row-content">7</span><span class="row-8 row-content">8</span><span class="row-9 row-content">9</span><span class="row-10 row-content">10</span><span class="locked" hidden=""></span>
|
|
<fieldset class="repeating_mancer-class-table">
|
|
<input name="attr_row_id" value="" type="hidden" title="@{repeating_mancer-class-table_$X_row_id}"/>
|
|
<input name="attr_ability_map" value="" type="hidden" title="@{repeating_mancer-class-table_$X_ability_map}"/><span class="capitalize header" name="attr_name" title="@{repeating_mancer-class-table_$X_name}"></span><span class="row-1" name="attr_value_1" title="@{repeating_mancer-class-table_$X_value_1}"></span><span class="row-2" name="attr_value_2" title="@{repeating_mancer-class-table_$X_value_2}"></span><span class="row-3" name="attr_value_3" title="@{repeating_mancer-class-table_$X_value_3}"></span><span class="row-4" name="attr_value_4" title="@{repeating_mancer-class-table_$X_value_4}"></span><span class="row-5" name="attr_value_5" title="@{repeating_mancer-class-table_$X_value_5}"></span><span class="row-6" name="attr_value_6" title="@{repeating_mancer-class-table_$X_value_6}"></span><span class="row-7" name="attr_value_7" title="@{repeating_mancer-class-table_$X_value_7}"></span><span class="row-8" name="attr_value_8" title="@{repeating_mancer-class-table_$X_value_8}"></span><span class="row-9" name="attr_value_9" title="@{repeating_mancer-class-table_$X_value_9}"></span><span class="row-10" name="attr_value_10" title="@{repeating_mancer-class-table_$X_value_10}"></span>
|
|
</fieldset>
|
|
</div>
|
|
<div class="flex-box mancer-nav-container sticky-corner justify-space-between">
|
|
<input class="display-control--non-zero preexisting-char" name="attr_level" value="" type="hidden" title="@{level}"/>
|
|
<button class="rollable modal-button modal-button--thick modal-button--content controlled-display" name="act_mancer-change-class" data-i18n="change class" type="action">
|
|
</button>
|
|
<input class="display-control--inverted" name="attr_mancer_has_spells" hidden="" value="1" type="checkbox" title="@{mancer_has_spells}"/>
|
|
<button class="controlled-display rollable modal-button modal-button--thick modal-button--content" name="act_mancer-finish-level-up" data-i18n="level up" type="action">
|
|
</button>
|
|
<input class="display-control" name="attr_mancer_has_spells" hidden="" value="1" type="checkbox" title="@{mancer_has_spells}"/>
|
|
<button class="rollable modal-button modal-button--thick modal-button--content controlled-display" name="act_mancer-select-spells" data-i18n="select spells" type="action">
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="spells" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-spells controlled-display mancer-startup fade-transition layout--grid half-gap">
|
|
<h3 data-i18n="select new spells"></h3>
|
|
<div class="layout--grid tiny-gap">
|
|
<p data-i18n="spell selection instructions">Here you can add new spells for each level of spell that you have unlocked. Spells you already have added to your character can be removed using the spell section of your sheet but are locked in the character creation wizard.</p>
|
|
<p data-i18n="spell selection instructions 2">If you need to see details about a spell, click the info icon to the right of the spell name to open the spell's page in the compendium.</p>
|
|
</div><span class="locked" hidden=""></span>
|
|
<fieldset class="repeating_mancer-spells">
|
|
<input name="attr_level" hidden="" type="number" title="@{repeating_mancer-spells_$X_level}"/>
|
|
<input name="attr_class" value="" type="hidden" title="@{repeating_mancer-spells_$X_class}"/>
|
|
<input name="attr_compendium_reference" value="" type="hidden" title="@{repeating_mancer-spells_$X_compendium_reference}"/>
|
|
<input class="display-control" name="attr_type" hidden="" value="content" checked="" type="checkbox" title="@{repeating_mancer-spells_$X_type}"/>
|
|
<div class="flex-box tiny-gap justify-space-between controlled-display">
|
|
<div class="flex-box tiny-gap">
|
|
<input class="interaction-control" name="attr_selectable" hidden="" value="1" checked="" type="checkbox" title="@{repeating_mancer-spells_$X_selectable}"/>
|
|
<input class="controlled-interaction true-checkbox" name="attr_selected" value="1" type="checkbox" title="@{repeating_mancer-spells_$X_selected}"/>
|
|
<input name="attr_name" value="" type="hidden" title="@{repeating_mancer-spells_$X_name}"/><span class="bold" name="attr_name" title="@{repeating_mancer-spells_$X_name}"></span>
|
|
</div>
|
|
<input name="attr_compendium_link" value="" type="hidden" title="@{repeating_mancer-spells_$X_compendium_link}"/>
|
|
<button class="compendium-button material-icons" type="compendium" name="attr_compendium_link">info</button>
|
|
</div>
|
|
<input class="display-control header-display" name="attr_type" hidden="" value="header" type="checkbox" title="@{repeating_mancer-spells_$X_type}"/>
|
|
<div class="controlled-display flex-box half-gap">
|
|
<div class="flex-box tiny-gap bold">
|
|
<input name="attr_label" value="level" type="hidden" title="@{repeating_mancer-spells_$X_label}"/><span class="capitalize" name="attr_label" data-i18n-dynamic="" title="@{repeating_mancer-spells_$X_label}">level</span>
|
|
<input name="attr_level" hidden="" type="number" title="@{repeating_mancer-spells_$X_level}"/><span name="attr_level" title="@{repeating_mancer-spells_$X_level}"></span>
|
|
</div>
|
|
<div class="flex-box tiny-gap">
|
|
<input name="attr_chosen" hidden="" type="number" title="@{repeating_mancer-spells_$X_chosen}"/><span class="slash-control" name="attr_chosen" title="@{repeating_mancer-spells_$X_chosen}"></span><span class="slash">/</span>
|
|
<input name="attr_chosen_max" hidden="" type="number" title="@{repeating_mancer-spells_$X_chosen|max}"/><span name="attr_chosen_max" title="@{repeating_mancer-spells_$X_chosen|max}"></span>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<div class="flex-box mancer-nav-container sticky-corner justify-end">
|
|
<button class="rollable modal-button modal-button--thick modal-button--content" name="act_mancer-finish-level-up" data-i18n="select spells and level up" type="action">
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<input name="attr_mancer_stage" value="" type="hidden" title="@{mancer_stage}"/>
|
|
<input class="display-control fade-transition-control" name="attr_mancer_stage" value="tables" hidden="" type="checkbox" title="@{mancer_stage}"/>
|
|
<div class="mancer-tables controlled-display mancer-startup fade-transition rollable-table-list">
|
|
<fieldset class="repeating_rollable-tables">
|
|
<input name="attr_name" value="" type="hidden" title="@{repeating_rollable-tables_$X_name}"/>
|
|
<button class="bold roller" name="roll_roll" value="@{action}" type="roll"><span name="attr_name" title="@{repeating_rollable-tables_$X_name}"></span>
|
|
</button>
|
|
<button name="act_action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_action" type="hidden" title="@{repeating_rollable-tables_$X_action}"/>
|
|
<label class="input-label die-display"><span class="input-label__text" data-i18n="d"></span>
|
|
<input class="underlined input-label__input" name="attr_die" type="text" title="@{repeating_rollable-tables_$X_die}"/>
|
|
</label>
|
|
<label class="input-label die-display"><span class="input-label__text" data-i18n="+"></span>
|
|
<input class="underlined input-label__input" name="attr_bonus" type="text" value="0" title="@{repeating_rollable-tables_$X_bonus}"/>
|
|
</label>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="pc">
|
|
<input class="filter-sibling-by-level" name="attr_level" type="hidden" title="@{level}"/>
|
|
<input class="filter-sibling-by-class" name="attr_class" type="hidden" title="@{class}"/>
|
|
<div class="border__images filtered-by-class"><img class="border__image show-if-class border__image--tl show-if-class--cleric" src="https://raw.githubusercontent.com/mperes/dcc-images/main/cleric-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--cleric" src="https://raw.githubusercontent.com/mperes/dcc-images/main/cleric-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--cleric" src="https://raw.githubusercontent.com/mperes/dcc-images/main/cleric-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--cleric" src="https://raw.githubusercontent.com/mperes/dcc-images/main/cleric-bl.png" loading="lazy"/><img class="border__image show-if-class border__image--tl show-if-class--dwarf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/dwarf-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--dwarf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/dwarf-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--dwarf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/dwarf-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--dwarf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/dwarf-bl.png" loading="lazy"/><img class="border__image show-if-class border__image--tl show-if-class--elf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/elf-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--elf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/elf-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--elf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/elf-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--elf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/elf-bl.png" loading="lazy"/><img class="border__image show-if-class border__image--tl show-if-class--halfling" src="https://raw.githubusercontent.com/mperes/dcc-images/main/halfling-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--halfling" src="https://raw.githubusercontent.com/mperes/dcc-images/main/halfling-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--halfling" src="https://raw.githubusercontent.com/mperes/dcc-images/main/halfling-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--halfling" src="https://raw.githubusercontent.com/mperes/dcc-images/main/halfling-bl.png" loading="lazy"/><img class="border__image show-if-class border__image--tl show-if-class--thief" src="https://raw.githubusercontent.com/mperes/dcc-images/main/thief-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--thief" src="https://raw.githubusercontent.com/mperes/dcc-images/main/thief-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--thief" src="https://raw.githubusercontent.com/mperes/dcc-images/main/thief-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--thief" src="https://raw.githubusercontent.com/mperes/dcc-images/main/thief-bl.png" loading="lazy"/><img class="border__image show-if-class border__image--tl show-if-class--warrior" src="https://raw.githubusercontent.com/mperes/dcc-images/main/warrior-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--warrior" src="https://raw.githubusercontent.com/mperes/dcc-images/main/warrior-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--warrior" src="https://raw.githubusercontent.com/mperes/dcc-images/main/warrior-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--warrior" src="https://raw.githubusercontent.com/mperes/dcc-images/main/warrior-bl.png" loading="lazy"/><img class="border__image show-if-class border__image--tl show-if-class--wizard" src="https://raw.githubusercontent.com/mperes/dcc-images/main/wizard-tl.png" loading="lazy"/><img class="border__image show-if-class border__image--tr show-if-class--wizard" src="https://raw.githubusercontent.com/mperes/dcc-images/main/wizard-tr.png" loading="lazy"/><img class="border__image show-if-class border__image--br show-if-class--wizard" src="https://raw.githubusercontent.com/mperes/dcc-images/main/wizard-br.png" loading="lazy"/><img class="border__image show-if-class border__image--bl show-if-class--wizard" src="https://raw.githubusercontent.com/mperes/dcc-images/main/wizard-bl.png" loading="lazy"/><img class="border__image border__image--tl show-if-level show-if-level--zero" src="https://raw.githubusercontent.com/mperes/dcc-images/main/zero-tl.png" loading="lazy"/><img class="border__image border__image--tr show-if-level show-if-level--zero" src="https://raw.githubusercontent.com/mperes/dcc-images/main/zero-tr.png" loading="lazy"/><img class="border__image border__image--br show-if-level show-if-level--zero" src="https://raw.githubusercontent.com/mperes/dcc-images/main/zero-br.png" loading="lazy"/><img class="border__image border__image--bl show-if-level show-if-level--zero" src="https://raw.githubusercontent.com/mperes/dcc-images/main/zero-bl.png" loading="lazy"/>
|
|
</div>
|
|
<div class="layout layout--grid layout--double layout--main filtered-by-class">
|
|
<div class="layout layout--grid layout--col-left layout--block layout--fit">
|
|
<div class="layout">
|
|
<div class="section">
|
|
<datalist id="insert-occupation">
|
|
<option data-i18n="occupation-alchemist"></option>
|
|
<option data-i18n="occupation-animal-trainer"></option>
|
|
<option data-i18n="occupation-armorer"></option>
|
|
<option data-i18n="occupation-astrologer"></option>
|
|
<option data-i18n="occupation-barber"></option>
|
|
<option data-i18n="occupation-beadle"></option>
|
|
<option data-i18n="occupation-beekeeper"></option>
|
|
<option data-i18n="occupation-blacksmith"></option>
|
|
<option data-i18n="occupation-butcher"></option>
|
|
<option data-i18n="occupation-caravan-guard"></option>
|
|
<option data-i18n="occupation-cheesemaker"></option>
|
|
<option data-i18n="occupation-cobbler"></option>
|
|
<option data-i18n="occupation-confidence-artist"></option>
|
|
<option data-i18n="occupation-cooper"></option>
|
|
<option data-i18n="occupation-costermonger"></option>
|
|
<option data-i18n="occupation-cutpurse"></option>
|
|
<option data-i18n="occupation-ditch-digger"></option>
|
|
<option data-i18n="occupation-dwarven-apothacarist"></option>
|
|
<option data-i18n="occupation-dwarven-blacksmith"></option>
|
|
<option data-i18n="occupation-dwarven-chest-maker"></option>
|
|
<option data-i18n="occupation-dwarven-herder"></option>
|
|
<option data-i18n="occupation-dwarven-miner"></option>
|
|
<option data-i18n="occupation-dwarven-mushroom-farmer"></option>
|
|
<option data-i18n="occupation-dwarven-rat-catcher"></option>
|
|
<option data-i18n="occupation-dwarven-stonemason"></option>
|
|
<option data-i18n="occupation-elven-artisan"></option>
|
|
<option data-i18n="occupation-elven-barrister"></option>
|
|
<option data-i18n="occupation-elven-chandler"></option>
|
|
<option data-i18n="occupation-elven-falconer"></option>
|
|
<option data-i18n="occupation-elven-forester"></option>
|
|
<option data-i18n="occupation-elven-glassblower"></option>
|
|
<option data-i18n="occupation-elven-navigator"></option>
|
|
<option data-i18n="occupation-elven-sage"></option>
|
|
<option data-i18n="occupation-farmer"></option>
|
|
<option data-i18n="occupation-fortune-teller"></option>
|
|
<option data-i18n="occupation-gambler"></option>
|
|
<option data-i18n="occupation-gongfarmer"></option>
|
|
<option data-i18n="occupation-grave-digger"></option>
|
|
<option data-i18n="occupation-guild-beggar"></option>
|
|
<option data-i18n="occupation-halfling-chicken-butcher"></option>
|
|
<option data-i18n="occupation-halfling-dyer"></option>
|
|
<option data-i18n="occupation-halfling-glovemaker"></option>
|
|
<option data-i18n="occupation-halfling-gypsy"></option>
|
|
<option data-i18n="occupation-halfling-haberdasher"></option>
|
|
<option data-i18n="occupation-halfling-mariner"></option>
|
|
<option data-i18n="occupation-halfling-moneylender"></option>
|
|
<option data-i18n="occupation-halfling-trader"></option>
|
|
<option data-i18n="occupation-halfling-vagrant"></option>
|
|
<option data-i18n="occupation-healer"></option>
|
|
<option data-i18n="occupation-herbalist"></option>
|
|
<option data-i18n="occupation-herder"></option>
|
|
<option data-i18n="occupation-hunter"></option>
|
|
<option data-i18n="occupation-indentured-servant"></option>
|
|
<option data-i18n="occupation-jester"></option>
|
|
<option data-i18n="occupation-jeweler"></option>
|
|
<option data-i18n="occupation-locksmith"></option>
|
|
<option data-i18n="occupation-mendicant"></option>
|
|
<option data-i18n="occupation-mercenary"></option>
|
|
<option data-i18n="occupation-merchant"></option>
|
|
<option data-i18n="occupation-miller/baker"></option>
|
|
<option data-i18n="occupation-minstrel"></option>
|
|
<option data-i18n="occupation-noble"></option>
|
|
<option data-i18n="occupation-orphan"></option>
|
|
<option data-i18n="occupation-ostler"></option>
|
|
<option data-i18n="occupation-outlaw"></option>
|
|
<option data-i18n="occupation-ropemaker"></option>
|
|
<option data-i18n="occupation-scribe"></option>
|
|
<option data-i18n="occupation-shaman"></option>
|
|
<option data-i18n="occupation-slave"></option>
|
|
<option data-i18n="occupation-smuggler"></option>
|
|
<option data-i18n="occupation-soldier"></option>
|
|
<option data-i18n="occupation-squire"></option>
|
|
<option data-i18n="occupation-tax-collector"></option>
|
|
<option data-i18n="occupation-trapper"></option>
|
|
<option data-i18n="occupation-urchin"></option>
|
|
<option data-i18n="occupation-wainwright"></option>
|
|
<option data-i18n="occupation-weaver"></option>
|
|
<option data-i18n="occupation-wizard's-apprentice"></option>
|
|
<option data-i18n="occupation-woodcutter"></option>
|
|
</datalist>
|
|
<div class="section-container section-container--header">
|
|
<div class="layout layout--grid layout--header">
|
|
<div class="labelled-edit labelled-edit--character-name labelled-edit--string"><span class="labelled-edit__label" data-i18n="character-name"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_character_name_mod" type="hidden" title="@{character_name_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_character_name" type="hidden" title="@{character_name}"/><span class="labelled-edit__display" name="attr_character_name" aria-hidden="true" title="@{character_name}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-name"></span>
|
|
<input class="labelled-edit__value" name="attr_character_name" data-i18n-placeholder="insert-name" type="text" title="@{character_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--title labelled-edit--string"><span class="labelled-edit__label" data-i18n="title"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_title_mod" type="hidden" title="@{title_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_title" type="hidden" title="@{title}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_title_overwritten" type="hidden" title="@{title_overwritten}"/><span class="labelled-edit__display" name="attr_title" aria-hidden="true" title="@{title}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-title"></span>
|
|
<input class="labelled-edit__value" name="attr_title" data-i18n-placeholder="insert-title" type="text" title="@{title}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--occupation labelled-edit--autocomplete"><span class="labelled-edit__label" data-i18n="occupation"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_occupation_mod" type="hidden" title="@{occupation_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_occupation" type="hidden" title="@{occupation}"/><span class="labelled-edit__display" name="attr_occupation" aria-hidden="true" title="@{occupation}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-occupation"></span>
|
|
<input class="labelled-edit__value" name="attr_occupation" data-i18n-placeholder="insert-occupation" list="insert-occupation" type="text" title="@{occupation}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--class labelled-edit--object"><span class="labelled-edit__label" data-i18n="class"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_class_mod" type="hidden" title="@{class_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_class" type="hidden" title="@{class}"/><span class="labelled-edit__display" name="attr_class" aria-hidden="true" title="@{class}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="zero"> </span>
|
|
<select class="labelled-edit__value" name="attr_class">
|
|
<option value="zero" data-i18n="zero"></option>
|
|
<option value="cleric" data-i18n="cleric"></option>
|
|
<option value="dwarf" data-i18n="dwarf"></option>
|
|
<option value="elf" data-i18n="elf"></option>
|
|
<option value="halfling" data-i18n="halfling"></option>
|
|
<option value="thief" data-i18n="thief"></option>
|
|
<option value="warrior" data-i18n="warrior"></option>
|
|
<option value="wizard" data-i18n="wizard"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--alignment labelled-edit--object"><span class="labelled-edit__label" data-i18n="alignment"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_alignment_mod" type="hidden" title="@{alignment_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_alignment" type="hidden" title="@{alignment}"/><span class="labelled-edit__display" name="attr_alignment" aria-hidden="true" title="@{alignment}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="choose"></span>
|
|
<select class="labelled-edit__value" name="attr_alignment">
|
|
<option value="" data-i18n="choose"></option>
|
|
<option value="lawful" data-i18n="lawful"></option>
|
|
<option value="chaotic" data-i18n="chaotic"></option>
|
|
<option value="neutral" data-i18n="neutral"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--speed labelled-edit--number"><span class="labelled-edit__label" data-i18n="speed"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_speed_mod" type="hidden" title="@{speed_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_speed" type="hidden" title="@{speed}"/><span class="labelled-edit__display" name="attr_speed" aria-hidden="true" title="@{speed}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">30</span>
|
|
<input class="labelled-edit__value" name="attr_speed" placeholder="30" type="number" title="@{speed}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--birth-augur labelled-edit--string"><span class="labelled-edit__label" data-i18n="birth-augur"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_birth_augur_mod" type="hidden" title="@{birth_augur_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_birth_augur" type="hidden" title="@{birth_augur}"/><span class="labelled-edit__display" name="attr_birth_augur" aria-hidden="true" title="@{birth_augur}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="harsh-winter--all-attack-rolls"></span>
|
|
<input class="labelled-edit__value" name="attr_birth_augur" data-i18n-placeholder="harsh-winter--all-attack-rolls" type="text" title="@{birth_augur}"/>
|
|
</div>
|
|
</div>
|
|
<div class="mancer-button-wrapper labelled-edit--level">
|
|
<div class="labelled-edit labelled-edit--level labelled-edit--number"><span class="labelled-edit__label" data-i18n="level"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_level_mod" type="hidden" title="@{level_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_level" type="hidden" title="@{level}"/><span class="labelled-edit__display" name="attr_level" aria-hidden="true" title="@{level}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_level" placeholder="0" type="number" title="@{level}"/>
|
|
</div>
|
|
</div>
|
|
<input class="display-control--non-zero--inverted" name="attr_level" type="hidden" title="@{level}"/>
|
|
<button class="material-icons disabled controlled-display mancer-level-button mancer-button" name="act_mancer-level-up" data-i18n-title="Level up" type="action">plus_one
|
|
</button>
|
|
<input class="display-control--non-zero" name="attr_level" type="hidden" title="@{level}"/>
|
|
<button class="material-icons disabled controlled-display mancer-level-button mancer-button" name="act_mancer-first-level" data-i18n-title="Level up" type="action">plus_one
|
|
</button>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--xp labelled-edit--number"><span class="labelled-edit__label" data-i18n="xp"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_xp_mod" type="hidden" title="@{xp_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_xp" type="hidden" title="@{xp}"/><span class="labelled-edit__display" name="attr_xp" aria-hidden="true" title="@{xp}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_xp" placeholder="0" type="number" title="@{xp}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--double layout--defense-combat">
|
|
<div class="layout layout--grid layout--col-left">
|
|
<div class="section">
|
|
<div class="section-container section-container--defense">
|
|
<div class="layout layout--grid layout--double">
|
|
<div class="layout layout--grid layout--col-left">
|
|
<div class="labelled-edit labelled-edit--armor-class labelled-edit--number"><span class="labelled-edit__label" data-i18n="armor-class"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_armor_class_mod" type="hidden" title="@{armor_class_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_armor_class" type="hidden" title="@{armor_class}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_armor_class_overwritten" type="hidden" title="@{armor_class_overwritten}"/><span class="labelled-edit__display" name="attr_armor_class" aria-hidden="true" title="@{armor_class}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">10</span>
|
|
<input class="labelled-edit__value" name="attr_armor_class" placeholder="10" type="number" title="@{armor_class}"/>
|
|
<div class="shield"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--col-right">
|
|
<div class="labelled-edit labelled-edit--hit-points labelled-edit--number"><span class="labelled-edit__label" data-i18n="hit-points"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_hit_points_mod" type="hidden" title="@{hit_points_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_hit_points" type="hidden" title="@{hit_points}"/><span class="labelled-edit__display" name="attr_hit_points" aria-hidden="true" title="@{hit_points}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_hit_points" placeholder="0" type="number" title="@{hit_points}"/>
|
|
<div class="shield"></div>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--hit-points-max labelled-edit--number"><span class="labelled-edit__label" data-i18n="hit-points-max"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_hit_points_max_mod" type="hidden" title="@{hit_points_max_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_hit_points_max" type="hidden" title="@{hit_points|max}"/><span class="labelled-edit__display" name="attr_hit_points_max" aria-hidden="true" title="@{hit_points|max}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_hit_points_max" placeholder="0" type="number" title="@{hit_points|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--hit-die labelled-edit--string">
|
|
<button class="rollable" name="act_roll-pc-hit-die" type="action"><span class="labelled-edit__label" data-i18n="hit-die"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_hit_die_mod" type="hidden" title="@{hit_die_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_hit_die" type="hidden" title="@{hit_die}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_hit_die_overwritten" type="hidden" title="@{hit_die_overwritten}"/><span class="labelled-edit__display" name="attr_hit_die" aria-hidden="true" title="@{hit_die}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="1d4"></span>
|
|
<input class="labelled-edit__value" name="attr_hit_die" data-i18n-placeholder="1d4" type="text" title="@{hit_die}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--col-right">
|
|
<div class="headed-section">
|
|
<div class="headed-section__header">
|
|
<h3><span data-i18n="combat"></span></h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="section-container section-container--combat filtered-by-class">
|
|
<div class="labelled-edit labelled-edit--initiative labelled-edit--string">
|
|
<button class="rollable" name="act_roll-pc-initiative" type="action"><span class="labelled-edit__label" data-i18n="initiative"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_initiative_mod" type="hidden" title="@{initiative_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_initiative" type="hidden" title="@{initiative}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_initiative_overwritten" type="hidden" title="@{initiative_overwritten}"/><span class="labelled-edit__display" name="attr_initiative" aria-hidden="true" title="@{initiative}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_initiative" placeholder="0" type="text" title="@{initiative}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--action-dice labelled-edit--string"><span class="labelled-edit__label" data-i18n="action-dice"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_action_dice_mod" type="hidden" title="@{action_dice_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_action_dice" type="hidden" title="@{action_dice}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_action_dice_overwritten" type="hidden" title="@{action_dice_overwritten}"/><span class="labelled-edit__display" name="attr_action_dice" aria-hidden="true" title="@{action_dice}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
<input class="labelled-edit__value" name="attr_action_dice" data-i18n-placeholder="-" type="text" title="@{action_dice}"/>
|
|
</div>
|
|
</div>
|
|
<input class="deed-die-result" name="attr_deed_die_result" type="hidden" title="@{deed_die_result}"/>
|
|
<div class="labelled-edit labelled-edit--attack labelled-edit--string show-if-class show-if-class--warrior show-if-class--dwarf">
|
|
<button class="rollable" name="act_roll-pc-deed" type="action"><span class="labelled-edit__label" data-i18n="attack-deed"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_attack_mod" type="hidden" title="@{attack_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_attack" type="hidden" title="@{attack}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_attack_overwritten" type="hidden" title="@{attack_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_attack" aria-hidden="true" title="@{attack}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
<input class="labelled-edit__value" name="attr_attack" data-i18n-placeholder="-" type="text" title="@{attack}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--attack labelled-edit--string show-if-class show-if-class--zero show-if-class--cleric show-if-class--thief show-if-class--wizard show-if-class--elf show-if-class--halfling">
|
|
<button class="rollable" name="act_roll-pc-attack" type="action"><span class="labelled-edit__label" data-i18n="attack"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_attack_mod" type="hidden" title="@{attack_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_attack" type="hidden" title="@{attack}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_attack_overwritten" type="hidden" title="@{attack_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_attack" aria-hidden="true" title="@{attack}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
<input class="labelled-edit__value" name="attr_attack" data-i18n-placeholder="-" type="text" title="@{attack}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--crit-die labelled-edit--string">
|
|
<button class="rollable" name="act_roll-pc-crit-die" type="action"><span class="labelled-edit__label" data-i18n="crit-die"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_crit_die_mod" type="hidden" title="@{crit_die_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_crit_die" type="hidden" title="@{crit_die}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_crit_die_overwritten" type="hidden" title="@{crit_die_overwritten}"/><span class="labelled-edit__display" name="attr_crit_die" aria-hidden="true" title="@{crit_die}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
<input class="labelled-edit__value" name="attr_crit_die" data-i18n-placeholder="-" type="text" title="@{crit_die}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--crit-table labelled-edit--object"><span class="labelled-edit__label" data-i18n="crit-table"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_crit_table_mod" type="hidden" title="@{crit_table_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_crit_table" type="hidden" title="@{crit_table}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_crit_table_overwritten" type="hidden" title="@{crit_table_overwritten}"/><span class="labelled-edit__display" name="attr_crit_table" aria-hidden="true" title="@{crit_table}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="I"> </span>
|
|
<select class="labelled-edit__value" name="attr_crit_table">
|
|
<option value="I" data-i18n="I"></option>
|
|
<option value="II" data-i18n="II"></option>
|
|
<option value="III" data-i18n="III"></option>
|
|
<option value="IV" data-i18n="IV"></option>
|
|
<option value="V" data-i18n="V"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--stats">
|
|
<div class="section section--score">
|
|
<div class="section-container section-container--score">
|
|
<div class="layout layout--grid layout--score">
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--strength">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-strength" type="action"><span class="labelled-edit__label" data-i18n="strength"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--strength-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_strength_modifier_mod" type="hidden" title="@{strength_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_strength_modifier" type="hidden" title="@{strength_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_strength_modifier" aria-hidden="true" title="@{strength_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_strength_diff" hidden="" value="1" type="checkbox" title="@{strength_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_strength_total" type="hidden" title="@{strength_total}"/>
|
|
<input name="attr_strength_mod" type="hidden" title="@{strength_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_strength" type="hidden" title="@{strength}"/><span class="labelled-edit__display" name="attr_strength_total" aria-hidden="true" title="@{strength_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_strength" placeholder="0" type="number" title="@{strength}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_strength_max" type="number" title="@{strength|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--agility">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-agility" type="action"><span class="labelled-edit__label" data-i18n="agility"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--agility-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_agility_modifier_mod" type="hidden" title="@{agility_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_agility_modifier" type="hidden" title="@{agility_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_agility_modifier" aria-hidden="true" title="@{agility_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_agility_diff" hidden="" value="1" type="checkbox" title="@{agility_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_agility_total" type="hidden" title="@{agility_total}"/>
|
|
<input name="attr_agility_mod" type="hidden" title="@{agility_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_agility" type="hidden" title="@{agility}"/><span class="labelled-edit__display" name="attr_agility_total" aria-hidden="true" title="@{agility_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_agility" placeholder="0" type="number" title="@{agility}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_agility_max" type="number" title="@{agility|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--stamina">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-stamina" type="action"><span class="labelled-edit__label" data-i18n="stamina"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--stamina-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_stamina_modifier_mod" type="hidden" title="@{stamina_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_stamina_modifier" type="hidden" title="@{stamina_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_stamina_modifier" aria-hidden="true" title="@{stamina_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_stamina_diff" hidden="" value="1" type="checkbox" title="@{stamina_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_stamina_total" type="hidden" title="@{stamina_total}"/>
|
|
<input name="attr_stamina_mod" type="hidden" title="@{stamina_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_stamina" type="hidden" title="@{stamina}"/><span class="labelled-edit__display" name="attr_stamina_total" aria-hidden="true" title="@{stamina_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_stamina" placeholder="0" type="number" title="@{stamina}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_stamina_max" type="number" title="@{stamina|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--personality">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-personality" type="action"><span class="labelled-edit__label" data-i18n="personality"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--personality-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_personality_modifier_mod" type="hidden" title="@{personality_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_personality_modifier" type="hidden" title="@{personality_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_personality_modifier" aria-hidden="true" title="@{personality_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_personality_diff" hidden="" value="1" type="checkbox" title="@{personality_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_personality_total" type="hidden" title="@{personality_total}"/>
|
|
<input name="attr_personality_mod" type="hidden" title="@{personality_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_personality" type="hidden" title="@{personality}"/><span class="labelled-edit__display" name="attr_personality_total" aria-hidden="true" title="@{personality_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_personality" placeholder="0" type="number" title="@{personality}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_personality_max" type="number" title="@{personality|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--luck">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-luck" type="action"><span class="labelled-edit__label" data-i18n="luck"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--luck-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_luck_modifier_mod" type="hidden" title="@{luck_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_luck_modifier" type="hidden" title="@{luck_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_luck_modifier" aria-hidden="true" title="@{luck_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_luck_diff" hidden="" value="1" type="checkbox" title="@{luck_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_luck_total" type="hidden" title="@{luck_total}"/>
|
|
<input name="attr_luck_mod" type="hidden" title="@{luck_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_luck" type="hidden" title="@{luck}"/><span class="labelled-edit__display" name="attr_luck_total" aria-hidden="true" title="@{luck_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_luck" placeholder="0" type="number" title="@{luck}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_luck_max" type="number" title="@{luck|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--score labelled-edit--intelligence">
|
|
<div class="layout layout--flex layout--grow">
|
|
<button class="rollable" name="act_roll-pc-intelligence" type="action"><span class="labelled-edit__label" data-i18n="intelligence"></span>
|
|
</button>
|
|
<div class="labelled-edit labelled-edit--intelligence-modifier labelled-edit--readyonly labelled-edit--number labelled-edit__modifier"><span class="labelled-edit__label" data-i18n="modifier"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_intelligence_modifier_mod" type="hidden" title="@{intelligence_modifier_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_intelligence_modifier" type="hidden" title="@{intelligence_modifier}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_intelligence_modifier" aria-hidden="true" title="@{intelligence_modifier}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input class="split-control" name="attr_intelligence_diff" hidden="" value="1" type="checkbox" title="@{intelligence_diff}"/>
|
|
<div class="labelled-edit__container split-display">
|
|
<input name="attr_intelligence_total" type="hidden" title="@{intelligence_total}"/>
|
|
<input name="attr_intelligence_mod" type="hidden" title="@{intelligence_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_intelligence" type="hidden" title="@{intelligence}"/><span class="labelled-edit__display" name="attr_intelligence_total" aria-hidden="true" title="@{intelligence_total}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_intelligence" placeholder="0" type="number" title="@{intelligence}"/>
|
|
<div class="split-slash"></div>
|
|
<input class="split-max" name="attr_intelligence_max" type="number" title="@{intelligence|max}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section section--savings">
|
|
<div class="section-container section-container--savings">
|
|
<div class="layout layout--grid layout--savings">
|
|
<div class="labelled-edit labelled-edit--ref-save labelled-edit--number labelled-edit--saving">
|
|
<button class="rollable" name="act_roll-pc-ref-save" type="action"><span class="labelled-edit__label" data-i18n="ref-save"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_ref_save_mod" type="hidden" title="@{ref_save_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_ref_save" type="hidden" title="@{ref_save}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_ref_save_overwritten" type="hidden" title="@{ref_save_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_ref_save" aria-hidden="true" title="@{ref_save}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_ref_save" placeholder="0" type="number" title="@{ref_save}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--fort-save labelled-edit--number labelled-edit--saving">
|
|
<button class="rollable" name="act_roll-pc-fort-save" type="action"><span class="labelled-edit__label" data-i18n="fort-save"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_fort_save_mod" type="hidden" title="@{fort_save_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_fort_save" type="hidden" title="@{fort_save}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_fort_save_overwritten" type="hidden" title="@{fort_save_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_fort_save" aria-hidden="true" title="@{fort_save}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_fort_save" placeholder="0" type="number" title="@{fort_save}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--will-save labelled-edit--number labelled-edit--saving">
|
|
<button class="rollable" name="act_roll-pc-will-save" type="action"><span class="labelled-edit__label" data-i18n="will-save"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_will_save_mod" type="hidden" title="@{will_save_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_will_save" type="hidden" title="@{will_save}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_will_save_overwritten" type="hidden" title="@{will_save_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_will_save" aria-hidden="true" title="@{will_save}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_will_save" placeholder="0" type="number" title="@{will_save}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section section--misc">
|
|
<div class="section-container section-container--misc">
|
|
<div class="layout layout--grid layout--misc">
|
|
<div class="luck">
|
|
<div class="luck__title"><span data-i18n="lucky-roll"></span>
|
|
</div>
|
|
<div class="layout layout--grid">
|
|
<div class="labelled-edit labelled-edit--luck-max labelled-edit--number labelled-edit--misc"><span class="labelled-edit__label" data-i18n="luck-max"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_luck_max_mod" type="hidden" title="@{luck_max_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_luck_max" type="hidden" title="@{luck|max}"/><span class="labelled-edit__display" name="attr_luck_max" aria-hidden="true" title="@{luck|max}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">Max</span>
|
|
<input class="labelled-edit__value" name="attr_luck_max" placeholder="Max" type="number" title="@{luck|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--lucky-roll labelled-edit--number labelled-edit--misc"><span class="labelled-edit__label" data-i18n="lucky-roll"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_lucky_roll_mod" type="hidden" title="@{lucky_roll_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_lucky_roll" type="hidden" title="@{lucky_roll}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_lucky_roll" aria-hidden="true" title="@{lucky_roll}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_lucky_roll" placeholder="0" type="number" title="@{lucky_roll}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--melee-attack labelled-edit--string labelled-edit--misc">
|
|
<button class="rollable" name="act_roll-pc-melee-attack" type="action"><span class="labelled-edit__label" data-i18n="melee-attack"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_melee_attack_mod" type="hidden" title="@{melee_attack_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_melee_attack" type="hidden" title="@{melee_attack}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_melee_attack_overwritten" type="hidden" title="@{melee_attack_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_melee_attack" aria-hidden="true" title="@{melee_attack}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="0"></span>
|
|
<input class="labelled-edit__value" name="attr_melee_attack" data-i18n-placeholder="0" type="text" title="@{melee_attack}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--melee-damage labelled-edit--number labelled-edit--misc"><span class="labelled-edit__label" data-i18n="melee-damage"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_melee_damage_mod" type="hidden" title="@{melee_damage_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_melee_damage" type="hidden" title="@{melee_damage}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_melee_damage_overwritten" type="hidden" title="@{melee_damage_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_melee_damage" aria-hidden="true" title="@{melee_damage}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_melee_damage" placeholder="0" type="number" title="@{melee_damage}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--missile-attack labelled-edit--string labelled-edit--misc">
|
|
<button class="rollable" name="act_roll-pc-missile-attack" type="action"><span class="labelled-edit__label" data-i18n="missile-attack"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_missile_attack_mod" type="hidden" title="@{missile_attack_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_missile_attack" type="hidden" title="@{missile_attack}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_missile_attack_overwritten" type="hidden" title="@{missile_attack_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_missile_attack" aria-hidden="true" title="@{missile_attack}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="0"></span>
|
|
<input class="labelled-edit__value" name="attr_missile_attack" data-i18n-placeholder="0" type="text" title="@{missile_attack}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--missile-damage labelled-edit--number labelled-edit--misc"><span class="labelled-edit__label" data-i18n="missile-damage"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_missile_damage_mod" type="hidden" title="@{missile_damage_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_missile_damage" type="hidden" title="@{missile_damage}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_missile_damage" aria-hidden="true" title="@{missile_damage}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_missile_damage" placeholder="0" type="number" title="@{missile_damage}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--portrait labelled-edit--avatar labelled-edit--misc labelled-edit--avatar"><span class="labelled-edit__label" data-i18n="portrait"></span>
|
|
<div class="labelled-edit__container">
|
|
<input class="labelled-edit__display--raw" name="attr_character_avatar" type="hidden" title="@{character_avatar}"/><img class="labelled-edit__avatar" name="attr_character_avatar"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--languages labelled-edit--string labelled-edit--misc labelled-edit--misc-left"><span class="labelled-edit__label" data-i18n="languages"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_languages_mod" type="hidden" title="@{languages_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_languages" type="hidden" title="@{languages}"/><span class="labelled-edit__display" name="attr_languages" aria-hidden="true" title="@{languages}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-languages"></span>
|
|
<input class="labelled-edit__value" name="attr_languages" data-i18n-placeholder="insert-languages" type="text" title="@{languages}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--col-right layout--block layout--fit">
|
|
<div class="layout layout--grid layout--double">
|
|
<div class="layout layout--grid layout--col-left">
|
|
<div class="headed-section">
|
|
<div class="headed-section__header">
|
|
<h3><span data-i18n="weapon"></span>
|
|
</h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="collapse-container section-container section-container--weapon">
|
|
<input class="collapse" name="attr_weapon" value="1" type="checkbox" title="@{weapon}"/>
|
|
<div class="flex-box justify-space-between weapon-button-container compendium-dependent-content disabled">
|
|
<button class="mancer-button modal-button modal-button--thin modal-button--content roller" name="roll_crit" data-i18n="roll crit" value="@{crit_action}" type="roll">
|
|
</button>
|
|
<button name="act_crit-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_crit_action" type="hidden" title="@{crit_action}"/>
|
|
<button class="mancer-button modal-button modal-button--thin modal-button--content roller" name="roll_fumble" data-i18n="roll fumble" value="@{fumble_action}" type="roll">
|
|
</button>
|
|
<button name="act_fumble-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_fumble_action" type="hidden" title="@{fumble_action}"/>
|
|
</div>
|
|
<div class="expanded view">
|
|
<div class="carded-repeating-section">
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-weapons" type="action">
|
|
</button>
|
|
<fieldset class="repeating_weapons">
|
|
<input class="on-off-hidden__state" name="attr_active" value="1" type="hidden" title="@{repeating_weapons_$X_active}"/>
|
|
<div class="layout layout--grid">
|
|
<div class="labelled-edit labelled-edit--name labelled-edit--readyonly labelled-edit--labelless labelled-edit--string carded-repeating-section--header">
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_name_mod" type="hidden" title="@{repeating_weapons_$X_name_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_name" type="hidden" title="@{repeating_weapons_$X_name}"/><span class="labelled-edit__display" name="attr_name" aria-hidden="true" title="@{repeating_weapons_$X_name}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="unnamed"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--attack-bonus labelled-edit--readyonly labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-attack-bonus" type="action"><span class="labelled-edit__label" data-i18n="attack-bonus"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_attack_bonus_mod" type="hidden" title="@{repeating_weapons_$X_attack_bonus_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_attack_bonus" type="hidden" title="@{repeating_weapons_$X_attack_bonus}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_attack_bonus" aria-hidden="true" title="@{repeating_weapons_$X_attack_bonus}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--damage labelled-edit--readyonly labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-damage" type="action"><span class="labelled-edit__label" data-i18n="damage"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_damage_mod" type="hidden" title="@{repeating_weapons_$X_damage_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_damage" type="hidden" title="@{repeating_weapons_$X_damage}"/><span class="labelled-edit__display" name="attr_damage" aria-hidden="true" title="@{repeating_weapons_$X_damage}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--type labelled-edit--readyonly labelled-edit--string"><span class="labelled-edit__label" data-i18n="type"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_type_mod" type="hidden" title="@{repeating_weapons_$X_type_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_type" type="hidden" title="@{repeating_weapons_$X_type}"/><span class="labelled-edit__display" name="attr_type" aria-hidden="true" title="@{repeating_weapons_$X_type}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="melee"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--range labelled-edit--readyonly labelled-edit--string"><span class="labelled-edit__label" data-i18n="range"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_range_mod" type="hidden" title="@{repeating_weapons_$X_range_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_range" type="hidden" title="@{repeating_weapons_$X_range}"/><span class="labelled-edit__display" name="attr_range" aria-hidden="true" title="@{repeating_weapons_$X_range}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--ammunition labelled-edit--number"><span class="labelled-edit__label" data-i18n="ammunition"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_ammunition_mod" type="hidden" title="@{repeating_weapons_$X_ammunition_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_ammunition" type="hidden" title="@{repeating_weapons_$X_ammunition}"/><span class="labelled-edit__display" name="attr_ammunition" aria-hidden="true" title="@{repeating_weapons_$X_ammunition}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_ammunition" placeholder="0" type="number" title="@{repeating_weapons_$X_ammunition}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--notes labelled-edit--readyonly labelled-edit--textarea"><span class="labelled-edit__label" data-i18n="notes"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_notes_mod" type="hidden" title="@{repeating_weapons_$X_notes_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_notes" type="hidden" title="@{repeating_weapons_$X_notes}"/><span class="labelled-edit__display" name="attr_notes" aria-hidden="true" title="@{repeating_weapons_$X_notes}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-notes"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div class="collapsed edit">
|
|
<div class="carded-repeating-section">
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-weapons" type="action">
|
|
</button>
|
|
<fieldset class="repeating_weapons">
|
|
<div class="layout layout--grid">
|
|
<input name="attr_linked" type="hidden" title="@{repeating_weapons_$X_linked}"/>
|
|
<div class="labelled-edit labelled-edit--name labelled-edit--string "><span class="labelled-edit__label" data-i18n="name"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_name_mod" type="hidden" title="@{repeating_weapons_$X_name_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_name" type="hidden" title="@{repeating_weapons_$X_name}"/><span class="labelled-edit__display" name="attr_name" aria-hidden="true" title="@{repeating_weapons_$X_name}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-name"></span>
|
|
<input class="labelled-edit__value" name="attr_name" data-i18n-placeholder="insert-name" type="text" title="@{repeating_weapons_$X_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--attack-bonus-base labelled-edit--number"><span class="labelled-edit__label" data-i18n="attack-bonus-base"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_attack_bonus_base_mod" type="hidden" title="@{repeating_weapons_$X_attack_bonus_base_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_attack_bonus_base" type="hidden" title="@{repeating_weapons_$X_attack_bonus_base}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_attack_bonus_base" aria-hidden="true" title="@{repeating_weapons_$X_attack_bonus_base}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_attack_bonus_base" placeholder="0" type="number" title="@{repeating_weapons_$X_attack_bonus_base}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--damage-base labelled-edit--string"><span class="labelled-edit__label" data-i18n="damage-base"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_damage_base_mod" type="hidden" title="@{repeating_weapons_$X_damage_base_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_damage_base" type="hidden" title="@{repeating_weapons_$X_damage_base}"/><span class="labelled-edit__display" name="attr_damage_base" aria-hidden="true" title="@{repeating_weapons_$X_damage_base}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-damage"></span>
|
|
<input class="labelled-edit__value" name="attr_damage_base" data-i18n-placeholder="insert-damage" type="text" title="@{repeating_weapons_$X_damage_base}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--type labelled-edit--object"><span class="labelled-edit__label" data-i18n="type"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_type_mod" type="hidden" title="@{repeating_weapons_$X_type_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_type" type="hidden" title="@{repeating_weapons_$X_type}"/><span class="labelled-edit__display" name="attr_type" aria-hidden="true" title="@{repeating_weapons_$X_type}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="melee"> </span>
|
|
<select class="labelled-edit__value" name="attr_type">
|
|
<option value="melee" data-i18n="melee"></option>
|
|
<option value="missile" data-i18n="missile"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--range labelled-edit--string"><span class="labelled-edit__label" data-i18n="range"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_range_mod" type="hidden" title="@{repeating_weapons_$X_range_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_range" type="hidden" title="@{repeating_weapons_$X_range}"/><span class="labelled-edit__display" name="attr_range" aria-hidden="true" title="@{repeating_weapons_$X_range}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="0"></span>
|
|
<input class="labelled-edit__value" name="attr_range" data-i18n-placeholder="0" type="text" title="@{repeating_weapons_$X_range}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--two-handed labelled-edit--object"><span class="labelled-edit__label" data-i18n="two-handed"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_two_handed_mod" type="hidden" title="@{repeating_weapons_$X_two_handed_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_two_handed" type="hidden" title="@{repeating_weapons_$X_two_handed}"/><span class="labelled-edit__display" name="attr_two_handed" aria-hidden="true" title="@{repeating_weapons_$X_two_handed}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="no"> </span>
|
|
<select class="labelled-edit__value" name="attr_two_handed">
|
|
<option value="no" data-i18n="no"></option>
|
|
<option value="yes" data-i18n="yes"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--notes labelled-edit--textarea "><span class="labelled-edit__label" data-i18n="notes"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_notes_mod" type="hidden" title="@{repeating_weapons_$X_notes_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_notes" type="hidden" title="@{repeating_weapons_$X_notes}"/><span class="labelled-edit__display" name="attr_notes" aria-hidden="true" title="@{repeating_weapons_$X_notes}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-notes"></span>
|
|
<textarea class="labelled-edit__value" name="attr_notes" data-i18n-placeholder="insert-notes" title="@{repeating_weapons_$X_notes}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="headed-section headed-section--treasure">
|
|
<div class="headed-section__header">
|
|
<h3 class="filtered-by-class"><span data-i18n="treasure"></span></h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="section-container section-container--treasure">
|
|
<div class="labelled-edit labelled-edit--treasure labelled-edit--labelless labelled-edit--textarea">
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_treasure_mod" type="hidden" title="@{treasure_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_treasure" type="hidden" title="@{treasure}"/><span class="labelled-edit__display" name="attr_treasure" aria-hidden="true" title="@{treasure}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-treasure"></span>
|
|
<textarea class="labelled-edit__value" name="attr_treasure" data-i18n-placeholder="insert-treasure" title="@{treasure}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--col-right">
|
|
<div class="headed-section">
|
|
<div class="headed-section__header">
|
|
<h3><span data-i18n="equipment"></span>
|
|
</h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="collapse-container section-container section-container--equipment">
|
|
<input class="collapse" name="attr_equipment" value="1" type="checkbox" title="@{equipment}"/>
|
|
<div class="expanded view">
|
|
<div class="headed-repeating-section">
|
|
<div class="headed-repeating-section__header"><span data-i18n="name"></span><span data-i18n="cost"></span>
|
|
</div>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-equipment" type="action">
|
|
</button>
|
|
<fieldset class="repeating_equipment">
|
|
<div class="layout layout--flex">
|
|
<div class="on-off on-off--active">
|
|
<input name="attr_active" value="1" checked="checked" type="checkbox" title="@{repeating_equipment_$X_active}"/>
|
|
</div><span class="sheet-attribute" name="attr_name" title="@{repeating_equipment_$X_name}"></span>
|
|
</div><span class="sheet-attribute" name="attr_cost" title="@{repeating_equipment_$X_cost}"></span>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div class="collapsed edit">
|
|
<div class="headed-repeating-section">
|
|
<div class="headed-repeating-section__header"><span data-i18n="name"></span><span data-i18n="cost"></span>
|
|
</div>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-equipment" type="action">
|
|
</button>
|
|
<fieldset class="repeating_equipment">
|
|
<div class="headed-repeating-section__cell">
|
|
<input name="attr_name" data-i18n-placeholder="unnamed" type="text" title="@{repeating_equipment_$X_name}"/>
|
|
</div>
|
|
<div class="headed-repeating-section__cell">
|
|
<input name="attr_cost" placeholder="0" type="text" title="@{repeating_equipment_$X_cost}"/>
|
|
</div>
|
|
<select name="attr_type" title="@{repeating_equipment_$X_type}">
|
|
<option value="" data-i18n="equipment">
|
|
</option>
|
|
<option value="armor" data-i18n="armor">
|
|
</option>
|
|
<option value="weapon" data-i18n="weapon">
|
|
</option>
|
|
</select>
|
|
<input name="attr_modifiers" data-i18n-placeholder="insert-modifiers" type="text" title="@{repeating_equipment_$X_modifiers}"/>
|
|
<input name="attr_linked" type="hidden" title="@{repeating_equipment_$X_linked}"/>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="headed-section">
|
|
<div class="headed-section__header">
|
|
<h3><span data-i18n="armor"></span>
|
|
</h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="collapse-container section-container section-container--armor">
|
|
<input class="collapse" name="attr_armor" value="1" type="checkbox" title="@{armor}"/>
|
|
<div class="expanded view">
|
|
<div class="carded-repeating-section">
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-armor" type="action">
|
|
</button>
|
|
<fieldset class="repeating_armor">
|
|
<input class="on-off-hidden__state" name="attr_active" value="1" type="hidden" title="@{repeating_armor_$X_active}"/>
|
|
<div class="layout layout--grid">
|
|
<div class="labelled-edit labelled-edit--name labelled-edit--readyonly labelled-edit--labelless labelled-edit--string carded-repeating-section--header">
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_name_mod" type="hidden" title="@{repeating_armor_$X_name_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_name" type="hidden" title="@{repeating_armor_$X_name}"/><span class="labelled-edit__display" name="attr_name" aria-hidden="true" title="@{repeating_armor_$X_name}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="unnamed"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--ac-bonus labelled-edit--readyonly labelled-edit--number"><span class="labelled-edit__label" data-i18n="ac-bonus"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_ac_bonus_mod" type="hidden" title="@{repeating_armor_$X_ac_bonus_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_ac_bonus" type="hidden" title="@{repeating_armor_$X_ac_bonus}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_ac_bonus" aria-hidden="true" title="@{repeating_armor_$X_ac_bonus}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--check-penalty labelled-edit--readyonly labelled-edit--number"><span class="labelled-edit__label" data-i18n="check-penalty"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_check_penalty_mod" type="hidden" title="@{repeating_armor_$X_check_penalty_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_check_penalty" type="hidden" title="@{repeating_armor_$X_check_penalty}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_check_penalty" aria-hidden="true" title="@{repeating_armor_$X_check_penalty}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--speed labelled-edit--readyonly labelled-edit--number"><span class="labelled-edit__label" data-i18n="speed"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_speed_mod" type="hidden" title="@{repeating_armor_$X_speed_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_speed" type="hidden" title="@{repeating_armor_$X_speed}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_speed" aria-hidden="true" title="@{repeating_armor_$X_speed}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--fumble-die labelled-edit--readyonly labelled-edit--string"><span class="labelled-edit__label" data-i18n="fumble-die"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_fumble_die_mod" type="hidden" title="@{repeating_armor_$X_fumble_die_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_fumble_die" type="hidden" title="@{repeating_armor_$X_fumble_die}"/><span class="labelled-edit__display" name="attr_fumble_die" aria-hidden="true" title="@{repeating_armor_$X_fumble_die}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="-"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div class="collapsed edit">
|
|
<div class="carded-repeating-section">
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-armor" type="action">
|
|
</button>
|
|
<fieldset class="repeating_armor">
|
|
<div class="layout layout--grid">
|
|
<input name="attr_linked" type="hidden" title="@{repeating_armor_$X_linked}"/>
|
|
<div class="labelled-edit labelled-edit--name labelled-edit--string "><span class="labelled-edit__label" data-i18n="name"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_name_mod" type="hidden" title="@{repeating_armor_$X_name_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_name" type="hidden" title="@{repeating_armor_$X_name}"/><span class="labelled-edit__display" name="attr_name" aria-hidden="true" title="@{repeating_armor_$X_name}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-name"></span>
|
|
<input class="labelled-edit__value" name="attr_name" data-i18n-placeholder="insert-name" type="text" title="@{repeating_armor_$X_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--ac-bonus labelled-edit--number"><span class="labelled-edit__label" data-i18n="ac-bonus"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_ac_bonus_mod" type="hidden" title="@{repeating_armor_$X_ac_bonus_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_ac_bonus" type="hidden" title="@{repeating_armor_$X_ac_bonus}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_ac_bonus" aria-hidden="true" title="@{repeating_armor_$X_ac_bonus}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_ac_bonus" placeholder="0" type="number" title="@{repeating_armor_$X_ac_bonus}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--check-penalty labelled-edit--number"><span class="labelled-edit__label" data-i18n="check-penalty"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_check_penalty_mod" type="hidden" title="@{repeating_armor_$X_check_penalty_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_check_penalty" type="hidden" title="@{repeating_armor_$X_check_penalty}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_check_penalty" aria-hidden="true" title="@{repeating_armor_$X_check_penalty}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_check_penalty" placeholder="0" type="number" title="@{repeating_armor_$X_check_penalty}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--speed labelled-edit--number"><span class="labelled-edit__label" data-i18n="speed"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_speed_mod" type="hidden" title="@{repeating_armor_$X_speed_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_speed" type="hidden" title="@{repeating_armor_$X_speed}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_speed" aria-hidden="true" title="@{repeating_armor_$X_speed}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_speed" placeholder="0" type="number" title="@{repeating_armor_$X_speed}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--fumble-die labelled-edit--object"><span class="labelled-edit__label" data-i18n="fumble-die"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_fumble_die_mod" type="hidden" title="@{repeating_armor_$X_fumble_die_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_fumble_die" type="hidden" title="@{repeating_armor_$X_fumble_die}"/><span class="labelled-edit__display" name="attr_fumble_die" aria-hidden="true" title="@{repeating_armor_$X_fumble_die}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="choose"></span>
|
|
<select class="labelled-edit__value" name="attr_fumble_die">
|
|
<option value="" data-i18n="choose"></option>
|
|
<option value="d3" data-i18n="d3"></option>
|
|
<option value="d4" data-i18n="d4"></option>
|
|
<option value="d5" data-i18n="d5"></option>
|
|
<option value="d6" data-i18n="d6"></option>
|
|
<option value="d7" data-i18n="d7"></option>
|
|
<option value="d8" data-i18n="d8"></option>
|
|
<option value="d10" data-i18n="d10"></option>
|
|
<option value="d12" data-i18n="d12"></option>
|
|
<option value="d14" data-i18n="d14"></option>
|
|
<option value="d16" data-i18n="d16"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--shield labelled-edit--object"><span class="labelled-edit__label" data-i18n="shield"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_shield_mod" type="hidden" title="@{repeating_armor_$X_shield_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_shield" type="hidden" title="@{repeating_armor_$X_shield}"/><span class="labelled-edit__display" name="attr_shield" aria-hidden="true" title="@{repeating_armor_$X_shield}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="no"> </span>
|
|
<select class="labelled-edit__value" name="attr_shield">
|
|
<option value="no" data-i18n="no"></option>
|
|
<option value="yes" data-i18n="yes"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--max">
|
|
<div class="headed-section show-if-class show-if-class--cleric show-if-class--dwarf show-if-class--elf show-if-class--halfling show-if-class--thief show-if-class--warrior show-if-class--wizard">
|
|
<div class="headed-section__header">
|
|
<input class="filter-sibling-by-level" name="attr_level" type="hidden" title="@{level}"/>
|
|
<input class="filter-sibling-by-class" name="attr_class" type="hidden" title="@{class}"/>
|
|
<h3 class="filtered-by-class"><span class="show-if-class show-if-class--cleric" data-i18n="cleric-spells-and-abilities"></span><span class="show-if-class show-if-class--dwarf" data-i18n="dwarf-abilities"></span><span class="show-if-class show-if-class--elf" data-i18n="elf-abilities"></span><span class="show-if-class show-if-class--halfling" data-i18n="halfling-abilities"></span><span class="show-if-class show-if-class--thief" data-i18n="thief-abilities"></span><span class="show-if-class show-if-class--warrior" data-i18n="warrior-abilities"></span><span class="show-if-class show-if-class--wizard" data-i18n="wizard-spells-and-abilities"></span></h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="section-container section-container--abilities">
|
|
<input class="filter-sibling-by-level" name="attr_level" type="hidden" title="@{level}"/>
|
|
<input class="filter-sibling-by-class" name="attr_class" type="hidden" title="@{class}"/>
|
|
<div class="filtered-by-class">
|
|
<div class="show-if-class show-if-class--cleric">
|
|
<div class="layout layout--grid layout--cleric-display">
|
|
<datalist id="insert-deity">
|
|
<option>Ahriman</option>
|
|
<option>Amun Tor</option>
|
|
<option>Aristemis</option>
|
|
<option>Azi Dahaka</option>
|
|
<option>Bobugbubilz</option>
|
|
<option>Cadixtat</option>
|
|
<option>Choranus</option>
|
|
<option>Cthulhu</option>
|
|
<option>Daenthar</option>
|
|
<option>Gorhan</option>
|
|
<option>Hidden Lord</option>
|
|
<option>Ildavir</option>
|
|
<option>Justicia</option>
|
|
<option>Klazath</option>
|
|
<option>Malotoch</option>
|
|
<option>Nimlurun</option>
|
|
<option>Pelagia</option>
|
|
<option>Shul</option>
|
|
<option>Ulesh</option>
|
|
</datalist>
|
|
<div class="layout layout--flex">
|
|
<div class="labelled-edit labelled-edit--deity labelled-edit--autocomplete"><span class="labelled-edit__label" data-i18n="deity"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_deity_mod" type="hidden" title="@{deity_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_deity" type="hidden" title="@{deity}"/><span class="labelled-edit__display" name="attr_deity" aria-hidden="true" title="@{deity}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-deity"></span>
|
|
<input class="labelled-edit__value" name="attr_deity" data-i18n-placeholder="insert-deity" list="insert-deity" type="text" title="@{deity}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--base-spell-check labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-base-spell-check" type="action"><span class="labelled-edit__label" data-i18n="base-spell-check"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_base_spell_check_mod" type="hidden" title="@{base_spell_check_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_base_spell_check" type="hidden" title="@{base_spell_check}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_base_spell_check_overwritten" type="hidden" title="@{base_spell_check_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_base_spell_check" aria-hidden="true" title="@{base_spell_check}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_base_spell_check" placeholder="0" type="number" title="@{base_spell_check}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="labelled labelled--disapproval-range"><span class="labelled__label" data-i18n="disapproval-range"></span>
|
|
<div class="fill-up-to fill-up-to--disapproval-range">
|
|
<div class="fill-up-to__value" style="order: 15">
|
|
<label><span>15</span>
|
|
<input mame="disapproval range" value="15" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 14">
|
|
<label><span>14</span>
|
|
<input mame="disapproval range" value="14" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 13">
|
|
<label><span>13</span>
|
|
<input mame="disapproval range" value="13" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 12">
|
|
<label><span>12</span>
|
|
<input mame="disapproval range" value="12" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 11">
|
|
<label><span>11</span>
|
|
<input mame="disapproval range" value="11" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 10">
|
|
<label><span>10</span>
|
|
<input mame="disapproval range" value="10" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 9">
|
|
<label><span>9</span>
|
|
<input mame="disapproval range" value="9" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 8">
|
|
<label><span>8</span>
|
|
<input mame="disapproval range" value="8" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 7">
|
|
<label><span>7</span>
|
|
<input mame="disapproval range" value="7" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 6">
|
|
<label><span>6</span>
|
|
<input mame="disapproval range" value="6" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 5">
|
|
<label><span>5</span>
|
|
<input mame="disapproval range" value="5" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 4">
|
|
<label><span>4</span>
|
|
<input mame="disapproval range" value="4" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 3">
|
|
<label><span>3</span>
|
|
<input mame="disapproval range" value="3" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 2">
|
|
<label><span>2</span>
|
|
<input mame="disapproval range" value="2" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
<div class="fill-up-to__value" style="order: 1">
|
|
<label><span>1</span>
|
|
<input mame="disapproval range" value="1" type="checkbox" name="attr_undefined" title="@{undefined}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="labelled labelled--abilities"><span class="labelled__label" data-i18n="abilities"></span>
|
|
<div class="i18n-list"><span data-i18n="divine-aid"></span><span><span data-i18n="turn-unholy"></span> <span class="between-parentheses" data-i18n="per-luck-mods"></span></span><span data-i18n="lay-on-hands"></span>
|
|
</div>
|
|
</div>
|
|
<div class="table table--lay-on-hands">
|
|
<div class="table__header">
|
|
<div class="table__cell truncated"><span class="truncated"><span data-i18n="lay-on-hands"></span><span> </span><span class="between-parentheses" data-i18n="names-alignment-step"></span></span></div>
|
|
<div class="table__cell table__cell--align-center"><span>12</span></div>
|
|
<div class="table__cell table__cell--align-center"><span>14</span></div>
|
|
<div class="table__cell table__cell--align-center"><span>20</span></div>
|
|
<div class="table__cell table__cell--align-center"><span>22+</span></div>
|
|
</div>
|
|
<div class="table__body">
|
|
<div class="table__cell">
|
|
<div class="layout layout--flex lay-on-hands-players">
|
|
<button class="rollable" name="act_roll-pc-lay-on-hands-same" type="action"><span class="between-parentheses" data-i18n="same"></span>
|
|
</button>
|
|
<input name="attr_lay_on_hands_same" data-i18n-placeholder="insert-players" type="text" title="@{lay_on_hands_same}"/>
|
|
</div>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>2 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>3 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>4 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>5 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell">
|
|
<div class="layout layout--flex lay-on-hands-players">
|
|
<button class="rollable" name="act_roll-pc-lay-on-hands-adjacent" type="action"><span class="between-parentheses" data-i18n="adjacent"></span>
|
|
</button>
|
|
<input name="attr_lay_on_hands_adjacent" data-i18n-placeholder="insert-players" type="text" title="@{lay_on_hands_adjacent}"/>
|
|
</div>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>1 </span><span data-i18n="die"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>2 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>3 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>4 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell">
|
|
<div class="layout layout--flex lay-on-hands-players">
|
|
<button class="rollable" name="act_roll-pc-lay-on-hands-opposed" type="action"><span class="between-parentheses" data-i18n="opposed"></span>
|
|
</button>
|
|
<input name="attr_lay_on_hands_opposed" data-i18n-placeholder="insert-players" type="text" title="@{lay_on_hands_opposed}"/>
|
|
</div>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>1 </span><span data-i18n="die"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>1 </span><span data-i18n="die"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>2 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
<div class="table__cell table__cell--align-center"><span>3 </span><span data-i18n="dice"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="show-if-class show-if-class--dwarf">
|
|
<div class="layout layout--grid layout--dwarf-display"><span class="sheet-ability" data-i18n="infravision"></span>
|
|
<div class="labelled labelled--abilities"><span class="labelled__label" data-i18n="underground-skills"></span>
|
|
<div class="i18n-list"><span data-i18n="smell-gold-gems"></span><span data-i18n="find-construction"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--lucky-weapon labelled-edit--string"><span class="labelled-edit__label" data-i18n="lucky-weapon"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_lucky_weapon_mod" type="hidden" title="@{lucky_weapon_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_lucky_weapon" type="hidden" title="@{lucky_weapon}"/><span class="labelled-edit__display" name="attr_lucky_weapon" aria-hidden="true" title="@{lucky_weapon}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-lucky-weapon"></span>
|
|
<input class="labelled-edit__value" name="attr_lucky_weapon" data-i18n-placeholder="insert-lucky-weapon" type="text" title="@{lucky_weapon}"/>
|
|
</div>
|
|
</div><span class="sheet-ability" data-i18n="mighty-deeds-of-arms"></span><span>
|
|
<button class="rollable" name="act_roll-pc-shield-bash" type="action">
|
|
<input name="attr_shield_bash" value="1d14" type="hidden" title="@{shield_bash}"/><span class="sheet-ability" data-i18n="shield-bash"></span><span> </span><span class="between-parentheses">1d14 <span data-i18n="action"></span></span>
|
|
</button></span>
|
|
</div>
|
|
</div>
|
|
<div class="show-if-class show-if-class--elf">
|
|
<div class="layout layout--grid layout--elf-display">
|
|
<div class="labelled-edit labelled-edit--base-spell-check labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-base-spell-check" type="action"><span class="labelled-edit__label" data-i18n="base-spell-check"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_base_spell_check_mod" type="hidden" title="@{base_spell_check_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_base_spell_check" type="hidden" title="@{base_spell_check}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_base_spell_check_overwritten" type="hidden" title="@{base_spell_check_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_base_spell_check" aria-hidden="true" title="@{base_spell_check}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_base_spell_check" placeholder="0" type="number" title="@{base_spell_check}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--familiar labelled-edit--string"><span class="labelled-edit__label" data-i18n="familiar"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_familiar_mod" type="hidden" title="@{familiar_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_familiar" type="hidden" title="@{familiar}"/><span class="labelled-edit__display" name="attr_familiar" aria-hidden="true" title="@{familiar}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-familiar"></span>
|
|
<input class="labelled-edit__value" name="attr_familiar" data-i18n-placeholder="insert-familiar" type="text" title="@{familiar}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--patrons labelled-edit--string"><span class="labelled-edit__label" data-i18n="patrons"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_patrons_mod" type="hidden" title="@{patrons_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_patrons" type="hidden" title="@{patrons}"/><span class="labelled-edit__display" name="attr_patrons" aria-hidden="true" title="@{patrons}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-patrons"></span>
|
|
<input class="labelled-edit__value" name="attr_patrons" data-i18n-placeholder="insert-patrons" type="text" title="@{patrons}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--corruption labelled-edit--string"><span class="labelled-edit__label" data-i18n="corruption"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_corruption_mod" type="hidden" title="@{corruption_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_corruption" type="hidden" title="@{corruption}"/><span class="labelled-edit__display" name="attr_corruption" aria-hidden="true" title="@{corruption}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-corruption"></span>
|
|
<input class="labelled-edit__value" name="attr_corruption" data-i18n-placeholder="insert-corruption" type="text" title="@{corruption}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled labelled--abilities"><span class="labelled__label" data-i18n="elf-traits"></span>
|
|
<div class="i18n-list"><span data-i18n="iron-vulnerability"></span><span data-i18n="heightened-senses"></span><span data-i18n="luck-mod-to-one-level-1-spell"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--other-notes labelled-edit--string"><span class="labelled-edit__label" data-i18n="other-notes"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_other_notes_mod" type="hidden" title="@{other_notes_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_other_notes" type="hidden" title="@{other_notes}"/><span class="labelled-edit__display" name="attr_other_notes" aria-hidden="true" title="@{other_notes}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-other-notes"></span>
|
|
<input class="labelled-edit__value" name="attr_other_notes" data-i18n-placeholder="insert-other-notes" type="text" title="@{other_notes}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="show-if-class show-if-class--halfling">
|
|
<div class="layout layout--grid layout--hafling-display">
|
|
<div class="layout layout--grid"><span class="sheet-ability" data-i18n="infravision"></span>
|
|
<div class="labelled-edit labelled-edit--stealth labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-stealth" type="action"><span class="labelled-edit__label" data-i18n="stealth"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_stealth_mod" type="hidden" title="@{stealth_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_stealth" type="hidden" title="@{stealth}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_stealth_overwritten" type="hidden" title="@{stealth_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_stealth" aria-hidden="true" title="@{stealth}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_stealth" placeholder="0" type="number" title="@{stealth}"/>
|
|
</div>
|
|
</div><span class="sheet-ability" data-i18n="lucky"></span>
|
|
</div>
|
|
<div class="layout layout--grid"><span class="sheet-ability" data-i18n="two-weapon-fighting"></span>
|
|
<ul>
|
|
<li><span data-i18n="action-dice-d16-d16"></span>
|
|
</li>
|
|
<li><span data-i18n="crit-on-nat-16"></span>
|
|
</li>
|
|
<li><span data-i18n="fumble-only-on-2x-1"></span>
|
|
</li>
|
|
<li><span data-i18n="if-agi-bigger-than-16-use-normal-rules"></span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="show-if-class show-if-class--thief">
|
|
<div class="layout layout--grid layout--thief-display">
|
|
<div class="labelled-edit labelled-edit--luck-die labelled-edit--object">
|
|
<button class="rollable" name="act_roll-pc-luck-die" type="action"><span class="labelled-edit__label" data-i18n="luck-die"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_luck_die_mod" type="hidden" title="@{luck_die_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_luck_die" type="hidden" title="@{luck_die}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_luck_die_overwritten" type="hidden" title="@{luck_die_overwritten}"/><span class="labelled-edit__display" name="attr_luck_die" aria-hidden="true" title="@{luck_die}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="choose"></span>
|
|
<select class="labelled-edit__value" name="attr_luck_die">
|
|
<option value="" data-i18n="choose"></option>
|
|
<option value="d3" data-i18n="d3"></option>
|
|
<option value="d4" data-i18n="d4"></option>
|
|
<option value="d5" data-i18n="d5"></option>
|
|
<option value="d6" data-i18n="d6"></option>
|
|
<option value="d7" data-i18n="d7"></option>
|
|
<option value="d8" data-i18n="d8"></option>
|
|
<option value="d10" data-i18n="d10"></option>
|
|
<option value="d12" data-i18n="d12"></option>
|
|
<option value="d14" data-i18n="d14"></option>
|
|
<option value="d16" data-i18n="d16"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--disable-trap labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-disable-trap" type="action"><span class="labelled-edit__label" data-i18n="disable-trap"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_disable_trap_mod" type="hidden" title="@{disable_trap_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_disable_trap" type="hidden" title="@{disable_trap}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_disable_trap_overwritten" type="hidden" title="@{disable_trap_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_disable_trap" aria-hidden="true" title="@{disable_trap}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_disable_trap" placeholder="0" type="number" title="@{disable_trap}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--backstab labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-backstab" type="action"><span class="labelled-edit__label" data-i18n="backstab"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_backstab_mod" type="hidden" title="@{backstab_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_backstab" type="hidden" title="@{backstab}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_backstab_overwritten" type="hidden" title="@{backstab_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_backstab" aria-hidden="true" title="@{backstab}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_backstab" placeholder="0" type="number" title="@{backstab}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--forge-document labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-forge-document" type="action"><span class="labelled-edit__label" data-i18n="forge-document"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_forge_document_mod" type="hidden" title="@{forge_document_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_forge_document" type="hidden" title="@{forge_document}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_forge_document_overwritten" type="hidden" title="@{forge_document_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_forge_document" aria-hidden="true" title="@{forge_document}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_forge_document" placeholder="0" type="number" title="@{forge_document}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--sneak-silently labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-sneak-silently" type="action"><span class="labelled-edit__label" data-i18n="sneak-silently"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_sneak_silently_mod" type="hidden" title="@{sneak_silently_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_sneak_silently" type="hidden" title="@{sneak_silently}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_sneak_silently_overwritten" type="hidden" title="@{sneak_silently_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_sneak_silently" aria-hidden="true" title="@{sneak_silently}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_sneak_silently" placeholder="0" type="number" title="@{sneak_silently}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--disguise-self labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-disguise-self" type="action"><span class="labelled-edit__label" data-i18n="disguise-self"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_disguise_self_mod" type="hidden" title="@{disguise_self_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_disguise_self" type="hidden" title="@{disguise_self}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_disguise_self_overwritten" type="hidden" title="@{disguise_self_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_disguise_self" aria-hidden="true" title="@{disguise_self}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_disguise_self" placeholder="0" type="number" title="@{disguise_self}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--hide-in-shadows labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-hide-in-shadows" type="action"><span class="labelled-edit__label" data-i18n="hide-in-shadows"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_hide_in_shadows_mod" type="hidden" title="@{hide_in_shadows_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_hide_in_shadows" type="hidden" title="@{hide_in_shadows}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_hide_in_shadows_overwritten" type="hidden" title="@{hide_in_shadows_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_hide_in_shadows" aria-hidden="true" title="@{hide_in_shadows}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_hide_in_shadows" placeholder="0" type="number" title="@{hide_in_shadows}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--read-languages labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-read-languages" type="action"><span class="labelled-edit__label" data-i18n="read-languages"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_read_languages_mod" type="hidden" title="@{read_languages_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_read_languages" type="hidden" title="@{read_languages}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_read_languages_overwritten" type="hidden" title="@{read_languages_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_read_languages" aria-hidden="true" title="@{read_languages}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_read_languages" placeholder="0" type="number" title="@{read_languages}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--pick-pocket labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-pick-pocket" type="action"><span class="labelled-edit__label" data-i18n="pick-pocket"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_pick_pocket_mod" type="hidden" title="@{pick_pocket_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_pick_pocket" type="hidden" title="@{pick_pocket}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_pick_pocket_overwritten" type="hidden" title="@{pick_pocket_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_pick_pocket" aria-hidden="true" title="@{pick_pocket}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_pick_pocket" placeholder="0" type="number" title="@{pick_pocket}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--handle-poison labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-handle-poison" type="action"><span class="labelled-edit__label" data-i18n="handle-poison"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_handle_poison_mod" type="hidden" title="@{handle_poison_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_handle_poison" type="hidden" title="@{handle_poison}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_handle_poison_overwritten" type="hidden" title="@{handle_poison_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_handle_poison" aria-hidden="true" title="@{handle_poison}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_handle_poison" placeholder="0" type="number" title="@{handle_poison}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--climb-sheer-surfaces labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-climb-sheer-surfaces" type="action"><span class="labelled-edit__label" data-i18n="climb-sheer-surfaces"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_climb_sheer_surfaces_mod" type="hidden" title="@{climb_sheer_surfaces_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_climb_sheer_surfaces" type="hidden" title="@{climb_sheer_surfaces}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_climb_sheer_surfaces_overwritten" type="hidden" title="@{climb_sheer_surfaces_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_climb_sheer_surfaces" aria-hidden="true" title="@{climb_sheer_surfaces}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_climb_sheer_surfaces" placeholder="0" type="number" title="@{climb_sheer_surfaces}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--cast-spell-from-scroll labelled-edit--object">
|
|
<button class="rollable" name="act_roll-pc-cast-spell-from-scroll" type="action"><span class="labelled-edit__label" data-i18n="cast-spell-from-scroll"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_cast_spell_from_scroll_mod" type="hidden" title="@{cast_spell_from_scroll_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_cast_spell_from_scroll" type="hidden" title="@{cast_spell_from_scroll}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_cast_spell_from_scroll_overwritten" type="hidden" title="@{cast_spell_from_scroll_overwritten}"/><span class="labelled-edit__display" name="attr_cast_spell_from_scroll" aria-hidden="true" title="@{cast_spell_from_scroll}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="choose"></span>
|
|
<select class="labelled-edit__value" name="attr_cast_spell_from_scroll">
|
|
<option value="" data-i18n="choose"></option>
|
|
<option value="d3" data-i18n="d3"></option>
|
|
<option value="d4" data-i18n="d4"></option>
|
|
<option value="d5" data-i18n="d5"></option>
|
|
<option value="d6" data-i18n="d6"></option>
|
|
<option value="d7" data-i18n="d7"></option>
|
|
<option value="d8" data-i18n="d8"></option>
|
|
<option value="d10" data-i18n="d10"></option>
|
|
<option value="d12" data-i18n="d12"></option>
|
|
<option value="d14" data-i18n="d14"></option>
|
|
<option value="d16" data-i18n="d16"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--pick-lock labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-pick-lock" type="action"><span class="labelled-edit__label" data-i18n="pick-lock"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_pick_lock_mod" type="hidden" title="@{pick_lock_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_pick_lock" type="hidden" title="@{pick_lock}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_pick_lock_overwritten" type="hidden" title="@{pick_lock_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_pick_lock" aria-hidden="true" title="@{pick_lock}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_pick_lock" placeholder="0" type="number" title="@{pick_lock}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--find-trap labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-find-trap" type="action"><span class="labelled-edit__label" data-i18n="find-trap"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_find_trap_mod" type="hidden" title="@{find_trap_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_find_trap" type="hidden" title="@{find_trap}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_find_trap_overwritten" type="hidden" title="@{find_trap_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_find_trap" aria-hidden="true" title="@{find_trap}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_find_trap" placeholder="0" type="number" title="@{find_trap}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="show-if-class show-if-class--warrior">
|
|
<div class="layout layout--grid layout--warrior-display">
|
|
<div class="labelled-edit labelled-edit--critical-threat-range labelled-edit--number"><span class="labelled-edit__label" data-i18n="critical-threat-range"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_critical_threat_range_mod" type="hidden" title="@{critical_threat_range_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_critical_threat_range" type="hidden" title="@{critical_threat_range}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_critical_threat_range_overwritten" type="hidden" title="@{critical_threat_range_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_critical_threat_range" aria-hidden="true" title="@{critical_threat_range}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">20</span>
|
|
<input class="labelled-edit__value" name="attr_critical_threat_range" placeholder="20" type="number" title="@{critical_threat_range}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--lucky-weapon labelled-edit--string"><span class="labelled-edit__label" data-i18n="lucky-weapon"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_lucky_weapon_mod" type="hidden" title="@{lucky_weapon_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_lucky_weapon" type="hidden" title="@{lucky_weapon}"/><span class="labelled-edit__display" name="attr_lucky_weapon" aria-hidden="true" title="@{lucky_weapon}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-lucky-weapon"></span>
|
|
<input class="labelled-edit__value" name="attr_lucky_weapon" data-i18n-placeholder="insert-lucky-weapon" type="text" title="@{lucky_weapon}"/>
|
|
</div>
|
|
</div><span class="sheet-ability"><span data-i18n="add-class-level-to-initiative"></span>, <span data-i18n="mighty-deeds-of-arms"></span></span>
|
|
</div>
|
|
</div>
|
|
<div class="show-if-class show-if-class--wizard">
|
|
<div class="layout layout--grid layout--wizard-display">
|
|
<div class="labelled-edit labelled-edit--base-spell-check labelled-edit--number">
|
|
<button class="rollable" name="act_roll-pc-base-spell-check" type="action"><span class="labelled-edit__label" data-i18n="base-spell-check"></span>
|
|
</button>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_base_spell_check_mod" type="hidden" title="@{base_spell_check_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_base_spell_check" type="hidden" title="@{base_spell_check}"/>
|
|
<input class="labelled-edit__display--overwritten" name="attr_base_spell_check_overwritten" type="hidden" title="@{base_spell_check_overwritten}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_base_spell_check" aria-hidden="true" title="@{base_spell_check}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_base_spell_check" placeholder="0" type="number" title="@{base_spell_check}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--familiar labelled-edit--string"><span class="labelled-edit__label" data-i18n="familiar"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_familiar_mod" type="hidden" title="@{familiar_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_familiar" type="hidden" title="@{familiar}"/><span class="labelled-edit__display" name="attr_familiar" aria-hidden="true" title="@{familiar}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-familiar"></span>
|
|
<input class="labelled-edit__value" name="attr_familiar" data-i18n-placeholder="insert-familiar" type="text" title="@{familiar}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--patrons labelled-edit--string"><span class="labelled-edit__label" data-i18n="patrons"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_patrons_mod" type="hidden" title="@{patrons_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_patrons" type="hidden" title="@{patrons}"/><span class="labelled-edit__display" name="attr_patrons" aria-hidden="true" title="@{patrons}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-patrons"></span>
|
|
<input class="labelled-edit__value" name="attr_patrons" data-i18n-placeholder="insert-patrons" type="text" title="@{patrons}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--corruption labelled-edit--string"><span class="labelled-edit__label" data-i18n="corruption"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_corruption_mod" type="hidden" title="@{corruption_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_corruption" type="hidden" title="@{corruption}"/><span class="labelled-edit__display" name="attr_corruption" aria-hidden="true" title="@{corruption}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-corruption"></span>
|
|
<input class="labelled-edit__value" name="attr_corruption" data-i18n-placeholder="insert-corruption" type="text" title="@{corruption}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--other-notes labelled-edit--string"><span class="labelled-edit__label" data-i18n="other-notes"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_other_notes_mod" type="hidden" title="@{other_notes_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_other_notes" type="hidden" title="@{other_notes}"/><span class="labelled-edit__display" name="attr_other_notes" aria-hidden="true" title="@{other_notes}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-other-notes"></span>
|
|
<input class="labelled-edit__value" name="attr_other_notes" data-i18n-placeholder="insert-other-notes" type="text" title="@{other_notes}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="headed-section show-if-class show-if-class--cleric show-if-class--elf show-if-class--wizard">
|
|
<div class="headed-section__header">
|
|
<h3><span data-i18n="spells"></span>
|
|
</h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="collapse-container section-container section-container--spells">
|
|
<input class="collapse" name="attr_spells" value="1" type="checkbox" title="@{spells}"/>
|
|
<input name="attr__reporder_repeating_spells" type="hidden" title="@{_reporder_repeating_spells}"/>
|
|
<input name="attr_spells" value="0" type="hidden" title="@{spells}"/>
|
|
<input class="filter-sibling-by-level" name="attr_level" type="hidden" title="@{level}"/>
|
|
<input class="filter-sibling-by-class" name="attr_class" type="hidden" title="@{class}"/>
|
|
<div class="filtered-by-class headed-repeating-section">
|
|
<div class="headed-repeating-section__header show-if-class show-if-class--elf show-if-class--wizard"><span data-i18n="name"></span><span data-i18n="level"></span><span data-i18n="check"></span><span data-i18n="mercurial-effects-and-notes"></span>
|
|
</div>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-spells" type="action">
|
|
</button>
|
|
<fieldset class="repeating_spells">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_spells_$X_collapse}" style="z-index:10;"/>
|
|
<input name="attr_master" value="" type="hidden" title="@{repeating_spells_$X_master}"/>
|
|
<input name="attr_compendium_reference" type="hidden" title="@{repeating_spells_$X_compendium_reference}"/>
|
|
<input class="display-control" name="attr_row_type" value="master" hidden="" checked="" type="checkbox" title="@{repeating_spells_$X_row_type}"/>
|
|
<div class="controlled-display spell-details collapse-container flex-span-all subgrid">
|
|
<input class="collapse" name="attr_collapse" hidden="" value="1" type="checkbox" title="@{repeating_spells_$X_collapse}"/>
|
|
<details class="filter-sibling-by-state collapsed">
|
|
<summary><span class="sheet-attribute show-if-class show-if-class--cleric show-if-class--elf show-if-class--wizard" name="attr_name" title="@{repeating_spells_$X_name}"></span>
|
|
</summary>
|
|
</details><span class="sheet-attribute show-if-class show-if-class--elf show-if-class--wizard collapsed" name="attr_level" title="@{repeating_spells_$X_level}"></span>
|
|
<input name="attr_total_check" value="0" type="hidden" title="@{repeating_spells_$X_total_check}"/>
|
|
<button class="rollable total check collapsed" name="act_roll-pc-total-check" type="action">
|
|
<input class="sheet-attribute sheet-attribute--roll-bonus-value" type="hidden" name="attr_total_check"/><span class="sheet-attribute sheet-attribute--roll-bonus sheet-attribute--with-default" name="attr_total_check" title="@{repeating_spells_$X_total_check}"></span><span class="sheet-attribute-default">0</span>
|
|
</button><span class="sheet-attribute show-if-class show-if-class--elf show-if-class--wizard collapsed" name="attr_notes" title="@{repeating_spells_$X_notes}"></span><span class="filtered-by-state sheet-attribute show-if-class show-if-class--cleric show-if-class--elf show-if-class--wizard collapsed" name="attr_description" title="@{repeating_spells_$X_description}"></span>
|
|
<input class="show-if-class show-if-class--cleric show-if-class--elf show-if-class--wizard expanded" name="attr_name" placeholder="unnamed" type="text" title="@{repeating_spells_$X_name}"/>
|
|
<input class="show-if-class show-if-class--elf show-if-class--wizard show-if-class--cleric expanded" name="attr_level" placeholder="0" type="number" title="@{repeating_spells_$X_level}"/>
|
|
<input class="show-if-class show-if-class--elf show-if-class--wizard expanded" name="attr_check" placeholder="0" type="number" title="@{repeating_spells_$X_check}"/>
|
|
<input class="show-if-class show-if-class--elf show-if-class--wizard expanded" name="attr_notes" placeholder="adjustment to spell effect..." type="text" title="@{repeating_spells_$X_notes}"/>
|
|
<div class="spell-stats expanded grid-span-all">
|
|
<input name="attr_range" value="" data-i18n-placeholder="spell range" type="text" title="@{repeating_spells_$X_range}"/>
|
|
<input name="attr_casting_time" value="" data-i18n-placeholder="casting time" type="text" title="@{repeating_spells_$X_casting_time}"/>
|
|
<select name="attr_save" title="@{repeating_spells_$X_save}">
|
|
<option value="will" selected="" data-i18n="will">
|
|
</option>
|
|
<option value="reflex" data-i18n="reflex">
|
|
</option>
|
|
<option value="fortitude" data-i18n="fortitude">
|
|
</option>
|
|
</select>
|
|
<input name="attr_duration" value="" data-i18n-placeholder="duration" type="text" title="@{repeating_spells_$X_duration}"/>
|
|
<div class="adaptive adaptive--text flex-span-all"><span class="adaptive--text__span" name="attr_manifestation" title="@{repeating_spells_$X_manifestation}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_manifestation" value="" data-i18n-placeholder="manifestation" title="@{repeating_spells_$X_manifestation}"></textarea>
|
|
</div>
|
|
<div class="flex-span-all inline-table-holder">
|
|
<button class="capitalize roller" name="roll_corruption" data-i18n="corruption" value="@{corruption_action}" type="roll">
|
|
</button>
|
|
<button name="act_corruption-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_corruption_action" type="hidden" title="@{repeating_spells_$X_corruption_action}"/>
|
|
<div class="popup-container flex-fill">
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_corruption" title="@{repeating_spells_$X_corruption}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_corruption" data-i18n-placeholder="corruption" title="@{repeating_spells_$X_corruption}"></textarea>
|
|
</div>
|
|
<div class="popup">
|
|
<div class="popup-contents">
|
|
<p data-i18n="string-table-instructions">In order for the sheet to roll this for you, enter the roll information exactly as it is in the rulebook. The dice to roll should be at the start (optionally preceded by \"roll\") followed by a colon. Then each roll result should be denoted by the number(s) to roll for that result followed by a closing parentheses. results should be separated by a semi-colon. e.g.:</p>
|
|
<p data-i18n="string-table-example">Roll 1d4: 1) result 1; 2) result 2; 3) result 3; 4) result 4.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button class="capitalize roller" name="roll_misfire" data-i18n="misfire" value="@{misfire_action}" type="roll">
|
|
</button>
|
|
<button name="act_misfire-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_misfire_action" type="hidden" title="@{repeating_spells_$X_misfire_action}"/>
|
|
<div class="popup-container flex-fill">
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_misfire" title="@{repeating_spells_$X_misfire}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_misfire" value="" data-i18n-placeholder="misfire" title="@{repeating_spells_$X_misfire}"></textarea>
|
|
</div>
|
|
<div class="popup">
|
|
<div class="popup-contents">
|
|
<p data-i18n="string-table-instructions">In order for the sheet to roll this for you, enter the roll information exactly as it is in the rulebook. The dice to roll should be at the start (optionally preceded by \"roll\") followed by a colon. Then each roll result should be denoted by the number(s) to roll for that result followed by a closing parentheses. results should be separated by a semi-colon. e.g.:</p>
|
|
<p data-i18n="string-table-example">Roll 1d4: 1) result 1; 2) result 2; 3) result 3; 4) result 4.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<textarea class="show-if-class show-if-class--cleric show-if-class--elf show-if-class--wizard expanded" name="attr_description" data-i18n-placeholder="spell description..." title="@{repeating_spells_$X_description}"></textarea>
|
|
<div class="expanded spell-row-header tiny-gap grid-span-all"><span class="capitalize" data-i18n="roll"></span><span class="capitalize" data-i18n="result" style="flex:1;text-align:center"></span>
|
|
<input class="complex-collapse spell-table-control" name="attr_row_collapse" value="1" type="checkbox" title="@{repeating_spells_$X_row_collapse}"/>
|
|
</div>
|
|
</div>
|
|
<input class="display-control" name="attr_row_type" value="table" hidden="" type="checkbox" title="@{repeating_spells_$X_row_type}"/>
|
|
<div class="controlled-display spell-table-row expanded grid-span-all tiny-gap">
|
|
<input class="roll-value" name="attr_roll" value="" data-i18n-placeholder="30+" type="text" title="@{repeating_spells_$X_roll}"/>
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_result" title="@{repeating_spells_$X_result}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_result" value="" data-i18n-placeholder="description..." title="@{repeating_spells_$X_result}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="headed-section headed-section--notes show-if-level show-if-level--zero show-if-class show-if-class--dwarf show-if-class--halfling show-if-class--thief show-if-class--warrior show-if-class--zero">
|
|
<div class="headed-section__header">
|
|
<h3 class="filtered-by-class"><span data-i18n="notes"></span></h3>
|
|
</div>
|
|
<div class="headed-section__content">
|
|
<div class="section-container section-container--notes">
|
|
<div class="labelled-edit labelled-edit--notes labelled-edit--labelless labelled-edit--textarea">
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_notes_mod" type="hidden" title="@{notes_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_notes" type="hidden" title="@{notes}"/><span class="labelled-edit__display" name="attr_notes" aria-hidden="true" title="@{notes}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="insert-notes"></span>
|
|
<textarea class="labelled-edit__value" name="attr_notes" data-i18n-placeholder="insert-notes" title="@{notes}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="border filtered-by-class">
|
|
<div class="border__title">
|
|
<div class="layout layout--flex"><img src="https://raw.githubusercontent.com/mperes/dcc-images/main/dungeon-crawl-classics.png" alt="character record sheet"/><img class="optional" src="https://raw.githubusercontent.com/mperes/dcc-images/main/character-record-sheet.png" alt="character record sheet"/></div>
|
|
</div>
|
|
<div class="border__subtitle">
|
|
<div class="layout layout--flex"><img class="left optional" src="https://raw.githubusercontent.com/mperes/dcc-images/main/misc-dragon.png" alt="an image of a dragon facing right"/>
|
|
<div class="class"><img class="border__image show-if-class show-if-class--cleric" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-cleric.png" loading="lazy"/><img class="border__image show-if-class show-if-class--dwarf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-dwarf.png" loading="lazy"/><img class="border__image show-if-class show-if-class--elf" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-elf.png" loading="lazy"/><img class="border__image show-if-class show-if-class--halfling" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-halfling.png" loading="lazy"/><img class="border__image show-if-class show-if-class--thief" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-thief.png" loading="lazy"/><img class="border__image show-if-class show-if-class--warrior" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-warrior.png" loading="lazy"/><img class="border__image show-if-class show-if-class--wizard" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-wizard.png" loading="lazy"/><img class="border__image show-if-level show-if-level--zero" src="https://raw.githubusercontent.com/mperes/dcc-images/main/subtitle-zero.png" loading="lazy"/>
|
|
</div><img class="right optional" src="https://raw.githubusercontent.com/mperes/dcc-images/main/misc-dragon.png" alt="an image of a dragon facing left"/>
|
|
</div>
|
|
</div>
|
|
<div class="border__outline"></div>
|
|
<div class="border__decoration"></div>
|
|
<div class="border__texture"></div>
|
|
</div>
|
|
</div>
|
|
<input class="rollmodal-is-disabled" name="attr_rollmodal_disabled" type="hidden" title="@{rollmodal_disabled}"/>
|
|
<input class="rollmodal-is-active" name="attr_rollmodal_active" type="hidden" title="@{rollmodal_active}"/>
|
|
<div class="rollmodal section">
|
|
<input name="attr_rollmodal_title" type="hidden" title="@{rollmodal_title}"/>
|
|
<input name="attr_rollmodal_subtitle" type="hidden" title="@{rollmodal_subtitle}"/>
|
|
<input name="attr_rollmodal_base_formula" type="hidden" title="@{rollmodal_base_formula}"/>
|
|
<input name="attr_rollmodal_source" type="hidden" title="@{rollmodal_source}"/>
|
|
<input name="attr_rollmodal_final_formula" type="hidden" title="@{rollmodal_final_formula}"/>
|
|
<div class="rollmodal__container section-container section-container--rollmodal">
|
|
<div class="layout layout--grid layout--rollmodal-header"><span class="rollmodal__title" name="attr_rollmodal_title" title="@{rollmodal_title}"></span><span class="rollmodal__subtitle" name="attr_rollmodal_subtitle" title="@{rollmodal_subtitle}"></span>
|
|
</div>
|
|
<div class="layout layout--grid layout--rollmodal-stats">
|
|
<input name="attr_rollmodal_description" type="hidden" title="@{rollmodal_description}"/>
|
|
<input class="rollmodal__valid-action-dice" name="attr_action_dice" type="hidden" title="@{action_dice}"/>
|
|
<input class="rollmodal__has-action-die" name="attr_rollmodal_has_action_die" type="hidden" title="@{rollmodal_has_action_die}"/>
|
|
<input name="attr_rollmodal_action_die" type="hidden" title="@{rollmodal_action_die}"/>
|
|
<div class="labelled-edit labelled-edit--rollmodal-base-formula labelled-edit--readyonly labelled-edit--string"><span class="labelled-edit__label" data-i18n="rollmodal-base-formula"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_rollmodal_base_formula_mod" type="hidden" title="@{rollmodal_base_formula_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_rollmodal_base_formula" type="hidden" title="@{rollmodal_base_formula}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_rollmodal_base_formula" aria-hidden="true" title="@{rollmodal_base_formula}"></span><span class="labelled-edit__display labelled-edit__display--placeholder"></span>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--rollmodal-action-die labelled-edit--object"><span class="labelled-edit__label" data-i18n="rollmodal-action-die"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_rollmodal_action_die_mod" type="hidden" title="@{rollmodal_action_die_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_rollmodal_action_die" type="hidden" title="@{rollmodal_action_die}"/><span class="labelled-edit__display" name="attr_rollmodal_action_die" aria-hidden="true" title="@{rollmodal_action_die}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="1d3"> </span>
|
|
<select class="labelled-edit__value" name="attr_rollmodal_action_die">
|
|
<option value="1d3" data-i18n="1d3"></option>
|
|
<option value="1d4" data-i18n="1d4"></option>
|
|
<option value="1d5" data-i18n="1d5"></option>
|
|
<option value="1d6" data-i18n="1d6"></option>
|
|
<option value="1d7" data-i18n="1d7"></option>
|
|
<option value="1d8" data-i18n="1d8"></option>
|
|
<option value="1d10" data-i18n="1d10"></option>
|
|
<option value="1d12" data-i18n="1d12"></option>
|
|
<option value="1d14" data-i18n="1d14"></option>
|
|
<option value="1d16" data-i18n="1d16"></option>
|
|
<option value="1d20" data-i18n="1d20"></option>
|
|
<option value="1d24" data-i18n="1d24"></option>
|
|
<option value="1d30" data-i18n="1d30"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--rollmodal-bonus labelled-edit--string"><span class="labelled-edit__label" data-i18n="rollmodal-bonus"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_rollmodal_bonus_mod" type="hidden" title="@{rollmodal_bonus_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_rollmodal_bonus" type="hidden" title="@{rollmodal_bonus}"/><span class="labelled-edit__display labelled-edit__display--bonus" name="attr_rollmodal_bonus" aria-hidden="true" title="@{rollmodal_bonus}"></span><span class="labelled-edit__display labelled-edit__display--placeholder">0</span>
|
|
<input class="labelled-edit__value" name="attr_rollmodal_bonus" placeholder="0" type="text" title="@{rollmodal_bonus}"/>
|
|
</div>
|
|
</div>
|
|
<div class="labelled-edit labelled-edit--rollmodal-type labelled-edit--object"><span class="labelled-edit__label" data-i18n="rollmodal-type"></span>
|
|
<div class="labelled-edit__container">
|
|
<input name="attr_rollmodal_type_mod" type="hidden" title="@{rollmodal_type_mod}"/>
|
|
<input class="labelled-edit__display--raw" name="attr_rollmodal_type" type="hidden" title="@{rollmodal_type}"/><span class="labelled-edit__display" name="attr_rollmodal_type" aria-hidden="true" title="@{rollmodal_type}"></span><span class="labelled-edit__display labelled-edit__display--placeholder" data-i18n="public"> </span>
|
|
<select class="labelled-edit__value" name="attr_rollmodal_type">
|
|
<option value="public" data-i18n="public"></option>
|
|
<option value="secret" data-i18n="secret"></option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="layout layout--grid layout--rollmodal-disable">
|
|
<div class="dcc-check">
|
|
<input name="attr_rollmodal_disabled" value="1" type="checkbox" title="@{rollmodal_disabled}"/>
|
|
</div><span data-i18n="disable-modal-checkbox"></span>
|
|
</div>
|
|
<button class="rollable modal-button modal-button--thick" name="act_roll-pc-rollmodal" type="action"><span data-i18n="roll"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<button class="rollmodal__blocker" name="act_rollmodal-blocker" type="action">
|
|
</button>
|
|
</div>
|
|
<div class="collapse-container npc">
|
|
<input class="collapse" name="attr_npc_collapse" value="1" type="checkbox" title="@{npc_collapse}"/>
|
|
<h1 class="npc__name"><span name="attr_character_name" title="@{character_name}"></span>
|
|
</h1>
|
|
<div class="collapsed npc__view">
|
|
<div class="npc__fields">
|
|
<button class="npc__field npc__field--rollable npc__init" name="act_roll-npc-init" type="action">
|
|
<h5 class="npc__title" data-i18n="init"></h5>
|
|
<input class="npc__attribute npc__attribute--roll-bonus-value" type="hidden" name="attr_init"/><span class="npc__attribute npc__attribute--roll-bonus npc__attribute--default-0" name="attr_init" title="@{init}"></span>
|
|
</button>
|
|
<div class="npc__atk npc__fields npc__fields--repeating hide-if-empty">
|
|
<h5 class="npc__title" data-i18n="atk"></h5>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-attacks" type="action">
|
|
</button>
|
|
<fieldset class="repeating_attacks">
|
|
<div class="atkholder npc__field">
|
|
<button class="npc__field--rollable" name="act_roll-npc-bonus" type="action"><span class="npc__attribute npc__attribute--lowercased" name="attr_name" title="@{repeating_attacks_$X_name}"></span>
|
|
<input class="npc__attribute npc__attribute--roll-bonus-value" type="hidden" name="attr_bonus"/><span class="npc__attribute npc__attribute--roll-bonus npc__attribute--default-0" name="attr_bonus" title="@{repeating_attacks_$X_bonus}"></span>
|
|
</button><span class="npc__attribute npc__attribute--lowercased" name="attr_type" title="@{repeating_attacks_$X_type}"></span>
|
|
<button class="npc__field--rollable" name="act_roll-npc-damage" type="action"><span class="npc__attribute npc__attribute--lowercased npc__attribute--parentheses" name="attr_damage" title="@{repeating_attacks_$X_damage}"></span>
|
|
</button><span class="npc__attribute npc__attribute--separator" data-i18n="or"></span>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="npc__ac npc__field">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="ac"></h5><span class="npc__attribute npc__attribute--default-10" name="attr_ac" title="@{ac}"></span>
|
|
</div>
|
|
<div class="npc__hd npc__field">
|
|
<button class="npc__field npc__field--rollable npc__hd" name="act_roll-npc-hd" type="action">
|
|
<h5 class="npc__title" data-i18n="hd"></h5><span class="npc__attribute npc__attribute--default-1d4" name="attr_hd" title="@{hd}"></span><span class="npc__attribute npc__attribute--hp" name="attr_hit_points" title="@{hit_points}"></span>
|
|
</button>
|
|
<!--attr_hit_points-->
|
|
<!--h5.npc__title.npc__title--uppercased(data-i18n='hd')-->
|
|
<!--+span({name:'hd', class:'npc__attribute npc__attribute--default-1d4'})-->
|
|
</div>
|
|
<div class="npc__mv npc__fields npc__fields--repeating hide-if-empty">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="mv"></h5>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-movement" type="action">
|
|
</button>
|
|
<fieldset class="repeating_movement"><span class="npc__attribute npc__attribute--lowercased" name="attr_name" title="@{repeating_movement_$X_name}"></span><span class="npc__attribute npc__attribute--lowercased npc__attribute--measured" name="attr_speed" title="@{repeating_movement_$X_speed}"></span><span class="npc__attribute npc__attribute--separator" data-i18n="or"></span>
|
|
</fieldset>
|
|
</div>
|
|
<!--+npc-rollable-field('act', '1d20')-->
|
|
<div class="npc__act npc__field">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="act"></h5><span class="npc__attribute npc__attribute--default-1d20" name="attr_act" title="@{act}"></span>
|
|
</div>
|
|
<div class="npc__sp npc__field hide-if-empty">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="sp"></h5><span class="npc__attribute empty-check" name="attr_sp" title="@{sp}"></span>
|
|
</div>
|
|
<div class="npc__sv npc__fields">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="sv"></h5>
|
|
<button class="npc__field npc__field--rollable npc__fort" name="act_roll-npc-fort" type="action">
|
|
<h5 class="npc__title" data-i18n="fort"></h5>
|
|
<input class="npc__attribute npc__attribute--roll-bonus-value" type="hidden" name="attr_fort"/><span class="npc__attribute npc__attribute--roll-bonus npc__attribute--default-0" name="attr_fort" title="@{fort}"></span>
|
|
</button>
|
|
<button class="npc__field npc__field--rollable npc__ref" name="act_roll-npc-ref" type="action">
|
|
<h5 class="npc__title" data-i18n="ref"></h5>
|
|
<input class="npc__attribute npc__attribute--roll-bonus-value" type="hidden" name="attr_ref"/><span class="npc__attribute npc__attribute--roll-bonus npc__attribute--default-0" name="attr_ref" title="@{ref}"></span>
|
|
</button>
|
|
<button class="npc__field npc__field--rollable npc__will" name="act_roll-npc-will" type="action">
|
|
<h5 class="npc__title" data-i18n="will"></h5>
|
|
<input class="npc__attribute npc__attribute--roll-bonus-value" type="hidden" name="attr_will"/><span class="npc__attribute npc__attribute--roll-bonus npc__attribute--default-0" name="attr_will" title="@{will}"></span>
|
|
</button>
|
|
</div>
|
|
<div class="npc__al npc__field hide-if-empty">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="al"></h5><span class="npc__attribute npc__attribute--uppercased empty-check" name="attr_alignment" title="@{alignment}"></span>
|
|
</div>
|
|
<div class="npc__crit-table npc__field hide-if-empty">
|
|
<h5 data-i18n="crit table"></h5><span name="attr_crit_table" title="@{crit_table}"></span>
|
|
</div>
|
|
<div class="npc__field npc__crit-die hide-if-empty">
|
|
<h5 data-i18n="crit die"></h5><span name="attr_crit_die" title="@{crit_die}"></span>
|
|
</div>
|
|
</div>
|
|
<div class="npc__description npc__field"><span class="npc__attribute npc__attribute--pre-wrap" name="attr_description" title="@{description}"></span>
|
|
</div>
|
|
</div>
|
|
<div class="expanded npc__edit">
|
|
<div class="npc__fields">
|
|
<div class="npc__init npc__field">
|
|
<h5 class="npc__title" data-i18n="name"></h5>
|
|
<input class="npc__name" name="attr_character_name" type="text" placeholder="unnamed" title="@{character_name}"/>
|
|
</div>
|
|
<div class="npc__init npc__field">
|
|
<h5 class="npc__title" data-i18n="init"></h5>
|
|
<input class="npc__input" name="attr_init" type="number" placeholder="0" title="@{init}"/>
|
|
</div>
|
|
<div class="npc__ac npc__field">
|
|
<h5 class="npc__title" data-i18n="ac"></h5>
|
|
<input class="npc__input" name="attr_ac" placeholder="10" type="number" title="@{ac}"/>
|
|
</div>
|
|
<div class="npc__hd npc__field">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="hd"></h5>
|
|
<input class="npc__input" name="attr_hd" placeholder="1d4" type="text" title="@{hd}"/>
|
|
</div>
|
|
<div class="npc__act npc__field">
|
|
<h5 class="npc__title" data-i18n="act"></h5>
|
|
<input class="npc__input" name="attr_act" placeholder="1d20" type="text" title="@{act}"/>
|
|
</div>
|
|
<div class="npc__sp npc__field">
|
|
<h5 class="npc__title" data-i18n="sp"></h5>
|
|
<input class="npc__input" name="attr_sp" placeholder="special..." type="text" title="@{sp}"/>
|
|
</div>
|
|
<div class="npc__sv--fort npc__field">
|
|
<h5 class="npc__title" data-i18n="fort"></h5>
|
|
<input class="npc__input" name="attr_fort" placeholder="0" type="number" title="@{fort}"/>
|
|
</div>
|
|
<div class="npc__sv--ref npc__field">
|
|
<h5 class="npc__title" data-i18n="ref"></h5>
|
|
<input class="npc__input" name="attr_ref" placeholder="0" type="number" title="@{ref}"/>
|
|
</div>
|
|
<div class="npc__sv--will npc__field">
|
|
<h5 class="npc__title" data-i18n="will"></h5>
|
|
<input class="npc__input" name="attr_will" placeholder="0" type="number" title="@{will}"/>
|
|
</div>
|
|
<div class="npc__al npc__field">
|
|
<h5 class="npc__title" data-i18n="al"></h5>
|
|
<select name="attr_alignment" title="@{alignment}">
|
|
<option value="" data-i18n="choose...">
|
|
</option>
|
|
<option value="lawful" data-i18n="lawful">
|
|
</option>
|
|
<option value="chaotic" data-i18n="chaotic">
|
|
</option>
|
|
<option value="neutral" data-i18n="neutral">
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="npc__field npc__crit-table">
|
|
<h5 class="npc__title" data-i18n="crit table"></h5>
|
|
<select name="attr_crit_table" title="@{crit_table}">
|
|
<option value="humanoid" data-i18n="humanoid">
|
|
</option>
|
|
<option value="demon" data-i18n="demon">
|
|
</option>
|
|
<option value="dragon" data-i18n="dragon">
|
|
</option>
|
|
<option value="giant" data-i18n="giant">
|
|
</option>
|
|
<option value="monster" data-i18n="monster" selected="">
|
|
</option>
|
|
<option value="undead" data-i18n="undead">
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="npc__field npc__crit-die">
|
|
<h5 class="npc__title" data-i18n="crit die"></h5>
|
|
<input class="die-display" name="attr_crit_die" value="d4" type="text" title="@{crit_die}"/>
|
|
</div>
|
|
<div class="npc__atk npc__fields npc__fields--repeating">
|
|
<h5 class="npc__title" data-i18n="attacks"></h5>
|
|
<div class="npc__fields-header"><span data-i18n="name"></span><span data-i18n="bonus"></span><span data-i18n="type"></span><span data-i18n="damage"></span>
|
|
</div>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-attacks" type="action">
|
|
</button>
|
|
<fieldset class="repeating_attacks">
|
|
<input name="attr_name" placeholder="unnamed" type="text" title="@{repeating_attacks_$X_name}"/>
|
|
<input name="attr_bonus" placeholder="0" type="number" title="@{repeating_attacks_$X_bonus}"/>
|
|
<select name="attr_type" title="@{repeating_attacks_$X_type}">
|
|
<option value="" data-i18n="choose...">
|
|
</option>
|
|
<option value="melee" data-i18n="melee">
|
|
</option>
|
|
<option value="missile fire" data-i18n="missile fire">
|
|
</option>
|
|
</select>
|
|
<input name="attr_damage" placeholder="1d4" type="text" title="@{repeating_attacks_$X_damage}"/>
|
|
</fieldset>
|
|
<div class="flex-box justify-space-between weapon-button-container compendium-dependent-content disabled">
|
|
<button class="mancer-button modal-button modal-button--thin modal-button--content roller" name="roll_crit" data-i18n="roll crit" value="@{crit_action}" type="roll">
|
|
</button>
|
|
<button name="act_crit-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_crit_action" type="hidden" title="@{crit_action}"/>
|
|
<button class="mancer-button modal-button modal-button--thin modal-button--content roller" name="roll_fumble" data-i18n="roll fumble" value="@{fumble_action}" type="roll">
|
|
</button>
|
|
<button name="act_fumble-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_fumble_action" type="hidden" title="@{fumble_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="npc__mv npc__fields npc__fields--repeating">
|
|
<h5 class="npc__title npc__title--uppercased" data-i18n="movement"></h5>
|
|
<div class="npc__fields-header"><span data-i18n="name"></span><span data-i18n="speed"></span>
|
|
</div>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-movement" type="action">
|
|
</button>
|
|
<fieldset class="repeating_movement">
|
|
<input name="attr_name" placeholder="walk" type="text" title="@{repeating_movement_$X_name}"/>
|
|
<input name="attr_speed" placeholder="20" type="number" title="@{repeating_movement_$X_speed}"/>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div class="npc__description npc__field">
|
|
<h5 class="npc__title" data-i18n="description"></h5>
|
|
<textarea name="attr_description" placeholder="Once upon a time..." title="@{description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input name="attr_template_start" value="@{whisper}&{template:undefined} {{character_name=@{character_name}}} {{character_id=@{character_id}}}" type="hidden" title="@{template_start}"/>
|
|
<rolltemplate class="sheet-rolltemplate-dcc">
|
|
<div class="roll">
|
|
<div class="roll__container">
|
|
<div class="roll__header">
|
|
<div class="critical">{{computed::critical}}</div>
|
|
<div class="fumble">{{computed::fumble}}</div>
|
|
<div class="success">{{computed::success}}</div>
|
|
<div class="failure">{{computed::failure}}</div>{{#author}}
|
|
<div class="roll__author"><span>{{author}}</span></div>{{/author}}
|
|
<div class="roll__title"><span>{{title}}</span></div>{{#subtitle}}
|
|
<div class="roll__subtitle"><span>{{subtitle}}</span></div>{{/subtitle}}
|
|
<div class="roll__critical"><span data-i18n="critical"></span>: {{computed::critical}}</div>
|
|
<div class="roll__fumble"><span data-i18n="fumble"></span></div>
|
|
<div class="roll__success"><span data-i18n="success"></span></div>
|
|
<div class="roll__failure"><span data-i18n="failure"></span></div>
|
|
</div>
|
|
<div class="roll__formulas">{{#formula0}}
|
|
<div class="roll__formula"><span>{{formula0}}</span></div>{{/formula0}}{{#formula1}}
|
|
<div class="roll__formula"><span>{{formula1}}</span></div>{{/formula1}}{{#formula2}}
|
|
<div class="roll__formula"><span>{{formula2}}</span></div>{{/formula2}}{{#formula3}}
|
|
<div class="roll__formula"><span>{{formula3}}</span></div>{{/formula3}}
|
|
</div>{{#description}}
|
|
<div class="roll__description"><span>{{description}}</span></div>{{/description}}{{#computeDescription}}
|
|
<div class="roll__description roll__description--computed"><span>{{computed::computeDescription}}</span></div>{{/computeDescription}}
|
|
</div>
|
|
<div class="roll__border"></div>
|
|
</div>
|
|
</rolltemplate>
|
|
<!--+scss('sheet').
|
|
.tabs--dcc{
|
|
container: dcc / inline-size;
|
|
}
|
|
-->
|
|
<script type="text/worker">//# sourceURL=dcc.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"},"act_k-network-call":{"name":"k-network-call","type":"action","triggeredFuncs":["kReceive"],"affects":[],"addFuncs":[],"listener":"clicked:k-network-call","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_character_id":{"name":"character_id","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:character_id","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_script_character_name":{"name":"script_character_name","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:script_character_name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_sheet_version":{"name":"sheet_version","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:sheet_version","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_push":{"name":"push","type":"action","triggeredFuncs":["pushRoll"],"affects":[],"addFuncs":[],"listener":"clicked:push","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_drop_name":{"name":"drop_name","type":"hidden","triggeredFuncs":["handleCompendiumDrop"],"affects":[],"addFuncs":[],"listener":"change:drop_name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_drop_data":{"name":"drop_data","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:drop_data","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_disabled":{"name":"rollmodal_disabled","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_disabled","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_is_npc":{"name":"is_npc","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:is_npc","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"act_open-table":{"name":"open-table","type":"action","triggeredFuncs":["toggleMancer"],"affects":[],"addFuncs":[],"listener":"clicked:open-table","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"tables"},"act_refresh-mancer":{"name":"refresh-mancer","type":"action","triggeredFuncs":["toggleMancer"],"affects":[],"addFuncs":[],"listener":"clicked:refresh-mancer","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"refresh"},"attr_kmodal-mancer":{"name":"kmodal-mancer","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:kmodal-mancer","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_mancer_stage":{"name":"mancer_stage","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_stage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_confirm_wipe":{"name":"mancer_confirm_wipe","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_confirm_wipe","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_mancer-toggle":{"name":"mancer-toggle","type":"action","triggeredFuncs":["resetWipe","toggleMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-toggle","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-wipe":{"name":"mancer-wipe","type":"action","triggeredFuncs":["wipeCharacter"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-wipe","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"create"},"attr_mancer_wipe_button_text":{"name":"mancer_wipe_button_text","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_wipe_button_text","listenerFunc":"accessSheet","defaultValue":"wipe character data","calculation":"","initialFunc":"","formula":""},"act_mancer-create":{"name":"mancer-create","type":"action","triggeredFuncs":["progressMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-create","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"create"},"act_mancer-randomize-new":{"name":"mancer-randomize-new","type":"action","triggeredFuncs":["rollAbilityScores","determineOccupation","rollHP","rollCoinage"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-randomize-new","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-roll-ability-scores":{"name":"mancer-roll-ability-scores","type":"action","triggeredFuncs":["rollAbilityScores"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-roll-ability-scores","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-strength":{"name":"roll-pc-strength","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-strength","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"strength_modifier"}},"attr_strength_modifier_mod":{"name":"strength_modifier_mod","type":"hidden","triggeredFuncs":[],"affects":["strength_modifier","strength modifier"],"addFuncs":[],"listener":"change:strength_modifier_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_strength_modifier":{"name":"strength_modifier","type":"hidden","triggeredFuncs":[],"affects":["melee_attack","melee_damage"],"addFuncs":[],"listener":"change:strength_modifier","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateScoreModifier","initialFunc":"","formula":""},"attr_strength_diff":{"name":"strength_diff","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:strength_diff","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcScoreDiff","initialFunc":"","formula":""},"attr_strength_total":{"name":"strength_total","type":"hidden","triggeredFuncs":[],"affects":["strength_modifier"],"addFuncs":[],"listener":"change:strength_total","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateGenericNumberFieldTotal","initialFunc":"","formula":""},"attr_strength_mod":{"name":"strength_mod","type":"hidden","triggeredFuncs":[],"affects":["strength_total"],"addFuncs":[],"listener":"change:strength_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_strength":{"name":"strength","type":"hidden","triggeredFuncs":[],"affects":["strength_diff","strength_total"],"addFuncs":[],"listener":"change:strength","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_strength_max":{"name":"strength_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:strength_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-pc-agility":{"name":"roll-pc-agility","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-agility","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"agility_modifier"}},"attr_agility_modifier_mod":{"name":"agility_modifier_mod","type":"hidden","triggeredFuncs":[],"affects":["agility_modifier","agility modifier"],"addFuncs":[],"listener":"change:agility_modifier_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_agility_modifier":{"name":"agility_modifier","type":"hidden","triggeredFuncs":[],"affects":["ref_save","armor_class","missile_attack","initiative","sneak_silently","hide_in_shadows","pick_pocket","climb_sheer_surfaces","pick_lock","disable_trap","forge_document"],"addFuncs":[],"listener":"change:agility_modifier","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateScoreModifier","initialFunc":"","formula":""},"attr_agility_diff":{"name":"agility_diff","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:agility_diff","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcScoreDiff","initialFunc":"","formula":""},"attr_agility_total":{"name":"agility_total","type":"hidden","triggeredFuncs":[],"affects":["agility_modifier"],"addFuncs":[],"listener":"change:agility_total","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateGenericNumberFieldTotal","initialFunc":"","formula":""},"attr_agility_mod":{"name":"agility_mod","type":"hidden","triggeredFuncs":[],"affects":["agility_total"],"addFuncs":[],"listener":"change:agility_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_agility":{"name":"agility","type":"hidden","triggeredFuncs":[],"affects":["agility_diff","agility_total"],"addFuncs":[],"listener":"change:agility","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_agility_max":{"name":"agility_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:agility_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-pc-stamina":{"name":"roll-pc-stamina","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-stamina","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"stamina_modifier"}},"attr_stamina_modifier_mod":{"name":"stamina_modifier_mod","type":"hidden","triggeredFuncs":[],"affects":["stamina_modifier","stamina modifier"],"addFuncs":[],"listener":"change:stamina_modifier_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_stamina_modifier":{"name":"stamina_modifier","type":"hidden","triggeredFuncs":[],"affects":["fort_save"],"addFuncs":[],"listener":"change:stamina_modifier","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateScoreModifier","initialFunc":"","formula":""},"attr_stamina_diff":{"name":"stamina_diff","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stamina_diff","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcScoreDiff","initialFunc":"","formula":""},"attr_stamina_total":{"name":"stamina_total","type":"hidden","triggeredFuncs":[],"affects":["stamina_modifier"],"addFuncs":[],"listener":"change:stamina_total","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateGenericNumberFieldTotal","initialFunc":"","formula":""},"attr_stamina_mod":{"name":"stamina_mod","type":"hidden","triggeredFuncs":[],"affects":["stamina_total"],"addFuncs":[],"listener":"change:stamina_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_stamina":{"name":"stamina","type":"hidden","triggeredFuncs":[],"affects":["stamina_diff","stamina_total"],"addFuncs":[],"listener":"change:stamina","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_stamina_max":{"name":"stamina_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stamina_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-pc-personality":{"name":"roll-pc-personality","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-personality","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"personality_modifier"}},"attr_personality_modifier_mod":{"name":"personality_modifier_mod","type":"hidden","triggeredFuncs":[],"affects":["personality_modifier","personality modifier"],"addFuncs":[],"listener":"change:personality_modifier_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_personality_modifier":{"name":"personality_modifier","type":"hidden","triggeredFuncs":[],"affects":["will_save","disguise_self","spell_check"],"addFuncs":[],"listener":"change:personality_modifier","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateScoreModifier","initialFunc":"","formula":""},"attr_personality_diff":{"name":"personality_diff","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:personality_diff","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcScoreDiff","initialFunc":"","formula":""},"attr_personality_total":{"name":"personality_total","type":"hidden","triggeredFuncs":[],"affects":["personality_modifier"],"addFuncs":[],"listener":"change:personality_total","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateGenericNumberFieldTotal","initialFunc":"","formula":""},"attr_personality_mod":{"name":"personality_mod","type":"hidden","triggeredFuncs":[],"affects":["personality_total"],"addFuncs":[],"listener":"change:personality_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_personality":{"name":"personality","type":"hidden","triggeredFuncs":[],"affects":["personality_diff","personality_total"],"addFuncs":[],"listener":"change:personality","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_personality_max":{"name":"personality_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:personality_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-pc-luck":{"name":"roll-pc-luck","type":"action","triggeredFuncs":["genericActionRoll","luckRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-luck","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"luck_modifier"}},"attr_luck_modifier_mod":{"name":"luck_modifier_mod","type":"hidden","triggeredFuncs":[],"affects":["luck_modifier","luck modifier"],"addFuncs":[],"listener":"change:luck_modifier_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_luck_modifier":{"name":"luck_modifier","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:luck_modifier","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateScoreModifier","initialFunc":"","formula":""},"attr_luck_diff":{"name":"luck_diff","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:luck_diff","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcScoreDiff","initialFunc":"","formula":""},"attr_luck_total":{"name":"luck_total","type":"hidden","triggeredFuncs":[],"affects":["luck_modifier"],"addFuncs":[],"listener":"change:luck_total","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateGenericNumberFieldTotal","initialFunc":"","formula":""},"attr_luck_mod":{"name":"luck_mod","type":"hidden","triggeredFuncs":[],"affects":["luck_total"],"addFuncs":[],"listener":"change:luck_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_luck":{"name":"luck","type":"hidden","triggeredFuncs":[],"affects":["luck_diff","luck_total"],"addFuncs":[],"listener":"change:luck","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_luck_max":{"name":"luck_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:luck_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-pc-intelligence":{"name":"roll-pc-intelligence","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-intelligence","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"intelligence_modifier"}},"attr_intelligence_modifier_mod":{"name":"intelligence_modifier_mod","type":"hidden","triggeredFuncs":[],"affects":["intelligence_modifier","intelligence modifier"],"addFuncs":[],"listener":"change:intelligence_modifier_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_intelligence_modifier":{"name":"intelligence_modifier","type":"hidden","triggeredFuncs":[],"affects":["base_spell_check","find_trap","read_languages","cast_spell_from_scroll"],"addFuncs":[],"listener":"change:intelligence_modifier","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateScoreModifier","initialFunc":"","formula":""},"attr_intelligence_diff":{"name":"intelligence_diff","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:intelligence_diff","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcScoreDiff","initialFunc":"","formula":""},"attr_intelligence_total":{"name":"intelligence_total","type":"hidden","triggeredFuncs":[],"affects":["intelligence_modifier"],"addFuncs":[],"listener":"change:intelligence_total","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateGenericNumberFieldTotal","initialFunc":"","formula":""},"attr_intelligence_mod":{"name":"intelligence_mod","type":"hidden","triggeredFuncs":[],"affects":["intelligence_total"],"addFuncs":[],"listener":"change:intelligence_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_intelligence":{"name":"intelligence","type":"hidden","triggeredFuncs":[],"affects":["intelligence_diff","intelligence_total"],"addFuncs":[],"listener":"change:intelligence","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_intelligence_max":{"name":"intelligence_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:intelligence_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_mancer-roll-birth-augur":{"name":"mancer-roll-birth-augur","type":"action","triggeredFuncs":["rollAugur"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-roll-birth-augur","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_augur_mod":{"name":"mancer_augur_mod","type":"hidden","triggeredFuncs":[],"affects":["augur"],"addFuncs":[],"listener":"change:mancer_augur_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_mancer_augur":{"name":"mancer_augur","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_augur","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-roll-hp":{"name":"mancer-roll-hp","type":"action","triggeredFuncs":["rollHP"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-roll-hp","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_hp_mod":{"name":"mancer_hp_mod","type":"hidden","triggeredFuncs":[],"affects":["hp"],"addFuncs":[],"listener":"change:mancer_hp_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_mancer_hp":{"name":"mancer_hp","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_hp","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-determine-occupation":{"name":"mancer-determine-occupation","type":"action","triggeredFuncs":["determineOccupation"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-determine-occupation","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_occupation_mod":{"name":"mancer_occupation_mod","type":"hidden","triggeredFuncs":[],"affects":["occupation"],"addFuncs":[],"listener":"change:mancer_occupation_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_mancer_occupation":{"name":"mancer_occupation","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_occupation","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_weapon_mod":{"name":"mancer_weapon_mod","type":"hidden","triggeredFuncs":[],"affects":["weapon"],"addFuncs":[],"listener":"change:mancer_weapon_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_mancer_weapon":{"name":"mancer_weapon","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_weapon","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_trade_goods_mod":{"name":"mancer_trade_goods_mod","type":"hidden","triggeredFuncs":[],"affects":["trade_goods","trade goods"],"addFuncs":[],"listener":"change:mancer_trade_goods_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_mancer_trade_goods":{"name":"mancer_trade_goods","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_trade_goods","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_alignment_mod":{"name":"alignment_mod","type":"hidden","triggeredFuncs":[],"affects":["alignment"],"addFuncs":[],"listener":"change:alignment_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_alignment":{"name":"alignment","type":"hidden","triggeredFuncs":[],"affects":["title","backstab","sneak_silently","hide_in_shadows","pick_pocket","climb_sheer_surfaces","pick_lock","find_trap","disable_trap","forge_document","disguise_self","read_languages","handle_poison","cast_spell_from_scroll"],"addFuncs":[],"listener":"change:alignment","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-roll-coinage":{"name":"mancer-roll-coinage","type":"action","triggeredFuncs":["rollCoinage"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-roll-coinage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_starting_coin_mod":{"name":"mancer_starting_coin_mod","type":"hidden","triggeredFuncs":[],"affects":["starting_coin","starting coin"],"addFuncs":[],"listener":"change:mancer_starting_coin_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_mancer_starting_coin":{"name":"mancer_starting_coin","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_starting_coin","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-new-finish":{"name":"mancer-new-finish","type":"action","triggeredFuncs":["createCharacter"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-new-finish","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mancer_class":{"name":"mancer_class","type":"select","triggeredFuncs":["setMancerClass"],"affects":[],"addFuncs":[],"listener":"change:mancer_class","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-options_$x_ability_map":{"name":"repeating_mancer-class-options_$x_ability_map","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-options:ability_map","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-options_$x_name":{"name":"repeating_mancer-class-options_$x_name","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-options:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-options_$x_description":{"name":"repeating_mancer-class-options_$x_description","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-options:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-options_$x_row_id":{"name":"repeating_mancer-class-options_$x_row_id","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-options:row_id","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-options_$x_mancer_sub_field_control":{"name":"repeating_mancer-class-options_$x_mancer_sub_field_control","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-options:mancer_sub_field_control","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-options_$x_select":{"name":"repeating_mancer-class-options_$x_select","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-options:select","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_row_id":{"name":"repeating_mancer-class-table_$x_row_id","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:row_id","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_ability_map":{"name":"repeating_mancer-class-table_$x_ability_map","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:ability_map","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_name":{"name":"repeating_mancer-class-table_$x_name","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_1":{"name":"repeating_mancer-class-table_$x_value_1","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_1","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_2":{"name":"repeating_mancer-class-table_$x_value_2","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_2","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_3":{"name":"repeating_mancer-class-table_$x_value_3","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_3","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_4":{"name":"repeating_mancer-class-table_$x_value_4","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_4","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_5":{"name":"repeating_mancer-class-table_$x_value_5","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_5","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_6":{"name":"repeating_mancer-class-table_$x_value_6","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_6","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_7":{"name":"repeating_mancer-class-table_$x_value_7","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_7","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_8":{"name":"repeating_mancer-class-table_$x_value_8","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_8","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_9":{"name":"repeating_mancer-class-table_$x_value_9","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_9","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-class-table_$x_value_10":{"name":"repeating_mancer-class-table_$x_value_10","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-class-table:value_10","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-class-finish":{"name":"mancer-class-finish","type":"action","triggeredFuncs":["progressMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-class-finish","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"level"},"attr_level_mod":{"name":"level_mod","type":"hidden","triggeredFuncs":[],"affects":["level"],"addFuncs":[],"listener":"change:level_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_level":{"name":"level","type":"hidden","triggeredFuncs":["levelUpButtonDisplay"],"affects":["ref_save","fort_save","will_save","attack","initiative","action_dice","crit_die","crit_table","luck_die","backstab","sneak_silently","hide_in_shadows","pick_pocket","climb_sheer_surfaces","pick_lock","find_trap","disable_trap","forge_document","disguise_self","read_languages","handle_poison","cast_spell_from_scroll","critical_threat_range","title","stealth","base_spell_check","spell_check"],"addFuncs":[],"listener":"change:level","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateLevel","initialFunc":"","formula":""},"attr_mancer_level":{"name":"mancer_level","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_level","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"setLevelDiff","formula":""},"attr_hit_points_max_mod":{"name":"hit_points_max_mod","type":"hidden","triggeredFuncs":[],"affects":["hit_points_max","hit points max"],"addFuncs":[],"listener":"change:hit_points_max_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_hit_points_max":{"name":"hit_points_max","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:hit_points_max","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-change-class":{"name":"mancer-change-class","type":"action","triggeredFuncs":["progressMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-change-class","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"class"},"attr_mancer_has_spells":{"name":"mancer_has_spells","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mancer_has_spells","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_mancer-finish-level-up":{"name":"mancer-finish-level-up","type":"action","triggeredFuncs":["levelUp"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-finish-level-up","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-select-spells":{"name":"mancer-select-spells","type":"action","triggeredFuncs":["progressMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-select-spells","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"spells"},"attr_repeating_mancer-spells_$x_level":{"name":"repeating_mancer-spells_$x_level","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:level","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_class":{"name":"repeating_mancer-spells_$x_class","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:class","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_compendium_reference":{"name":"repeating_mancer-spells_$x_compendium_reference","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:compendium_reference","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_type":{"name":"repeating_mancer-spells_$x_type","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:type","listenerFunc":"accessSheet","defaultValue":"content","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_selectable":{"name":"repeating_mancer-spells_$x_selectable","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:selectable","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_selected":{"name":"repeating_mancer-spells_$x_selected","type":"checkbox","triggeredFuncs":["updateMancerSpellSelections"],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:selected","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_name":{"name":"repeating_mancer-spells_$x_name","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_compendium_link":{"name":"repeating_mancer-spells_$x_compendium_link","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:compendium_link","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_label":{"name":"repeating_mancer-spells_$x_label","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:label","listenerFunc":"accessSheet","defaultValue":"level","calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_chosen":{"name":"repeating_mancer-spells_$x_chosen","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:chosen","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_mancer-spells_$x_chosen_max":{"name":"repeating_mancer-spells_$x_chosen_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_mancer-spells:chosen_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"fieldset_repeating_rollable-tables":{"name":"repeating_rollable-tables","type":"fieldset","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"remove:repeating_rollable-tables","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_rollable-tables_$x_name":{"name":"repeating_rollable-tables_$x_name","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_rollable-tables:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_rollable-tables_$x_action":{"name":"repeating_rollable-tables_$x_action","type":"action","triggeredFuncs":["rollSheetTable"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_rollable-tables:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_rollable-tables_$x_action":{"name":"repeating_rollable-tables_$x_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_rollable-tables:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_rollable-tables_$x_die":{"name":"repeating_rollable-tables_$x_die","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_rollable-tables:die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_rollable-tables_$x_bonus":{"name":"repeating_rollable-tables_$x_bonus","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_rollable-tables:bonus","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_class":{"name":"class","type":"hidden","triggeredFuncs":[],"affects":["hit_die","level","ref_save","fort_save","will_save","attack","initiative","action_dice","crit_die","crit_table","luck_die","backstab","sneak_silently","hide_in_shadows","pick_pocket","climb_sheer_surfaces","pick_lock","find_trap","disable_trap","forge_document","disguise_self","read_languages","handle_poison","cast_spell_from_scroll","critical_threat_range","title","speed","stealth","base_spell_check","spell_check"],"addFuncs":[],"listener":"change:class","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_character_name_mod":{"name":"character_name_mod","type":"hidden","triggeredFuncs":[],"affects":["character_name","character name"],"addFuncs":[],"listener":"change:character_name_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_title_mod":{"name":"title_mod","type":"hidden","triggeredFuncs":[],"affects":["title"],"addFuncs":[],"listener":"change:title_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_title":{"name":"title","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:title","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateTitleValue","initialFunc":"","formula":""},"attr_title_overwritten":{"name":"title_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:title_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_occupation_mod":{"name":"occupation_mod","type":"hidden","triggeredFuncs":[],"affects":["occupation"],"addFuncs":[],"listener":"change:occupation_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_occupation":{"name":"occupation","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:occupation","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_class_mod":{"name":"class_mod","type":"hidden","triggeredFuncs":[],"affects":["class"],"addFuncs":[],"listener":"change:class_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_speed_mod":{"name":"speed_mod","type":"hidden","triggeredFuncs":[],"affects":["speed"],"addFuncs":[],"listener":"change:speed_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_speed":{"name":"speed","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:speed","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateSpeedValue","initialFunc":"","formula":""},"attr_birth_augur_mod":{"name":"birth_augur_mod","type":"hidden","triggeredFuncs":[],"affects":["birth_augur","birth augur"],"addFuncs":[],"listener":"change:birth_augur_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_birth_augur":{"name":"birth_augur","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:birth_augur","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_mancer-level-up":{"name":"mancer-level-up","type":"action","triggeredFuncs":["progressMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-level-up","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"level"},"act_mancer-first-level":{"name":"mancer-first-level","type":"action","triggeredFuncs":["progressMancer"],"affects":[],"addFuncs":[],"listener":"clicked:mancer-first-level","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","stage":"class"},"attr_xp_mod":{"name":"xp_mod","type":"hidden","triggeredFuncs":[],"affects":["xp"],"addFuncs":[],"listener":"change:xp_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_xp":{"name":"xp","type":"hidden","triggeredFuncs":["levelUpButtonDisplay"],"affects":[],"addFuncs":[],"listener":"change:xp","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor_class_mod":{"name":"armor_class_mod","type":"hidden","triggeredFuncs":[],"affects":["armor_class","armor class"],"addFuncs":[],"listener":"change:armor_class_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_armor_class":{"name":"armor_class","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:armor_class","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateACValue","initialFunc":"","formula":""},"attr_armor_class_overwritten":{"name":"armor_class_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor_class_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_hit_points_mod":{"name":"hit_points_mod","type":"hidden","triggeredFuncs":[],"affects":["hit_points","hit points"],"addFuncs":[],"listener":"change:hit_points_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_hit_points":{"name":"hit_points","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:hit_points","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-hit-die":{"name":"roll-pc-hit-die","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-hit-die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_hit_die_mod":{"name":"hit_die_mod","type":"hidden","triggeredFuncs":[],"affects":["hit_die","hit die"],"addFuncs":[],"listener":"change:hit_die_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_hit_die":{"name":"hit_die","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:hit_die","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateHitDie","initialFunc":"","formula":""},"attr_hit_die_overwritten":{"name":"hit_die_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:hit_die_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-initiative":{"name":"roll-pc-initiative","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-initiative","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_initiative_mod":{"name":"initiative_mod","type":"hidden","triggeredFuncs":[],"affects":["initiative"],"addFuncs":[],"listener":"change:initiative_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_initiative":{"name":"initiative","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:initiative","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateInitiativeValue","initialFunc":"","formula":""},"attr_initiative_overwritten":{"name":"initiative_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:initiative_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_action_dice_mod":{"name":"action_dice_mod","type":"hidden","triggeredFuncs":[],"affects":["action_dice","action dice"],"addFuncs":[],"listener":"change:action_dice_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_action_dice":{"name":"action_dice","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:action_dice","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateActionDiceValue","initialFunc":"","formula":""},"attr_action_dice_overwritten":{"name":"action_dice_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:action_dice_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_deed_die_result":{"name":"deed_die_result","type":"hidden","triggeredFuncs":[],"affects":["repeating_weapons_$x_attack_bonus","repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:deed_die_result","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-deed":{"name":"roll-pc-deed","type":"action","triggeredFuncs":["deedRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-deed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_attack_mod":{"name":"attack_mod","type":"hidden","triggeredFuncs":[],"affects":["attack"],"addFuncs":[],"listener":"change:attack_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_attack":{"name":"attack","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":["melee_attack","missile_attack","deed_die"],"addFuncs":[],"listener":"change:attack","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateAttackModifier","initialFunc":"","formula":""},"attr_attack_overwritten":{"name":"attack_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:attack_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-attack":{"name":"roll-pc-attack","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-attack","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"act_roll-pc-crit-die":{"name":"roll-pc-crit-die","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-crit-die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_crit_die_mod":{"name":"crit_die_mod","type":"hidden","triggeredFuncs":[],"affects":["crit_die","crit die"],"addFuncs":[],"listener":"change:crit_die_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_crit_die":{"name":"crit_die","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:crit_die","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateCritDieValue","initialFunc":"","formula":""},"attr_crit_die_overwritten":{"name":"crit_die_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:crit_die_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_crit_table_mod":{"name":"crit_table_mod","type":"hidden","triggeredFuncs":[],"affects":["crit_table","crit table"],"addFuncs":[],"listener":"change:crit_table_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_crit_table":{"name":"crit_table","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":["crit_die","crit die"],"addFuncs":[],"listener":"change:crit_table","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateCritTableValue","initialFunc":"","formula":""},"attr_crit_table_overwritten":{"name":"crit_table_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:crit_table_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-ref-save":{"name":"roll-pc-ref-save","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-ref-save","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_ref_save_mod":{"name":"ref_save_mod","type":"hidden","triggeredFuncs":[],"affects":["ref_save","ref save"],"addFuncs":[],"listener":"change:ref_save_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_ref_save":{"name":"ref_save","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:ref_save","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateSavingModifier","initialFunc":"","formula":""},"attr_ref_save_overwritten":{"name":"ref_save_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ref_save_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-fort-save":{"name":"roll-pc-fort-save","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-fort-save","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_fort_save_mod":{"name":"fort_save_mod","type":"hidden","triggeredFuncs":[],"affects":["fort_save","fort save"],"addFuncs":[],"listener":"change:fort_save_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_fort_save":{"name":"fort_save","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:fort_save","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateSavingModifier","initialFunc":"","formula":""},"attr_fort_save_overwritten":{"name":"fort_save_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:fort_save_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-will-save":{"name":"roll-pc-will-save","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-will-save","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_will_save_mod":{"name":"will_save_mod","type":"hidden","triggeredFuncs":[],"affects":["will_save","will save"],"addFuncs":[],"listener":"change:will_save_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_will_save":{"name":"will_save","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:will_save","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateSavingModifier","initialFunc":"","formula":""},"attr_will_save_overwritten":{"name":"will_save_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:will_save_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_luck_max_mod":{"name":"luck_max_mod","type":"hidden","triggeredFuncs":[],"affects":["luck_max","luck max"],"addFuncs":[],"listener":"change:luck_max_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_lucky_roll_mod":{"name":"lucky_roll_mod","type":"hidden","triggeredFuncs":[],"affects":["lucky_roll","lucky roll"],"addFuncs":[],"listener":"change:lucky_roll_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_lucky_roll":{"name":"lucky_roll","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:lucky_roll","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-melee-attack":{"name":"roll-pc-melee-attack","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-melee-attack","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_melee_attack_mod":{"name":"melee_attack_mod","type":"hidden","triggeredFuncs":[],"affects":["melee_attack","melee attack"],"addFuncs":[],"listener":"change:melee_attack_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_melee_attack":{"name":"melee_attack","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":["repeating_weapons_$x_attack_bonus","repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:melee_attack","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMeleeAndMissileModifiers","initialFunc":"","formula":""},"attr_melee_attack_overwritten":{"name":"melee_attack_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:melee_attack_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_melee_damage_mod":{"name":"melee_damage_mod","type":"hidden","triggeredFuncs":[],"affects":["melee_damage","melee damage"],"addFuncs":[],"listener":"change:melee_damage_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_melee_damage":{"name":"melee_damage","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":["repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:melee_damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMeleeDamage","initialFunc":"","formula":""},"attr_melee_damage_overwritten":{"name":"melee_damage_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:melee_damage_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-missile-attack":{"name":"roll-pc-missile-attack","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-missile-attack","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_missile_attack_mod":{"name":"missile_attack_mod","type":"hidden","triggeredFuncs":[],"affects":["missile_attack","missile attack"],"addFuncs":[],"listener":"change:missile_attack_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_missile_attack":{"name":"missile_attack","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":["repeating_weapons_$x_attack_bonus","repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:missile_attack","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMeleeAndMissileModifiers","initialFunc":"","formula":""},"attr_missile_attack_overwritten":{"name":"missile_attack_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:missile_attack_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_missile_damage_mod":{"name":"missile_damage_mod","type":"hidden","triggeredFuncs":[],"affects":["missile_damage","missile damage"],"addFuncs":[],"listener":"change:missile_damage_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_missile_damage":{"name":"missile_damage","type":"hidden","triggeredFuncs":[],"affects":["repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:missile_damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_character_avatar":{"name":"character_avatar","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:character_avatar","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_languages_mod":{"name":"languages_mod","type":"hidden","triggeredFuncs":[],"affects":["languages"],"addFuncs":[],"listener":"change:languages_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_languages":{"name":"languages","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:languages","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_weapon":{"name":"weapon","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:weapon","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_crit-action":{"name":"crit-action","type":"action","triggeredFuncs":["rollCrit"],"affects":[],"addFuncs":[],"listener":"clicked:crit-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_crit_action":{"name":"crit_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:crit_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_fumble-action":{"name":"fumble-action","type":"action","triggeredFuncs":["rollFumble"],"affects":[],"addFuncs":[],"listener":"clicked:fumble-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_fumble_action":{"name":"fumble_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:fumble_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_add-weapons":{"name":"add-weapons","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-weapons","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_active":{"name":"repeating_weapons_$x_active","type":"hidden","triggeredFuncs":[],"affects":["initiative"],"addFuncs":[],"listener":"change:repeating_weapons:active","listenerFunc":"accessSheet","defaultValue":"1","calculation":"calculateLinkedEquipment","initialFunc":"","formula":""},"attr_repeating_weapons_$x_name_mod":{"name":"repeating_weapons_$x_name_mod","type":"hidden","triggeredFuncs":[],"affects":["name"],"addFuncs":[],"listener":"change:repeating_weapons:name_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_name":{"name":"repeating_weapons_$x_name","type":"hidden","triggeredFuncs":["calculateEquipmentLinkedItem"],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_weapons_$x_roll-pc-attack-bonus":{"name":"repeating_weapons_$x_roll-pc-attack-bonus","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_weapons:roll-pc-attack-bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_repeating_weapons_$x_attack_bonus_mod":{"name":"repeating_weapons_$x_attack_bonus_mod","type":"hidden","triggeredFuncs":[],"affects":["attack_bonus","attack bonus"],"addFuncs":[],"listener":"change:repeating_weapons:attack_bonus_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_attack_bonus":{"name":"repeating_weapons_$x_attack_bonus","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:attack_bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateWeaponAttack","initialFunc":"","formula":""},"act_repeating_weapons_$x_roll-pc-damage":{"name":"repeating_weapons_$x_roll-pc-damage","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_weapons:roll-pc-damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_damage_mod":{"name":"repeating_weapons_$x_damage_mod","type":"hidden","triggeredFuncs":[],"affects":["damage"],"addFuncs":[],"listener":"change:repeating_weapons:damage_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_damage":{"name":"repeating_weapons_$x_damage","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateWeaponDamage","initialFunc":"","formula":""},"attr_repeating_weapons_$x_type_mod":{"name":"repeating_weapons_$x_type_mod","type":"hidden","triggeredFuncs":[],"affects":["type"],"addFuncs":[],"listener":"change:repeating_weapons:type_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_type":{"name":"repeating_weapons_$x_type","type":"hidden","triggeredFuncs":[],"affects":["repeating_weapons_$x_attack_bonus","repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:repeating_weapons:type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_range_mod":{"name":"repeating_weapons_$x_range_mod","type":"hidden","triggeredFuncs":[],"affects":["range"],"addFuncs":[],"listener":"change:repeating_weapons:range_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_range":{"name":"repeating_weapons_$x_range","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:range","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_ammunition_mod":{"name":"repeating_weapons_$x_ammunition_mod","type":"hidden","triggeredFuncs":[],"affects":["ammunition"],"addFuncs":[],"listener":"change:repeating_weapons:ammunition_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_ammunition":{"name":"repeating_weapons_$x_ammunition","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:ammunition","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_notes_mod":{"name":"repeating_weapons_$x_notes_mod","type":"hidden","triggeredFuncs":[],"affects":["notes"],"addFuncs":[],"listener":"change:repeating_weapons:notes_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_notes":{"name":"repeating_weapons_$x_notes","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:notes","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"fieldset_repeating_weapons":{"name":"repeating_weapons","type":"fieldset","triggeredFuncs":["removeEquipmentLinkedItem"],"affects":[],"addFuncs":["addEquipmentLinkedItem"],"listener":"remove:repeating_weapons","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_linked":{"name":"repeating_weapons_$x_linked","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:linked","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_attack_bonus_base_mod":{"name":"repeating_weapons_$x_attack_bonus_base_mod","type":"hidden","triggeredFuncs":[],"affects":["attack_bonus_base","attack bonus base"],"addFuncs":[],"listener":"change:repeating_weapons:attack_bonus_base_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_attack_bonus_base":{"name":"repeating_weapons_$x_attack_bonus_base","type":"hidden","triggeredFuncs":[],"affects":["repeating_weapons_$x_attack_bonus"],"addFuncs":[],"listener":"change:repeating_weapons:attack_bonus_base","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_damage_base_mod":{"name":"repeating_weapons_$x_damage_base_mod","type":"hidden","triggeredFuncs":[],"affects":["damage_base","damage base"],"addFuncs":[],"listener":"change:repeating_weapons:damage_base_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_damage_base":{"name":"repeating_weapons_$x_damage_base","type":"hidden","triggeredFuncs":[],"affects":["repeating_weapons_$x_damage"],"addFuncs":[],"listener":"change:repeating_weapons:damage_base","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_two_handed_mod":{"name":"repeating_weapons_$x_two_handed_mod","type":"hidden","triggeredFuncs":[],"affects":["two_handed","two handed"],"addFuncs":[],"listener":"change:repeating_weapons:two_handed_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_weapons_$x_two_handed":{"name":"repeating_weapons_$x_two_handed","type":"hidden","triggeredFuncs":[],"affects":["initiative"],"addFuncs":[],"listener":"change:repeating_weapons:two_handed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_treasure_mod":{"name":"treasure_mod","type":"hidden","triggeredFuncs":[],"affects":["treasure"],"addFuncs":[],"listener":"change:treasure_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_treasure":{"name":"treasure","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:treasure","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_equipment":{"name":"equipment","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:equipment","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_add-equipment":{"name":"add-equipment","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-equipment","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_equipment_$x_active":{"name":"repeating_equipment_$x_active","type":"checkbox","triggeredFuncs":["toggleEquipment"],"affects":[],"addFuncs":[],"listener":"change:repeating_equipment:active","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_repeating_equipment_$x_name":{"name":"repeating_equipment_$x_name","type":"span","triggeredFuncs":["calculateEquipmentLinkedItem"],"affects":[],"addFuncs":[],"listener":"change:repeating_equipment:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_equipment_$x_cost":{"name":"repeating_equipment_$x_cost","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_equipment:cost","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"fieldset_repeating_equipment":{"name":"repeating_equipment","type":"fieldset","triggeredFuncs":["removeEquipmentLinkedItem"],"affects":[],"addFuncs":[],"listener":"remove:repeating_equipment","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_equipment_$x_type":{"name":"repeating_equipment_$x_type","type":"select","triggeredFuncs":["toggleEquipmentType"],"affects":[],"addFuncs":[],"listener":"change:repeating_equipment:type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_equipment_$x_modifiers":{"name":"repeating_equipment_$x_modifiers","type":"text","triggeredFuncs":["calculateModifiedAttributes"],"affects":[],"addFuncs":[],"listener":"change:repeating_equipment:modifiers","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_equipment_$x_linked":{"name":"repeating_equipment_$x_linked","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_equipment:linked","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor":{"name":"armor","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_add-armor":{"name":"add-armor","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-armor","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_active":{"name":"repeating_armor_$x_active","type":"hidden","triggeredFuncs":[],"affects":["armor_class","speed"],"addFuncs":[],"listener":"change:repeating_armor:active","listenerFunc":"accessSheet","defaultValue":"1","calculation":"calculateLinkedEquipment","initialFunc":"","formula":""},"attr_repeating_armor_$x_name_mod":{"name":"repeating_armor_$x_name_mod","type":"hidden","triggeredFuncs":[],"affects":["name"],"addFuncs":[],"listener":"change:repeating_armor:name_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_armor_$x_name":{"name":"repeating_armor_$x_name","type":"hidden","triggeredFuncs":["calculateEquipmentLinkedItem"],"affects":[],"addFuncs":[],"listener":"change:repeating_armor:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_ac_bonus_mod":{"name":"repeating_armor_$x_ac_bonus_mod","type":"hidden","triggeredFuncs":[],"affects":["ac_bonus","ac bonus"],"addFuncs":[],"listener":"change:repeating_armor:ac_bonus_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_armor_$x_ac_bonus":{"name":"repeating_armor_$x_ac_bonus","type":"hidden","triggeredFuncs":[],"affects":["armor_class"],"addFuncs":[],"listener":"change:repeating_armor:ac_bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_check_penalty_mod":{"name":"repeating_armor_$x_check_penalty_mod","type":"hidden","triggeredFuncs":[],"affects":["check_penalty","check penalty"],"addFuncs":[],"listener":"change:repeating_armor:check_penalty_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_armor_$x_check_penalty":{"name":"repeating_armor_$x_check_penalty","type":"hidden","triggeredFuncs":[],"affects":["base_spell_check","climb_sheer_surfaces","sneak_silently"],"addFuncs":[],"listener":"change:repeating_armor:check_penalty","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_speed_mod":{"name":"repeating_armor_$x_speed_mod","type":"hidden","triggeredFuncs":[],"affects":["speed"],"addFuncs":[],"listener":"change:repeating_armor:speed_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_armor_$x_speed":{"name":"repeating_armor_$x_speed","type":"hidden","triggeredFuncs":[],"affects":["speed"],"addFuncs":[],"listener":"change:repeating_armor:speed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_fumble_die_mod":{"name":"repeating_armor_$x_fumble_die_mod","type":"hidden","triggeredFuncs":[],"affects":["fumble_die","fumble die"],"addFuncs":[],"listener":"change:repeating_armor:fumble_die_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_armor_$x_fumble_die":{"name":"repeating_armor_$x_fumble_die","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_armor:fumble_die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"fieldset_repeating_armor":{"name":"repeating_armor","type":"fieldset","triggeredFuncs":["removeEquipmentLinkedItem","removeArmor"],"affects":[],"addFuncs":["addEquipmentLinkedItem"],"listener":"remove:repeating_armor","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_linked":{"name":"repeating_armor_$x_linked","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_armor:linked","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armor_$x_shield_mod":{"name":"repeating_armor_$x_shield_mod","type":"hidden","triggeredFuncs":[],"affects":["shield"],"addFuncs":[],"listener":"change:repeating_armor:shield_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_repeating_armor_$x_shield":{"name":"repeating_armor_$x_shield","type":"hidden","triggeredFuncs":[],"affects":["armor_class"],"addFuncs":[],"listener":"change:repeating_armor:shield","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_deity_mod":{"name":"deity_mod","type":"hidden","triggeredFuncs":[],"affects":["deity"],"addFuncs":[],"listener":"change:deity_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_deity":{"name":"deity","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:deity","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-base-spell-check":{"name":"roll-pc-base-spell-check","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-base-spell-check","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_base_spell_check_mod":{"name":"base_spell_check_mod","type":"hidden","triggeredFuncs":[],"affects":["base_spell_check","base spell check"],"addFuncs":[],"listener":"change:base_spell_check_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_base_spell_check":{"name":"base_spell_check","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":["repeating_spells_$x_total_check"],"addFuncs":[],"listener":"change:base_spell_check","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateSpellCheckModifier","initialFunc":"","formula":""},"attr_base_spell_check_overwritten":{"name":"base_spell_check_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:base_spell_check_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_undefined":{"name":"undefined","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:undefined","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-pc-lay-on-hands-same":{"name":"roll-pc-lay-on-hands-same","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-lay-on-hands-same","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"spell_check","title":"lay on hands","subtitle":"(same)"}},"attr_lay_on_hands_same":{"name":"lay_on_hands_same","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:lay_on_hands_same","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-lay-on-hands-adjacent":{"name":"roll-pc-lay-on-hands-adjacent","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-lay-on-hands-adjacent","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"spell_check","title":"lay on hands","subtitle":"(adjacent)"}},"attr_lay_on_hands_adjacent":{"name":"lay_on_hands_adjacent","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:lay_on_hands_adjacent","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-lay-on-hands-opposed":{"name":"roll-pc-lay-on-hands-opposed","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-lay-on-hands-opposed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"formula":"spell_check","title":"lay on hands","subtitle":"(opposed)"}},"attr_lay_on_hands_opposed":{"name":"lay_on_hands_opposed","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:lay_on_hands_opposed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_lucky_weapon_mod":{"name":"lucky_weapon_mod","type":"hidden","triggeredFuncs":[],"affects":["lucky_weapon","lucky weapon"],"addFuncs":[],"listener":"change:lucky_weapon_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_lucky_weapon":{"name":"lucky_weapon","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:lucky_weapon","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-shield-bash":{"name":"roll-pc-shield-bash","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-shield-bash","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"actionDie":"1d14","formula":"melee_attack"}},"attr_shield_bash":{"name":"shield_bash","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:shield_bash","listenerFunc":"accessSheet","defaultValue":"1d14","calculation":"","initialFunc":"","formula":""},"attr_familiar_mod":{"name":"familiar_mod","type":"hidden","triggeredFuncs":[],"affects":["familiar"],"addFuncs":[],"listener":"change:familiar_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_familiar":{"name":"familiar","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:familiar","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_patrons_mod":{"name":"patrons_mod","type":"hidden","triggeredFuncs":[],"affects":["patrons"],"addFuncs":[],"listener":"change:patrons_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_patrons":{"name":"patrons","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:patrons","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_corruption_mod":{"name":"corruption_mod","type":"hidden","triggeredFuncs":[],"affects":["corruption"],"addFuncs":[],"listener":"change:corruption_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_corruption":{"name":"corruption","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:corruption","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_other_notes_mod":{"name":"other_notes_mod","type":"hidden","triggeredFuncs":[],"affects":["other_notes","other notes"],"addFuncs":[],"listener":"change:other_notes_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_other_notes":{"name":"other_notes","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:other_notes","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-stealth":{"name":"roll-pc-stealth","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-stealth","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_stealth_mod":{"name":"stealth_mod","type":"hidden","triggeredFuncs":[],"affects":["stealth"],"addFuncs":[],"listener":"change:stealth_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_stealth":{"name":"stealth","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:stealth","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateStealthModifier","initialFunc":"","formula":""},"attr_stealth_overwritten":{"name":"stealth_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stealth_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-luck-die":{"name":"roll-pc-luck-die","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-luck-die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_luck_die_mod":{"name":"luck_die_mod","type":"hidden","triggeredFuncs":[],"affects":["luck_die","luck die"],"addFuncs":[],"listener":"change:luck_die_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_luck_die":{"name":"luck_die","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:luck_die","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateLuckDieValue","initialFunc":"","formula":""},"attr_luck_die_overwritten":{"name":"luck_die_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:luck_die_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-disable-trap":{"name":"roll-pc-disable-trap","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-disable-trap","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_disable_trap_mod":{"name":"disable_trap_mod","type":"hidden","triggeredFuncs":[],"affects":["disable_trap","disable trap"],"addFuncs":[],"listener":"change:disable_trap_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_disable_trap":{"name":"disable_trap","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:disable_trap","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_disable_trap_overwritten":{"name":"disable_trap_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:disable_trap_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-backstab":{"name":"roll-pc-backstab","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-backstab","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_backstab_mod":{"name":"backstab_mod","type":"hidden","triggeredFuncs":[],"affects":["backstab"],"addFuncs":[],"listener":"change:backstab_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_backstab":{"name":"backstab","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:backstab","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_backstab_overwritten":{"name":"backstab_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:backstab_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-forge-document":{"name":"roll-pc-forge-document","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-forge-document","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_forge_document_mod":{"name":"forge_document_mod","type":"hidden","triggeredFuncs":[],"affects":["forge_document","forge document"],"addFuncs":[],"listener":"change:forge_document_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_forge_document":{"name":"forge_document","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:forge_document","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_forge_document_overwritten":{"name":"forge_document_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:forge_document_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-sneak-silently":{"name":"roll-pc-sneak-silently","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-sneak-silently","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_sneak_silently_mod":{"name":"sneak_silently_mod","type":"hidden","triggeredFuncs":[],"affects":["sneak_silently","sneak silently"],"addFuncs":[],"listener":"change:sneak_silently_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_sneak_silently":{"name":"sneak_silently","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:sneak_silently","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_sneak_silently_overwritten":{"name":"sneak_silently_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:sneak_silently_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-disguise-self":{"name":"roll-pc-disguise-self","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-disguise-self","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_disguise_self_mod":{"name":"disguise_self_mod","type":"hidden","triggeredFuncs":[],"affects":["disguise_self","disguise self"],"addFuncs":[],"listener":"change:disguise_self_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_disguise_self":{"name":"disguise_self","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:disguise_self","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_disguise_self_overwritten":{"name":"disguise_self_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:disguise_self_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-hide-in-shadows":{"name":"roll-pc-hide-in-shadows","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-hide-in-shadows","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_hide_in_shadows_mod":{"name":"hide_in_shadows_mod","type":"hidden","triggeredFuncs":[],"affects":["hide_in_shadows","hide in shadows"],"addFuncs":[],"listener":"change:hide_in_shadows_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_hide_in_shadows":{"name":"hide_in_shadows","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:hide_in_shadows","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_hide_in_shadows_overwritten":{"name":"hide_in_shadows_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:hide_in_shadows_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-read-languages":{"name":"roll-pc-read-languages","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-read-languages","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_read_languages_mod":{"name":"read_languages_mod","type":"hidden","triggeredFuncs":[],"affects":["read_languages","read languages"],"addFuncs":[],"listener":"change:read_languages_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_read_languages":{"name":"read_languages","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:read_languages","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_read_languages_overwritten":{"name":"read_languages_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:read_languages_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-pick-pocket":{"name":"roll-pc-pick-pocket","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-pick-pocket","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_pick_pocket_mod":{"name":"pick_pocket_mod","type":"hidden","triggeredFuncs":[],"affects":["pick_pocket","pick pocket"],"addFuncs":[],"listener":"change:pick_pocket_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_pick_pocket":{"name":"pick_pocket","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:pick_pocket","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_pick_pocket_overwritten":{"name":"pick_pocket_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:pick_pocket_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-handle-poison":{"name":"roll-pc-handle-poison","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-handle-poison","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_handle_poison_mod":{"name":"handle_poison_mod","type":"hidden","triggeredFuncs":[],"affects":["handle_poison","handle poison"],"addFuncs":[],"listener":"change:handle_poison_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_handle_poison":{"name":"handle_poison","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:handle_poison","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_handle_poison_overwritten":{"name":"handle_poison_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:handle_poison_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-climb-sheer-surfaces":{"name":"roll-pc-climb-sheer-surfaces","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-climb-sheer-surfaces","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_climb_sheer_surfaces_mod":{"name":"climb_sheer_surfaces_mod","type":"hidden","triggeredFuncs":[],"affects":["climb_sheer_surfaces","climb sheer surfaces"],"addFuncs":[],"listener":"change:climb_sheer_surfaces_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_climb_sheer_surfaces":{"name":"climb_sheer_surfaces","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:climb_sheer_surfaces","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_climb_sheer_surfaces_overwritten":{"name":"climb_sheer_surfaces_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:climb_sheer_surfaces_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-cast-spell-from-scroll":{"name":"roll-pc-cast-spell-from-scroll","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-cast-spell-from-scroll","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_cast_spell_from_scroll_mod":{"name":"cast_spell_from_scroll_mod","type":"hidden","triggeredFuncs":[],"affects":["cast_spell_from_scroll","cast spell from scroll"],"addFuncs":[],"listener":"change:cast_spell_from_scroll_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_cast_spell_from_scroll":{"name":"cast_spell_from_scroll","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:cast_spell_from_scroll","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_cast_spell_from_scroll_overwritten":{"name":"cast_spell_from_scroll_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:cast_spell_from_scroll_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-pick-lock":{"name":"roll-pc-pick-lock","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-pick-lock","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_pick_lock_mod":{"name":"pick_lock_mod","type":"hidden","triggeredFuncs":[],"affects":["pick_lock","pick lock"],"addFuncs":[],"listener":"change:pick_lock_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_pick_lock":{"name":"pick_lock","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:pick_lock","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_pick_lock_overwritten":{"name":"pick_lock_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:pick_lock_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-find-trap":{"name":"roll-pc-find-trap","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-find-trap","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","actionDie":"1d20"},"attr_find_trap_mod":{"name":"find_trap_mod","type":"hidden","triggeredFuncs":[],"affects":["find_trap","find trap"],"addFuncs":[],"listener":"change:find_trap_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_find_trap":{"name":"find_trap","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:find_trap","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThiefSkillsModifiers","initialFunc":"","formula":""},"attr_find_trap_overwritten":{"name":"find_trap_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:find_trap_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_critical_threat_range_mod":{"name":"critical_threat_range_mod","type":"hidden","triggeredFuncs":[],"affects":["critical_threat_range","critical threat range"],"addFuncs":[],"listener":"change:critical_threat_range_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_critical_threat_range":{"name":"critical_threat_range","type":"hidden","triggeredFuncs":["overwriteDefaultAttributeValue"],"affects":[],"addFuncs":[],"listener":"change:critical_threat_range","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateThreatRangeValue","initialFunc":"","formula":""},"attr_critical_threat_range_overwritten":{"name":"critical_threat_range_overwritten","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:critical_threat_range_overwritten","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_spells":{"name":"spells","type":"checkbox","triggeredFuncs":[],"affects":["repeating_spells_$x_collapse","repeating_spells_$X_collapse"],"addFuncs":[],"listener":"change:spells","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr__reporder_repeating_spells":{"name":"_reporder_repeating_spells","type":"hidden","triggeredFuncs":["moveTableRows"],"affects":[],"addFuncs":[],"listener":"change:_reporder:spells","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_add-spells":{"name":"add-spells","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-spells","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"fieldset_repeating_spells":{"name":"repeating_spells","type":"fieldset","triggeredFuncs":["removeSpell"],"affects":[],"addFuncs":["addSpell"],"listener":"remove:repeating_spells","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_collapse":{"name":"repeating_spells_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"collapseSpell","initialFunc":"collapseSpellTable","formula":""},"attr_repeating_spells_$x_master":{"name":"repeating_spells_$x_master","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:master","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_compendium_reference":{"name":"repeating_spells_$x_compendium_reference","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:compendium_reference","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_row_type":{"name":"repeating_spells_$x_row_type","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:row_type","listenerFunc":"accessSheet","defaultValue":"master","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_name":{"name":"repeating_spells_$x_name","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_level":{"name":"repeating_spells_$x_level","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:level","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_total_check":{"name":"repeating_spells_$x_total_check","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:total_check","listenerFunc":"accessSheet","defaultValue":0,"calculation":"calcSpellCheck","initialFunc":"","formula":""},"act_repeating_spells_$x_roll-pc-total-check":{"name":"repeating_spells_$x_roll-pc-total-check","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_spells:roll-pc-total-check","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","settings":{"manipulator":"determineSpellEffects","fields":["{{computeDescription=[[0[computed value]]]}}"]}},"attr_repeating_spells_$x_notes":{"name":"repeating_spells_$x_notes","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:notes","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_description":{"name":"repeating_spells_$x_description","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_check":{"name":"repeating_spells_$x_check","type":"number","triggeredFuncs":[],"affects":["repeating_spells_$x_total_check"],"addFuncs":[],"listener":"change:repeating_spells:check","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_range":{"name":"repeating_spells_$x_range","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:range","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_casting_time":{"name":"repeating_spells_$x_casting_time","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:casting_time","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_save":{"name":"repeating_spells_$x_save","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:save","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_duration":{"name":"repeating_spells_$x_duration","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:duration","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_manifestation":{"name":"repeating_spells_$x_manifestation","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:manifestation","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_spells_$x_corruption-action":{"name":"repeating_spells_$x_corruption-action","type":"action","triggeredFuncs":["rollStringTable"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_spells:corruption-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_corruption_action":{"name":"repeating_spells_$x_corruption_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:corruption_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_corruption":{"name":"repeating_spells_$x_corruption","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:corruption","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_spells_$x_misfire-action":{"name":"repeating_spells_$x_misfire-action","type":"action","triggeredFuncs":["rollStringTable"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_spells:misfire-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_misfire_action":{"name":"repeating_spells_$x_misfire_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:misfire_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_misfire":{"name":"repeating_spells_$x_misfire","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:misfire","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_row_collapse":{"name":"repeating_spells_$x_row_collapse","type":"checkbox","triggeredFuncs":["collapseSpellTable"],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:row_collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_roll":{"name":"repeating_spells_$x_roll","type":"text","triggeredFuncs":["tableRowAdd"],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:roll","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_spells_$x_result":{"name":"repeating_spells_$x_result","type":"span","triggeredFuncs":["tableCleanup"],"affects":[],"addFuncs":[],"listener":"change:repeating_spells:result","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_notes_mod":{"name":"notes_mod","type":"hidden","triggeredFuncs":[],"affects":["notes"],"addFuncs":[],"listener":"change:notes_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_notes":{"name":"notes","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:notes","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_active":{"name":"rollmodal_active","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_active","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_title":{"name":"rollmodal_title","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_title","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_subtitle":{"name":"rollmodal_subtitle","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_subtitle","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_base_formula":{"name":"rollmodal_base_formula","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_final_formula"],"addFuncs":[],"listener":"change:rollmodal_base_formula","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_source":{"name":"rollmodal_source","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_source","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_final_formula":{"name":"rollmodal_final_formula","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_final_formula","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateRollmodalFormula","initialFunc":"","formula":""},"attr_rollmodal_description":{"name":"rollmodal_description","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_has_action_die":{"name":"rollmodal_has_action_die","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_has_action_die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_action_die":{"name":"rollmodal_action_die","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_final_formula"],"addFuncs":[],"listener":"change:rollmodal_action_die","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_base_formula_mod":{"name":"rollmodal_base_formula_mod","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_base_formula","rollmodal base formula"],"addFuncs":[],"listener":"change:rollmodal_base_formula_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_rollmodal_action_die_mod":{"name":"rollmodal_action_die_mod","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_action_die","rollmodal action die"],"addFuncs":[],"listener":"change:rollmodal_action_die_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_rollmodal_bonus_mod":{"name":"rollmodal_bonus_mod","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_bonus","rollmodal bonus"],"addFuncs":[],"listener":"change:rollmodal_bonus_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_rollmodal_bonus":{"name":"rollmodal_bonus","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_final_formula"],"addFuncs":[],"listener":"change:rollmodal_bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rollmodal_type_mod":{"name":"rollmodal_type_mod","type":"hidden","triggeredFuncs":[],"affects":["rollmodal_type","rollmodal type"],"addFuncs":[],"listener":"change:rollmodal_type_mod","listenerFunc":"accessSheet","defaultValue":"","calculation":"calculateMods","initialFunc":"","formula":""},"attr_rollmodal_type":{"name":"rollmodal_type","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rollmodal_type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-pc-rollmodal":{"name":"roll-pc-rollmodal","type":"action","triggeredFuncs":["modalRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-pc-rollmodal","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_rollmodal-blocker":{"name":"rollmodal-blocker","type":"action","triggeredFuncs":["closeModal"],"affects":[],"addFuncs":[],"listener":"clicked:rollmodal-blocker","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_npc_collapse":{"name":"npc_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:npc_collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_roll-npc-init":{"name":"roll-npc-init","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-npc-init","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_init":{"name":"init","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:init","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_add-attacks":{"name":"add-attacks","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-attacks","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_attacks_$x_roll-npc-bonus":{"name":"repeating_attacks_$x_roll-npc-bonus","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_attacks:roll-npc-bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_attacks_$x_name":{"name":"repeating_attacks_$x_name","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_attacks:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_attacks_$x_bonus":{"name":"repeating_attacks_$x_bonus","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_attacks:bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_attacks_$x_type":{"name":"repeating_attacks_$x_type","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_attacks:type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_attacks_$x_roll-npc-damage":{"name":"repeating_attacks_$x_roll-npc-damage","type":"action","triggeredFuncs":["genericRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_attacks:roll-npc-damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_attacks_$x_damage":{"name":"repeating_attacks_$x_damage","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_attacks:damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ac":{"name":"ac","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ac","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-npc-hd":{"name":"roll-npc-hd","type":"action","triggeredFuncs":["hpRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-npc-hd","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_hd":{"name":"hd","type":"span","triggeredFuncs":[],"affects":["crit_die","crit die"],"addFuncs":[],"listener":"change:hd","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_add-movement":{"name":"add-movement","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-movement","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_movement_$x_name":{"name":"repeating_movement_$x_name","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_movement:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_movement_$x_speed":{"name":"repeating_movement_$x_speed","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_movement:speed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_act":{"name":"act","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:act","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_sp":{"name":"sp","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:sp","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-npc-fort":{"name":"roll-npc-fort","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-npc-fort","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_fort":{"name":"fort","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:fort","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-npc-ref":{"name":"roll-npc-ref","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-npc-ref","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ref":{"name":"ref","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ref","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_roll-npc-will":{"name":"roll-npc-will","type":"action","triggeredFuncs":["genericActionRoll"],"affects":[],"addFuncs":[],"listener":"clicked:roll-npc-will","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_will":{"name":"will","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:will","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_description":{"name":"description","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_template_start":{"name":"template_start","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:template_start","listenerFunc":"accessSheet","defaultValue":"@{whisper}&{template:undefined} {{character_name=@{character_name}}} {{character_id=@{character_id}}}","calculation":"","initialFunc":"","formula":""}};
|
|
|
|
kFuncs.cascades = cascades;
|
|
|
|
const repeatingSectionDetails = [{"section":"repeating_mancer-class-options","fields":["ability_map","name","description","row_id","mancer_sub_field_control","select"]},{"section":"repeating_mancer-class-table","fields":["row_id","ability_map","name","value_1","value_2","value_3","value_4","value_5","value_6","value_7","value_8","value_9","value_10"]},{"section":"repeating_mancer-spells","fields":["level","class","compendium_reference","type","selectable","selected","name","compendium_link","label","chosen","chosen_max"]},{"section":"repeating_rollable-tables","fields":["name","action","die","bonus"]},{"section":"repeating_weapons","fields":["active","name_mod","name","attack_bonus_mod","attack_bonus","damage_mod","damage","type_mod","type","range_mod","range","ammunition_mod","ammunition","notes_mod","notes","linked","attack_bonus_base_mod","attack_bonus_base","damage_base_mod","damage_base","two_handed_mod","two_handed"]},{"section":"repeating_equipment","fields":["active","name","cost","type","modifiers","linked"]},{"section":"repeating_armor","fields":["active","name_mod","name","ac_bonus_mod","ac_bonus","check_penalty_mod","check_penalty","speed_mod","speed","fumble_die_mod","fumble_die","linked","shield_mod","shield"]},{"section":"repeating_spells","fields":["collapse","master","compendium_reference","row_type","name","level","total_check","notes","description","check","range","casting_time","save","duration","manifestation","corruption_action","corruption","misfire_action","misfire","row_collapse","roll","result"]},{"section":"repeating_attacks","fields":["name","bonus","type","damage"]},{"section":"repeating_movement","fields":["name","speed"]}];
|
|
|
|
kFuncs.repeatingSectionDetails = repeatingSectionDetails;
|
|
|
|
const persistentTabs = [];
|
|
|
|
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';
|
|
/**
|
|
* Defines the rollstring that rolls made using k.startRoll begin with. Defaults to "&{template:default}".
|
|
* @memberof Variables
|
|
* @var
|
|
* @type {string}
|
|
*/
|
|
let defaultRollStart = '&{template:default}';
|
|
kFuncs.defaultRollStart = defaultRollStart;/*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');
|
|
const rollObj = {
|
|
query:`[[0[response=?{${query}}]]]`
|
|
};
|
|
let {roll} = await _startRoll(rollObj,'!');
|
|
roll.finish();
|
|
return roll.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){
|
|
const rollObj = {
|
|
query:`[[0[response=${value}]]]`
|
|
};
|
|
let {roll} = await _startRoll(rollObj,'!');
|
|
roll.finish();
|
|
return roll.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,casc){
|
|
Object.keys(sections).forEach((section)=>{
|
|
attributes.attributes[`_reporder_${section}`] = commaArray(attributes[`_reporder_${section}`]);
|
|
sections[section] = orderSection(attributes.attributes[`_reporder_${section}`],sections[section],attributes,section,casc);
|
|
});
|
|
};
|
|
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
|
|
* @param {AttributesProxy} [attributes] - The Kscaffold attributes object
|
|
* @param {string} [section] - the name of the section being ordered. If section and attributes are passed, will return an ordered array that does not include IDs for rows that do not exist.
|
|
* @param {object} [casc] - the object describing the default state of the sheet.
|
|
* @returns {string[]} - The ordered id array
|
|
*/
|
|
const orderSection = function(repOrder,IDs=[], attributes, section,casc){
|
|
const idArr = [...repOrder.filter(v => v),...IDs.filter(id => !repOrder.includes(id.toLowerCase()))]
|
|
.filter(id => {
|
|
const testAttr = Object.keys(casc).find(a => a.toLowerCase().startsWith(`attr_${section}_${id}`));
|
|
const testName = testAttr?.replace(/attr_/,'');
|
|
const idName = testName?.replace(/\$x/,id);
|
|
return (!section && !casc) ||
|
|
(
|
|
idName &&
|
|
(
|
|
attributes.attributes.hasOwnProperty(idName) ||
|
|
attributes.updates.hasOwnProperty(idName)
|
|
)
|
|
);
|
|
});
|
|
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});
|
|
|
|
/**
|
|
* Parses a macro so that it is reduced to the final values of all attributes contained in the macro. Will drill down up to 99 levels deep. If the string was not parseable, string will be returned with as much parsed as possible.
|
|
* @memberof Utilities
|
|
* @param {string} mutStr - The string macro to parse
|
|
* @param {AttributesProxy} attributes - The K-scaffold Attributes Proxy
|
|
* @param {Object} sections - The K-scaffold sections object
|
|
* @returns {string} - The string with all attributes replaced by their values (if possible).
|
|
*/
|
|
const parseMacro = (str,attributes,sections) => {
|
|
let iter = 0;
|
|
let mutStr = str;
|
|
while(mutStr.match(/@{.+?}/) && iter < 99){
|
|
mutStr = mutStr.replace(/@{(.+?)}/g,(match,name) => {
|
|
name = name.replace(/\|/,'_');
|
|
return attributes[name] !== null && attributes[name] !== undefined ?
|
|
attributes[name] :
|
|
`@(${name})`;
|
|
})
|
|
iter++;
|
|
}
|
|
mutStr = mutStr.replace(/@\((.+?)\)/g,'@{$1}');
|
|
return mutStr;
|
|
}
|
|
kFuncs.parseMacro = parseMacro;
|
|
|
|
/**
|
|
* Sends data to another character sheet to cause a change on that sheet. WARNING, this function should not be used in response to an attribute change to avoid spamming the chat with api messages.
|
|
*
|
|
* 
|
|
* @memberof Utilities
|
|
* @param {string} characterName - The character to connect to
|
|
* @param {string} funcName - Name of the function to call similar to function name used in {@link callFunc}.
|
|
* @param {...any} args - The arguments to pass to the function call no the other sheet. These are passed after the normal destructure object for a K-scaffold function call.
|
|
* @example
|
|
* //Function that is called by the source sheet
|
|
* const dispatchPartner = async function({trigger,attributes,sections,casc}){
|
|
* const partnerName = await (
|
|
* attributes.partner_name ?
|
|
* k.pseudoQuery(attributes.partner_name) :
|
|
* k.extractQueryResult('Partner name')
|
|
* );
|
|
* attributes.partner_name = partnerName;
|
|
* //passing the attributes of the source sheet
|
|
* k.send(partnerName,'receivePartner',attributes);
|
|
* attributes.set();
|
|
* };
|
|
* k.registerFuncs({dispatchPartner});
|
|
*
|
|
* //Function called on target sheet. Partner is the attributes from the source sheet
|
|
* const receivePartner = function({trigger,attributes,sections,casc},partner){
|
|
* attributes.from_partner = partner.for_partner;
|
|
* attributes.partner_name = partner.character_name;
|
|
* };
|
|
* k.registerFuncs({receivePartner });
|
|
*/
|
|
const send = async function(characterName,funcName,...args){
|
|
const data = RE.escape({
|
|
funcName,
|
|
args
|
|
});
|
|
const roll = await startRoll(`!@{${characterName}|character_name}%{${characterName}|k-network-call||${data}}&{noerror}`);
|
|
finishRoll(roll.rollId);
|
|
};
|
|
kFuncs.send = send;
|
|
|
|
const kReceive = function({trigger,attributes,sections,casc}) {
|
|
const data = trigger.rollData;
|
|
callFunc(data.funcName,{attributes,sections,casc},...data.args);
|
|
};
|
|
funcs.kReceive = kReceive;/*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){
|
|
Object.assign(cascObj,event);
|
|
if(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){
|
|
// Handle autocalc formula
|
|
if(trigger.formula){
|
|
attributes[trigger.name] = parseKFormula({trigger,attributes,sections,casc});
|
|
}
|
|
// handle calculation of element
|
|
if(
|
|
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 === 'toJSON'){
|
|
return () => ({...obj.attributes,...obj.updates});
|
|
} else 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')}`.toLowerCase();
|
|
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 that reduces Roll20 macro syntax formulas down to their calculated value.
|
|
* @memberof Sheetworkers
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
*/
|
|
const parseKFormula = ({trigger,attributes,sections,casc}) => {
|
|
const [baseSection,rowID,attrName] = parseTriggerName(trigger.name);
|
|
const repeatBlockRx = baseSection ?
|
|
/(@{repeating_.+?_\$X_.+?})/g :
|
|
/={([^)]*repeating_[^_]+[^)]*)}=/g;
|
|
let mutFormula = trigger.formula;
|
|
mutFormula = mutFormula.replace(repeatBlockRx,(match,repeatMacro) => {
|
|
const [section] = repeatMacro.match(/repeating_[^_]+/);
|
|
const idArray = baseSection ?
|
|
[rowID] :
|
|
sections[section];
|
|
return idArray.map(id => {
|
|
return `(${repeatMacro.replace(/repeating_[^_]+?_[^_]+?_([^}]+)/g,`${section}_${id}_$1`)})`;
|
|
}).join(
|
|
trigger.type === 'number' ?
|
|
' + ' :
|
|
''
|
|
);
|
|
});
|
|
mutFormula = parseMacro(mutFormula,attributes)
|
|
.replace(/@{.+?}/g,'0');
|
|
const mathKeys = ['floor','ceil','round','abs'];
|
|
mathKeys.forEach(func => mutFormula = mutFormula.replace(new RegExp(`${func}\\(`,'g'),`Math.${func}(`));
|
|
const mathRx = new RegExp(`Math\\.(?:${mathKeys.join('|')})`,'g');
|
|
let noAlphaStr = mutFormula
|
|
.replace(mathRx,'');
|
|
return trigger.type !== 'text' ?
|
|
(
|
|
!noAlphaStr.match(/[a-z]/i) ?
|
|
eval(mutFormula) :
|
|
undefined
|
|
) :
|
|
mutFormula;
|
|
};
|
|
funcs.parseKFormula = parseKFormula;
|
|
kFuncs.parseKFormula = parseKFormula;
|
|
|
|
/**
|
|
* 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
|
|
/**
|
|
* Function that calls the K-scaffold's update and sheet initialization routines.
|
|
*/
|
|
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');
|
|
}});
|
|
};
|
|
kFuncs.updateSheet = updateSheet;
|
|
|
|
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;
|
|
},{});
|
|
};
|
|
kFuncs.expandCascade = (sections) => expandCascade(cascades,sections);
|
|
|
|
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(affected.startsWith(section)){//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,casc);
|
|
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
|
|
* @alias setAttrs
|
|
* @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);// => repeating_equipment_-p8rg908ug0suzz
|
|
* //Create a custom row ID
|
|
* const customID = k.generateRowID('repeating_equipment',sections,'custom');
|
|
* console.log(customID);// => repeating_equipment_-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;
|
|
|
|
/**
|
|
* An alias for [Roll20's getTranslationByKey](https://wiki.roll20.net/Sheet_Worker_Scripts#getTranslationByKey.28.5Bkey.5D.29) that also supports data-i18n-vars syntax replacement and returns the translation key if no value is found instead of `false`.
|
|
* @memberof Sheetworker Aliases
|
|
* @name getTranslationByKey
|
|
* @param {string} key - The translation key to look up.
|
|
* @param {string[]} [variables = []] - An array of variable values to replace variable indexes with.
|
|
* @returns {string}
|
|
*/
|
|
const _getTranslationByKey = (key,variables = []) => {
|
|
let translate = getTranslationByKey(key) || key;
|
|
console.warn('getTranslationByKey',getTranslationByKey(key));
|
|
console.warn('translate:',translate);
|
|
variables.forEach((v,i) => {
|
|
translate = translate.replace(new RegExp(`\\{\\{${i}\\}\\}`,'g'),v);
|
|
});
|
|
return translate;
|
|
}
|
|
kFuncs.getTranslationByKey = _getTranslationByKey;
|
|
|
|
/**
|
|
* 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 = kFuncs.defaultRollStart) => {
|
|
return Object.entries(rollObj).reduce((str,[field,content])=>{
|
|
return str += content ?
|
|
` {{${field}=${content}}}` :
|
|
'';
|
|
},`${rollStart}`);
|
|
};
|
|
|
|
|
|
/**
|
|
* @typedef {Object} kRoll
|
|
* @property {Object} roll - The roll object returned by [Roll20's startRoll](https://wiki.roll20.net/Custom_Roll_Parsing#Sheetworker_Functions).
|
|
* @property {Function} roll.finish - Finishes the associated roll passing it the computeObj and rollId.
|
|
* @property {Object} computeObj - object for storing manipulations to the roll. Assign manipulations to this, DO NOT reassign it to a new object.
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* @param {object} rollObj - Object specifying the fields to pass to the rolltemplate. Object keys are field names. Object values are the field values.
|
|
* @param {string} [startString = '@{template_start}'] - Text that should be prepended to the roll string that results from rollObj.
|
|
* @returns {kRoll}
|
|
*/
|
|
const _startRoll = async (rollObj,startString) => {
|
|
const rollString = assembleRoll(rollObj,startString);
|
|
const roll = await startRoll(rollString);
|
|
const computeObj = {};
|
|
roll.finish = () => {
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
return {roll, computeObj};
|
|
};
|
|
kFuncs.startRoll = _startRoll;/*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,newRow:row});
|
|
}
|
|
});
|
|
}
|
|
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 = ["repeating_rollable-tables_$X_action","crit_action","fumble_action","repeating_spells_$X_corruption_action","repeating_spells_$X_misfire_action"];const itemCategories = ["Wizard Spells","Cleric Spells","Weapons","Armor","Equipment","Attacks"];const specialCategories = {"Wizard":"Wizard Spells","wizard":"Wizard Spells","Cleric":"Cleric Spells","cleric":"Cleric Spells"};const maxAttr = [];const sectionLookup = {"Wizard":"spells","wizard":"spells","Cleric":"spells","cleric":"spells"};const scores = ["strength","agility","stamina","personality","luck","intelligence"];const levelUpAttributes = ["level"];const levelUpSections = ["mancer-class-options","mancer-class-table"];const mancerStageFuncs = {"refresh":{"load":["resetWipe"],"exit":["resetWipe"]},"startup":{"load":[],"exit":[]},"create":{"load":[],"exit":[]},"class":{"load":[],"exit":[]},"level":{"load":["setupLevelMancer"],"exit":["leaveLevelMancer"]},"spells":{"load":["loadMancerSpells"],"exit":[]},"tables":{"load":[],"exit":[]}};const dynamicSelects = {".class-select":[{"value":"","data-i18n":"none","selected":"","condition":"static"},{"value":"Category:Classes","condition":"compendium"}]};const dynamicAttributes = {".class-select":["mancer_class"]};const dynamicSources = {"compendium:class":[".class-select"]};k.version = 1.04;
|
|
k.defaultRollStart = '&{template:dcc}';
|
|
|
|
const expandEffects = (attributes,casc,queue,recurred = []) => {
|
|
const key = queue.shift();
|
|
const [section,rID] = k.parseTriggerName(key);
|
|
if(
|
|
section &&
|
|
!recurred.includes(section)
|
|
){
|
|
const newKeys = Object.keys(casc).reduce((m,k) =>{
|
|
if(k.startsWith(`attr_${section}_${rID}`)){
|
|
m.push(k.replace(/attr_/,''));
|
|
}
|
|
return m;
|
|
},[]);
|
|
recurred.push(section)
|
|
expandEffects(attributes,casc,newKeys,recurred);
|
|
}else if(!section || recurred.includes(section)){
|
|
const cascObj = casc[`attr_${key}`];
|
|
cascObj?.affects?.forEach(ref => {
|
|
if(
|
|
!attributes.updates.hasOwnProperty(ref) &&
|
|
!attributes.queue.includes(ref)
|
|
){
|
|
attributes.queue.push(ref);
|
|
}
|
|
})
|
|
}
|
|
if(queue.length){
|
|
expandEffects(attributes,casc,queue,recurred);
|
|
}
|
|
};
|
|
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
|
/*jshint -W014,-W084,-W030,-W033*/
|
|
const handleCompendiumDrop = function({attributes,sections,casc}){
|
|
clearDropAttributes();
|
|
let data = 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');
|
|
|
|
// Ensure that dropped values don't get reset by other calculations
|
|
const lookupKeys = Object.keys(lookupObj);
|
|
const iterateQueue = [...attributes.queue];
|
|
iterateQueue.forEach((q,i) =>{
|
|
if(lookupKeys.includes(`data-cs-${q}`)){
|
|
const qI = attributes.queue.indexOf(q);
|
|
attributes.queue.splice(qI,1);
|
|
}
|
|
});
|
|
const updateKeys = Object.keys(attributes.updates);
|
|
const newCasc = k.expandCascade(sections);
|
|
Object.assign(casc,newCasc);
|
|
if(updateKeys.length){
|
|
expandEffects(attributes,casc,updateKeys);
|
|
}
|
|
attributes.sheet_version = k.version;
|
|
k.setActionCalls({attributes,sections});
|
|
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.Name = attributes.drop_name;
|
|
data = parseJSONProperties(data)
|
|
return processSpecialCategories(data,attributes,sections,casc);
|
|
}catch(err){
|
|
k.debug({'Invalid Drop Data! Drop aborted. Error:':err,drop_data},true);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const parseJSONProperties = (data) =>
|
|
Object.entries(data)
|
|
.reduce((memo,[key,val])=>{
|
|
if(val){
|
|
if(typeof val === 'string' &&
|
|
(
|
|
val.startsWith('[{') ||
|
|
val.startsWith('{')
|
|
)
|
|
){
|
|
val = JSON.parse(val);
|
|
}
|
|
memo[key] = val;
|
|
}
|
|
return memo;
|
|
},{});
|
|
|
|
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();
|
|
basicAttrSet(attributes,section,setKey,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();
|
|
processDataContent(attributes,val,section)
|
|
}
|
|
}
|
|
}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));
|
|
};
|
|
|
|
const basicAttrSet = (attributes,section,setKey,val) => {
|
|
attributes[`${section}${setKey}`] = val;
|
|
if(maxAttr.includes(setKey)){
|
|
attributes[`${section}${setKey}_max`] = val;
|
|
}
|
|
}
|
|
const processDataContent = (attributes,val,section) => {
|
|
|
|
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+$/,'');
|
|
}
|
|
|
|
/**
|
|
* 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,retArr = [])=>{
|
|
const itemObj = queue.shift();
|
|
itemObj['data-cs-collapse'] = 1;
|
|
const section = k.generateRowID(type,sections);
|
|
addRowToCasc(section,casc);
|
|
const retValue = await callback(itemObj,section);
|
|
retArr.push(retValue);
|
|
if(queue.length){
|
|
return worker(queue,retArr);
|
|
}else{
|
|
return retArr;
|
|
}
|
|
};
|
|
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}`]){
|
|
let searchNames = statblock[`data-${type}`].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});
|
|
return 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.is_npc = data?.Category.toLowerCase() === 'npcs';
|
|
const tokenObj = {
|
|
width:70,
|
|
height:70,
|
|
};
|
|
// token bar association
|
|
const barNums = [1,2,3];
|
|
const barAttrs = [];
|
|
attributes.character_name = data['data-cs-name'];
|
|
delete data['data-Weapons'];
|
|
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}`];
|
|
}
|
|
});
|
|
if(attributes.is_npc){
|
|
attributes.npc_collapse = 1;
|
|
}
|
|
// toggleMancer({attributes});
|
|
setDefaultToken(tokenObj);
|
|
};
|
|
/**
|
|
* 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 = async (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
|
|
return repeatWorker(lookupKey,arr,sections,casc,async (itemObj,section)=>{
|
|
const [,id] = k.parseRepeatName(section);
|
|
itemObj['data-cs-skill'] = itemObj['data-cs-range'] ?
|
|
'ranged combat' :
|
|
'close combat';
|
|
itemObj['data-cs-damage_base'] = itemObj['data-cs-damage'];
|
|
delete itemObj['data-cs-damage'];
|
|
const equipObj = {...itemObj,'data-cs-linked':id,'data-cs-type':'weapon'};
|
|
const [equipSection] = await basicDrop('Equipment',[equipObj],attributes,sections,casc,sectionsToQuery);
|
|
const [,equipID] = k.parseRepeatName(equipSection);
|
|
itemObj['data-cs-linked'] = equipID;
|
|
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
|
|
});
|
|
};const tableDrop = async (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
|
|
const tableTypes = {
|
|
};
|
|
const burn = async (queue) => {
|
|
const table = queue.shift();
|
|
if(tableTypes[table.Name]){
|
|
tableTypes[table.Name]({attributes,sections,casc});
|
|
await k.pseudoQuery();
|
|
}else{
|
|
let result = await rollTable(table['data-type'],table['data-Results']);
|
|
result = typeof result === 'object' ?
|
|
object.values.reduce((m,v) => m += `\n${v}`) :
|
|
result;
|
|
const {roll:output} = await k.startRoll({description:result,title:table.Name});
|
|
output.finish();
|
|
}
|
|
};
|
|
await burn([...arr]);
|
|
return k.pseudoQuery();
|
|
};/**
|
|
* Handles drops for spells
|
|
* @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 spellDrop = (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
|
|
return repeatWorker(lookupKey,arr,sections,casc,async (itemObj,section)=>{
|
|
if(/wizard/i.test(lookupKey)){
|
|
// this is done asynchronously and will resolve after the drop has completed.
|
|
rollMercurial(section,attributes,sections);
|
|
}
|
|
if(
|
|
itemObj[`data-manifestation_roll`] &&
|
|
itemObj['data-table-manifestation']
|
|
){
|
|
itemObj['data-cs-manifestation'] = await rollTable(itemObj['data-manifestation_roll'],itemObj['data-table-manifestation']);
|
|
}else{
|
|
await k.pseudoQuery();
|
|
}
|
|
itemObj['data-cs-row_type'] = 'master';
|
|
itemObj['data-cs-collapse'] = attributes.spells;
|
|
itemObj['data-cs-compendium_reference'] = `Category:${itemObj.Category} data-cs-name:${itemObj['data-cs-name']} Expansion:${itemObj.Expansion}`;
|
|
await processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
|
|
const origMasterID = section.replace(/repeating_spells_/,'');
|
|
const masterID = origMasterID.toLowerCase();
|
|
const childIDs = [];
|
|
// process spell result table
|
|
await repeatWorker(lookupKey,itemObj['data-table-results'],sections,casc,async (data,row)=>{
|
|
data['data-cs-roll'] = data.die;
|
|
data['data-cs-result'] = data.result;
|
|
data['data-cs-row_type'] = 'table';
|
|
data['data-cs-master'] = masterID;
|
|
data['data-cs-collapse'] = attributes.spells;
|
|
const rowID = row.replace(/repeating_spells_/,'');
|
|
childIDs.push(rowID);
|
|
await processDropData({data,attributes,sections,casc,sectionsToQuery,section:row});
|
|
});
|
|
|
|
let insertIndex = sections.repeating_spells.indexOf(origMasterID) + 1;
|
|
childIDs
|
|
.sort((a,b) => {
|
|
const aRow = `repeating_spells_${a}`;
|
|
const bRow = `repeating_spells_${b}`;
|
|
const aVal = +`${attributes[`${aRow}_roll`]}`.match(/\d+/)[0];
|
|
const bVal = +`${attributes[`${bRow}_roll`]}`.match(/\d+/)[0];
|
|
return bVal - aVal;
|
|
})
|
|
.forEach(id => {
|
|
const childIndex = sections.repeating_spells.indexOf(id);
|
|
sections.repeating_spells.splice(
|
|
insertIndex,
|
|
0,
|
|
sections.repeating_spells.splice(
|
|
childIndex,
|
|
1
|
|
)[0]
|
|
);
|
|
});
|
|
k.setSectionOrder('spells',sections.repeating_spells);
|
|
});
|
|
};
|
|
|
|
const rollMercurial = (row,attributes,prevRoll) => {
|
|
getTable('Mercurial Magic',(result) => {
|
|
attributes[`${row}_notes`] = result;
|
|
attributes.set();
|
|
})
|
|
};const getTable = (tableName,callback) => {
|
|
getPage(tableName,async (data,table) => {
|
|
const result = await rollTable(data['data-type'],table);
|
|
if(result){
|
|
callback(result);
|
|
}
|
|
})
|
|
};const getPage = (tableName,callback) => {
|
|
getComp(tableName,async (data) => {
|
|
if(data['data-Results']){
|
|
callback(data,JSON.parse(data['data-Results']));
|
|
}
|
|
});
|
|
}// gets a compendium page data
|
|
const getComp = (tableName,callback) => {
|
|
getCompendiumPage(tableName, async (ret) => {
|
|
const data = ret[0]?.data || ret.data;
|
|
callback(data);
|
|
})
|
|
}/**
|
|
* Handles dropping of armor repeating section items. Does minimal editing of the gear data to make it valid for the sheet.
|
|
* @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 = (lookupKey,arr,attributes,sections,casc,sectionsToQuery) => {
|
|
return repeatWorker(lookupKey,arr,sections,casc,async (itemObj,section)=>{
|
|
const [,id] = k.parseRepeatName(section);
|
|
itemObj['data-cs-active'] = 1;
|
|
itemObj[`data-cs-quantity`] = itemObj[`data-cs-quantity`] || 1;
|
|
if(itemObj['data-cs-affects']){
|
|
itemObj['data-cs-affects'] = itemObj['data-cs-affects'].toLowerCase();
|
|
}
|
|
const equipObj = {...itemObj,'data-cs-linked':id,'data-cs-type':'armor'};
|
|
const [equipSection] = await basicDrop('Equipment',[equipObj],attributes,sections,casc,sectionsToQuery);
|
|
const [,equipID] = k.parseRepeatName(equipSection);
|
|
itemObj['data-cs-linked'] = equipID;
|
|
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 = {
|
|
'wizard': spellDrop,
|
|
'Wizard': spellDrop,
|
|
'cleric': spellDrop,
|
|
'Cleric': spellDrop,
|
|
"Weapons": weaponDrop,
|
|
'weapons': weaponDrop,
|
|
'equipment': basicDrop,
|
|
'Equipment': basicDrop,
|
|
'Armor': armorDrop,
|
|
'armor': armorDrop,
|
|
'Rollable': tableDrop,
|
|
'rollable': tableDrop,
|
|
Attacks: basicDrop,
|
|
attacks: 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 = (data,attributes,sections,casc) => {
|
|
if(!/npcs/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});
|
|
});
|
|
}
|
|
}else{
|
|
npcHandler(data,attributes,sections,casc);
|
|
}
|
|
return data;
|
|
};
|
|
const getRoll = (customSettings = {}) => {
|
|
|
|
const settings = Object.assign({
|
|
trigger:{},
|
|
attributes: {},
|
|
actionDie: '',
|
|
title: false,
|
|
subtitle: false,
|
|
formulaAttribute: false,
|
|
}, customSettings);
|
|
|
|
const isRepeating = settings.trigger.name.includes('repeating_');
|
|
let title = '';
|
|
let subtitle = '';
|
|
let formulaAttribute = '';
|
|
let description = '';
|
|
if(isRepeating) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(settings.trigger.name);
|
|
const name = settings.attributes[`${section}_${rowID}_name`] ? settings.attributes[`${section}_${rowID}_name`] : false;
|
|
if(name) {
|
|
title = settings.title ? settings.title : name;
|
|
subtitle = settings.subtitle ? settings.subtitle : attrName.replace('roll-pc-', '').replace('roll-npc-', '').replace(/-/g,'_');
|
|
} else {
|
|
title = settings.title ? settings.title : attrName.replace('roll-pc-', '').replace('roll-npc-', '').replace(/-/g,'_');
|
|
if(settings.subtitle) subtitle = settings.subtitle;
|
|
}
|
|
formulaAttribute = settings.formulaAttribute ? settings.formulaAttribute : `${section}_${rowID}_${attrName.replace('roll-pc-', '').replace('roll-npc-', '').replace(/-/g,'_')}`;
|
|
if(settings.attributes[`${section}_${rowID}_description`]) description = settings.attributes[`${section}_${rowID}_description`];
|
|
} else {
|
|
title = settings.title ? settings.title : settings.trigger.name.replace('roll-pc-', '').replace('roll-npc-', '').replace(/-/g,'_');
|
|
formulaAttribute = settings.formulaAttribute ? settings.formulaAttribute : title;
|
|
}
|
|
const rolls = {
|
|
title: title.toLowerCase().replace(/_/g,' ').replace('bonus','').replace('modifier','').trim()
|
|
}
|
|
if(subtitle) rolls.subtitle = subtitle.toLowerCase().replace(/_/g,' ').replace('bonus','').trim();
|
|
const signal = settings.actionDie && settings.attributes[formulaAttribute] ? /^[^\w\s]/gi.test(String(settings.attributes[formulaAttribute]).trim()) ? '' : '+' : '';
|
|
const formula1 = settings.attributes[formulaAttribute] ? `[[${settings.actionDie}${signal}${settings.attributes[formulaAttribute]}]]` : `[[${settings.actionDie}]]`;
|
|
if (formula1) rolls.formula1 = formula1;
|
|
else rolls.formula1 = '[[0]]';
|
|
if(description) rolls.description = description;
|
|
return rolls;
|
|
};/**
|
|
* Returns the result of a random table roll. Returns the simple result text for a basic table or the complex result object for a more complex table.
|
|
* @param {string} type - Roll expression describing the table's roll
|
|
* @param {object[]} table - array of objects describing each result on the table
|
|
* @param {string|number} table.die - The die result for a given result
|
|
* @param {string} table.result - the result text for the table entry
|
|
*/
|
|
const rollTable = async (type,table) => {
|
|
const {roll} = await k.startRoll({roll:`[[${type}]]`},'!');
|
|
roll.finish();
|
|
const tableValue = roll.results.roll.result;
|
|
const result = table.find(o => {
|
|
const [,endDie,plus] = `${o.die}`.match(/(?:\d+\-)?(\d+)(\+)?(?: or less)?$/i);
|
|
return tableValue <= (+endDie);
|
|
}) || table[table.length - 1];
|
|
return result.result2 ?
|
|
result :
|
|
result?.result;
|
|
};/**
|
|
* rolls a rollable table that is entered in string format like the spell misfires and corruptions
|
|
* @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 rollStringTable = async function({trigger,attributes,sections,casc}){
|
|
const [section,rowID,actionName] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${rowID}`;
|
|
const attrName = actionName.replace(/-action/,'').replace(/-/g,'_');
|
|
if(!attributes[`${row}_${attrName}`]) return;
|
|
|
|
const [,dice,tableText] = attributes[`${row}_${attrName}`].match(/^(?:roll)?\s*(\d*d\d*).+?(\d+(?:[—–-]\d+)?\).+)/i);
|
|
const tableRx = /(\d+)(?:[—–-](\d+))?\)(.+?)(?:;|\(|$)/;
|
|
const table = tableText.match(new RegExp(tableRx,'g')).reduce((m,match) => {
|
|
const [,indexStart,indexEnd,result] = match.match(tableRx);
|
|
m[indexEnd ?? indexStart] = result;
|
|
return m;
|
|
},{});
|
|
const {roll,computeObj} = await k.startRoll({
|
|
title: attrName.replace(/_/g,' '),
|
|
author: attributes.character_name,
|
|
formula1:`[[${dice}]]`,
|
|
computeDescription: '[[0[computed value]]]'
|
|
});
|
|
const rolled = roll.results.formula1.result;
|
|
[,computeObj.computeDescription] = getTableResult(table,rolled)
|
|
roll.finish();
|
|
};
|
|
k.registerFuncs({rollStringTable});
|
|
|
|
// parses a sorted table of roll results to determine which result was rolled.
|
|
const getTableResult = (table,rolled) => Object.entries(table).find(([key,val]) => rolled <= +key) || [,''];
|
|
const addModsTo = (baseValue, trigger, attributes) => {
|
|
const modAttribute = attributes[`${trigger.name}_mod`];
|
|
const mods = modAttribute && !isNaN(modAttribute) ? parseInt(modAttribute) : 0;
|
|
const stringValue = String(baseValue);
|
|
if(stringValue.includes('+')) {
|
|
const bonus = (parseInt(stringValue.split('+').at(-1).trim())+mods) > 0 ? `+${parseInt(stringValue.split('+').at(-1).trim())+mods}` : '';
|
|
return stringValue.replace(/ /g, '').replace(/\+\d+/g, `${bonus}`);
|
|
} else {
|
|
if(stringValue && !isNaN(stringValue)) {
|
|
return parseInt(stringValue) + mods;
|
|
} else {
|
|
const bonus = mods > 0 ? `+${mods}` : '';
|
|
return `${stringValue}${bonus}`;
|
|
}
|
|
}
|
|
};
|
|
const calculateGenericNumberFieldTotal = function({trigger,attributes,sections,casc}) {
|
|
const modAttribute = attributes[trigger.name.replace('_total', '_mod')];
|
|
const baseAttribute = attributes[trigger.name.replace('_total', '')];
|
|
const mods = modAttribute && !isNaN(modAttribute) ? parseInt(modAttribute) : 0;
|
|
const base = baseAttribute && !isNaN(baseAttribute) ? parseInt(baseAttribute) : 0;
|
|
return (mods+base > 0) ? mods+base : '';
|
|
};
|
|
const affect = (attributes, a) => {
|
|
if(!attributes.queue.includes(a)){
|
|
attributes.queue.push(a);
|
|
}
|
|
};
|
|
k.registerFuncs({calculateGenericNumberFieldTotal});
|
|
const calculateMods = function({trigger,attributes,sections,casc}) {
|
|
const modifiers = filterSection('equipment', 'modifiers', attributes, sections, (modifiers) => {
|
|
return modifiers && modifiers.includes(':');
|
|
}, true);
|
|
let mods = 0;
|
|
Object.values(modifiers).forEach(mod => {
|
|
const parsedMod = parseModifiers(mod);
|
|
Object.entries(parsedMod).filter(([key, value]) => { return key === trigger.name }).forEach(([key, value]) => {
|
|
mods += value;
|
|
});
|
|
});
|
|
return mods;
|
|
};
|
|
k.registerFuncs({calculateMods});
|
|
const filterSection = function(section, attribute, attributes, sections, criteria, onlyActives=false) {
|
|
const results = {};
|
|
const repeatingSection = `repeating_${section}`;
|
|
sections[repeatingSection].forEach(rowID => {
|
|
const parent = `${repeatingSection}_${rowID}`;
|
|
if(!attributes[`${parent}_${attribute}`] || !criteria(attributes[`${parent}_${attribute}`])) return;
|
|
if(onlyActives && (!attributes[`${parent}_active`] || attributes[`${parent}_active`] != 1)) return;
|
|
results[`${parent}_${attribute}`] = attributes[`${parent}_${attribute}`];
|
|
});
|
|
return results;
|
|
};const overwriteDefaultAttributeValue = function({trigger,attributes,sections,casc}) {
|
|
if(!trigger.sourceType || trigger.sourceType !== 'player') return;
|
|
if(trigger.previousValue && trigger.newValue && trigger.previousValue == trigger.newValue) return;
|
|
if(!trigger.previousValue && !trigger.newValue) return;
|
|
if(!trigger.previousValue && trigger.newValue == 0) return;
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const calculated = trigger.calculation && k.funcs[trigger.calculation] ?
|
|
k.funcs[trigger.calculation]({trigger,attributes,sections,casc}) : false;
|
|
const overwritten = trigger.newValue && trigger.newValue != calculated ? 1 : '';
|
|
k.setAttrs({[overwriteAttribute]:overwritten},null,()=>{
|
|
if(overwritten != 1 && trigger.calculation && k.funcs[trigger.calculation]) {
|
|
attributes[overwriteAttribute] = '';
|
|
k.setAttrs({[trigger.name]:calculated});
|
|
};
|
|
});
|
|
};
|
|
k.registerFuncs({overwriteDefaultAttributeValue});
|
|
const reduceSection = function(section, attribute, attributes, sections, criteria, onlyActives=false) {
|
|
const results = filterSection(section, attribute, attributes, sections, ()=> { return true; }, onlyActives);
|
|
const reduced = Object.keys(results).reduce((accumulator, currentValue) => { return criteria(accumulator, {[currentValue]:results[currentValue]}); }, {});
|
|
return reduced;
|
|
};const modalRoll = function({trigger,attributes,sections,casc}) {
|
|
let action = false;
|
|
const options = {
|
|
trigger: trigger,
|
|
attributes: attributes,
|
|
formulaAttribute: 'rollmodal_final_formula',
|
|
title: attributes['rollmodal_title']
|
|
};
|
|
if(attributes['rollmodal_has_action_die'] && attributes['rollmodal_has_action_die'] == 1) {
|
|
const actionDie = attributes['rollmodal_action_die'] || '1d20';
|
|
options.actionDie = actionDie;
|
|
action = true;
|
|
}
|
|
const type = attributes['rollmodal_type'] || 'public';
|
|
const roll = getRoll(options);
|
|
if(attributes['rollmodal_subtitle']) roll.subtitle = attributes['rollmodal_subtitle'];
|
|
if(attributes['rollmodal_description']) roll.description = attributes['rollmodal_description'];
|
|
let manipulator;
|
|
let fields;
|
|
if(casc[`act_${attributes.rollmodal_source}`]){
|
|
manipulator = casc[`act_${attributes.rollmodal_source}`]?.settings?.manipulator;
|
|
fields = casc[`act_${attributes.rollmodal_source}`]?.settings?.fields;
|
|
}
|
|
|
|
const rollProps = {
|
|
roll,
|
|
attributes,
|
|
type,
|
|
action,
|
|
source:attributes.rollmodal_source,
|
|
sections,
|
|
manipulator,
|
|
fields,
|
|
casc
|
|
};
|
|
if(roll.title && roll.title === 'luck') {
|
|
rollLuck(rollProps);
|
|
} else if(roll.title && roll.title === 'deed die') {
|
|
rollDeed(rollProps);
|
|
} else if(roll.title && roll.title === 'hd') {
|
|
rollNpcHP(rollProps);
|
|
} else {
|
|
rollSomething(rollProps);
|
|
}
|
|
closeRollmodal();
|
|
};
|
|
k.registerFuncs({modalRoll});const genericRoll = function({trigger,attributes,sections,casc}) {
|
|
const roll = getRoll({trigger, attributes});
|
|
if(!forceOpenModal && attributes['rollmodal_disabled'] && attributes['rollmodal_disabled'] == 1) {
|
|
rollSomething({
|
|
roll,
|
|
attributes,
|
|
sections,
|
|
casc,
|
|
source:trigger.name,
|
|
fields:trigger?.settings?.fields,
|
|
manipulator:trigger?.settings?.manipulator
|
|
});
|
|
} else {
|
|
forceOpenModal = false;
|
|
|
|
attributes.rollmodal_active = 1;
|
|
attributes.rollmodal_title = k.getTranslationByKey(roll.title);
|
|
attributes.rollmodal_base_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.rollmodal_final_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.source = trigger.name;
|
|
|
|
if(roll.subtitle) attributes.rollmodal_subtitle = k.getTranslationByKey(roll.subtitle);
|
|
}
|
|
};
|
|
k.registerFuncs({genericRoll});const genericActionRoll = function({trigger,attributes,sections,casc}) {
|
|
const {actionDie = '1d20'} = trigger.settings || {};
|
|
const {formula = trigger.name} = trigger.settings || {};
|
|
const {title = trigger.title} = trigger.settings || {};
|
|
const {subtitle = trigger.subtitle} = trigger.settings || {};
|
|
const customTrigger = {...trigger, ...{name:formula}};
|
|
const roll = getRoll({trigger:trigger, attributes});
|
|
const customRoll = getRoll({trigger:customTrigger, actionDie:actionDie, attributes});
|
|
const modalRoll = getRoll({trigger:customTrigger, attributes});
|
|
if(subtitle) customRoll.subtitle = subtitle;
|
|
if(title) customRoll.title = title;
|
|
if(!forceOpenModal && attributes['rollmodal_disabled'] && attributes['rollmodal_disabled'] == 1) {
|
|
rollSomething({
|
|
roll:customRoll,
|
|
attributes,
|
|
sections,
|
|
casc,
|
|
action:true,
|
|
source:trigger.name,
|
|
manipulator:trigger?.settings?.manipulator,
|
|
fields: trigger?.settings?.fields
|
|
});
|
|
} else {
|
|
forceOpenModal = false;
|
|
const rollModalTitle = (title) ? title : modalRoll.title;
|
|
|
|
attributes.rollmodal_active= 1;
|
|
attributes.rollmodal_title= k.getTranslationByKey(rollModalTitle);
|
|
attributes.rollmodal_base_formula= modalRoll.formula1.replace('[[','').replace(']]','');
|
|
attributes.rollmodal_final_formula= modalRoll.formula1.replace('[[','').replace(']]','');
|
|
attributes.rollmodal_has_action_die= 1;
|
|
attributes.rollmodal_action_die= actionDie;
|
|
attributes.rollmodal_source = trigger.name;
|
|
|
|
if(subtitle) attributes.rollmodal_subtitle = k.getTranslationByKey(subtitle);
|
|
else if(modalRoll.subtitle) attributes.rollmodal_subtitle = k.getTranslationByKey(modalRoll.subtitle);
|
|
if(roll.description) attributes.rollmodal_description = roll.description;
|
|
}
|
|
};
|
|
|
|
k.registerFuncs({genericActionRoll});const luckRoll = function({trigger,attributes,sections,casc}) {
|
|
|
|
const roll = {
|
|
title: "luck",
|
|
formula1: "[[1d20]]"
|
|
};
|
|
|
|
if(!forceOpenModal && attributes['rollmodal_disabled'] && attributes['rollmodal_disabled'] == 1) {
|
|
rollLuck({
|
|
roll,
|
|
attributes,
|
|
sections,
|
|
casc,
|
|
source:trigger.name,
|
|
fields:trigger?.settings?.fields,
|
|
manipulator:trigger?.settings?.manipulator
|
|
});
|
|
} else {
|
|
forceOpenModal = false;
|
|
|
|
attributes.rollmodal_active = 1;
|
|
attributes.rollmodal_title = k.getTranslationByKey(roll.title);
|
|
attributes.rollmodal_has_action_die = '';
|
|
attributes.rollmodal_base_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.rollmodal_final_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.source = trigger.name;
|
|
|
|
if(roll.subtitle) attributes.rollmodal_subtitle = k.getTranslationByKey(roll.subtitle);
|
|
}
|
|
};
|
|
|
|
const rollLuck = (customSettings = {}) => {
|
|
|
|
const settings = Object.assign({
|
|
roll:{},
|
|
attributes: {},
|
|
sections: [],
|
|
// casc may also be passed, but is expected to only be present when explicitly passed
|
|
formulas: {},
|
|
type: 'public',
|
|
action: false,
|
|
fields: [], //additional fields that need to be added to the roll
|
|
manipulator: null, //Holds callback that a roll call needs to do on a roll's results. can be a string for calling function with k.callFunc or reference to the actual function to call.
|
|
}, customSettings);
|
|
|
|
//TODO: Do some refactoring on this terrible code:
|
|
const query = Object.entries(settings.roll).map(([key, value]) => {return `{{${key}=${value}}}`;});
|
|
query.push(`{{success=[[0]]}}`);
|
|
query.push(`{{failure=[[0]]}}`);
|
|
|
|
const includeAuthor = true;
|
|
if(includeAuthor && settings.attributes['character_name']) query.push(`{{author=${settings.attributes['character_name']}}}`);
|
|
|
|
const template = settings.type === 'secret' ? `/w gm &{template:dcc}` : `&{template:dcc}`;
|
|
startRoll(`${template} ${query.join(' ')}`, (results) => {
|
|
finish = {};
|
|
Object.keys(settings.roll).forEach(roll => {
|
|
if(results.results[roll]) {
|
|
const originalResult = results.results[roll].result;
|
|
finish[roll] = (typeof settings.formulas[roll] === 'function') ? settings.formulas[roll](originalResult) : originalResult;
|
|
} else {
|
|
finish[roll] = settings.roll[roll];
|
|
}
|
|
});
|
|
|
|
const cs = settings.attributes.luck || 0;
|
|
const luckDie = results.results.formula1.rolls[0].results[0];
|
|
|
|
if(luckDie <= cs) {
|
|
finish.success = 1;
|
|
finish.failure = '';
|
|
}
|
|
else {
|
|
finish.success = '';
|
|
finish.failure = 1;
|
|
}
|
|
|
|
if(settings.manipulator){
|
|
if(typeof settings.manipulator === 'string'){
|
|
k.callFunc(settings.manipulator,results,finish,settings);
|
|
}else if(typeof settings.manipulator === 'function'){
|
|
settings.manipulator(results,finish,settings);
|
|
}
|
|
}
|
|
finishRoll(
|
|
results.rollId,
|
|
finish
|
|
);
|
|
});
|
|
};
|
|
|
|
k.registerFuncs({luckRoll});const deedRoll = function({trigger,attributes,sections,casc}) {
|
|
|
|
const roll = {
|
|
title: "deed die",
|
|
formula1: `[[${attributes.attack || 0}]]`
|
|
};
|
|
|
|
if(!forceOpenModal && attributes['rollmodal_disabled'] && attributes['rollmodal_disabled'] == 1) {
|
|
rollDeed({
|
|
roll,
|
|
attributes,
|
|
sections,
|
|
casc,
|
|
source:trigger.name,
|
|
fields:trigger?.settings?.fields,
|
|
manipulator:trigger?.settings?.manipulator
|
|
});
|
|
} else {
|
|
forceOpenModal = false;
|
|
|
|
attributes.rollmodal_active = 1;
|
|
attributes.rollmodal_title = k.getTranslationByKey(roll.title);
|
|
attributes.rollmodal_has_action_die = '';
|
|
attributes.rollmodal_base_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.rollmodal_final_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.source = trigger.name;
|
|
|
|
if(roll.subtitle) attributes.rollmodal_subtitle = k.getTranslationByKey(roll.subtitle);
|
|
}
|
|
};
|
|
|
|
const rollDeed = (customSettings = {}) => {
|
|
|
|
const settings = Object.assign({
|
|
roll:{},
|
|
attributes: {},
|
|
sections: [],
|
|
// casc may also be passed, but is expected to only be present when explicitly passed
|
|
formulas: {},
|
|
type: 'public',
|
|
action: false,
|
|
fields: [], //additional fields that need to be added to the roll
|
|
manipulator: null, //Holds callback that a roll call needs to do on a roll's results. can be a string for calling function with k.callFunc or reference to the actual function to call.
|
|
}, customSettings);
|
|
|
|
const query = Object.entries(settings.roll).map(([key, value]) => {return `{{${key}=${value}}}`;});
|
|
|
|
const includeAuthor = true;
|
|
if(includeAuthor && settings.attributes['character_name']) query.push(`{{author=${settings.attributes['character_name']}}}`);
|
|
|
|
const template = settings.type === 'secret' ? `/w gm &{template:dcc}` : `&{template:dcc}`;
|
|
startRoll(`${template} ${query.join(' ')}`, (results) => {
|
|
finish = {};
|
|
Object.keys(settings.roll).forEach(roll => {
|
|
if(results.results[roll]) {
|
|
const originalResult = results.results[roll].result;
|
|
finish[roll] = (typeof settings.formulas[roll] === 'function') ? settings.formulas[roll](originalResult) : originalResult;
|
|
} else {
|
|
finish[roll] = settings.roll[roll];
|
|
}
|
|
});
|
|
|
|
const deedDie = results.results.formula1.result;
|
|
|
|
if(settings.manipulator){
|
|
if(typeof settings.manipulator === 'string'){
|
|
k.callFunc(settings.manipulator,results,finish,settings);
|
|
}else if(typeof settings.manipulator === 'function'){
|
|
settings.manipulator(results,finish,settings);
|
|
}
|
|
}
|
|
|
|
settings.attributes.deed_die_result = deedDie;
|
|
settings.attributes.set();
|
|
|
|
finishRoll(
|
|
results.rollId,
|
|
finish
|
|
);
|
|
});
|
|
};
|
|
|
|
k.registerFuncs({deedRoll});const hpRoll = function({trigger,attributes,sections,casc}) {
|
|
|
|
const roll = {
|
|
title: "HD",
|
|
formula1: `[[${attributes.hd || 0}]]`
|
|
};
|
|
|
|
if(!forceOpenModal && attributes['rollmodal_disabled'] && attributes['rollmodal_disabled'] == 1) {
|
|
rollNpcHP({
|
|
roll,
|
|
attributes,
|
|
sections,
|
|
casc,
|
|
source:trigger.name,
|
|
fields:trigger?.settings?.fields,
|
|
manipulator:trigger?.settings?.manipulator
|
|
});
|
|
} else {
|
|
forceOpenModal = false;
|
|
|
|
attributes.rollmodal_active = 1;
|
|
attributes.rollmodal_title = k.getTranslationByKey(roll.title);
|
|
attributes.rollmodal_has_action_die = '';
|
|
attributes.rollmodal_base_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.rollmodal_final_formula = roll.formula1.replace('[[','').replace(']]','');
|
|
attributes.source = trigger.name;
|
|
|
|
if(roll.subtitle) attributes.rollmodal_subtitle = k.getTranslationByKey(roll.subtitle);
|
|
}
|
|
};
|
|
|
|
const rollNpcHP = (customSettings = {}) => {
|
|
|
|
const settings = Object.assign({
|
|
roll:{},
|
|
attributes: {},
|
|
sections: [],
|
|
// casc may also be passed, but is expected to only be present when explicitly passed
|
|
formulas: {},
|
|
type: 'public',
|
|
action: false,
|
|
fields: [], //additional fields that need to be added to the roll
|
|
manipulator: null, //Holds callback that a roll call needs to do on a roll's results. can be a string for calling function with k.callFunc or reference to the actual function to call.
|
|
}, customSettings);
|
|
|
|
const query = Object.entries(settings.roll).map(([key, value]) => {return `{{${key}=${value}}}`;});
|
|
|
|
const includeAuthor = true;
|
|
if(includeAuthor && settings.attributes['character_name']) query.push(`{{author=${settings.attributes['character_name']}}}`);
|
|
|
|
const template = settings.type === 'secret' ? `/w gm &{template:dcc}` : `&{template:dcc}`;
|
|
startRoll(`${template} ${query.join(' ')}`, (results) => {
|
|
finish = {};
|
|
Object.keys(settings.roll).forEach(roll => {
|
|
if(results.results[roll]) {
|
|
const originalResult = results.results[roll].result;
|
|
finish[roll] = (typeof settings.formulas[roll] === 'function') ? settings.formulas[roll](originalResult) : originalResult;
|
|
} else {
|
|
finish[roll] = settings.roll[roll];
|
|
}
|
|
});
|
|
|
|
const hpDie = results.results.formula1.result;
|
|
|
|
if(settings.manipulator){
|
|
if(typeof settings.manipulator === 'string'){
|
|
k.callFunc(settings.manipulator,results,finish,settings);
|
|
}else if(typeof settings.manipulator === 'function'){
|
|
settings.manipulator(results,finish,settings);
|
|
}
|
|
}
|
|
|
|
settings.attributes.hit_points = hpDie;
|
|
settings.attributes.set();
|
|
|
|
finishRoll(
|
|
results.rollId,
|
|
finish
|
|
);
|
|
});
|
|
};
|
|
|
|
k.registerFuncs({hpRoll});const rollSomething = (customSettings = {}) => {
|
|
|
|
const settings = Object.assign({
|
|
roll:{},
|
|
attributes: {},
|
|
sections: [],
|
|
// casc may also be passed, but is expected to only be present when explicitly passed
|
|
formulas: {},
|
|
type: 'public',
|
|
action: false,
|
|
fields: [], //additional fields that need to be added to the roll
|
|
manipulator: null, //Holds callback that a roll call needs to do on a roll's results. can be a string for calling function with k.callFunc or reference to the actual function to call.
|
|
}, customSettings);
|
|
|
|
if(settings.roll.title === 'initiative') settings.roll.formula1 = settings.roll.formula1.replace(']]', ' &{tracker}]]');
|
|
let cs = 20;
|
|
if(
|
|
(settings.roll.title.includes('attack') || (settings.roll.subtitle && settings.roll.subtitle.includes('attack')))
|
|
&& settings.attributes.class
|
|
&& settings.attributes.class === 'warrior'
|
|
&& settings.attributes.critical_threat_range
|
|
&& !isNaN(settings.attributes.critical_threat_range)
|
|
) {
|
|
cs = parseInt(settings.attributes.critical_threat_range);
|
|
}
|
|
|
|
const query = Object.entries(settings.roll).map(([key, value]) => {return `{{${key}=${value}}}`;});
|
|
|
|
if(settings.action) {
|
|
query.push(`{{critical=[[0]]}}`);
|
|
query.push(`{{fumble=[[0]]}}`);
|
|
}
|
|
if(settings.fields){
|
|
query.push(...settings.fields);
|
|
}
|
|
const includeAuthor = true;
|
|
if(includeAuthor && settings.attributes['character_name']) query.push(`{{author=${settings.attributes['character_name']}}}`);
|
|
|
|
const template = settings.type === 'secret' ? `/w gm &{template:dcc}` : `&{template:dcc}`;
|
|
startRoll(`${template} ${query.join(' ')}`, (results) => {
|
|
finish = {};
|
|
Object.keys(settings.roll).forEach(roll => {
|
|
if(results.results[roll]) {
|
|
const originalResult = results.results[roll].result;
|
|
finish[roll] = (typeof settings.formulas[roll] === 'function') ? settings.formulas[roll](originalResult) : originalResult;
|
|
} else {
|
|
finish[roll] = settings.roll[roll];
|
|
}
|
|
});
|
|
|
|
if(settings.action) {
|
|
const actionDie = results.results.formula1.rolls[0].results[0];
|
|
if(actionDie >= cs) {
|
|
finish.critical = actionDie;
|
|
finish.fumble = '';
|
|
}
|
|
else if(actionDie === 1) {
|
|
finish.fumble = 1;
|
|
finish.critical = '';
|
|
}
|
|
else {
|
|
finish.fumble = '';
|
|
finish.critical = '';
|
|
}
|
|
}
|
|
if(settings.manipulator){
|
|
if(typeof settings.manipulator === 'string'){
|
|
k.callFunc(settings.manipulator,results,finish,settings);
|
|
}else if(typeof settings.manipulator === 'function'){
|
|
settings.manipulator(results,finish,settings);
|
|
}
|
|
}
|
|
finishRoll(
|
|
results.rollId,
|
|
finish
|
|
);
|
|
});
|
|
};/**
|
|
* updates to 1.04, converts old npc alignment values
|
|
* @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 v1x04 = function({trigger,attributes,sections,casc}){
|
|
if(attributes.is_npc){
|
|
const alignConvert = {
|
|
'l': 'lawful',
|
|
'c': 'chaotic',
|
|
'n': 'neutral'
|
|
};
|
|
attributes.alignment = alignConvert[attributes.alignment] || attributes.alignment;
|
|
}
|
|
scores.forEach(score => {
|
|
attributes[`${score}_max`] = attributes[score];
|
|
});
|
|
};
|
|
k.registerFuncs({'1.04':v1x04},{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 calcScoreDiff = function({trigger,attributes,sections,casc}){
|
|
const baseAttr = trigger.name.replace(/_diff/,'');
|
|
return attributes[baseAttr] === attributes[`${baseAttr}_max`] ?
|
|
0 :
|
|
1;
|
|
};
|
|
k.registerFuncs({calcScoreDiff});
|
|
|
|
|
|
/**
|
|
* Populates a select based on the content of a repeating section or other dynamic content
|
|
* @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 dynamicPopulate = function({trigger,attributes,sections,casc}){
|
|
const genericName = trigger.name.replace(/(repeating_.+?_).+?(_.+)/,'$1$x$2');
|
|
populateSelects({genericName,attributes,sections,casc});
|
|
};
|
|
k.registerFuncs({dynamicPopulate});
|
|
|
|
|
|
const populateBurndown = (selector,details,attributes,sections,casc,arr = []) => {
|
|
const origObj = details.shift();
|
|
const obj = {...origObj};
|
|
const section = obj.section;
|
|
const condition = obj.condition;
|
|
delete obj.section;
|
|
delete obj.condition;
|
|
if(condition === 'dynamic' && section){
|
|
sections[section].forEach(id => {
|
|
const secObj = {...obj};
|
|
secObj['value'] = secObj['value']?.replace(/\$x/g,id);
|
|
secObj['data-i18n'] = secObj['data-i18n']?.replace(/\$x/g,id);
|
|
addOption(arr,secObj,attributes,sections);
|
|
continueBurn(selector,details,attributes,sections,casc,arr);
|
|
})
|
|
}else if(condition === 'compendium'){
|
|
getCompendiumQuery(obj.value,(data) => {
|
|
const uniqueClasses = data.reduce((m,o) => {
|
|
const identifierString = `${o.name}--${o.expansion}`;
|
|
if(!m.some(n => n === identifierString)){
|
|
m.push(identifierString);
|
|
}
|
|
return m;
|
|
},[]);
|
|
uniqueClasses.forEach(identifierString => {
|
|
const secObj = {
|
|
'value': identifierString,
|
|
'data-i18n': identifierString.replace(/--.+/,'')
|
|
};
|
|
addOption(arr,secObj,attributes,sections);
|
|
});
|
|
continueBurn(selector,details,attributes,sections,casc,arr);
|
|
})
|
|
}else if(
|
|
condition === 'static' ||
|
|
(
|
|
condition === 'isrepeating' &&
|
|
section &&
|
|
sections[section].length
|
|
)
|
|
){
|
|
addOption(arr,obj,attributes,sections);
|
|
continueBurn(selector,details,attributes,sections,casc,arr);
|
|
}
|
|
}
|
|
|
|
const continueBurn = (selector,details,attributes,sections,casc,arr) => {
|
|
if(details.length){
|
|
populateBurndown(selector,details,attributes,sections,casc,arr)
|
|
}else{
|
|
const tempSet = dynamicAttributes[selector].reduce((m,full) => {
|
|
const [section,,attr] = k.parseTriggerName(full);
|
|
if(section){
|
|
sections[section].forEach(id =>
|
|
m[`${section}_${id}_${attr}`] = '');
|
|
}else{
|
|
m[attr] = '';
|
|
}
|
|
return m;
|
|
},{});
|
|
k.setAttrs(tempSet,null,()=>{
|
|
populateListOptions({
|
|
elemSelector: selector,
|
|
optionsArray:arr,
|
|
callback() {
|
|
dynamicAttributes[selector].forEach(full => {
|
|
const [section,,attr] = k.parseTriggerName(full);
|
|
if(section){
|
|
sections[section].forEach(id =>
|
|
updateSelect(`${section}_${id}_${attr}`,arr,attributes,casc));
|
|
}else{
|
|
updateSelect(attr,arr,attributes,casc);
|
|
}
|
|
});
|
|
attributes.set();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* populates the dynamic selects on the 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 populateSelects = function({genericName,attributes,sections,casc}){
|
|
const selectors = genericName ?
|
|
dynamicSources[genericName] :
|
|
Object.keys(dynamicSelects);
|
|
selectors.forEach(selector => {
|
|
const details = JSON.parse(JSON.stringify(dynamicSelects[selector]));
|
|
populateBurndown(selector,details,attributes,sections,casc);
|
|
})
|
|
};
|
|
k.registerFuncs({populateSelects},{type:['opener']});
|
|
|
|
const updateSelect = (attr,optionsArray,attributes,casc) => {
|
|
attributes[attr] = optionsArray.some(obj => obj.value === attributes[attr]) ?
|
|
attributes[attr] :
|
|
(casc[`attr_${attr}`].defaultValue || '');
|
|
};
|
|
|
|
const addOption = (memo,obj,attributes,sections) => {
|
|
['value','data-i18n'].forEach(prop => {
|
|
if(obj[prop]){
|
|
obj[prop] = k.parseMacro(obj[prop],attributes,sections);
|
|
}
|
|
});
|
|
if(obj['data-i18n']){
|
|
obj.label = k.getTranslationByKey(obj['data-i18n']);
|
|
}
|
|
delete obj['data-i18n'];
|
|
delete obj.selected
|
|
if(obj.value || obj.label){
|
|
memo.push(obj);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* controlls whether the levelup button displays or not based on current level and compendium access
|
|
* @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 critButtonDisplay = function({trigger,attributes,sections,casc}){
|
|
const levelXP = [10,50,110,190,290,410,550,710,890,1090];
|
|
const reqXP = levelXP[+attributes.level|| 0];
|
|
getPage('Occupations',()=>{
|
|
$20('.compendium-dependent-content').removeClass('disabled');
|
|
})
|
|
};
|
|
k.registerFuncs({critButtonDisplay},{type:['opener']});
|
|
|
|
/**
|
|
*
|
|
* @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 rollFumble = function({trigger,attributes,sections,casc}){
|
|
const armorID = sections.repeating_armor.find(id => attributes[`repeating_armor_${id}_fumble_die`]);
|
|
const fumbleDie = (
|
|
armorID ?
|
|
attributes[`repeating_armor_${armorID}_fumble_die`] :
|
|
`1d4`
|
|
) + `+ [[${attributes.luck_modifier || 0}*-1]]`;
|
|
getPage('Fumbles (No Armor)',async (data,table) => {
|
|
const result = await rollTable(fumbleDie,table);
|
|
const {roll:output} = await k.startRoll({description:result,title:'^{fumble}'});
|
|
output.finish();
|
|
})
|
|
};
|
|
k.registerFuncs({rollFumble});
|
|
|
|
const getNPCCritTable = (attributes) => {
|
|
if(attributes.crit_table === 'humanoid'){
|
|
const hitDieNum = calcHitDieNum(attributes);
|
|
return hitDieNum <= 5 ?
|
|
'III' :
|
|
hitDieNum <= 10 ?
|
|
'IV' :
|
|
'V';
|
|
}else{
|
|
const abbreviations = {
|
|
demon: 'DN',
|
|
dragon: 'DR',
|
|
monster: 'M',
|
|
undead: 'U',
|
|
giant: 'G'
|
|
}
|
|
return abbreviations[attributes.crit_table];
|
|
}
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @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 rollCrit = function({trigger,attributes,sections,casc}){
|
|
getCompendiumQuery([`Category:Rollable Tables Name:*Crit Table`],async (data) => {
|
|
const critTableName = attributes.is_npc ?
|
|
getNPCCritTable(attributes) :
|
|
attributes.crit_table;
|
|
const page = data.find(t => t.name.replace(/ \-.+/,'') === `Crit Table ${critTableName}`);
|
|
const table = JSON.parse(page.data['data-Results']);
|
|
const critDie = attributes.is_npc ?
|
|
`${attributes.crit_die} - ?{${k.getTranslationByKey('crit query')}}` :
|
|
`${attributes.crit_die} + ${attributes.luck_modifier}`;
|
|
const tableResult = await rollTable(critDie,table);
|
|
const {roll:output} = await k.startRoll({description:tableResult,title:'^{critical}'});
|
|
output.finish();
|
|
})
|
|
|
|
};
|
|
k.registerFuncs({rollCrit});
|
|
|
|
|
|
/**
|
|
* starts up the mancer when the sheet is opened for the first time.
|
|
* @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 mancerStartup = function({trigger,attributes,sections,casc}){
|
|
getPage('Occupations',(data,table)=>{
|
|
attributes['kmodal-mancer'] = 1;
|
|
attributes.mancer_stage = 'startup';
|
|
attributes.set();
|
|
})
|
|
};
|
|
k.registerFuncs({mancerStartup},{type:['new']});
|
|
|
|
|
|
/**
|
|
* Rolls for the birth augur
|
|
* @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 rollAugur = function({trigger,attributes,sections,casc}){
|
|
getTable('Luck Score',result => {
|
|
attributes.mancer_augur = result;
|
|
attributes.set();
|
|
})
|
|
};
|
|
k.registerFuncs({rollAugur});
|
|
/**
|
|
* rolls a random amount of hp based on the level being achieved
|
|
* @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 rollHP = async function({trigger,attributes,sections,casc,levels = 1,hpDie = 'd4'}){
|
|
const {roll} = await k.startRoll({roll:`[[${levels}${hpDie}]]`},'!');
|
|
roll.finish();
|
|
attributes.mancer_hp = roll.results.roll.result;
|
|
attributes.set();
|
|
};
|
|
k.registerFuncs({rollHP });
|
|
/**
|
|
* Rolls the ability scores for a new 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 rollAbilityScores = async function({trigger,attributes,sections,casc}){
|
|
const rollObj = scores.reduce((m,score) => {
|
|
m[score] = '[[3d6]]';
|
|
return m;
|
|
},{});
|
|
const {roll} = await k.startRoll(rollObj,'!');
|
|
roll.finish();
|
|
scores.forEach(score => {
|
|
attributes[score] = roll.results[score].result;
|
|
attributes[`${score}_max`] = attributes[score];
|
|
});
|
|
attributes.lucky_roll = attributes.luck_modifier;
|
|
rollAugur({trigger,attributes,sections,casc});
|
|
attributes.set();
|
|
};
|
|
k.registerFuncs({rollAbilityScores});
|
|
|
|
/**
|
|
* Rolls a random occupation from the compendium
|
|
* @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 determineOccupation = function({trigger,attributes,sections,casc}){
|
|
getTable('Occupations',result => {
|
|
attributes.mancer_occupation = result.result;
|
|
attributes.mancer_trade_goods = result.result3;
|
|
attributes.mancer_weapon = result.result2;
|
|
attributes.set();
|
|
})
|
|
};
|
|
k.registerFuncs({determineOccupation});
|
|
|
|
/**
|
|
* rolls the starting coin for a 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 rollCoinage = async function({trigger,attributes,sections,casc}){
|
|
const {roll} = await k.startRoll({roll:'[[5d12]]'},'!');
|
|
roll.finish();
|
|
attributes.mancer_starting_coin = `${roll.results.roll.result} cp`;
|
|
attributes.set();
|
|
};
|
|
k.registerFuncs({rollCoinage});
|
|
|
|
/**
|
|
* applies the character settings rolled during character creation
|
|
* @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 createCharacter = function({trigger,attributes,sections,casc}){
|
|
attributes.treasure = attributes.mancer_starting_coin
|
|
// +
|
|
// `${attributes.mancer_trade_goods}`;
|
|
addRepeatItems(attributes,sections,casc);
|
|
['occupation'].forEach(attr => {
|
|
attributes[attr] = attributes[`mancer_${attr}`];
|
|
});
|
|
attributes.hit_points = attributes.mancer_hp + attributes.stamina_modifier;
|
|
attributes.hit_points_max = attributes.hit_points;
|
|
['alignment','occupation','starting_coin','trade_goods'].forEach(attr => attributes[`mancer_${attr}`] = casc[`attr_mancer_${attr}`]?.defaultValue || '');
|
|
attributes.crit_die = '1d4';
|
|
attributes.action_dice = '1d20';
|
|
attributes.birth_augur = attributes.mancer_augur;
|
|
attributes.attack = 0;
|
|
attributes.level = 0;
|
|
attributes['kmodal-mancer'] = 0;
|
|
};
|
|
k.registerFuncs({createCharacter});
|
|
|
|
const propagateEffects = (attributes,sections,casc) => {
|
|
const updateKeys = Object.keys(attributes.updates);
|
|
const newCasc = k.expandCascade(sections);
|
|
Object.assign(casc,newCasc);
|
|
if(updateKeys.length){
|
|
expandEffects(attributes,casc,updateKeys);
|
|
}
|
|
}
|
|
/**
|
|
* Adds the trade goods and weapon from occupation
|
|
* @param {AttributesProxy} attributes - The kscaffold attributes object
|
|
* @param {object} sections - the kscaffold sections object
|
|
* @param {object} casc - the kscaffold casc object
|
|
*/
|
|
const addRepeatItems = (attributes,sections,casc) => {
|
|
const weaponName = attributes.mancer_weapon;
|
|
const searchWeaponName = weaponName.replace(/^.+?\(as\s*(.+?)\).*/,'$1');
|
|
const trade = attributes.mancer_trade_goods;
|
|
if(searchWeaponName){
|
|
getCompendiumPage(`Weapons:${k.capitalize(searchWeaponName)}`,async (data) => {
|
|
Object.assign(data,data.data);
|
|
delete data.data;
|
|
await weaponDrop('Weapons',[data],attributes,sections,casc);
|
|
propagateEffects(attributes,sections,casc);
|
|
attributes.set();
|
|
});
|
|
}
|
|
if(trade){
|
|
const tradeRow = k.generateRowID('repeating_equipment',sections);
|
|
attributes[`${tradeRow}_name`] = trade;
|
|
getCompendiumPage(`Equipment:${k.capitalize(trade)}`, async (data) => {
|
|
Object.assign(data,data.data);
|
|
await processDropData({data,attributes,sections,casc,section: tradeRow});
|
|
propagateEffects(attributes,sections,casc);
|
|
clearDuplicateTrade(attributes,sections);
|
|
attributes.set();
|
|
})
|
|
getCompendiumPage(`Armor:${k.capitalize(trade)}`,async (data) => {
|
|
Object.assign(data,data.data);
|
|
await armorDrop('Armor',[data],attributes,sections,casc);
|
|
propagateEffects(attributes,sections,casc);
|
|
clearDuplicateTrade(attributes,sections);
|
|
attributes.set();
|
|
})
|
|
}
|
|
}
|
|
|
|
const clearDuplicateTrade = (attributes,sections) => {
|
|
const found = {};
|
|
const dups = [];
|
|
sections.repeating_equipment.forEach(id => {
|
|
const row = `repeating_equipment_${id}`;
|
|
if(
|
|
!found[attributes[`${row}_name`]] ||
|
|
attributes[`${row}_linked`]
|
|
){
|
|
if(
|
|
found[attributes[`${row}_name`]] &&
|
|
attributes[`${row}_linked`]
|
|
){
|
|
dups.push(found[attributes[`${row}_name`]]);
|
|
}
|
|
found[attributes[`${row}_name`]] = id;
|
|
}else if(found[attributes[`${row}_name`]]){
|
|
dups.push(id);
|
|
}
|
|
});
|
|
dups.forEach(id => {
|
|
k.removeRepeatingRow(`repeating_equipment_${id}`,attributes,sections);
|
|
Object.keys(attributes.updates).forEach(name => {
|
|
if(name.includes(id)){
|
|
delete atttributes.updates[name];
|
|
}
|
|
})
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Cleans up after the level mancer is left
|
|
* @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 leaveLevelMancer = function({trigger,attributes,sections,casc}){
|
|
$20('.level-progress-indicator').addClass('disabled');
|
|
[1,2,3,4,5,6,7,8,9,10].forEach(level => {
|
|
$20(`.row-${level}`).removeClass('disabled');
|
|
$20(`.row-${level}`).removeClass('new-row');
|
|
$20(`.row-${level}`).removeClass('old-row');
|
|
})
|
|
};
|
|
k.registerFuncs({leaveLevelMancer});
|
|
/**
|
|
* Sets the level difference and controls display of information related to the new level.
|
|
* @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 setLevelDiff = function({trigger,attributes,sections,casc}){
|
|
if(attributes.mancer_stage !== 'level') return;
|
|
if(
|
|
attributes.level !== 0 &&
|
|
attributes.level !== attributes.mancer_level
|
|
){
|
|
$20('.level-progress-indicator').removeClass('disabled');
|
|
}else{
|
|
$20('.level-progress-indicator').addClass('disabled');
|
|
}
|
|
[1,2,3,4,5,6,7,8,9,10].forEach(level => {
|
|
if(
|
|
level === attributes.level ||
|
|
level === attributes.mancer_level
|
|
){
|
|
$20(`.row-${level}`).removeClass('disabled');
|
|
if(
|
|
attributes.level !== 0 &&
|
|
attributes.level !== attributes.mancer_level
|
|
){
|
|
if(level === attributes.level){
|
|
$20(`.row-${level}`).addClass('old-row');
|
|
}else{
|
|
$20(`.row-${level}`).addClass('new-row');
|
|
}
|
|
}
|
|
}else{
|
|
$20(`.row-${level}`).addClass('disabled')
|
|
}
|
|
})
|
|
// roll hp
|
|
const hpID = sections['repeating_mancer-class-options'].find(id => {
|
|
const hpRow = `repeating_mancer-class-options_${id}`;
|
|
return attributes[`${hpRow}_name`] === 'Hit Points';
|
|
});
|
|
if(hpID){
|
|
const hpDie = attributes[`repeating_mancer-class-options_${hpID}_description`].replace(/.*\d(d\d+).*/,'$1');
|
|
const levels = attributes.mancer_level - (attributes.level || 0);
|
|
rollHP({attributes,sections,casc,levels,hpDie});
|
|
}
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @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 setupLevelMancer = function({trigger,attributes,sections,casc}){
|
|
setMancerClass({trigger,attributes,sections,casc},(data) => {
|
|
attributes.mancer_has_spells = data['data-class-table'].find(o => o.name.startsWith('spells')) ? 1 : 0;
|
|
attributes.mancer_level = attributes.level + 1;
|
|
setLevelDiff({trigger,attributes,sections,casc});
|
|
})
|
|
};
|
|
k.registerFuncs({setupLevelMancer});
|
|
/**
|
|
* Applies level up changes
|
|
* @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 levelUp = function({trigger,attributes,sections,casc}){
|
|
levelUpAttributes.forEach(attr => {
|
|
if(attributes[`mancer_${attr}`]){
|
|
attributes[attr] = attributes[`mancer_${attr}`];
|
|
|
|
// clear the mancer attribute value to clear the mancer for future use
|
|
attributes[`mancer_${attr}`] = casc[`attr_mancer_${attr}`]?.defaultValue || '';
|
|
}
|
|
});
|
|
// put any complex attribute handling here (e.g. crit roll and crit table specification)
|
|
if(attributes.attributes.class === 'zero'){
|
|
attributes.mancer_class.replace(/(.+?)--/,(match,cl) => {
|
|
attributes.class = cl.toLowerCase();
|
|
})
|
|
}
|
|
attributes.hit_points_max = attributes.hit_points_max + attributes.mancer_hp;
|
|
attributes.hit_points = attributes.hit_points_max;
|
|
levelUpSections.forEach(section => {
|
|
sections[`repeating_${section}`].forEach(id => {
|
|
const row = `repeating_${section}_${id}`;
|
|
const abilityMap = attributes[`${row}_ability_map`];
|
|
if(abilityMap){
|
|
const typeRef = `${row}_mancer_sub_field_control`;
|
|
// handling for class ability rows
|
|
if(attributes[typeRef]){
|
|
if(
|
|
attributes[typeRef] === 'select' &&
|
|
attributes[`${row}_select`]
|
|
){
|
|
attributes[abilityMap] = attributes[`${row}_select`];
|
|
}
|
|
}else{
|
|
if(Array.isArray(abilityMap)){
|
|
values = attributes[`${row}_value_${attributes.level}`].split(/\//);
|
|
abilityMap.forEach((attr,i) => {
|
|
attributes[attr] = values[i];
|
|
});
|
|
}else{
|
|
attributes[abilityMap] = attributes[`${row}_value_${attributes.level}`];
|
|
}
|
|
}
|
|
// finally remove the row to clear the mancer for future use
|
|
k.removeRepeatingRow(row,attributes,sections);
|
|
}
|
|
})
|
|
});
|
|
|
|
// add new spells
|
|
const spellSearch = sections[`repeating_mancer-spells`]
|
|
.filter(id =>
|
|
attributes[`repeating_mancer-spells_${id}_type`] !== 'header' &&
|
|
attributes[`repeating_mancer-spells_${id}_selected`] &&
|
|
attributes[`repeating_mancer-spells_${id}_selectable`])
|
|
.map(id => {
|
|
const row = `repeating_mancer-spells_${id}`;
|
|
|
|
return `Category:${attributes[`${row}_class`]} data-cs-name:${attributes[`${row}_name`]}`;
|
|
});
|
|
if(spellSearch.length){
|
|
getCompendiumQuery(spellSearch,async (spells) => {
|
|
let spellClass;
|
|
const data = spells.map(spell => {
|
|
Object.assign(spell,spell.data);
|
|
spellClass = spell.Category;
|
|
delete spell.data;
|
|
return parseJSONProperties(spell);
|
|
});
|
|
await spellDrop(attributes.class,data,attributes,sections,casc);
|
|
propagateEffects(attributes,sections,casc);
|
|
attributes.set();
|
|
});
|
|
}
|
|
levelUpButtonDisplay({trigger,attributes,sections,casc});
|
|
toggleMancer({attributes});
|
|
};
|
|
k.registerFuncs({levelUp});
|
|
k.registerFuncs({setLevelDiff},{type:['opener']});
|
|
|
|
|
|
/**
|
|
* applies the character mancer class selection, providing a summary of what the class gives.
|
|
* @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
|
|
* @param {function} callback - callback for doing additional work based on the compendium query
|
|
*/
|
|
const setMancerClass = function({trigger,attributes,sections,casc},callback){
|
|
const className = attributes.class !== 'zero' ?
|
|
attributes.class :
|
|
attributes.mancer_class;
|
|
const [,name,expansion = 31302] = className.match(/^(.+?)(?:--(.+))?$/) || [];
|
|
sections['repeating_mancer-class-options'].forEach(id => {
|
|
k.removeRepeatingRow(`repeating_mancer-class-options_${id}`,attributes,sections);
|
|
});
|
|
sections['repeating_mancer-class-table'].forEach(id => {
|
|
k.removeRepeatingRow(`repeating_mancer-class-table_${id}`,attributes,sections);
|
|
});
|
|
// get the appropriate class page
|
|
getCompendiumQuery(`Category:Classes Name:${name} Expansion:${expansion}`,([{data}]) => {
|
|
// parse the json data contained in the data
|
|
data = parseJSONProperties(data);
|
|
data['data-abilities']?.forEach(ability =>
|
|
createMancerAbility(data,ability,attributes,sections));
|
|
data['data-class-table']?.forEach(ability => {
|
|
const row = k.generateRowID('mancer-class-table',sections);
|
|
attributes[`${row}_name`] = ability.name;
|
|
attributes[`${row}_ability_map`] = ability.ability_map;
|
|
const progressProcess = (queue, i=0) => {
|
|
const val = queue.shift();
|
|
const index = i + 1;
|
|
if(typeof val === 'object'){
|
|
const newArr = getFilteredValues(val.value,attributes,sections,false,val.filter);
|
|
queue.push(...newArr);
|
|
}else{
|
|
attributes[`${row}_value_${index}`] = val;
|
|
i++;
|
|
}
|
|
if(queue.length){
|
|
progressProcess(queue,i);
|
|
}
|
|
}
|
|
progressProcess([...ability.progression]);
|
|
});
|
|
if(callback){
|
|
callback(data)
|
|
}
|
|
attributes.set();
|
|
})
|
|
};
|
|
k.registerFuncs({setMancerClass});
|
|
|
|
const createMancerAbility = (masterData,ability,attributes,sections,rowType = 'generic_ability') => {
|
|
const row = k.generateRowID('mancer-class-options',sections);
|
|
attributes[`${row}_row_id`] = row.replace(/repeating_.+?_/,'');
|
|
attributes[`${row}_mancer_sub_field_control`] = rowType;
|
|
if(rowType === 'select'){
|
|
createMancerAbilitySelect(masterData,row,ability,attributes,sections);
|
|
}else{
|
|
const abilityAttrs = ['name','ability_map'];
|
|
if(!ability.filter){
|
|
abilityAttrs.push('description');
|
|
}else{
|
|
attributes[`${row}_description`] = getFilteredValues(masterData,attributes,sections,ability.description,ability.filter);
|
|
}
|
|
abilityAttrs.forEach(attr => {
|
|
if(ability[attr]){
|
|
attributes[`${row}_${attr}`] = ability[attr];
|
|
}
|
|
});
|
|
|
|
}
|
|
ability.children?.forEach(child => {
|
|
createMancerAbility(masterData,child,attributes,sections,child.type || 'sub_ability')
|
|
})
|
|
};
|
|
|
|
/**
|
|
* Filters the values of a given array based.
|
|
* @param {Object} data - the data to get values from
|
|
* @param {AttributesProxy} attributes - the k-scaffold attributes object
|
|
* @param {Object} sections - the K-scaffold sections object
|
|
* @param {String} toFilter - The string describing what to filter
|
|
* @param {String} filter - the attribute name to filter by
|
|
* @param {Function} callback - callback function to be used when filtering other compendium pages. Not yet implemented.
|
|
*/
|
|
const getFilteredValues = (data,attributes,sections,toFilter,filter,callback) => {
|
|
const filterValue = attributes[filter];
|
|
if(!filterValue){
|
|
k.log('Character does not have valid filter state.')
|
|
return;
|
|
}
|
|
const [,pageName,dataPath] = toFilter ?
|
|
toFilter.match(/(.+?):(.+)/) || []:
|
|
[];
|
|
if(!pageName && toFilter !== false){
|
|
k.log('Invalid filter target, mancer incomplete.');
|
|
return;
|
|
}
|
|
const [filterProp,...parsedPath] = dataPath?.split(/\./) || [];
|
|
if(pageName === 'Self' || !pageName){
|
|
let retValue = filterProp ?
|
|
data[`data-${filterProp}`][filterValue] :
|
|
data[filterValue];
|
|
parsedPath.forEach(prop =>
|
|
retValue = retValue[prop]
|
|
);
|
|
return retValue;
|
|
}else{
|
|
// handling for filtering values from other compendium pages.
|
|
// will use callback to pass filtered values instead of returning them.
|
|
}
|
|
};
|
|
|
|
const createMancerAbilitySelect = (masterData,row,ability,attributes,sections) => {
|
|
const choices = ability.filter ?
|
|
getFilteredValues(masterData,attributes,sections,ability.choices,ability.filter) :
|
|
ability.choices;
|
|
choices.unshift('select one');
|
|
const rowID = row.replace(/repeating_.+?_/,'');
|
|
const details = choices.map(choice => {
|
|
const obj = {};
|
|
obj.value = choice === 'select one' ?
|
|
'' :
|
|
choice;
|
|
obj.label = choice;
|
|
return obj;
|
|
});
|
|
attributes[`${row}_name`] = ability.name;
|
|
k.send(attributes.character_name,'delayedListPopulate',{
|
|
elemSelector: `.repitem[data-reprowid="${rowID}"] .mancer-select`,
|
|
optionsArray: details
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @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 delayedListPopulate = function({trigger,attributes,sections,casc},listOptions){
|
|
populateListOptions(listOptions);
|
|
};
|
|
k.registerFuncs({delayedListPopulate});
|
|
|
|
|
|
const findHeaderSection = (orig_arr,start,attributes,section) => {
|
|
const arr = orig_arr.slice(0,start + 1);
|
|
return (
|
|
attributes.mancer_class.match(/wizard/i) ||
|
|
attributes.class.match(/wizard/i)
|
|
) ?
|
|
arr.find(id => attributes[`${section}_${id}_type`] === 'header') :
|
|
arr.findLast(id => attributes[`${section}_${id}_type`] === 'header');
|
|
}
|
|
/**
|
|
* updates the count of selected spells
|
|
* @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 updateMancerSpellSelections = function({trigger,attributes,sections,casc}){
|
|
const [,rowID] = k.parseTriggerName(trigger.name);
|
|
const headerID = findHeaderSection(sections['repeating_mancer-spells'],sections['repeating_mancer-spells'].indexOf(rowID),attributes,'repeating_mancer-spells');
|
|
const row = `repeating_mancer-spells_${headerID}`;
|
|
attributes[`${row}_chosen`] += trigger.newValue * 2 - 1;
|
|
const affectedLevel = attributes[`repeating_mancer-spells_${rowID}_level`];
|
|
const editable = attributes[`${row}_chosen`] >= attributes[`${row}_chosen_max`] ?
|
|
0 :
|
|
1;
|
|
sections['repeating_mancer-spells'].forEach(id => {
|
|
const spellRow = `repeating_mancer-spells_${id}`;
|
|
if(
|
|
attributes[`${spellRow}_level`] === affectedLevel &&
|
|
!attributes[`${spellRow}_selected`] &&
|
|
id !== headerID
|
|
){
|
|
attributes[`${spellRow}_selectable`] = editable;
|
|
}
|
|
})
|
|
};
|
|
k.registerFuncs({updateMancerSpellSelections});
|
|
/**
|
|
* processes class information and pulls relevant spell options.
|
|
* @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 loadMancerSpells = function({trigger,attributes,sections,casc}){
|
|
// clear preexisting information
|
|
[`repeating_mancer-spells`, `repeating_mancer-spells`].forEach(section => sections[section].forEach(id => k.removeRepeatingRow(`${section}_${id}`,attributes,sections)))
|
|
// get the data for the class
|
|
const knownID = sections['repeating_mancer-class-table'].find(id => attributes[`repeating_mancer-class-table_${id}_name`] === "spells known");
|
|
const maxID = knownID ?
|
|
sections['repeating_mancer-class-table'].find(id => attributes[`repeating_mancer-class-table_${id}_name`] === "max spell level") :
|
|
null;
|
|
const isWizard = knownID ? true : false;
|
|
const spellClass = knownID ? 'Wizard' : 'Cleric';
|
|
const spellLevelIDs = isWizard ?
|
|
maxID :
|
|
sections['repeating_mancer-class-table'].filter(id => attributes[`repeating_mancer-class-table_${id}_name`].startsWith('spells'));
|
|
const spellSearch = [];
|
|
if(isWizard){
|
|
const progRow = `repeating_mancer-class-table_${maxID}`;
|
|
[...Array(+attributes[`${progRow}_value_${attributes.mancer_level}`]).keys()].reduce((m,n) => {
|
|
m.push(`Category:Wizard Spells data-cs-level:${n + 1}`);
|
|
return m;
|
|
},spellSearch);
|
|
}else{
|
|
spellLevelIDs.reduce((m,id) => {
|
|
const progRow = `repeating_mancer-class-table_${id}`;
|
|
const spellQuant = attributes[`${progRow}_value_${attributes.mancer_level}`];
|
|
let searchString = `Category:Cleric Spells data-cs-level`;
|
|
if(isNaN(spellQuant)) return m;
|
|
|
|
const spellLevel = attributes[`${progRow}_name`].replace(/spells\s*/,'');
|
|
m.push(`Category:${k.capitalize(o.class)} Spells data-cs-level:${spellLevel}`);
|
|
return m;
|
|
},spellSearch);
|
|
}
|
|
getCompendiumQuery(spellSearch,(spells) => {
|
|
spells.sort((a,b) => {
|
|
const aLevel = +a.data['data-cs-level'] || 1;
|
|
const bLevel = +b.data['data-cs-level'] || 1;
|
|
if(aLevel > bLevel) return 1;
|
|
if(aLevel < bLevel) return -1;
|
|
return a.name.localeCompare(b.name);
|
|
});
|
|
let currentSpellHeader = 0;
|
|
|
|
if(isWizard){
|
|
const wizRow = k.generateRowID('repeating_mancer-spells',sections);
|
|
attributes[`${wizRow}_type`] = 'header';
|
|
attributes[`${wizRow}_label`] = 'spells known'
|
|
attributes[`${wizRow}_chosen`] = sections['repeating_spells'].filter(id =>
|
|
attributes[`repeating_spells_${id}_row_type`] === 'master' &&
|
|
attributes[`${wizRow}_level`] === attributes[`repeating_spells_${id}_level`]).length;
|
|
attributes[`${wizRow}_chosen_max`] = attributes[`repeating_mancer-class-table_${maxID}_value_${attributes.mancer_level}`];
|
|
}
|
|
|
|
const createSpellHeader = () => {
|
|
currentSpellHeader++;
|
|
|
|
|
|
|
|
const row = k.generateRowID('repeating_mancer-spells',sections);
|
|
const spellLevel = currentSpellHeader;
|
|
attributes[`${row}_type`] = 'header';
|
|
attributes[`${row}_level`] = spellLevel;
|
|
if(!isWizard){
|
|
const spellSet = spellLevels.find(o => o.name === `spells ${currentSpellHeader}`);
|
|
const spellQuant = spellSet.progression[attributes.mancer_level - 1];
|
|
attributes[`${row}_chosen`] = sections['repeating_spells'].filter(id =>
|
|
attributes[`repeating_spells_${id}_row_type`] === 'master' &&
|
|
attributes[`${row}_level`] === attributes[`repeating_spells_${id}_level`]).length;
|
|
attributes[`${row}_chosen_max`] = spellQuant;
|
|
}
|
|
}
|
|
spells.forEach((page) => {
|
|
const { data: spell } = page;
|
|
if(currentSpellHeader < +spell['data-cs-level']){
|
|
createSpellHeader();
|
|
}
|
|
const row = k.generateRowID('repeating_mancer-spells',sections);
|
|
attributes[`${row}_type`] = 'content';
|
|
attributes[`${row}_name`] = spell['data-cs-name'];
|
|
attributes[`${row}_level`] = currentSpellHeader;
|
|
attributes[`${row}_class`] = spell.Category;
|
|
attributes[`${row}_compendium_reference`] = `Category:${page.Category} data-cs-name:${spell['data-cs-name']} Expansion:${page.Expansion}`;
|
|
attributes[`${row}_compendium_link`] = `${spell.Category}:${page.name}`;
|
|
attributes[`${row}_selected`] = sections.repeating_spells.find(id => {
|
|
const compName = attributes[`repeating_spells_${id}_compendium_reference`] !== '' ?
|
|
attributes[`repeating_spells_${id}_compendium_reference`] :
|
|
attributes[`repeating_spells_${id}_name`];
|
|
return compName === spell['data-cs-name'];
|
|
}) ? 1 : 0;
|
|
if(attributes[`${row}_selected`]){
|
|
attributes[`${row}_selectable`] = 0;
|
|
}
|
|
});
|
|
attributes.set();
|
|
})
|
|
};
|
|
k.registerFuncs({loadMancerSpells});
|
|
|
|
|
|
/**
|
|
* Does the initial setup for the rollable tables
|
|
* @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 setupTableSection = function({trigger,attributes,sections,casc}){
|
|
// wipe the repeating tables from the sheet
|
|
sections['repeating_rollable-tables'].forEach(id => k.removeRepeatingRow(`repeating_rollable-tables_${id}`,attributes,sections));
|
|
getCompendiumQuery('Category:Rollable Tables',(pages) => {
|
|
pages
|
|
.sort((a,b) => a.name.localeCompare(b.name))
|
|
.reduce((memo,page) => {
|
|
if(!memo.names.includes(page.name)){
|
|
memo.names.push(page.name);
|
|
memo.pages.push(page);
|
|
}
|
|
return memo;
|
|
},{names:[],pages:[]})
|
|
.pages
|
|
.forEach(page => {
|
|
const row = k.generateRowID('rollable-tables',sections);
|
|
attributes[`${row}_name`] = page.name;
|
|
attributes[`${row}_die`] = page?.data?.['data-type'].replace(/d/,'') || '';
|
|
})
|
|
k.setActionCalls({attributes,sections})
|
|
attributes.set();
|
|
});
|
|
};
|
|
k.registerFuncs({setupTableSection},{type:['opener']});
|
|
|
|
/**
|
|
*
|
|
* @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 rollSheetTable = function({trigger,attributes,sections,casc}){
|
|
const [section,id] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${id}`;
|
|
const die = `d${attributes[`${row}_die`]} + ${attributes[`${row}_bonus`]}`;
|
|
getCompendiumQuery(`Category:Rollable Tables Name:${attributes[`${row}_name`]}`,async ([page]) => {
|
|
const table = JSON.parse(page.data['data-Results']);
|
|
const result = await rollTable(die,table);
|
|
const stringResult = typeof result === 'object' ?
|
|
Object
|
|
.entries(result)
|
|
.reduce((str,[key,val])=>{
|
|
if(key !== 'die'){
|
|
if(str){
|
|
str += '\n';
|
|
}
|
|
str += val;
|
|
}
|
|
return str;
|
|
},'') :
|
|
result;
|
|
const {roll:output} = await k.startRoll({description:stringResult,title:attributes[`${row}_name`]});
|
|
output.finish();
|
|
})
|
|
};
|
|
k.registerFuncs({rollSheetTable});
|
|
|
|
|
|
/**
|
|
* resets all character data to original state.
|
|
* @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 wipeCharacter = function({trigger,attributes,sections,casc}){
|
|
if(!attributes.mancer_confirm_wipe){
|
|
// have the user confirm that they want to wipe
|
|
attributes.mancer_confirm_wipe = 1;
|
|
attributes.mancer_wipe_button_text = 'confirm data deletion';
|
|
}else{
|
|
Object
|
|
.entries(casc)
|
|
.filter(([key]) =>
|
|
!/repeating_|^(?:kmodal-mancer|mancer_stage|rollmodal_disabled)$/.test(key))
|
|
.forEach(([obj]) => {
|
|
attributes[obj.name] = obj.defaultValue;
|
|
});
|
|
Object
|
|
.entries(sections)
|
|
.filter(([section]) => section !== 'repeating_rollable-tables')
|
|
.forEach(([section,ids],i,arr) => {
|
|
ids.forEach(id => k.removeRepeatingRow(`${section}_${id}`,attributes,sections));
|
|
});
|
|
progressMancer({trigger,attributes,sections,casc});
|
|
}
|
|
};
|
|
k.registerFuncs({wipeCharacter});
|
|
|
|
/**
|
|
*
|
|
* @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 resetWipe = function({trigger,attributes,sections,casc}){
|
|
attributes.mancer_confirm_wipe = 0;
|
|
attributes.mancer_wipe_button_text = casc.attr_mancer_wipe_button_text.defaultValue;
|
|
};
|
|
k.registerFuncs({resetWipe});
|
|
|
|
|
|
/**
|
|
* toggles the character mancer open/close state
|
|
* @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 toggleMancer = function({trigger,attributes,sections,casc}){
|
|
attributes['kmodal-mancer'] = Math.abs(attributes['kmodal-mancer'] - 1);
|
|
if(trigger?.stage){
|
|
const prevObj = mancerStageFuncs[attributes.mancer_stage];
|
|
const stageObj = mancerStageFuncs[trigger.stage];
|
|
prevObj?.exit.forEach(funcName => k.callFunc(funcName,{trigger,attributes,sections,casc}));
|
|
stageObj?.load.forEach(funcName => k.callFunc(funcName,{trigger,attributes,sections,casc}))
|
|
attributes.mancer_stage = trigger.stage;
|
|
}
|
|
};
|
|
k.registerFuncs({toggleMancer});
|
|
|
|
/**
|
|
* progresses the mancer stage attribute. called from many different buttons, each of which should provide a `stage` property on the trigger to tell the function where to send the mancer.
|
|
* @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 progressMancer = function({trigger,attributes,sections,casc}){
|
|
const prevObj = mancerStageFuncs[attributes.mancer_stage];
|
|
const stageObj = mancerStageFuncs[trigger.stage];
|
|
prevObj?.exit.forEach(funcName => k.callFunc(funcName,{trigger,attributes,sections,casc}));
|
|
attributes['kmodal-mancer'] = 1;
|
|
attributes.mancer_stage = trigger.stage;
|
|
stageObj?.load.forEach(funcName => k.callFunc(funcName,{trigger,attributes,sections,casc}))
|
|
};
|
|
k.registerFuncs({progressMancer});
|
|
|
|
|
|
/**
|
|
* controlls whether the levelup button displays or not based on current level and compendium access
|
|
* @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 levelUpButtonDisplay = function({trigger,attributes,sections,casc}){
|
|
const levelXP = [10,50,110,190,290,410,550,710,890,1090];
|
|
const reqXP = levelXP[+attributes.level|| 0];
|
|
getPage('Occupations',()=>{
|
|
if(reqXP && attributes.xp >= reqXP){
|
|
$20('.mancer-level-button').removeClass('disabled');
|
|
}else{
|
|
$20('.mancer-level-button').addClass('disabled');
|
|
}
|
|
})
|
|
};
|
|
k.registerFuncs({levelUpButtonDisplay},{type:['opener']});
|
|
|
|
const calculateLevel = function({trigger,attributes,sections,casc}) {
|
|
const cclass = attributes['class'] ? attributes['class'] : 'zero';
|
|
const level = attributes.level ? parseInt(attributes.level) : 0;
|
|
return cclass === 'zero' ? 0 : level == 0 ? 1 : level;
|
|
};
|
|
const calculateTitleValue = function({trigger,attributes,sections,casc}) {
|
|
const getTitle = (type, alignment, level) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(5, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
cleric: {
|
|
lawful: ['', 'acolyte', 'heathen-slayer', 'brother', 'curate', 'father'],
|
|
chaotic: ['', 'zealot', 'convert', 'cultist', 'apostle', 'high-priest'],
|
|
neutral: ['', 'witness', 'pupil', 'chronicler', 'judge', 'druid'],
|
|
},
|
|
thief: {
|
|
lawful: ['', 'bravo', 'apprentice', 'rogue', 'capo', 'boss'],
|
|
chaotic: ['', 'thug', 'murderer', 'cutthroat', 'executioner', 'assassin'],
|
|
neutral: ['', 'beggar', 'cutpurse', 'burglar', 'robber', 'swindler'],
|
|
},
|
|
warrior: {
|
|
lawful: ['', 'squire', 'champion', 'knight', 'cavalier', 'paladin'],
|
|
chaotic: ['', 'bandit', 'brigand', 'marauder', 'ravager', 'reaver'],
|
|
neutral: ['', 'wildling', 'barbarian', 'berserker', 'headman-headwoman', 'chieftain'],
|
|
},
|
|
wizard: {
|
|
lawful: ['', 'evoker', 'controller', 'conjurer', 'summoner', 'elementalist'],
|
|
chaotic: ['', 'cultist', 'shaman', 'diabolist', 'warlock-witch', 'necromancer'],
|
|
neutral: ['', 'astrologist', 'enchanter', 'magician', 'thaumaturgist', 'sorcerer'],
|
|
},
|
|
dwarf: {
|
|
lawful: ['', 'agent', 'broker', 'delegate', 'envoy', 'syndic'],
|
|
chaotic: ['', 'rebel', 'dissident', 'exile', 'iconoclast', 'renegade'],
|
|
neutral: ['', 'apprentice', 'novice', 'journeyer', 'crafter', 'thegn'],
|
|
},
|
|
elf: {
|
|
lawful: ['', 'wanderer', 'seer', 'quester', 'savant', 'elder'],
|
|
chaotic: ['', 'wanderer', 'seer', 'quester', 'savant', 'elder'],
|
|
neutral: ['', 'wanderer', 'seer', 'quester', 'savant', 'elder'],
|
|
},
|
|
halfling: {
|
|
lawful: ['', 'wanderer', 'explorer', 'collector', 'accumulator', 'wise-one'],
|
|
chaotic: ['', 'wanderer', 'explorer', 'collector', 'accumulator', 'wise-one'],
|
|
neutral: ['', 'wanderer', 'explorer', 'collector', 'accumulator', 'wise-one'],
|
|
}
|
|
}
|
|
if(!valueLookup[type] || !valueLookup[type][alignment]) return '';
|
|
return valueLookup[type][alignment][referenceLevel];
|
|
}
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const alignment = attributes.alignment || false;
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(!alignment) return '';
|
|
if(characterClass === 'zero') return '';
|
|
const title = getTitle(characterClass, alignment, attributes.level);
|
|
return (title) ? k.getTranslationByKey(`title-${title}`) || title.replace(/-/g, ' ') : '';
|
|
};
|
|
const calculateSpeedValue = function({trigger,attributes,sections,casc}) {
|
|
let armorPenalty = 0;
|
|
const activeArmor = reduceSection('armor', 'ac_bonus', attributes, sections, (previous, current) => {
|
|
const previousAC = previous && Object.entries(previous).length > 0 && !isNaN(Object.entries(previous)[0][1]) ? parseInt(Object.entries(previous)[0][1]) : 0;
|
|
const currentAC = isNaN(Object.entries(current)[0][1]) ? 0 : parseInt(Object.entries(current)[0][1]);
|
|
return currentAC > previousAC ? current : previous;
|
|
}, true);
|
|
if(Object.keys(activeArmor).length > 0) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(Object.keys(activeArmor)[0]);
|
|
const speedAttribute = `${section}_${rowID}_speed`;
|
|
if(attributes[speedAttribute] && !isNaN(attributes[speedAttribute])) armorPenalty = parseInt(attributes[speedAttribute]);
|
|
}
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const speed = (characterClass === 'dwarf') ? 20+armorPenalty : 30+armorPenalty;
|
|
return addModsTo(speed, trigger, attributes);
|
|
};
|
|
|
|
const calculateBirthAugur = function({trigger,attributes,sections,casc}) {
|
|
const luckyroll = attributes['lucky_roll_max'] && !isNaN(attributes['lucky_roll_max']) ? parseInt(attributes['lucky_roll_max']) : false;
|
|
const augur = luckyroll && luckyroll > 0 && luckyroll <= 30 ? k.getTranslationByKey(`luck-score-${luckyroll}`) : '';
|
|
return augur;
|
|
};
|
|
|
|
k.registerFuncs({calculateBirthAugur});
|
|
k.registerFuncs({calculateLevel});
|
|
k.registerFuncs({calculateSpeedValue});
|
|
k.registerFuncs({calculateTitleValue});
|
|
|
|
|
|
const calculateACValue = function({trigger,attributes,sections,casc}) {
|
|
const total = {
|
|
armor: 0,
|
|
shield: 0
|
|
}
|
|
const agilityModifier = (attributes['agility_modifier'] && !isNaN(attributes['agility_modifier'])) ? parseInt(attributes['agility_modifier']) : 0;
|
|
const armorRepeatingSection = 'repeating_armor';
|
|
sections[armorRepeatingSection].forEach(armorID => {
|
|
const parent = `${armorRepeatingSection}_${armorID}`;
|
|
if(!attributes[`${parent}_active`] || attributes[`${parent}_active`] != 1) return;
|
|
if(!attributes[`${parent}_ac_bonus`] || isNaN(attributes[`${parent}_ac_bonus`])) return;
|
|
const type = (attributes[`${parent}_shield`] && attributes[`${parent}_shield`] === 'yes') ? 'shield' : 'armor';
|
|
total[type] = Math.max(parseInt(attributes[`${parent}_ac_bonus`]), total[type]);
|
|
});
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
const ac = 10 + total.armor + total.shield + agilityModifier;
|
|
return addModsTo(ac, trigger, attributes);
|
|
};
|
|
const calculateHitDie = function({trigger,attributes,sections,casc}) {
|
|
const hitDieLookup = {
|
|
cleric: '1d8',
|
|
dwarf: '1d10',
|
|
elf: '1d6',
|
|
halfling: '1d6',
|
|
thief: '1d6',
|
|
warrior: '1d12',
|
|
wizard: '1d4'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero' && !hitDieLookup[characterClass]) return '1d4';
|
|
const hitDie = hitDieLookup[characterClass];
|
|
return addModsTo(hitDie, trigger, attributes);
|
|
};
|
|
k.registerFuncs({calculateACValue});
|
|
k.registerFuncs({calculateHitDie});
|
|
|
|
|
|
const calcHitDieNum = (attributes) => {
|
|
[,hitDieNum = 0] = attributes.hd.match(/(\d+)d/) || [];
|
|
return hitDieNum;
|
|
}
|
|
const calculateCritDieValue = function({trigger,attributes,sections,casc}) {
|
|
if(attributes.is_npc){
|
|
if(!attributes.critTable || !attributes.hd) return;
|
|
const npcCritDice = {
|
|
humanoid: ['d4','d6','d8','d8','d10','d10','d12','d12','d14','d14','d16','d16','d20','d20','2d10','2d10','2d12','2d12','2d14','2d14','3d10','3d10'],
|
|
demon: ['d3','d4','d4','d4','d4','d6','d6','d8','d8','d10','d10','d12','d12','d14','d14','d16','d16','d20','d20','d24','d24','d30'],
|
|
dragon: ['d4','d6','d8','d10','d12','d14','d16','d20','d20','d24','d24','2d14','2d14','d30','d30','2d16','2d16','2d20','2d20','3d20','3d20','4d20'],
|
|
giant: ['-','-','-','-','d4','d4','d4','d4','d4','d4','d4','d4','d6','d6','d7','d7','d8','d8','d10','d10','d12','d12'],
|
|
monster: ['d4','d6','d8','d8','d10','d10','d12','d12','d14','d14','d16','d16','d20','d20','d20','d20','d24','d24','d24','d30','d30','d30'],
|
|
undead: ['d4','d6','d6','d8','d8','d10','d10','d12','d12','d14','d14','d16','d16','d20','d20','d24','d24','d30','d30','d30','d30','d30']
|
|
};
|
|
const hitDieNum = calcHitDieNum(attributes);
|
|
const critTable = npcCritDice[attributes.crit_table];
|
|
return critTable[hitDieNum] || critTable[critTable.length - 1];
|
|
}else{
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
a: ['1d4', '1d8', '1d8', '1d10', '1d10', '1d12', '1d12', '1d14', '1d14', '1d16', '1d16'],
|
|
b: ['1d4', '1d10', '1d12', '1d14', '1d16', '1d20', '1d24', '1d30', '1d30+2', '1d30+4', '1d30+6'],
|
|
c: ['1d4', '1d12', '1d14', '1d16', '1d20', '1d24', '1d30', '1d30', '2d20', '2d20', '2d20'],
|
|
d: ['1d4', '1d6', '1d6', '1d8', '1d8', '1d10', '1d10', '1d12', '1d12', '1d14', '1d14'],
|
|
e: ['1d4', '1d10', '1d12', '1d14', '1d16', '1d20', '1d24', '1d30', '1d30', '2d20', '2d20'],
|
|
f: ['1d4', '1d6', '1d8', '1d8', '1d10', '1d10', '1d12', '1d12', '1d14', '1d14', '1d16'],
|
|
}
|
|
if(!valueLookup[type]) return '1d20';
|
|
return valueLookup[type][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
cleric: 'a',
|
|
dwarf: 'e',
|
|
elf: 'f',
|
|
halfling: 'a',
|
|
thief: 'b',
|
|
warrior: 'c',
|
|
wizard: 'd'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero') return '1d4';
|
|
const critDie = calcModifier(attributes.level, profLookup[characterClass]);
|
|
return addModsTo(critDie, trigger, attributes);
|
|
}
|
|
};
|
|
const calculateAttackModifier = function({trigger,attributes,sections,casc}) {
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
a: [0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4],
|
|
b: [0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7],
|
|
c: [0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5],
|
|
d: [0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8],
|
|
e: [0, 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd10+1', 'd10+2', 'd10+3', 'd10+4']
|
|
}
|
|
if(!valueLookup[type]) return 0;
|
|
return valueLookup[type][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
cleric: 'b',
|
|
dwarf: 'e',
|
|
elf: 'c',
|
|
halfling: 'd',
|
|
thief: 'b',
|
|
warrior: 'e',
|
|
wizard: 'a'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero') return 0;
|
|
const baseModifier = calcModifier(attributes.level, profLookup[characterClass]);
|
|
return addModsTo(baseModifier, trigger, attributes);
|
|
};
|
|
const calculateInitiativeValue = function({trigger,attributes,sections,casc}) {
|
|
const agilityModifier = (attributes['agility_modifier'] && !isNaN(attributes['agility_modifier'])) ? parseInt(attributes['agility_modifier']) : 0;
|
|
const levelModifier = (attributes['class'] && attributes['class'] === 'warrior' && !isNaN(attributes['level'])) ? parseInt(attributes['level']) || 0 : 0;
|
|
const twoHandedWeapons = filterSection('weapons', 'two_handed', attributes, sections, (isTwoHanded) => {
|
|
return isTwoHanded && isTwoHanded === 'yes';
|
|
}, true);
|
|
const dice = Object.keys(twoHandedWeapons).length === 0 ? '1d20' : '1d16'
|
|
const init = agilityModifier+levelModifier > 0 ? `${dice}+${agilityModifier+levelModifier}` : dice;
|
|
return addModsTo(init, trigger, attributes);
|
|
};
|
|
const calculateActionDiceValue = function({trigger,attributes,sections,casc}) {
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
a: ['1d20', '1d20', '1d20', '1d20', '1d20', '1d20', '1d20+1d14', '1d20+1d14', '1d20+1d16', '1d20+1d20', '1d20+1d20'],
|
|
b: ['1d20', '1d20', '1d20', '1d20', '1d20', '1d20', '1d20+1d14', '1d20+1d16', '1d20+1d20', '1d20+1d20', '1d20+1d20'],
|
|
c: ['1d20', '1d20', '1d20', '1d20', '1d20', '1d20+1d14', '1d20+1d16', '1d20+1d20', '1d20+1d20', '1d20+1d20', '1d20+1d20+1d14']
|
|
}
|
|
if(!valueLookup[type]) return '1d20';
|
|
return valueLookup[type][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
cleric: 'a',
|
|
dwarf: 'c',
|
|
elf: 'c',
|
|
halfling: 'b',
|
|
thief: 'a',
|
|
warrior: 'c',
|
|
wizard: 'c'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero') return '1d20';
|
|
return calcModifier(attributes.level, profLookup[characterClass]);
|
|
};
|
|
const calculateCritTableValue = function({trigger,attributes,sections,casc}) {
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
a: ['I', 'III', 'III', 'III', 'III', 'III', 'III', 'III', 'III', 'III', 'III'],
|
|
b: ['I', 'II', 'II', 'II', 'II', 'II', 'II', 'II', 'II', 'II', 'II'],
|
|
c: ['I', 'III', 'III', 'IV', 'IV', 'V', 'V', 'V', 'V', 'V', 'V'],
|
|
d: ['I', 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'],
|
|
e: ['I', 'III', 'III', 'III', 'IV', 'IV', 'V', 'V', 'V', 'V', 'V'],
|
|
}
|
|
if(!valueLookup[type]) return '1d20';
|
|
return valueLookup[type][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
cleric: 'a',
|
|
dwarf: 'e',
|
|
elf: 'b',
|
|
halfling: 'a',
|
|
thief: 'b',
|
|
warrior: 'c',
|
|
wizard: 'd'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero') return 'I';
|
|
return calcModifier(attributes.level, profLookup[characterClass]);
|
|
};
|
|
k.registerFuncs({calculateAttackModifier});
|
|
k.registerFuncs({calculateInitiativeValue});
|
|
k.registerFuncs({calculateActionDiceValue});
|
|
k.registerFuncs({calculateCritTableValue});
|
|
k.registerFuncs({calculateCritDieValue});
|
|
|
|
|
|
const calculateScoreModifier = function({trigger,attributes,sections,casc}) {
|
|
const lookup = [-3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3];
|
|
const parentAttribute = trigger.name.replace('_modifier', '_total');
|
|
const parentValue = attributes[parentAttribute] && !isNaN(attributes[parentAttribute]) ? parseInt(attributes[parentAttribute]) : 10;
|
|
const referenceValue = Math.max(Math.min(18, parentValue), 3);
|
|
const modifier = lookup[referenceValue-3];
|
|
return modifier;
|
|
};
|
|
k.registerFuncs({calculateScoreModifier});
|
|
|
|
|
|
const calculateSavingModifier = function({trigger,attributes,sections,casc}) {
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
a: [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3],
|
|
b: [0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4],
|
|
c: [0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6]
|
|
}
|
|
if(!valueLookup[type]) return 0;
|
|
return valueLookup[type][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
cleric: { ref:'a', fort:'b', will:'c' },
|
|
dwarf: { ref:'b', fort:'c', will:'b' },
|
|
elf: { ref:'b', fort:'b', will:'c' },
|
|
halfling: { ref:'c', fort:'b', will:'c' },
|
|
thief: { ref:'c', fort:'b', will:'a' },
|
|
warrior: { ref:'b', fort:'c', will:'a' },
|
|
wizard: { ref:'b', fort:'a', will:'c' }
|
|
};
|
|
const scoreLookup = {
|
|
ref: 'agility',
|
|
fort: 'stamina',
|
|
will: 'personality'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const savingAttribute = trigger.name.replace('_save', '');
|
|
const modifierAttribute = `${scoreLookup[savingAttribute]}_modifier`;
|
|
const scoreModifier = attributes[modifierAttribute] ? attributes[modifierAttribute] : 0;
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero') return scoreModifier;
|
|
const saving = calcModifier(attributes.level, profLookup[characterClass][savingAttribute]) + scoreModifier;
|
|
return addModsTo(saving, trigger, attributes);
|
|
};
|
|
k.registerFuncs({calculateSavingModifier});
|
|
|
|
|
|
const calculateMeleeAndMissileModifiers = function({trigger,attributes,sections,casc}) {
|
|
const scoreLookup = {
|
|
melee: 'strength',
|
|
missile: 'agility'
|
|
};
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const valueLookup = {
|
|
a: [0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4],
|
|
b: [0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7],
|
|
c: [0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5],
|
|
d: [0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8],
|
|
e: [0, 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd10+1', 'd10+2', 'd10+3', 'd10+4']
|
|
}
|
|
if(!valueLookup[type]) return 0;
|
|
return valueLookup[type][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
cleric: 'b',
|
|
dwarf: 'e',
|
|
elf: 'c',
|
|
halfling: 'd',
|
|
thief: 'b',
|
|
warrior: 'e',
|
|
wizard: 'a'
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const attackAttribute = trigger.name.replace('_attack', '');
|
|
const modifierAttribute = `${scoreLookup[attackAttribute]}_modifier`;
|
|
const scoreModifier = attributes[modifierAttribute] ? attributes[modifierAttribute] : 0;
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass === 'zero') return scoreModifier;
|
|
const baseModifier = attributes.attack ? attributes.attack : calcModifier(attributes.level, profLookup[characterClass]);
|
|
let totalModifier = 0;
|
|
if(isNaN(baseModifier)) {
|
|
if(baseModifier.includes('+')) {
|
|
const bonus = (parseInt(baseModifier.split('+').at(-1).trim())+scoreModifier) > 0 ? `+${parseInt(baseModifier.split('+').at(-1).trim())+scoreModifier}` : '';
|
|
const value = baseModifier.replace(/ /g, '').replace(/\+\d/g, `${bonus}`);
|
|
return addModsTo(value, trigger, attributes);
|
|
} else {
|
|
const bonus = scoreModifier > 0 ? `+${scoreModifier}` : '';
|
|
const value = `${baseModifier}${bonus}`;
|
|
return addModsTo(value, trigger, attributes);
|
|
}
|
|
} else {
|
|
const value = baseModifier+scoreModifier;
|
|
return addModsTo(value, trigger, attributes);
|
|
}
|
|
};
|
|
const calculateMeleeDamage = function({trigger,attributes,sections,casc}) {
|
|
const lookup = [-3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3];
|
|
const parentAttribute = 'strength';
|
|
const parentValue = attributes[parentAttribute] && !isNaN(attributes[parentAttribute]) ? parseInt(attributes[parentAttribute]) : 10;
|
|
const referenceValue = Math.max(Math.min(18, parentValue), 3);
|
|
const modifier = lookup[referenceValue-3];
|
|
return addModsTo(modifier, trigger, attributes);
|
|
};
|
|
const calculateMissileDamage = function({trigger,attributes,sections,casc}) {
|
|
const lookup = [-3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3];
|
|
const parentAttribute = 'strength';
|
|
const parentValue = attributes[parentAttribute] && !isNaN(attributes[parentAttribute]) ? parseInt(attributes[parentAttribute]) : 10;
|
|
const referenceValue = Math.max(Math.min(18, parentValue), 3);
|
|
const modifier = lookup[referenceValue-3];
|
|
return addModsTo(modifier, trigger, attributes);
|
|
};
|
|
k.registerFuncs({calculateScoreModifier});
|
|
k.registerFuncs({calculateMeleeAndMissileModifiers});
|
|
k.registerFuncs({calculateMeleeDamage});
|
|
k.registerFuncs({calculateMissileDamage});
|
|
|
|
|
|
const calculateWeaponAttack = function({trigger,attributes,sections,casc}) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
const pararent = `${section}_${rowID}`;
|
|
const type = attributes[`${pararent}_type`] || 'melee';
|
|
const baseAttackBonusAttribute = `${type}_attack`;
|
|
const deedClasses = ['dwarf', 'warrior'];
|
|
const attributeBonus = type === 'melee' ? parseInt(attributes['strength_modifier']) || 0 : parseInt(attributes['agility_modifier']) || 0;
|
|
const baseAttackBonus = attributes['class'] && deedClasses.includes(attributes['class']) ? (parseInt(attributes['deed_die_result'])||0)+attributeBonus || 0 : attributes[baseAttackBonusAttribute] || 0;
|
|
const weaponAttackBonus = attributes[`${section}_${rowID}_attack_bonus_base`] || 0;
|
|
if(isNaN(baseAttackBonus)) {
|
|
if(baseAttackBonus.includes('+')) {
|
|
const bonus = (parseInt(baseAttackBonus.split('+').at(-1).trim())+weaponAttackBonus) > 0 ? `+${parseInt(baseAttackBonus.split('+').at(-1).trim())+weaponAttackBonus}` : '';
|
|
const value = baseAttackBonus.replace(/ /g, '').replace(/\+\d/g, `${bonus}`);
|
|
return value;
|
|
} else {
|
|
const bonus = weaponAttackBonus > 0 ? `+${weaponAttackBonus}` : '';
|
|
const value = `${baseAttackBonus}${bonus}`;
|
|
return value;
|
|
}
|
|
} else {
|
|
const value = baseAttackBonus+weaponAttackBonus;
|
|
return value;
|
|
}
|
|
};
|
|
const calculateWeaponDamage = function({trigger,attributes,sections,casc}) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
const pararent = `${section}_${rowID}`;
|
|
const type = attributes[`${pararent}_type`] || 'melee';
|
|
const baseDamageBonusAttribute = `${type}_damage`;
|
|
const deedClasses = ['dwarf', 'warrior'];
|
|
const deedDie = attributes['class'] && deedClasses.includes(attributes['class']) ? `+${parseInt(attributes['deed_die_result']) || 0}` : '';
|
|
let baseDamageBonus = '';
|
|
if(type === 'missile') {
|
|
baseDamageBonus = attributes[`${type}_damage_total`] || attributes[baseDamageBonusAttribute] || 0;
|
|
} else {
|
|
baseDamageBonus = attributes[baseDamageBonusAttribute] || 0;
|
|
}
|
|
const weaponDamage = attributes[`${section}_${rowID}_damage_base`] || 0;
|
|
if(isNaN(weaponDamage)) {
|
|
if(weaponDamage.includes('+')) {
|
|
const bonus = (parseInt(weaponDamage.split('+').at(-1).trim())+baseDamageBonus) > 0 ? `+${parseInt(weaponDamage.split('+').at(-1).trim())+baseDamageBonus}` : '';
|
|
const value = weaponDamage.replace(/ /g, '').replace(/\+\d/g, `${bonus}`);
|
|
return (value+deedDie).replace('+0','');
|
|
} else {
|
|
const bonus = baseDamageBonus > 0 ? `+${baseDamageBonus}` : '';
|
|
const value = `${weaponDamage}${bonus}`;
|
|
return (value+deedDie).replace('+0','');
|
|
}
|
|
} else {
|
|
const value = weaponDamage+baseDamageBonus;
|
|
return value+deedDie;
|
|
}
|
|
};
|
|
k.registerFuncs({calculateWeaponAttack});
|
|
k.registerFuncs({calculateWeaponDamage});
|
|
|
|
|
|
const calculateLinkedEquipment = function({trigger,attributes,sections,casc}) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
const linked = attributes[`${section}_${rowID}_linked`] || false;
|
|
const value = linked ?
|
|
attributes[`repeating_equipment_${linked.toLowerCase()}_active`] :
|
|
null;
|
|
|
|
return value;
|
|
};
|
|
const toggleEquipment = function({trigger,attributes,sections,casc}) {
|
|
if(trigger.sourceType !== 'player') return;
|
|
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
const linked = attributes[`${section}_${rowID}_linked`] || false;
|
|
const type = attributes[`${section}_${rowID}_type`] || 'equipment';
|
|
const mods = attributes[trigger.name.replace('active', 'modifiers')] || {};
|
|
|
|
if(linked) {
|
|
if(type === 'armor') {
|
|
affect(attributes, `repeating_${type}_${linked.toLowerCase()}_active`);
|
|
}
|
|
else if(type === 'weapon') {
|
|
affect(attributes, `repeating_${type}s_${linked.toLowerCase()}_active`);
|
|
}
|
|
}
|
|
|
|
Object.keys(parseModifiers(mods)).forEach(a => {
|
|
affect(attributes, a);
|
|
});
|
|
};
|
|
const calculateEquipmentLinkedItem = function({trigger,attributes,sections,casc}) {
|
|
if(trigger.sourceType !== 'player') return;
|
|
|
|
const update = {};
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
const linked = attributes[`${section}_${rowID}_linked`] || false;
|
|
const typeLookup = {
|
|
weapon: 'weapons',
|
|
armor: 'armor'
|
|
};
|
|
const type = section.includes('equipment') ? typeLookup[attributes[`${section}_${rowID}_type`]] : 'equipment';
|
|
const value = (attributes[`${section}_${rowID}_${attrName}`]) ? attributes[`${section}_${rowID}_${attrName}`] : (attrName === 'active') ? 0 : '';
|
|
|
|
if(linked && `repeating_${type}` !== section) {
|
|
update[`repeating_${type}_${linked}_${attrName}`] = value;
|
|
k.setAttrs(update);
|
|
}
|
|
};
|
|
const addEquipmentLinkedItem = function({attributes,sections,casc,trigger,newRow}) {
|
|
const update = {};
|
|
const [section,rowID,attrName] = k.parseRepeatName(newRow);
|
|
const typeLookup = {
|
|
weapon: 'weapons',
|
|
armor: 'armor'
|
|
};
|
|
const type = section.replace('repeating_', '');
|
|
const newItemRow = k.generateRowID(`repeating_equipment`,sections);
|
|
const [newItemSection,newItemRowID,newItemAttrName] = k.parseRepeatName(newItemRow);
|
|
update[`${newItemRow}_linked`] = rowID;
|
|
update[`${newItemRow}_type`] = typeLookup[type];
|
|
update[`${section}_${rowID}_linked`] = newItemRowID;
|
|
k.setAttrs(update);
|
|
};
|
|
const removeEquipmentLinkedItem = function({trigger,attributes,sections,casc}) {
|
|
const update = {};
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
// do any modifications that are required for attributes that were removed
|
|
const [removeSection,removeID] = k.parseRepeatName(Object.keys(trigger.removedInfo)[0]);
|
|
const removeSections = JSON.parse(JSON.stringify(sections));
|
|
removeSections[removeSection] = removeSections[removeSection] || [];
|
|
removeSections[removeSection].push(removeID);
|
|
const linkedItems = Object.keys(attributes.attributes).filter(attr => {
|
|
return (attr.includes('_linked') && attr.includes('repeating_') && attributes[attr].toLowerCase() === rowID.toLowerCase());
|
|
});
|
|
const linkedRemovedInfo = {};
|
|
linkedItems.forEach(item => {
|
|
const [itemSection,itemRowID,itemAttrName] = k.parseRepeatName(item);
|
|
linkedRemovedInfo[item] = attributes[item];
|
|
k.removeRepeatingRow(`${itemSection}_${itemRowID}`, attributes, sections);
|
|
});
|
|
const newCasc = k.expandCascade(removeSections);
|
|
Object
|
|
.keys({...trigger.removedInfo,...linkedRemovedInfo})
|
|
.forEach(k => {
|
|
newCasc[`attr_${k}`]?.affects?.forEach(aff => {
|
|
if(attributes[aff] !== null || attributes[aff] !== undefined){
|
|
attributes.queue.push(aff);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
const toggleEquipmentType = function({trigger,attributes,sections,casc}) {
|
|
if(trigger.sourceType !== 'player') return;
|
|
const update = {};
|
|
const [section,rowID,attrName] = k.parseRepeatName(trigger.sourceAttribute);
|
|
const linked = attributes[`repeating_equipment_${rowID}_linked`] || false;
|
|
const name = attributes[`repeating_equipment_${rowID}_name`] || false;
|
|
const typeLookup = {
|
|
weapon: 'weapons',
|
|
armor: 'armor'
|
|
};
|
|
if(trigger.previousValue && !trigger.newValue) {
|
|
if(linked) { //Removes previosly linked Armor or Weapon
|
|
k.removeRepeatingRow(`repeating_${typeLookup[trigger.previousValue]}_${linked}`, attributes, sections);
|
|
update[`repeating_equipment_${rowID}_linked`] = '';
|
|
}
|
|
} else { //Set Type to Armor or Weapon
|
|
if(trigger.previousValue && linked) { //Removes previosly linked Armor or Weapon
|
|
k.removeRepeatingRow(`repeating_${typeLookup[trigger.previousValue]}_${linked}`, attributes, sections);
|
|
}
|
|
//Create new linked Armor or Weapon
|
|
if(!name) return;
|
|
const newItemRow = k.generateRowID(`repeating_${typeLookup[trigger.newValue]}`,sections);
|
|
const [newItemSection,newItemRowID,newItemAttrName] = k.parseRepeatName(newItemRow);
|
|
update[`${newItemRow}_name`] = name;
|
|
update[`${newItemRow}_linked`] = rowID;
|
|
update[`repeating_equipment_${rowID}_linked`] = newItemRowID;
|
|
}
|
|
if(Object.keys(update).length > 0) k.setAttrs(update);
|
|
};
|
|
const parseModifiers = modifiers => {
|
|
if(typeof modifiers === 'object') return modifiers;
|
|
return (modifiers) ?
|
|
Object.fromEntries(modifiers.split(',').map(attribute => {
|
|
const entry = attribute.split(':').map(entry => entry.trim().toLowerCase());
|
|
entry[0] = `${entry[0].replace(/ /g, '_')}_mod`;
|
|
entry[1] = !isNaN(entry[1]) ? Number(entry[1]) : entry[1];
|
|
return entry;
|
|
}))
|
|
: {};
|
|
};
|
|
const calculateModifiedAttributes = function({trigger,attributes,sections,casc}) {
|
|
const parsedAttributes = {
|
|
...parseModifiers(trigger.previousValue),
|
|
...parseModifiers(trigger.newValue)
|
|
};
|
|
Object.keys(parsedAttributes).forEach(a => {
|
|
affect(attributes, a);
|
|
});
|
|
};
|
|
k.registerFuncs({addEquipmentLinkedItem});
|
|
k.registerFuncs({removeEquipmentLinkedItem});
|
|
k.registerFuncs({calculateEquipmentLinkedItem});
|
|
k.registerFuncs({toggleEquipmentType});
|
|
k.registerFuncs({toggleEquipment});
|
|
k.registerFuncs({calculateLinkedEquipment});
|
|
k.registerFuncs({calculateModifiedAttributes});
|
|
|
|
|
|
/**
|
|
*
|
|
* @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 removeArmor = function({trigger,attributes,sections,casc}){
|
|
attributes.armor_class = calculateACValue({trigger:{name:'armor_class'},attributes,sections,casc})
|
|
};
|
|
k.registerFuncs({removeArmor});
|
|
|
|
|
|
const calculateSpellCheckModifier = function({trigger,attributes,sections,casc}) {
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const characterLevel = attributes.level ? parseInt(attributes.level) : '';
|
|
const referenceLevel = isNaN(characterLevel) ? 0 : Math.max(Math.min(10, parseInt(characterLevel)), 0);
|
|
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(referenceLevel === 0) return '';
|
|
|
|
if(characterClass === 'cleric') {
|
|
const personalityModifier = (attributes['personality_modifier'] && !isNaN(attributes['personality_modifier'])) ? parseInt(attributes['personality_modifier']) : 0;
|
|
const check = referenceLevel + personalityModifier;
|
|
return addModsTo(check, trigger, attributes);
|
|
} else if(characterClass === 'wizard' || characterClass === 'elf') {
|
|
const intelligenceModifier = (attributes['intelligence_modifier'] && !isNaN(attributes['intelligence_modifier'])) ? parseInt(attributes['intelligence_modifier']) : 0;
|
|
|
|
let armorPenalty = 0;
|
|
const activeArmor = reduceSection('armor', 'ac_bonus', attributes, sections, (previous, current) => {
|
|
const previousAC = previous && Object.entries(previous).length > 0 && !isNaN(Object.entries(previous)[0][1]) ? parseInt(Object.entries(previous)[0][1]) : 0;
|
|
const currentAC = isNaN(Object.entries(current)[0][1]) ? 0 : parseInt(Object.entries(current)[0][1]);
|
|
return currentAC > previousAC ? current : previous;
|
|
}, true);
|
|
if(Object.keys(activeArmor).length > 0) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(Object.keys(activeArmor)[0]);
|
|
const penaltyAttribute = `${section}_${rowID}_check_penalty`;
|
|
if(attributes[penaltyAttribute] && !isNaN(attributes[penaltyAttribute])) armorPenalty = parseInt(attributes[penaltyAttribute]);
|
|
}
|
|
|
|
const check = referenceLevel + intelligenceModifier;
|
|
return addModsTo(check, trigger, attributes) + armorPenalty;
|
|
} else {
|
|
return '';
|
|
}
|
|
};
|
|
k.registerFuncs({calculateSpellCheckModifier});
|
|
|
|
|
|
const calculateStealthModifier = function({trigger,attributes,sections,casc}) {
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const characterLevel = attributes.level ? parseInt(attributes.level) : '';
|
|
const referenceLevel = isNaN(characterLevel) ? 0 : Math.max(Math.min(10, parseInt(characterLevel)), 0);
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass != 'halfling') return '';
|
|
if(referenceLevel === 0) return '';
|
|
const value = [0, 3, 5, 7, 8, 9, 11, 12, 13, 14, 15][referenceLevel];
|
|
return addModsTo(value, trigger, attributes);
|
|
};
|
|
k.registerFuncs({calculateStealthModifier});
|
|
|
|
|
|
const calculateThiefSkillsModifiers = function({trigger,attributes,sections,casc}) {
|
|
const calcModifier = (level, type) => {
|
|
const referenceLevel = isNaN(level) ? 0 : Math.max(Math.min(10, parseInt(level)), 0);
|
|
const scoreBonus = (type.bonus && attributes[`${type.bonus}_modifier`]) ? parseInt(attributes[`${type.bonus}_modifier`]) : 0;
|
|
const valueLookup = {
|
|
a: [0, 3, 5, 7, 8, 9, 11, 12, 13, 14, 15],
|
|
b: [0, 1, 3, 5, 7, 8, 9, 10, 11, 12, 13],
|
|
c: [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
d: [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8],
|
|
e: [0, 'd10', 'd10', 'd12', 'd12', 'd14', 'd14', 'd16', 'd16', 'd20', 'd20'],
|
|
f: [0, 'd12', 'd12', 'd14', 'd14', 'd16', 'd16', 'd20', 'd20', 'd20', 'd20'],
|
|
}
|
|
if(!valueLookup[type.table]) return 0;
|
|
return scoreBonus > 0 ?
|
|
(typeof valueLookup[type.table][referenceLevel] === 'string') ?
|
|
`${valueLookup[type.table][referenceLevel]}+${scoreBonus}`
|
|
: valueLookup[type.table][referenceLevel] + scoreBonus
|
|
: valueLookup[type.table][referenceLevel];
|
|
}
|
|
const profLookup = {
|
|
lawful: {
|
|
'backstab': {table: 'b', bonus: null},
|
|
'sneak_silently': {table: 'b', bonus: 'agility'},
|
|
'hide_in_shadows': {table: 'a', bonus: 'agility'},
|
|
'pick_pocket': {table: 'b', bonus: 'agility'},
|
|
'climb_sheer_surfaces': {table: 'a', bonus: 'agility'},
|
|
'pick_lock': {table: 'b', bonus: 'agility'},
|
|
'find_trap': {table: 'a', bonus: 'intelligence'},
|
|
'disable_trap': {table: 'a', bonus: 'agility'},
|
|
'forge_document': {table: 'd', bonus: 'agility'},
|
|
'disguise_self': {table: 'c', bonus: 'personality'},
|
|
'read_languages': {table: 'd', bonus: 'intelligence'},
|
|
'handle_poison': {table: 'c', bonus: null},
|
|
'cast_spell_from_scroll': {table: 'e', bonus: 'intelligence'}
|
|
},
|
|
chaotic: {
|
|
'backstab': {table: 'a', bonus: null},
|
|
'sneak_silently': {table: 'a', bonus: 'agility'},
|
|
'hide_in_shadows': {table: 'b', bonus: 'agility'},
|
|
'pick_pocket': {table: 'c', bonus: 'agility'},
|
|
'climb_sheer_surfaces': {table: 'b', bonus: 'agility'},
|
|
'pick_lock': {table: 'b', bonus: 'agility'},
|
|
'find_trap': {table: 'b', bonus: 'intelligence'},
|
|
'disable_trap': {table: 'c', bonus: 'agility'},
|
|
'forge_document': {table: 'd', bonus: 'agility'},
|
|
'disguise_self': {table: 'a', bonus: 'personality'},
|
|
'read_languages': {table: 'd', bonus: 'intelligence'},
|
|
'handle_poison': {table: 'a', bonus: null},
|
|
'cast_spell_from_scroll': {table: 'e', bonus: 'intelligence'}
|
|
},
|
|
neutral: {
|
|
'backstab': {table: 'c', bonus: null},
|
|
'sneak_silently': {table: 'a', bonus: 'agility'},
|
|
'hide_in_shadows': {table: 'b', bonus: 'agility'},
|
|
'pick_pocket': {table: 'a', bonus: 'agility'},
|
|
'climb_sheer_surfaces': {table: 'a', bonus: 'agility'},
|
|
'pick_lock': {table: 'b', bonus: 'agility'},
|
|
'find_trap': {table: 'b', bonus: 'intelligence'},
|
|
'disable_trap': {table: 'b', bonus: 'agility'},
|
|
'forge_document': {table: 'a', bonus: 'agility'},
|
|
'disguise_self': {table: 'd', bonus: 'personality'},
|
|
'read_languages': {table: 'c', bonus: 'intelligence'},
|
|
'handle_poison': {table: 'd', bonus: null},
|
|
'cast_spell_from_scroll': {table: 'f', bonus: 'intelligence'}
|
|
}
|
|
};
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const alignment = attributes.alignment || false;
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(!alignment) return 0;
|
|
if(characterClass != 'thief') return 0;
|
|
if(characterClass === 'zero') return 0;
|
|
if(!profLookup[alignment]) return 0;
|
|
if(!profLookup[alignment][trigger.name]) return 0;
|
|
const baseModifier = calcModifier(attributes.level, profLookup[alignment][trigger.name]);
|
|
|
|
let armorPenalty = 0;
|
|
const activeArmor = reduceSection('armor', 'ac_bonus', attributes, sections, (previous, current) => {
|
|
const previousAC = previous && Object.entries(previous).length > 0 && !isNaN(Object.entries(previous)[0][1]) ? parseInt(Object.entries(previous)[0][1]) : 0;
|
|
const currentAC = isNaN(Object.entries(current)[0][1]) ? 0 : parseInt(Object.entries(current)[0][1]);
|
|
return currentAC > previousAC ? current : previous;
|
|
}, true);
|
|
if(Object.keys(activeArmor).length > 0) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(Object.keys(activeArmor)[0]);
|
|
const penaltyAttribute = `${section}_${rowID}_check_penalty`;
|
|
if(attributes[penaltyAttribute] && !isNaN(attributes[penaltyAttribute])) armorPenalty = parseInt(attributes[penaltyAttribute]);
|
|
}
|
|
|
|
const affectedByArmor = ['climb_sheer_surfaces', 'sneak_silently'];
|
|
const value = addModsTo(baseModifier, trigger, attributes);
|
|
|
|
return affectedByArmor.includes(trigger.name) ? value + armorPenalty : value;
|
|
};
|
|
const calculateLuckDieValue = function({trigger,attributes,sections,casc}) {
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const characterLevel = attributes.level ? parseInt(attributes.level) : '';
|
|
const referenceLevel = isNaN(characterLevel) ? 0 : Math.max(Math.min(10, parseInt(characterLevel)), 0);
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass != 'thief') return '';
|
|
if(referenceLevel === 0) return '';
|
|
if(referenceLevel < 6) return addModsTo(`d${referenceLevel+2}`, trigger, attributes);
|
|
else return addModsTo(`d${8+(referenceLevel-6)*2}`, trigger, attributes);
|
|
};
|
|
k.registerFuncs({calculateLuckDieValue});
|
|
k.registerFuncs({calculateThiefSkillsModifiers});
|
|
|
|
|
|
const calculateThreatRangeValue = function({trigger,attributes,sections,casc}) {
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const characterLevel = attributes.level ? parseInt(attributes.level) : 0;
|
|
const referenceLevel = isNaN(characterLevel) ? 0 : Math.max(Math.min(10, parseInt(characterLevel)), 0);
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass != 'warrior') return addModsTo(20, trigger, attributes);
|
|
const warrior = referenceLevel > 0 ? 19 - Math.floor(referenceLevel/4.5) : 20;
|
|
return addModsTo(warrior, trigger, attributes);
|
|
};
|
|
k.registerFuncs({calculateThreatRangeValue});
|
|
|
|
|
|
const calculateBaseSpellCheckModifier = function({trigger,attributes,sections,casc}) {
|
|
const overwriteAttribute = `${trigger.name}_overwritten`;
|
|
const characterClass = attributes.class ? attributes.class : 'zero';
|
|
const characterLevel = attributes.level ? parseInt(attributes.level) : '';
|
|
const referenceLevel = isNaN(characterLevel) ? 0 : Math.max(Math.min(10, parseInt(characterLevel)), 0);
|
|
const intelligenceModifier = (attributes['intelligence_modifier'] && !isNaN(attributes['intelligence_modifier'])) ? parseInt(attributes['intelligence_modifier']) : 0;
|
|
|
|
let armorPenalty = 0;
|
|
const activeArmor = reduceSection('armor', 'ac_bonus', attributes, sections, (previous, current) => {
|
|
const previousAC = previous && Object.entries(previous).length > 0 && !isNaN(Object.entries(previous)[0][1]) ? parseInt(Object.entries(previous)[0][1]) : 0;
|
|
const currentAC = isNaN(Object.entries(current)[0][1]) ? 0 : parseInt(Object.entries(current)[0][1]);
|
|
return currentAC > previousAC ? current : previous;
|
|
}, true);
|
|
if(Object.keys(activeArmor).length > 0) {
|
|
const [section,rowID,attrName] = k.parseRepeatName(Object.keys(activeArmor)[0]);
|
|
const penaltyAttribute = `${section}_${rowID}_check_penalty`;
|
|
if(attributes[penaltyAttribute] && !isNaN(attributes[penaltyAttribute])) armorPenalty = parseInt(attributes[penaltyAttribute]);
|
|
}
|
|
|
|
if(attributes[overwriteAttribute] && attributes[overwriteAttribute] == 1) return attributes[trigger.name];
|
|
if(characterClass != 'wizard' && characterClass != 'elf') return '';
|
|
if(referenceLevel === 0) return '';
|
|
const check = referenceLevel + intelligenceModifier;
|
|
return addModsTo(check, trigger, attributes) + armorPenalty;
|
|
};
|
|
k.registerFuncs({calculateBaseSpellCheckModifier});
|
|
|
|
|
|
/**
|
|
* collapses the spell rows
|
|
* @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 collapseSpell = function({trigger,attributes,sections,casc}){
|
|
return attributes.spells;
|
|
};
|
|
k.registerFuncs({collapseSpell});
|
|
/**
|
|
* adds the rows required for a new 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 addSpell = function({trigger,attributes,sections,casc,newRow}){
|
|
attributes[`${newRow}_row_type`] = 'master';
|
|
addTableRow(newRow.replace(/repeating_spells_/,'').toLowerCase(),attributes,sections);
|
|
};
|
|
k.registerFuncs({addSpell});
|
|
|
|
const addTableRow = (masterID,attributes,sections,) => {
|
|
const tableRow = k.generateRowID('repeating_spells',sections);
|
|
attributes[`${tableRow}_row_type`] = 'table';
|
|
attributes[`${tableRow}_master`] = masterID;
|
|
return tableRow;
|
|
}
|
|
|
|
/**
|
|
* adds/removes additional table Rows for a given spell. If the roll of the table doesn't have a `+` in it, adds a new table row. If it does, it ignores it, or if there are rows beyond this one, it will delete those rows once they are empty
|
|
* @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 tableRowAdd = function({trigger,attributes,sections,casc}){
|
|
const [section,currID] = k.parseTriggerName(trigger.name);
|
|
const currRow = `${section}_${currID}`;
|
|
const currIndex = sections.repeating_spells.indexOf(currID);
|
|
// exit if this is the master row
|
|
if(!attributes[`${currRow}_master`]) return;
|
|
if(/\+\s*$/.test(attributes[`${currRow}_roll`])){
|
|
let checkIndex = currIndex + 1;
|
|
let nextID = sections.repeating_spells[checkIndex];
|
|
let nextRow = nextID ? `${section}_${nextID}` : null;
|
|
do{
|
|
if(
|
|
nextRow &&
|
|
attributes[`${nextRow}_master`] === attributes[`${currRow}_master`] &&
|
|
!attributes[`${nextRow}_result`]
|
|
){
|
|
k.removeRepeatingRow(nextRow,attributes,sections);
|
|
}else{
|
|
checkIndex++;
|
|
}
|
|
nextID = sections.repeating_spells[checkIndex];
|
|
nextRow = nextID ? `${section}_${nextID}` : null;
|
|
}while(
|
|
nextRow &&
|
|
attributes[`${nextRow}_master`] === attributes[`${currRow}_master`]);
|
|
}else{
|
|
let nextID = sections.repeating_spells[currIndex + 1];
|
|
const nextRow = nextID ? `${section}_${nextID}` : null;
|
|
if(
|
|
!nextID ||
|
|
attributes[`${nextRow}_master`] !== attributes[`${currRow}_master`]
|
|
){
|
|
const newRow = addTableRow(attributes[`${currRow}_master`],attributes,sections);
|
|
const newID = newRow.replace(`${section}_`,'');
|
|
const createdIndex = sections.repeating_spells.indexOf(newID);
|
|
if(createdIndex !== currIndex + 1){
|
|
sections.repeating_spells.splice(currIndex + 1,0,sections.repeating_spells.splice(createdIndex,1)[0]);
|
|
k.setSectionOrder(section,sections.repeating_spells);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
k.registerFuncs({tableRowAdd});
|
|
|
|
/**
|
|
* Cleans up spell tables when results are emptied
|
|
* @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 tableCleanup = function({trigger,attributes,sections,casc}){
|
|
const [section,rowID] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${rowID}`;
|
|
const thisMaster = attributes[`${row}_master`];
|
|
if(!thisMaster || trigger.newValue) return;
|
|
|
|
const finalIndex = sections[section].findLastIndex(id =>{
|
|
const iterRow = `${section}_${id}`;
|
|
return attributes[`${iterRow}_master`] === thisMaster &&
|
|
/\+\s*$/.test(attributes[`${iterRow}_roll`]);
|
|
});
|
|
const thisIndex = sections.repeating_spells.indexOf(rowID);
|
|
if(
|
|
finalIndex >= 0 &&
|
|
finalIndex < thisIndex
|
|
){
|
|
k.removeRepeatingRow(row,attributes,sections);
|
|
}
|
|
};
|
|
k.registerFuncs({tableCleanup});
|
|
|
|
/**
|
|
* Removes spells and all their table rows
|
|
* @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 removeSpell = function({trigger,attributes,sections,casc}){
|
|
const [section,rID] = k.parseRepeatName(trigger.sourceAttribute);
|
|
// don't do this logic for table rows that are removed.
|
|
if(trigger.removedInfo[`repeating_spells_${rID}_master`])return;
|
|
const rowID = rID.toLowerCase();
|
|
sections.repeating_spells.forEach(id => {
|
|
const row = `${section}_${id}`;
|
|
if(attributes[`${row}_master`] === rowID){
|
|
k.removeRepeatingRow(row,attributes,sections);
|
|
}
|
|
})
|
|
};
|
|
k.registerFuncs({removeSpell });
|
|
|
|
/**
|
|
* Moves table rows when a master row is reordered
|
|
* @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 moveTableRows = function({trigger,attributes,sections,casc}){
|
|
const masterRows = sections.repeating_spells.filter(id => {
|
|
const row = `repeating_spells_${id}`;
|
|
return attributes[`${row}_row_type`] === 'master';
|
|
});
|
|
masterRows.forEach(masterID => {
|
|
const childIDs = sections.repeating_spells.filter(id =>{
|
|
const row = `repeating_spells_${id}`;
|
|
return attributes[`${row}_master`] === masterID;
|
|
});
|
|
let startIndex = sections.repeating_spells.indexOf(masterID) + 1;
|
|
childIDs.forEach(id => {
|
|
const childIndex = sections.repeating_spells.indexOf(id);
|
|
sections.repeating_spells.splice(
|
|
startIndex,
|
|
0,
|
|
sections.repeating_spells.splice(
|
|
childIndex,
|
|
1
|
|
)[0]
|
|
);
|
|
startIndex++;
|
|
});
|
|
});
|
|
k.setSectionOrder('spells',sections.repeating_spells);
|
|
};
|
|
k.registerFuncs({moveTableRows});
|
|
|
|
/**
|
|
* toggles collapsing of a spell's results table so that the spell takes up less screen real estate
|
|
* @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 collapseSpellTable = function({trigger,attributes,sections,casc}){
|
|
const [section,rowID,attrName] = k.parseTriggerName(trigger.name);
|
|
const baseRow = `${section}_${rowID}`;
|
|
sections[section].forEach(id => {
|
|
const row = `${section}_${id}`;
|
|
if(attributes[`${row}_master`] === rowID){
|
|
if(attrName === 'collapse'){
|
|
attributes[`${row}_collapse`] = attributes[trigger.name] ?
|
|
attributes[trigger.name] :
|
|
attributes[`${baseRow}_row_collapse`];
|
|
}else{
|
|
attributes[`${row}_collapse`] = attributes[trigger.name];
|
|
}
|
|
}
|
|
});
|
|
};
|
|
k.registerFuncs({collapseSpellTable});
|
|
|
|
/**
|
|
* determines what spell effect to use for a given roll result.
|
|
* @param {object} results - the results property of the roll argument from startRoll
|
|
* @param {object} computeObj - the object to change the display content of rolls for finishRoll
|
|
* @param {string} source - the item that initially called the roll. Used to get the row ID for the source.
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const determineSpellEffects = function({results},computeObj,{casc,attributes,sections,source}){
|
|
const [section,masterID] = k.parseTriggerName(source);
|
|
const table = sections.repeating_spells
|
|
.filter(id =>
|
|
attributes[`repeating_spells_${id}_master`] === masterID)
|
|
.reduce((m,id) =>{
|
|
const row = `${section}_${id}`;
|
|
const [,indexStart,indexEnd] = `${attributes[`${row}_roll`]}`.match(/(\d+)(?:[—–-](\d+))?/) || [];
|
|
m[indexEnd ?? indexStart] = attributes[`${row}_result`];
|
|
return m;
|
|
},{});
|
|
[,computeObj.computeDescription] = getTableResult(table,results.formula1.result);
|
|
};
|
|
k.registerFuncs({determineSpellEffects});
|
|
|
|
/**
|
|
* calculates the total spell check for a given 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 calcSpellCheck = function({trigger,attributes,sections,casc}){
|
|
const [section,id] = k.parseTriggerName(trigger.name);
|
|
return attributes.base_spell_check + attributes[`${section}_${id}_check`];
|
|
};
|
|
k.registerFuncs({calcSpellCheck});
|
|
|
|
|
|
const calculateRollmodalFormula = function({trigger,attributes,sections,casc}) {
|
|
const baseFormula = attributes['rollmodal_base_formula'] ? attributes['rollmodal_base_formula'] : '';
|
|
const bonus = attributes['rollmodal_bonus'] ? attributes['rollmodal_bonus'] : '';
|
|
const signal = bonus ? /^[^\w\s]/gi.test(String(bonus).trim()) ? '' : '+' : '';
|
|
return `${baseFormula}${signal}${bonus}`.toLowerCase();
|
|
};
|
|
closeModal = function({trigger,attributes,sections,casc}) {
|
|
closeRollmodal();
|
|
};
|
|
const closeRollmodal = () => {
|
|
k.setAttrs({
|
|
rollmodal_active: 0,
|
|
rollmodal_title: '',
|
|
rollmodal_subtitle: '',
|
|
rollmodal_has_action_die: '',
|
|
rollmodal_action_die: '',
|
|
rollmodal_base_formula: '',
|
|
rollmodal_bonus: '',
|
|
rollmodal_final_formula: '',
|
|
rollmodal_type: 'public',
|
|
rollmodal_description: '',
|
|
rollmodal_source: ''
|
|
});
|
|
};
|
|
k.registerFuncs({calculateRollmodalFormula});
|
|
k.registerFuncs({closeModal});
|
|
|
|
|
|
let forceOpenModal = false;
|
|
$20('button.rollable, button.npc__field--rollable').on('click', e => {
|
|
const altKeyed = e.altKey ? true : false;
|
|
forceOpenModal = altKeyed;
|
|
});
|
|
</script>
|
|
|