mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-08-30 11:42:29 +00:00
5525 lines
338 KiB
HTML
5525 lines
338 KiB
HTML
|
|
<button name="act_k-network-call" hidden="" type="action">
|
|
</button>
|
|
<rolltemplate class="sheet-rolltemplate-alien">{{#rollTotal() edition 2}}
|
|
<div class="edition-value--2" style="display:none;"></div>{{/rollTotal() edition 2}}
|
|
<div class="body">{{#character_name}}{{#character_id}}
|
|
<h4 class="character_name">[{{character_name}}](http://journal.roll20.net/character/{{character_id}})</h4>{{/character_id}}{{^character_id}}
|
|
<h4 class="character_name">{{character_name}}</h4>{{/character_id}}{{/character_name}}
|
|
<h2 class="title">{{title}}</h2>{{#successes}}
|
|
<div class="results justify-space-between plain">
|
|
<div class="flex-box half-gap">
|
|
<h3 data-i18n="successes"></h3>{{computed::successes}}
|
|
</div>{{#panic}}
|
|
<div class="flex-box half-gap">
|
|
<h3 data-i18n="panic"></h3>{{computed::panic}}
|
|
</div>{{/panic}}
|
|
</div>{{/successes}}{{#d66}}
|
|
<div class="results dice">{{computed::d66}}</div>{{/d66}}{{#stress_roll}}
|
|
<div class="results plain">{{stress_roll}}</div>
|
|
<div class="results plain">{{#rollLess() stress_roll 7}}
|
|
<p data-i18n="panic-result-1-6"></p>{{/rollLess() stress_roll 7}}{{#rollTotal() stress_roll 7}}
|
|
<p data-i18n="panic-result-7"></p>{{/rollTotal() stress_roll 7}}{{#rollTotal() stress_roll 8}}
|
|
<p data-i18n="panic-result-8"></p>{{/rollTotal() stress_roll 8}}{{#rollTotal() stress_roll 9}}
|
|
<p data-i18n="panic-result-9"></p>{{/rollTotal() stress_roll 9}}{{#rollTotal() stress_roll 10}}
|
|
<p data-i18n="panic-result-10"></p>{{/rollTotal() stress_roll 10}}{{#rollTotal() stress_roll 11}}
|
|
<p data-i18n="panic-result-11"></p>{{/rollTotal() stress_roll 11}}{{#rollTotal() stress_roll 12}}
|
|
<p data-i18n="panic-result-12"></p>{{/rollTotal() stress_roll 12}}{{#rollTotal() stress_roll 13}}
|
|
<p data-i18n="panic-result-13"></p>{{/rollTotal() stress_roll 13}}{{#rollTotal() stress_roll 14}}
|
|
<p data-i18n="panic-result-14"></p>{{/rollTotal() stress_roll 14}}{{#rollGreater() stress_roll 14}}
|
|
<p data-i18n="panic-result-15"></p>{{/rollGreater() stress_roll 14}}
|
|
</div>{{/stress_roll}}{{#base_dice_1}}
|
|
<div class="results dice">
|
|
<div class="base">{{base_dice_1}}{{base_dice_2}}{{base_dice_3}}{{base_dice_4}}{{base_dice_5}}{{base_dice_6}}{{base_dice_7}}{{base_dice_8}}{{base_dice_9}}{{base_dice_10}}{{base_dice_11}}{{base_dice_12}}{{base_dice_13}}{{base_dice_14}}{{base_dice_15}}{{base_dice_16}}{{base_dice_17}}{{base_dice_18}}{{base_dice_19}}{{base_dice_20}}{{base_dice_21}}{{base_dice_22}}{{base_dice_23}}{{base_dice_24}}{{base_dice_25}}{{base_dice_26}}{{base_dice_27}}{{base_dice_28}}{{base_dice_29}}
|
|
</div>
|
|
<div class="stress">{{stress_dice_1}}{{stress_dice_2}}{{stress_dice_3}}{{stress_dice_4}}{{stress_dice_5}}{{stress_dice_6}}{{stress_dice_7}}{{stress_dice_8}}{{stress_dice_9}}{{stress_dice_10}}{{stress_dice_11}}{{stress_dice_12}}{{stress_dice_13}}{{stress_dice_14}}{{stress_dice_15}}{{stress_dice_16}}{{stress_dice_17}}{{stress_dice_18}}{{stress_dice_19}}{{stress_dice_20}}{{stress_dice_21}}{{stress_dice_22}}{{stress_dice_23}}{{stress_dice_24}}{{stress_dice_25}}{{stress_dice_26}}{{stress_dice_27}}{{stress_dice_28}}{{stress_dice_29}}
|
|
</div>{{#no_dice}}
|
|
<h3 data-i18n="no dice to roll"></h3>{{/no_dice}}
|
|
</div>{{/base_dice_1}}{{^base_dice_1}}{{#stress_dice_1}}
|
|
<div class="results dice">
|
|
<div class="base">{{base_dice_1}}{{base_dice_2}}{{base_dice_3}}{{base_dice_4}}{{base_dice_5}}{{base_dice_6}}{{base_dice_7}}{{base_dice_8}}{{base_dice_9}}{{base_dice_10}}{{base_dice_11}}{{base_dice_12}}{{base_dice_13}}{{base_dice_14}}{{base_dice_15}}{{base_dice_16}}{{base_dice_17}}{{base_dice_18}}{{base_dice_19}}{{base_dice_20}}{{base_dice_21}}{{base_dice_22}}{{base_dice_23}}{{base_dice_24}}{{base_dice_25}}{{base_dice_26}}{{base_dice_27}}{{base_dice_28}}{{base_dice_29}}
|
|
</div>
|
|
<div class="stress">{{stress_dice_1}}{{stress_dice_2}}{{stress_dice_3}}{{stress_dice_4}}{{stress_dice_5}}{{stress_dice_6}}{{stress_dice_7}}{{stress_dice_8}}{{stress_dice_9}}{{stress_dice_10}}{{stress_dice_11}}{{stress_dice_12}}{{stress_dice_13}}{{stress_dice_14}}{{stress_dice_15}}{{stress_dice_16}}{{stress_dice_17}}{{stress_dice_18}}{{stress_dice_19}}{{stress_dice_20}}{{stress_dice_21}}{{stress_dice_22}}{{stress_dice_23}}{{stress_dice_24}}{{stress_dice_25}}{{stress_dice_26}}{{stress_dice_27}}{{stress_dice_28}}{{stress_dice_29}}
|
|
</div>{{#no_dice}}
|
|
<h3 data-i18n="no dice to roll"></h3>{{/no_dice}}
|
|
</div>{{/stress_dice_1}}{{/base_dice_1}}{{#base_damage}}
|
|
<div class="results plain">
|
|
<h3 data-i18n="base damage"></h3><span>{{base_damage}}</span>
|
|
</div>{{/base_damage}}
|
|
<div class="results hide-if-no-buttons">{{#character_id}}{{#^rollTotal() computed::push_through 0}}{{#base_dice_1}}{{#push_label}}[{{push_label}}](~{{character_id}}|push||{{computed::push_through}}){{/push_label}}{{^push_label}}[push](~{{character_id}}|push||{{computed::push_through}}){{/push_label}}{{/base_dice_1}}{{^base_dice_1}}{{#stress_dice_1}}{{#push_label}}[{{push_label}}](~{{character_id}}|push||{{computed::push_through}}){{/push_label}}{{^push_label}}[push](~{{character_id}}|push||{{computed::push_through}}){{/push_label}}{{/stress_dice_1}}{{/base_dice_1}}{{/^rollTotal() computed::push_through 0}}{{#^rollTotal() computed::supply_roll 0}}{{#supply_label}}[{{supply_label}}](~{{character_id}}|supply||{{computed::supply_roll}}){{/supply_label}}{{^supply_label}}[^{Resupply}](~{{character_id}}|supply||{{computed::supply_roll}}){{/supply_label}}{{/^rollTotal() computed::supply_roll 0}}{{/character_id}}
|
|
</div>{{#tableResult}}
|
|
<h3 data-i18n="results"></h3>
|
|
<div class="results plain computed-text">{{computed::tableResult}}</div>{{/tableResult}}{{#results}}
|
|
<h3 data-i18n="results"></h3>
|
|
<div class="results plain">{{results}}</div>{{/results}}{{#comment}}
|
|
<h3 data-i18n="comments"></h3>
|
|
<div class="results plain">{{comment}}</div>{{/comment}}{{#description}}
|
|
<div class="results plain">{{description}}</div>{{/description}}
|
|
</div>
|
|
</rolltemplate>
|
|
<button name="act_push" hidden="" type="action">
|
|
</button>
|
|
<button name="act_supply" hidden="" type="action">
|
|
</button>
|
|
<input class="edition-value" name="attr_edition" value="1" type="hidden" title="@{edition}"/>
|
|
<input class="color-mode" name="attr_color_mode" value="edition" type="hidden" title="@{color_mode}"/>
|
|
<div class="sheet-alien compendium-drop-target npcs vehicles ships hostiles edition-style">
|
|
<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}"/><!-- sectionName:menu -->
|
|
<input name="attr_menu_tab" value="nav-tabs-menu--settings" type="hidden" title="@{menu_tab}"/>
|
|
<div class="tabs tabs--menu">
|
|
<nav class="tabs__header tabs--menu__header"><span class="firstedition capitalize edition-label" data-i18n="1st edition"></span><span class="secondedition capitalize edition-label" data-i18n="2nd edition"></span>
|
|
<div class="generic_rolls">
|
|
<h1>Roll Menu</h1>
|
|
<button name="roll_roll_1d3" value="@{template_start} {{title=^{generic 1d3}}} {{description=[[1d3]]}}" type="roll">1d3
|
|
</button>
|
|
<button name="roll_roll_1d6" value="@{template_start} {{title=^{generic 1d6}}} {{description=[[1d6]]}}" type="roll">1d6
|
|
</button>
|
|
<button name="roll_roll_2d6" value="@{template_start} {{title=^{generic 2d6}}} {{description=[[2d6]]}}" type="roll">2d6
|
|
</button>
|
|
<button name="roll_roll_3d6" value="@{template_start} {{title=^{generic 3d6}}} {{description=[[3d6]]}}" type="roll">3d6
|
|
</button>
|
|
<button class="roller" name="roll_roll_1d66" data-i18n-title="Roll 1d66" title="Roll 1d66" value="@{roll_1d66_action}" type="roll">1d66
|
|
</button>
|
|
<button name="act_roll-1d66-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_roll_1d66_action" type="hidden" title="@{roll_1d66_action}"/>
|
|
</div>
|
|
<ul class="tabs__nav-list">
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--settings pictos" name="act_nav-tabs-menu--settings" data-container-button="menu" data-button="settings" type="action" data-container-tab="menu" data-tab="settings">y
|
|
</button>
|
|
</li>
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--character" name="act_nav-tabs-menu--character" data-container-button="menu" data-button="character" data-i18n="tabs-menu-character" type="action" data-container-tab="menu" data-tab="character">
|
|
</button>
|
|
</li>
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--npc" name="act_nav-tabs-menu--npc" data-container-button="menu" data-button="npc" data-i18n="tabs-menu-npc" type="action" data-container-tab="menu" data-tab="npc">
|
|
</button>
|
|
</li>
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--hostile" name="act_nav-tabs-menu--hostile" data-container-button="menu" data-button="hostile" data-i18n="tabs-menu-hostile" type="action" data-container-tab="menu" data-tab="hostile">
|
|
</button>
|
|
</li>
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--ship" name="act_nav-tabs-menu--ship" data-container-button="menu" data-button="ship" data-i18n="tabs-menu-ship" type="action" data-container-tab="menu" data-tab="ship">
|
|
</button>
|
|
</li>
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--vehicle" name="act_nav-tabs-menu--vehicle" data-container-button="menu" data-button="vehicle" data-i18n="tabs-menu-vehicle" type="action" data-container-tab="menu" data-tab="vehicle">
|
|
</button>
|
|
</li>
|
|
<li class="tabs__nav-item">
|
|
<button class="tabs__button tabs--menu__button tabs--menu__button--initiative" name="act_nav-tabs-menu--initiative" data-container-button="menu" data-button="initiative" data-i18n="tabs-menu-initiative" type="action" data-container-tab="menu" data-tab="initiative">
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
<div class="tabs__body tabs--menu__body">
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--settings" data-container-tab="menu" data-tab="settings">
|
|
<div class="tab settings">
|
|
<div class="box sheet_behavior edition-style notch--tl notch--tr notch--big">
|
|
<div class="underlay">
|
|
<h1 data-i18n="sheet behavior"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<label class="input_row">
|
|
<h3 data-i18n="character type"></h3>
|
|
<select name="attr_sheet_type" title="@{sheet_type}">
|
|
<option value="character" data-i18n="character">
|
|
</option>
|
|
<option value="npc" data-i18n="npc">
|
|
</option>
|
|
<option value="hostile" data-i18n="hostile">
|
|
</option>
|
|
<option value="ship" data-i18n="ship">
|
|
</option>
|
|
<option value="vehicle" data-i18n="vehicle">
|
|
</option>
|
|
<option value="party screen" data-i18n="party screen">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="whisper to gm"></h3>
|
|
<select name="attr_whisper" title="@{whisper}">
|
|
<option value="" data-i18n="never" selected="">
|
|
</option>
|
|
<option value="/w gm " data-i18n="always">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="edition"></h3>
|
|
<select name="attr_edition" title="@{edition}">
|
|
<option value="1" data-i18n="1st Edition" selected="selected">
|
|
</option>
|
|
<option value="2" data-i18n="2nd Edition">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<input class="color-mode" name="attr_color_mode" value="edition" type="hidden" title="@{color_mode}"/>
|
|
<label class="input_row">
|
|
<h3 data-i18n="color mode"></h3>
|
|
<select name="attr_color_mode" title="@{color_mode}">
|
|
<option value="edition" data-i18n="edition based" selected="selected">
|
|
</option>
|
|
<option value="color" data-i18n="game color setting">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label class="input_row firstedition">
|
|
<h3 data-i18n="nerves of steel"></h3>
|
|
<input name="attr_nerves_of_steel" value="2" type="checkbox" title="@{nerves_of_steel}"/>
|
|
</label>
|
|
<label class="input_row secondedition">
|
|
<h3 data-i18n="range automation"></h3>
|
|
<select name="attr_range_automation" title="@{range_automation}">
|
|
<option value="query" data-i18n="use specific query" selected="selected">
|
|
</option>
|
|
<option value="" data-i18n="use generic bonus query">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
</div><span data-i18n="settings instructions"></span>
|
|
</div>
|
|
</div>
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--character" data-container-tab="menu" data-tab="character">
|
|
<div class="tab character">
|
|
<div class="box Personal_Agenda edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Personal Agenda"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<textarea name="attr_personal_agenda" title="@{personal_agenda}"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="box Relationships edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Relationships"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="input_row">
|
|
<h3 data-i18n="buddy:">Buddy:</h3>
|
|
<input name="attr_buddy" type="text" title="@{buddy}"/>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 data-i18n="rival:">Rival:</h3>
|
|
<input name="attr_rival" type="text" title="@{rival}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Stress_Level edition-style firstedition">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_panic" data-i18n="Stress Level" role="heading" aria-level="1" value="@{panic_action}" type="roll">
|
|
</button>
|
|
<button name="act_panic-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_panic_action" type="hidden" title="@{panic_action}"/>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left stress_level">
|
|
<input class="fill-left__radio" name="attr_stress_level" value="0" type="hidden" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="1" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="2" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="3" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="4" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="5" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="6" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="7" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="8" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="9" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="10" type="checkbox" title="@{stress_level}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Stress_Level edition-style secondedition">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Stress Level"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left stress_level">
|
|
<input class="fill-left__radio" name="attr_stress_level" value="0" type="hidden" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="1" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="2" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="3" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="4" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="5" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="6" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="7" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="8" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="9" type="checkbox" title="@{stress_level}"/>
|
|
<input class="fill-left__radio" name="attr_stress_level" value="10" type="checkbox" title="@{stress_level}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Health edition-style firstedition">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Health"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left health_level">
|
|
<input class="fill-left__radio" name="attr_health_level" value="0" type="hidden" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="1" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="2" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="3" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="4" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="5" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="6" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="7" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="8" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="9" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="10" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="11" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="12" type="checkbox" title="@{health_level}"/>
|
|
</div>
|
|
<div class="border radiation">
|
|
<input name="attr_radiation_damage" value="0" type="hidden" title="@{radiation_damage}"/><span></span>
|
|
<input name="attr_radiation_damage" value="0" type="number" title="@{radiation_damage}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Health edition-style secondedition">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_death" data-i18n="Health" role="heading" aria-level="1" value="@{death_action}" type="roll">
|
|
</button>
|
|
<button name="act_death-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_death_action" type="hidden" title="@{death_action}"/>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left health_level">
|
|
<input class="fill-left__radio" name="attr_health_level" value="0" type="hidden" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="1" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="2" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="3" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="4" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="5" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="6" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="7" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="8" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="9" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="10" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="11" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="12" type="checkbox" title="@{health_level}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="resolve-radiation">
|
|
<div class="box Resolve edition-style secondedition">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Resolve"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left resolve">
|
|
<input class="fill-left__radio" name="attr_resolve" value="0" type="hidden" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="1" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="2" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="3" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="4" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="5" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="6" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="7" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="8" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="9" type="checkbox" title="@{resolve}"/>
|
|
<input class="fill-left__radio" name="attr_resolve" value="10" type="checkbox" title="@{resolve}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Radiation edition-style">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_radiation" data-i18n="Radiation" role="heading" aria-level="1" value="@{radiation_action}" type="roll">
|
|
</button>
|
|
<button name="act_radiation-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_radiation_action" type="hidden" title="@{radiation_action}"/>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left radiation_level">
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="0" type="hidden" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="1" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="2" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="3" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="4" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="5" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="6" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="7" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="8" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="9" type="checkbox" title="@{radiation_level}"/>
|
|
<input class="fill-left__radio" name="attr_radiation_level" value="10" type="checkbox" title="@{radiation_level}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Critical_Injuries edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Critical Injuries"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="input_row">
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_critical_injuries" title="@{critical_injuries}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_critical_injuries" title="@{critical_injuries}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Conditions short edition-style firstedition">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Conditions"></h1>
|
|
<div class="border short"></div>
|
|
</div>
|
|
<div class="overlay short">
|
|
<label class="input_row">
|
|
<h3 data-i18n="starving">starving</h3>
|
|
<input name="attr_starving" type="checkbox" title="@{starving}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="dehydrated">dehydrated</h3>
|
|
<input name="attr_dehydrated" type="checkbox" title="@{dehydrated}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="exhausted">exhausted</h3>
|
|
<input name="attr_exhausted" type="checkbox" title="@{exhausted}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="freezing">freezing</h3>
|
|
<input name="attr_freezing" type="checkbox" title="@{freezing}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="stress-panic secondedition no-compendium">
|
|
<div class="box Stress_Responses short edition-style">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_stress_response" data-i18n="Stress Responses" role="heading" aria-level="1" value="@{stress_response_action}" type="roll">
|
|
</button>
|
|
<button name="act_stress-response-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_stress_response_action" type="hidden" title="@{stress_response_action}"/>
|
|
<div class="border short"></div>
|
|
</div>
|
|
<div class="overlay short">
|
|
<label class="input_row">
|
|
<h3 data-i18n="jumpy">jumpy</h3>
|
|
<input name="attr_jumpy" value="1" type="checkbox" title="@{jumpy}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="tunnel vision">tunnel vision</h3>
|
|
<input name="attr_tunnel_vision" value="1" type="checkbox" title="@{tunnel_vision}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="aggravated">aggravated</h3>
|
|
<input name="attr_aggravated" value="1" type="checkbox" title="@{aggravated}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="shakes">shakes</h3>
|
|
<input name="attr_shakes" value="1" type="checkbox" title="@{shakes}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="frantic">frantic</h3>
|
|
<input name="attr_frantic" value="1" type="checkbox" title="@{frantic}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="deflated">deflated</h3>
|
|
<input name="attr_deflated" value="1" type="checkbox" title="@{deflated}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="box Panic_Responses short edition-style">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_panic_response" data-i18n="Panic Responses" role="heading" aria-level="1" value="@{panic_response_action}" type="roll">
|
|
</button>
|
|
<button name="act_panic-response-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_panic_response_action" type="hidden" title="@{panic_response_action}"/>
|
|
<div class="border short"></div>
|
|
</div>
|
|
<div class="overlay short">
|
|
<label class="input_row">
|
|
<h3 data-i18n="paranoid">paranoid</h3>
|
|
<input name="attr_paranoid" value="1" type="checkbox" title="@{paranoid}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="hesitant">hesitant</h3>
|
|
<input name="attr_hesitant" value="1" type="checkbox" title="@{hesitant}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="freeze">freeze</h3>
|
|
<input name="attr_freeze" value="1" type="checkbox" title="@{freeze}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="seek cover">seek cover</h3>
|
|
<input name="attr_seek_cover" value="1" type="checkbox" title="@{seek_cover}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="scream">scream</h3>
|
|
<input name="attr_scream" value="1" type="checkbox" title="@{scream}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="flee">flee</h3>
|
|
<input name="attr_flee" value="1" type="checkbox" title="@{flee}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="frenzy">frenzy</h3>
|
|
<input name="attr_frenzy" value="1" type="checkbox" title="@{frenzy}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="catatonic">catatonic</h3>
|
|
<input name="attr_catatonic" value="1" type="checkbox" title="@{catatonic}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="stress-panic secondedition compendium-required">
|
|
<div class="box Stress_Responses short edition-style">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_stress_compendium" data-i18n="Stress Responses" role="heading" aria-level="1" value="@{stress_compendium_action}" type="roll">
|
|
</button>
|
|
<button name="act_stress-compendium-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_stress_compendium_action" type="hidden" title="@{stress_compendium_action}"/>
|
|
<div class="border short"></div>
|
|
</div>
|
|
<div class="overlay short">
|
|
<label class="input_row">
|
|
<h3 data-i18n="jumpy">jumpy</h3>
|
|
<input name="attr_jumpy" value="1" type="checkbox" title="@{jumpy}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="tunnel vision">tunnel vision</h3>
|
|
<input name="attr_tunnel_vision" value="1" type="checkbox" title="@{tunnel_vision}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="aggravated">aggravated</h3>
|
|
<input name="attr_aggravated" value="1" type="checkbox" title="@{aggravated}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="shakes">shakes</h3>
|
|
<input name="attr_shakes" value="1" type="checkbox" title="@{shakes}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="frantic">frantic</h3>
|
|
<input name="attr_frantic" value="1" type="checkbox" title="@{frantic}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="deflated">deflated</h3>
|
|
<input name="attr_deflated" value="1" type="checkbox" title="@{deflated}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="box Panic_Responses short edition-style">
|
|
<div class="underlay">
|
|
<button class="roll_icon roller" name="roll_panic_compendium" data-i18n="Panic Responses" role="heading" aria-level="1" value="@{panic_compendium_action}" type="roll">
|
|
</button>
|
|
<button name="act_panic-compendium-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_panic_compendium_action" type="hidden" title="@{panic_compendium_action}"/>
|
|
<div class="border short"></div>
|
|
</div>
|
|
<div class="overlay short">
|
|
<label class="input_row">
|
|
<h3 data-i18n="paranoid">paranoid</h3>
|
|
<input name="attr_paranoid" value="1" type="checkbox" title="@{paranoid}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="hesitant">hesitant</h3>
|
|
<input name="attr_hesitant" value="1" type="checkbox" title="@{hesitant}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="freeze">freeze</h3>
|
|
<input name="attr_freeze" value="1" type="checkbox" title="@{freeze}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="seek cover">seek cover</h3>
|
|
<input name="attr_seek_cover" value="1" type="checkbox" title="@{seek_cover}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="scream">scream</h3>
|
|
<input name="attr_scream" value="1" type="checkbox" title="@{scream}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="flee">flee</h3>
|
|
<input name="attr_flee" value="1" type="checkbox" title="@{flee}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="frenzy">frenzy</h3>
|
|
<input name="attr_frenzy" value="1" type="checkbox" title="@{frenzy}"/>
|
|
</label>
|
|
<label class="input_row">
|
|
<h3 data-i18n="catatonic">catatonic</h3>
|
|
<input name="attr_catatonic" value="1" type="checkbox" title="@{catatonic}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="Consumables">
|
|
<h1>Consumables </h1>
|
|
<div class="sm_box">
|
|
<div class="input_row">
|
|
<button class="roller" name="roll_air" value="@{air_action}" type="roll">
|
|
<h3 data-i18n="air"></h3>
|
|
</button>
|
|
<button name="act_air-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_air_action" type="hidden" title="@{air_action}"/>
|
|
<label class="__big">
|
|
<input class="__big" name="attr_air" value="0" type="number" title="@{air}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="sm_box">
|
|
<div class="input_row">
|
|
<button class="roller" name="roll_food" value="@{food_action}" type="roll">
|
|
<h3 data-i18n="food"></h3>
|
|
</button>
|
|
<button name="act_food-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_food_action" type="hidden" title="@{food_action}"/>
|
|
<label class="__big">
|
|
<input class="__big" name="attr_food" value="0" type="number" title="@{food}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="sm_box">
|
|
<div class="input_row">
|
|
<button class="roller" name="roll_power" value="@{power_action}" type="roll">
|
|
<h3 data-i18n="power"></h3>
|
|
</button>
|
|
<button name="act_power-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_power_action" type="hidden" title="@{power_action}"/>
|
|
<label class="__big">
|
|
<input class="__big" name="attr_power" value="0" type="number" title="@{power}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="sm_box">
|
|
<div class="input_row">
|
|
<button class="roller" name="roll_water" value="@{water_action}" type="roll">
|
|
<h3 data-i18n="water"></h3>
|
|
</button>
|
|
<button name="act_water-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_water_action" type="hidden" title="@{water_action}"/>
|
|
<label class="__big">
|
|
<input class="__big" name="attr_water" value="0" type="number" title="@{water}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bioSection">
|
|
<div class="camelBox">
|
|
<h1>Name</h1>
|
|
<div class="input_row">
|
|
<input name="attr_character_name" type="text" title="@{character_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1>Career</h1>
|
|
<div class="input_row">
|
|
<input name="attr_career" type="text" title="@{career}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1>Appearance</h1>
|
|
<textarea name="attr_appearance_notes" title="@{appearance_notes}"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="attribute_section">
|
|
<div class="strength_segment">
|
|
<div class="skill_button __strength">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_strength" value="0" type="number" title="@{strength}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_strength" value="@{strength_action}">
|
|
<h3 data-i18n="strength"></h3>
|
|
</button>
|
|
<button name="act_strength-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_strength_action" type="hidden" title="@{strength_action}"/>
|
|
</div>
|
|
<div class="skill_button __heavy_machinery">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_heavy_machinery" value="0" type="number" title="@{heavy_machinery}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_heavy_machinery" value="@{heavy_machinery_action}">
|
|
<h3 data-i18n="heavy machinery"></h3>
|
|
</button>
|
|
<button name="act_heavy-machinery-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_heavy_machinery_action" type="hidden" title="@{heavy_machinery_action}"/>
|
|
</div>
|
|
<div class="skill_button __stamina">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_stamina" value="0" type="number" title="@{stamina}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_stamina" value="@{stamina_action}">
|
|
<h3 data-i18n="stamina"></h3>
|
|
</button>
|
|
<button name="act_stamina-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_stamina_action" type="hidden" title="@{stamina_action}"/>
|
|
</div>
|
|
<div class="skill_button __close_combat">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_close_combat" value="0" type="number" title="@{close_combat}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_close_combat" value="@{close_combat_action}">
|
|
<h3 data-i18n="close combat"></h3>
|
|
</button>
|
|
<button name="act_close-combat-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_close_combat_action" type="hidden" title="@{close_combat_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="agility_segment">
|
|
<div class="skill_button __agility">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_agility" value="0" type="number" title="@{agility}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_agility" value="@{agility_action}">
|
|
<h3 data-i18n="agility"></h3>
|
|
</button>
|
|
<button name="act_agility-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_agility_action" type="hidden" title="@{agility_action}"/>
|
|
</div>
|
|
<div class="skill_button __ranged_combat">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_ranged_combat" value="0" type="number" title="@{ranged_combat}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_ranged_combat" value="@{ranged_combat_action}">
|
|
<h3 data-i18n="ranged combat"></h3>
|
|
</button>
|
|
<button name="act_ranged-combat-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_ranged_combat_action" type="hidden" title="@{ranged_combat_action}"/>
|
|
</div>
|
|
<div class="skill_button __mobility">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_mobility" value="0" type="number" title="@{mobility}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_mobility" value="@{mobility_action}">
|
|
<h3 data-i18n="mobility"></h3>
|
|
</button>
|
|
<button name="act_mobility-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_mobility_action" type="hidden" title="@{mobility_action}"/>
|
|
</div>
|
|
<div class="skill_button __piloting">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_piloting" value="0" type="number" title="@{piloting}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_piloting" value="@{piloting_action}">
|
|
<h3 data-i18n="piloting"></h3>
|
|
</button>
|
|
<button name="act_piloting-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_piloting_action" type="hidden" title="@{piloting_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="wits_segment">
|
|
<div class="skill_button __wits">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_wits" value="0" type="number" title="@{wits}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_wits" value="@{wits_action}">
|
|
<h3 data-i18n="wits"></h3>
|
|
</button>
|
|
<button name="act_wits-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_wits_action" type="hidden" title="@{wits_action}"/>
|
|
</div>
|
|
<div class="skill_button __observation">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_observation" value="0" type="number" title="@{observation}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_observation" value="@{observation_action}">
|
|
<h3 data-i18n="observation"></h3>
|
|
</button>
|
|
<button name="act_observation-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_observation_action" type="hidden" title="@{observation_action}"/>
|
|
</div>
|
|
<div class="skill_button __survival">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_survival" value="0" type="number" title="@{survival}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_survival" value="@{survival_action}">
|
|
<h3 data-i18n="survival"></h3>
|
|
</button>
|
|
<button name="act_survival-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_survival_action" type="hidden" title="@{survival_action}"/>
|
|
</div>
|
|
<div class="skill_button __comtech">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_comtech" value="0" type="number" title="@{comtech}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_comtech" value="@{comtech_action}">
|
|
<h3 data-i18n="comtech"></h3>
|
|
</button>
|
|
<button name="act_comtech-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_comtech_action" type="hidden" title="@{comtech_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="empathy_segment">
|
|
<div class="skill_button __empathy">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_empathy" value="0" type="number" title="@{empathy}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_empathy" value="@{empathy_action}">
|
|
<h3 data-i18n="empathy"></h3>
|
|
</button>
|
|
<button name="act_empathy-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_empathy_action" type="hidden" title="@{empathy_action}"/>
|
|
</div>
|
|
<div class="skill_button __command">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_command" value="0" type="number" title="@{command}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_command" value="@{command_action}">
|
|
<h3 data-i18n="command"></h3>
|
|
</button>
|
|
<button name="act_command-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_command_action" type="hidden" title="@{command_action}"/>
|
|
</div>
|
|
<div class="skill_button __medical_aid">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_medical_aid" value="0" type="number" title="@{medical_aid}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_medical_aid" value="@{medical_aid_action}">
|
|
<h3 data-i18n="medical aid"></h3>
|
|
</button>
|
|
<button name="act_medical-aid-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_medical_aid_action" type="hidden" title="@{medical_aid_action}"/>
|
|
</div>
|
|
<div class="skill_button __manipulation">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_manipulation" value="0" type="number" title="@{manipulation}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_manipulation" value="@{manipulation_action}">
|
|
<h3 data-i18n="manipulation"></h3>
|
|
</button>
|
|
<button name="act_manipulation-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_manipulation_action" type="hidden" title="@{manipulation_action}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="combat">
|
|
<div class="box Armor short collapse-container edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Armor"></h1>
|
|
<div class="border short collapse-container"></div>
|
|
</div>
|
|
<div class="overlay short collapse-container">
|
|
<input class="collapse" name="attr_armor_collapse" value="1" type="checkbox" title="@{armor_collapse}"/>
|
|
<div class="input_row">
|
|
<button class="roll_icon firstedition roller" name="roll_armor" value="@{armor_action}" type="roll">
|
|
</button>
|
|
<button name="act_armor-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_armor_action" type="hidden" title="@{armor_action}"/>
|
|
<input name="attr_armor_name" type="text" title="@{armor_name}"/>
|
|
<input name="attr_armor" value="0" type="number" title="@{armor}"/>
|
|
</div>
|
|
<div class="input_row border expanded">
|
|
<label class="input-label"><span class="capitalize input-label__text" data-i18n="weight"></span>
|
|
<input class="input_row__border input-label__input" type="number" name="attr_armor_weight" title="@{armor_weight}"/>
|
|
</label>
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_armor_comment" title="@{armor_comment}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_armor_comment" placeholder="armor comment" title="@{armor_comment}"></textarea>
|
|
</div>
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_armor_description" title="@{armor_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_armor_description" placeholder="armor description" title="@{armor_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sm_box">
|
|
<div class="input_row">
|
|
<h3 data-i18n="encumbrance">encumbrance</h3>
|
|
<input name="attr_encumbrance" type="number" title="@{encumbrance}"/>/
|
|
<input name="attr_encumbrance_max" type="number" title="@{encumbrance|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="box Weapons edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Weapons"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay"><span class="__underline_items" hidden=""></span>
|
|
<fieldset class="repeating_weapons">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_weapons_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<button class="roll_icon roller" name="roll_roll" value="@{action}" type="roll">
|
|
</button>
|
|
<button name="act_action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_action" type="hidden" title="@{repeating_weapons_$X_action}"/>
|
|
<input name="attr_name" data-i18n-placeholder="weapon name" type="text" title="@{repeating_weapons_$X_name}"/>
|
|
<div class="dual-number">
|
|
<input name="attr_bonus" value="0" type="number" title="@{repeating_weapons_$X_bonus}"/>
|
|
<input name="attr_damage" value="0" type="number" title="@{repeating_weapons_$X_damage}"/>
|
|
</div>
|
|
</div>
|
|
<input class="display-control--not-zero" name="attr_ammo_max" value="" type="hidden" title="@{repeating_weapons_$X_ammo|max}"/>
|
|
<div class="input_row controlled-display secondedition justify-end second-row"><span class="capitalize" data-i18n="ammo"></span>
|
|
<div class="dual-number">
|
|
<input name="attr_ammo" type="number" title="@{repeating_weapons_$X_ammo}"/><span class="slash">/</span>
|
|
<input name="attr_ammo_max" readonly="" type="number" title="@{repeating_weapons_$X_ammo|max}"/>
|
|
</div>
|
|
</div>
|
|
<input class="display-control" name="attr_use_type" value="single" hidden="" type="checkbox" title="@{repeating_weapons_$X_use_type}"/>
|
|
<label class="input-label justify-space-between controlled-display input_row secondedition second-row"><span class="capitalize input-label__text" data-i18n="single shot"></span>
|
|
<input class="input-label__input" name="attr_quantity" type="number" value="1" title="@{repeating_weapons_$X_quantity}"/>
|
|
</label>
|
|
<div class="expanded border">
|
|
<div class="input_row--grid" style="grid-template-columns:1fr 1fr">
|
|
<div class="display-contents firstedition">
|
|
<select name="attr_type" title="@{repeating_weapons_$X_type}">
|
|
<option value="close_combat" data-i18n="close" selected="">
|
|
</option>
|
|
<option value="ranged_combat" data-i18n="ranged">
|
|
</option>
|
|
</select>
|
|
<select name="attr_range" title="@{repeating_weapons_$X_range}">
|
|
<option value="Engaged" data-i18n="engaged" selected="">
|
|
</option>
|
|
<option value="Short" data-i18n="short">
|
|
</option>
|
|
<option value="Medium" data-i18n="medium">
|
|
</option>
|
|
<option value="Long" data-i18n="long">
|
|
</option>
|
|
<option value="Extreme" data-i18n="extreme">
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="display-contents secondedition">
|
|
<label class="input-label grid-span-all"><span class="capitalize input-label__text" data-i18n="stat"></span>
|
|
<select class="input-label__input" name="attr_type" title="@{repeating_weapons_$X_type}">
|
|
<option value="close_combat" data-i18n="close" selected="">
|
|
</option>
|
|
<option value="ranged_combat" data-i18n="ranged">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<div class="input-label grid-span-all"><span class="capitalize input-label__text" data-i18n="range"></span>
|
|
<select name="attr_range" title="@{repeating_weapons_$X_range}">
|
|
<option value="Adjacent" data-i18n="a" selected="">
|
|
</option>
|
|
<option value="Short" data-i18n="s">
|
|
</option>
|
|
<option value="Medium" data-i18n="m">
|
|
</option>
|
|
<option value="Long" data-i18n="l">
|
|
</option>
|
|
<option value="Extreme" data-i18n="e">
|
|
</option>
|
|
</select><span class="slash">/</span>
|
|
<select name="attr_range_max" title="@{repeating_weapons_$X_range|max}">
|
|
<option value="Adjacent" data-i18n="a" selected="">
|
|
</option>
|
|
<option value="Short" data-i18n="s">
|
|
</option>
|
|
<option value="Medium" data-i18n="m">
|
|
</option>
|
|
<option value="Long" data-i18n="l">
|
|
</option>
|
|
<option value="Extreme" data-i18n="e">
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="input_row input-label justify-space-between second-row">
|
|
<select class="capitalize" name="attr_use_type" title="@{repeating_weapons_$X_use_type}">
|
|
<option value="air/power" data-i18n="Ammunition" selected="">
|
|
</option>
|
|
<option value="single" data-i18n="single shot">
|
|
</option>
|
|
</select>
|
|
<input class="display-control" name="attr_use_type" value="air/power" hidden="" checked="" type="checkbox" title="@{repeating_weapons_$X_use_type}"/>
|
|
<input class="controlled-display" name="attr_ammo_max" type="number" title="@{repeating_weapons_$X_ammo|max}"/>
|
|
</div>
|
|
<label class="input-label input_row secondedition"><span class="capitalize input-label__text" data-i18n="weight"></span>
|
|
<input class="input-label__input" type="number" name="attr_weight" title="@{repeating_weapons_$X_weight}"/>
|
|
</label>
|
|
<label class="input-label input_row"><span class="capitalize input-label__text" data-i18n="comments"></span>
|
|
<input class="input_row__border input-label__input" type="text" name="attr_comment" title="@{repeating_weapons_$X_comment}"/>
|
|
</label>
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_weapons_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" data-i18n-placeholder="weapon description" title="@{repeating_weapons_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Talents repeat_menu collapse-container edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Talents"></h1>
|
|
<div class="border repeat_menu collapse-container"></div>
|
|
</div>
|
|
<div class="overlay repeat_menu collapse-container">
|
|
<input class="collapse" name="attr_talent_collapse" value="1" type="checkbox" title="@{talent_collapse}"/>
|
|
<input name="attr_talent_id" type="hidden" title="@{talent_id}"/>
|
|
<input name="attr_talent_name" id="talent_name" data-i18n-placeholder="talent name" type="text" title="@{talent_name}"/>
|
|
<div class="talent_details collapse-container">
|
|
<textarea name="attr_talent_description" data-i18n-placeholder="talent description" title="@{talent_description}"></textarea>
|
|
<label class="input-label expanded"><span class="capitalize input-label__text" data-i18n="push"></span>
|
|
<input class="expanded input-label__input" name="attr_talent_push_twice" type="text" value="1" data-i18n-placeholder="e.g. agility" title="@{talent_push_twice}"/>
|
|
</label>
|
|
</div>
|
|
<button class="repcontrol-button repcontrol-button--add" name="act_add-talents" type="action">
|
|
</button>
|
|
<fieldset class="repeating_talents">
|
|
<input class="active-control" name="attr_active" hidden="" value="1" type="checkbox" title="@{repeating_talents_$X_active}"/>
|
|
<button name="act_display" type="action"><span name="attr_name" title="@{repeating_talents_$X_name}"></span>
|
|
<input name="attr_description" type="hidden" title="@{repeating_talents_$X_description}"/>
|
|
<input name="attr_push_twice" type="hidden" title="@{repeating_talents_$X_push_twice}"/>
|
|
</button>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div class="box Experience_Points short edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Experience Points"></h1>
|
|
<div class="border short"></div>
|
|
</div>
|
|
<div class="overlay short">
|
|
<div class="fill-left experience_points">
|
|
<input class="fill-left__radio" name="attr_experience_points" value="0" type="hidden" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="1" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="2" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="3" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="4" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="5" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="6" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="7" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="8" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="9" type="checkbox" title="@{experience_points}"/>
|
|
<input class="fill-left__radio" name="attr_experience_points" value="10" type="checkbox" title="@{experience_points}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Story_Points edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Story Points"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="fill-left story_points">
|
|
<input class="fill-left__radio" name="attr_story_points" value="0" checked="" type="radio" title="@{story_points}"/>
|
|
<input class="fill-left__radio" name="attr_story_points" value="1" type="radio" title="@{story_points}"/>
|
|
<input class="fill-left__radio" name="attr_story_points" value="2" type="radio" title="@{story_points}"/>
|
|
<input class="fill-left__radio" name="attr_story_points" value="3" type="radio" title="@{story_points}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Tiny_Items edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Tiny Items"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<textarea name="attr_tiny_items" title="@{tiny_items}"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="inventory">
|
|
<div class="box Signature_Item edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Signature Item"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="input_row">
|
|
<input name="attr_signature_item" type="text" title="@{signature_item}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box gear edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="gear"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay"><span class="underline_items" hidden=""></span>
|
|
<fieldset class="repeating_gear">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_gear_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<input name="attr_name" placeholder="gear name" type="text" title="@{repeating_gear_$X_name}"/>
|
|
<input name="attr_weight" value="1" type="number" title="@{repeating_gear_$X_weight}"/>
|
|
</div>
|
|
<input class="display-control--not-zero" name="attr_power_max" value="" type="hidden" title="@{repeating_gear_$X_power|max}"/>
|
|
<div class="input_row controlled-display secondedition justify-end second-row">
|
|
<button class="uppercase roll_icon icon_hover roller" name="roll_air_power" data-i18n="air/power" value="@{air_power_action}" type="roll">
|
|
</button>
|
|
<button name="act_air-power-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_air_power_action" type="hidden" title="@{repeating_gear_$X_air_power_action}"/>
|
|
<div class="dual-number">
|
|
<input name="attr_power" type="number" title="@{repeating_gear_$X_power}"/><span class="slash">/</span>
|
|
<input name="attr_power_max" readonly="" type="number" title="@{repeating_gear_$X_power|max}"/>
|
|
</div>
|
|
</div>
|
|
<input class="display-control" name="attr_use_type" value="single" hidden="" type="checkbox" title="@{repeating_gear_$X_use_type}"/>
|
|
<label class="input-label justify-space-between controlled-display input_row secondedition second-row"><span class="capitalize input-label__text" data-i18n="single use"></span>
|
|
<input class="input-label__input" name="attr_quantity" type="number" value="1" title="@{repeating_gear_$X_quantity}"/>
|
|
</label>
|
|
<div class="expanded border">
|
|
<label class="input-label input_row"><span class="capitalize input-label__text" data-i18n="effect"></span>
|
|
<input class="input_row__border input-label__input" type="text" name="attr_effect" title="@{repeating_gear_$X_effect}"/>
|
|
</label>
|
|
<div class="input_row input-label justify-space-between second-row">
|
|
<select class="capitalize" name="attr_use_type" title="@{repeating_gear_$X_use_type}">
|
|
<option value="air/power" data-i18n="air/power" selected="">
|
|
</option>
|
|
<option value="single" data-i18n="single use">
|
|
</option>
|
|
</select>
|
|
<input class="display-control" name="attr_use_type" value="air/power" hidden="" checked="" type="checkbox" title="@{repeating_gear_$X_use_type}"/>
|
|
<input class="controlled-display" name="attr_power_max" type="number" title="@{repeating_gear_$X_power|max}"/>
|
|
</div>
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_gear_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" data-i18n-placeholder="gear description" title="@{repeating_gear_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--npc" data-container-tab="menu" data-tab="npc">
|
|
<div class="tab npc">
|
|
<div class="camelBox">
|
|
<h1 data-i18n="name"></h1>
|
|
<div class="input_row">
|
|
<input name="attr_character_name" type="text" autocomplete="off" title="@{character_name}"/>
|
|
</div>
|
|
</div><img class="portrait" name="attr_character_avatar"/>
|
|
<div class="box Records edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Records"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="title"></h3>
|
|
<input name="attr_title" type="text" autocomplete="off" title="@{title}"/>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="nickname"></h3>
|
|
<input name="attr_nickname" type="text" autocomplete="nope" title="@{nickname}"/>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="age"></h3>
|
|
<input name="attr_age" type="text" autocomplete="off" title="@{age}"/>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="personality"></h3>
|
|
<input name="attr_personality" type="text" title="@{personality}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Biography edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Biography"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<textarea name="attr_biography" title="@{biography}"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="box Personal_Agenda edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Personal Agenda"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<textarea name="attr_personal_agenda" title="@{personal_agenda}"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="box Data edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Data"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="attributes"></h3>
|
|
<input name="attr_strength" type="hidden" title="@{strength}"/>
|
|
<div class="skill_button __strength">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_strength" value="0" type="number" title="@{strength}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_strength" value="@{strength_action}">
|
|
<h3 data-i18n="strength"></h3>
|
|
</button>
|
|
<button name="act_strength-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_strength_action" type="hidden" title="@{strength_action}"/>
|
|
</div>
|
|
<input name="attr_agility" type="hidden" title="@{agility}"/>
|
|
<div class="skill_button __agility">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_agility" value="0" type="number" title="@{agility}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_agility" value="@{agility_action}">
|
|
<h3 data-i18n="agility"></h3>
|
|
</button>
|
|
<button name="act_agility-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_agility_action" type="hidden" title="@{agility_action}"/>
|
|
</div>
|
|
<input name="attr_wits" type="hidden" title="@{wits}"/>
|
|
<div class="skill_button __wits">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_wits" value="0" type="number" title="@{wits}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_wits" value="@{wits_action}">
|
|
<h3 data-i18n="wits"></h3>
|
|
</button>
|
|
<button name="act_wits-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_wits_action" type="hidden" title="@{wits_action}"/>
|
|
</div>
|
|
<input name="attr_empathy" type="hidden" title="@{empathy}"/>
|
|
<div class="skill_button __empathy">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_empathy" value="0" type="number" title="@{empathy}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_empathy" value="@{empathy_action}">
|
|
<h3 data-i18n="empathy"></h3>
|
|
</button>
|
|
<button name="act_empathy-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_empathy_action" type="hidden" title="@{empathy_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="skills"></h3>
|
|
<input class="reveal" name="attr_reveal_skills" value="1" checked="" type="checkbox" title="@{reveal_skills}"/>
|
|
<input name="attr_heavy_machinery" type="hidden" title="@{heavy_machinery}"/>
|
|
<div class="skill_button __heavy_machinery">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_heavy_machinery" value="0" type="number" title="@{heavy_machinery}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_heavy_machinery" value="@{heavy_machinery_action}">
|
|
<h3 data-i18n="heavy machinery"></h3>
|
|
</button>
|
|
<button name="act_heavy-machinery-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_heavy_machinery_action" type="hidden" title="@{heavy_machinery_action}"/>
|
|
</div>
|
|
<input name="attr_stamina" type="hidden" title="@{stamina}"/>
|
|
<div class="skill_button __stamina">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_stamina" value="0" type="number" title="@{stamina}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_stamina" value="@{stamina_action}">
|
|
<h3 data-i18n="stamina"></h3>
|
|
</button>
|
|
<button name="act_stamina-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_stamina_action" type="hidden" title="@{stamina_action}"/>
|
|
</div>
|
|
<input name="attr_close_combat" type="hidden" title="@{close_combat}"/>
|
|
<div class="skill_button __close_combat">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_close_combat" value="0" type="number" title="@{close_combat}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_close_combat" value="@{close_combat_action}">
|
|
<h3 data-i18n="close combat"></h3>
|
|
</button>
|
|
<button name="act_close-combat-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_close_combat_action" type="hidden" title="@{close_combat_action}"/>
|
|
</div>
|
|
<input name="attr_ranged_combat" type="hidden" title="@{ranged_combat}"/>
|
|
<div class="skill_button __ranged_combat">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_ranged_combat" value="0" type="number" title="@{ranged_combat}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_ranged_combat" value="@{ranged_combat_action}">
|
|
<h3 data-i18n="ranged combat"></h3>
|
|
</button>
|
|
<button name="act_ranged-combat-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_ranged_combat_action" type="hidden" title="@{ranged_combat_action}"/>
|
|
</div>
|
|
<input name="attr_mobility" type="hidden" title="@{mobility}"/>
|
|
<div class="skill_button __mobility">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_mobility" value="0" type="number" title="@{mobility}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_mobility" value="@{mobility_action}">
|
|
<h3 data-i18n="mobility"></h3>
|
|
</button>
|
|
<button name="act_mobility-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_mobility_action" type="hidden" title="@{mobility_action}"/>
|
|
</div>
|
|
<input name="attr_piloting" type="hidden" title="@{piloting}"/>
|
|
<div class="skill_button __piloting">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_piloting" value="0" type="number" title="@{piloting}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_piloting" value="@{piloting_action}">
|
|
<h3 data-i18n="piloting"></h3>
|
|
</button>
|
|
<button name="act_piloting-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_piloting_action" type="hidden" title="@{piloting_action}"/>
|
|
</div>
|
|
<input name="attr_observation" type="hidden" title="@{observation}"/>
|
|
<div class="skill_button __observation">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_observation" value="0" type="number" title="@{observation}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_observation" value="@{observation_action}">
|
|
<h3 data-i18n="observation"></h3>
|
|
</button>
|
|
<button name="act_observation-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_observation_action" type="hidden" title="@{observation_action}"/>
|
|
</div>
|
|
<input name="attr_survival" type="hidden" title="@{survival}"/>
|
|
<div class="skill_button __survival">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_survival" value="0" type="number" title="@{survival}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_survival" value="@{survival_action}">
|
|
<h3 data-i18n="survival"></h3>
|
|
</button>
|
|
<button name="act_survival-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_survival_action" type="hidden" title="@{survival_action}"/>
|
|
</div>
|
|
<input name="attr_comtech" type="hidden" title="@{comtech}"/>
|
|
<div class="skill_button __comtech">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_comtech" value="0" type="number" title="@{comtech}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_comtech" value="@{comtech_action}">
|
|
<h3 data-i18n="comtech"></h3>
|
|
</button>
|
|
<button name="act_comtech-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_comtech_action" type="hidden" title="@{comtech_action}"/>
|
|
</div>
|
|
<input name="attr_command" type="hidden" title="@{command}"/>
|
|
<div class="skill_button __command">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_command" value="0" type="number" title="@{command}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_command" value="@{command_action}">
|
|
<h3 data-i18n="command"></h3>
|
|
</button>
|
|
<button name="act_command-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_command_action" type="hidden" title="@{command_action}"/>
|
|
</div>
|
|
<input name="attr_medical_aid" type="hidden" title="@{medical_aid}"/>
|
|
<div class="skill_button __medical_aid">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_medical_aid" value="0" type="number" title="@{medical_aid}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_medical_aid" value="@{medical_aid_action}">
|
|
<h3 data-i18n="medical aid"></h3>
|
|
</button>
|
|
<button name="act_medical-aid-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_medical_aid_action" type="hidden" title="@{medical_aid_action}"/>
|
|
</div>
|
|
<input name="attr_manipulation" type="hidden" title="@{manipulation}"/>
|
|
<div class="skill_button __manipulation">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_manipulation" value="0" type="number" title="@{manipulation}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_manipulation" value="@{manipulation_action}">
|
|
<h3 data-i18n="manipulation"></h3>
|
|
</button>
|
|
<button name="act_manipulation-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_manipulation_action" type="hidden" title="@{manipulation_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="talent"></h3><span class="inline_repeating no_control" hidden=""></span>
|
|
<fieldset class="repeating_talents">
|
|
<div class="tooltip-container"><span class="tooltip-control" name="attr_name" title="@{repeating_talents_$X_name}"></span>
|
|
<div class="adaptive adaptive--text tooltip-target border expanded"><span class="adaptive--text__span" name="attr_description" title="@{repeating_talents_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" title="@{repeating_talents_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="buddy"></h3>
|
|
<input name="attr_buddy" type="text" title="@{buddy}"/>
|
|
</div>
|
|
<div class="input_row">
|
|
<h3 class="colon" data-i18n="rival"></h3>
|
|
<input name="attr_rival" type="text" title="@{rival}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Gear edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Gear"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div><span class="inline_repeating no_control" hidden=""></span>
|
|
<fieldset class="repeating_weapons">
|
|
<label class="skill_button">
|
|
<button class="roller" name="roll_roll" value="@{action}" type="roll">
|
|
<h3><span name="attr_name" title="@{repeating_weapons_$X_name}"></span>
|
|
</h3>
|
|
</button>
|
|
<button name="act_action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_action" type="hidden" title="@{repeating_weapons_$X_action}"/>
|
|
</label>
|
|
</fieldset><span class="inline_repeating" hidden=""></span>
|
|
<fieldset class="repeating_gear">
|
|
<div class="adaptive adaptive--input" style="min-width:6ch;"><span class="adaptive--input__span" name="attr_name" title="@{repeating_gear_$X_name}"></span>
|
|
<input class="adaptive--input__input" name="attr_name" type="text" data-i18n-placeholder="name" title="@{repeating_gear_$X_name}"/>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--hostile" data-container-tab="menu" data-tab="hostile">
|
|
<div class="tab hostile">
|
|
<div class="name">
|
|
<div class="camelBox">
|
|
<div class="input_row">
|
|
<h1 data-i18n="hostile"></h1>
|
|
<input name="attr_character_name" type="text" title="@{character_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<div class="input_row">
|
|
<h1 data-i18n="stage"></h1>
|
|
<input name="attr_stage" type="text" title="@{stage}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="attributes">
|
|
<input name="attr_mobility" type="hidden" title="@{mobility}"/>
|
|
<div class="skill_button __mobility">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_mobility" value="0" type="number" title="@{mobility}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_mobility" value="@{mobility_action}">
|
|
<h3 data-i18n="mobility"></h3>
|
|
</button>
|
|
<button name="act_mobility-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_mobility_action" type="hidden" title="@{mobility_action}"/>
|
|
</div>
|
|
<input name="attr_observation" type="hidden" title="@{observation}"/>
|
|
<div class="skill_button __observation">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_observation" value="0" type="number" title="@{observation}"/>
|
|
</label>
|
|
<button class="roller" type="roll" name="roll_observation" value="@{observation_action}">
|
|
<h3 data-i18n="observation"></h3>
|
|
</button>
|
|
<button name="act_observation-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_observation_action" type="hidden" title="@{observation_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="combat_stats">
|
|
<div class="box Health edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Health"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="input_row">
|
|
<div class="fill-left health_level">
|
|
<input class="fill-left__radio" name="attr_health_level" value="0" type="hidden" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="1" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="2" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="3" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="4" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="5" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="6" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="7" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="8" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="9" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="10" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="11" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="12" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="13" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="14" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="15" type="checkbox" title="@{health_level}"/>
|
|
<input class="fill-left__radio" name="attr_health_level" value="16" type="checkbox" title="@{health_level}"/>
|
|
</div>
|
|
<label class="__big">
|
|
<input name="attr_health_max" value="8" type="number" title="@{health|max}"/>
|
|
</label>
|
|
</div>
|
|
<div class="collapse-container">
|
|
<input class="collapse" name="attr_armor_collapse" value="1" type="checkbox" title="@{armor_collapse}"/>
|
|
<div class="input_row">
|
|
<button class="roll_icon roller" name="roll_armor" value="@{armor_action}" type="roll">
|
|
</button>
|
|
<button name="act_armor-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_armor_action" type="hidden" title="@{armor_action}"/>
|
|
<h3 data-i18n="armor rating:"></h3>
|
|
<label class="__big margin-justify-right">
|
|
<input name="attr_armor" type="number" title="@{armor}"/>
|
|
</label>
|
|
<input name="attr_armor_description" type="text" title="@{armor_description}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button input_row">
|
|
<h3 data-i18n="speed"></h3>
|
|
<label class="__big">
|
|
<input name="attr_Speed" value="0" type="number" title="@{Speed}"/>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="box Information edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Information"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_information" title="@{information}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_information" title="@{information}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box Containment_and_Termination_Protocols edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Containment and Termination Protocols"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_containment" title="@{containment}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_containment" title="@{containment}"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box multibox attack_table">
|
|
<button class="roll_icon roller" name="roll_attacks" role="heading" aria-level="1" data-i18n="attacks" value="@{attacks_action}" type="roll">
|
|
</button>
|
|
<button name="act_attacks-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_attacks_action" type="hidden" title="@{attacks_action}"/>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="chance"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="name"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="bonus"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="damage"></h2>
|
|
</div>
|
|
<fieldset class="repeating_signature">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_signature_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<button class="roll_icon input_row__borderless roller" name="roll_roll" value="@{action}" type="roll">
|
|
</button>
|
|
<button name="act_action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_action" type="hidden" title="@{repeating_signature_$X_action}"/>
|
|
<input name="attr_chance" type="number" title="@{repeating_signature_$X_chance}"/>
|
|
<input name="attr_name" value="" type="text" title="@{repeating_signature_$X_name}"/>
|
|
<input name="attr_bonus" type="number" title="@{repeating_signature_$X_bonus}"/>
|
|
<input name="attr_damage" type="number" title="@{repeating_signature_$X_damage}"/>
|
|
</div>
|
|
<div class="input_row border span-all expanded">
|
|
<div class="adaptive adaptive--text span-all" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_description" title="@{repeating_signature_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" title="@{repeating_signature_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox ability_table">
|
|
<h1 data-i18n="abilities"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="name"></h2>
|
|
</div>
|
|
<fieldset class="repeating_abilities">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_abilities_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<button class="roll_icon input_row__borderless" name="roll_roll" value="@{template_start} {{title=@{name}}} {{description=@{description}}}" type="roll">
|
|
</button>
|
|
<input name="attr_name" value="" type="text" title="@{repeating_abilities_$X_name}"/>
|
|
</div>
|
|
<div class="input_row border span-all expanded">
|
|
<div class="adaptive adaptive--text span-all" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_description" title="@{repeating_abilities_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" title="@{repeating_abilities_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--ship" data-container-tab="menu" data-tab="ship">
|
|
<div class="tab ship">
|
|
<div class="ship_top">
|
|
<div class="ship_modules">
|
|
<div class="box multibox Internal_Modules">
|
|
<h1 data-i18n="internal modules"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="qty"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="size"></h2>
|
|
</div>
|
|
<fieldset class="repeating_internal-modules">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_internal-modules_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<div class="flex-box tiny-gap input_row__borderless">
|
|
<input name="attr_online" value="1" checked="" type="checkbox" title="@{repeating_internal-modules_$X_online}"/>
|
|
<input class="input_row__border" name="attr_name" value="" data-i18n-placeholder="internal module" type="text" title="@{repeating_internal-modules_$X_name}"/>
|
|
</div>
|
|
<input name="attr_quantity" type="number" title="@{repeating_internal-modules_$X_quantity}"/>
|
|
<input name="attr_size" type="text" title="@{repeating_internal-modules_$X_size}"/>
|
|
</div>
|
|
<div class="input_row border expanded">
|
|
<label class="input-label justify-content-space-between span-all"><span class="input-label__text" data-i18n="type"></span>
|
|
<select class="input-label__input" name="attr_type" title="@{repeating_internal-modules_$X_type}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="artificial intelligence" data-i18n="artificial intelligence">
|
|
</option>
|
|
<option value="air scrubber" data-i18n="air scrubber">
|
|
</option>
|
|
<option value="cargo bay" data-i18n="cargo bay">
|
|
</option>
|
|
<option value="corporate suite" data-i18n="corporate suite">
|
|
</option>
|
|
<option value="cryo deck" data-i18n="cryo deck">
|
|
</option>
|
|
<option value="docking umbilical" data-i18n="docking umbilical">
|
|
</option>
|
|
<option value="emergency escape vehicle" data-i18n="emergency escape vehicle">
|
|
</option>
|
|
<option value="galley" data-i18n="galley">
|
|
</option>
|
|
<option value="hangar" data-i18n="hangar">
|
|
</option>
|
|
<option value="medlab" data-i18n="medlab">
|
|
</option>
|
|
<option value="salvage crane" data-i18n="salvage crane">
|
|
</option>
|
|
<option value="science lab" data-i18n="science lab">
|
|
</option>
|
|
<option value="tractor hitch" data-i18n="tractor hitch">
|
|
</option>
|
|
<option value="vehicle bay" data-i18n="vehicle bay">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<input class="display-control" name="attr_type" hidden="" value="artificial intelligence" type="checkbox" title="@{repeating_internal-modules_$X_type}"/>
|
|
<div class="input_row border expanded">
|
|
<label class="input-label flex-box tiny-gap justify-content-space-between" style="width:100%;margin:0;"><span class="input-label__text" data-i18n="comtech" style="white-space:nowrap;text-overflow:ellipsis;overflow:hidden;"></span>
|
|
<input class="input-label__input" type="number" name="attr_ai_comtech" title="@{repeating_internal-modules_$X_ai_comtech}"/>
|
|
</label>
|
|
<label class="input-label flex-box tiny-gap justify-content-space-between" style="width:100%;margin:0;"><span class="input-label__text" data-i18n="piloting" style="white-space:nowrap;text-overflow:ellipsis;overflow:hidden;"></span>
|
|
<input class="input-label__input" type="number" name="attr_ai_piloting" title="@{repeating_internal-modules_$X_ai_piloting}"/>
|
|
</label>
|
|
<label class="input-label flex-box tiny-gap justify-content-space-between" style="width:100%;margin:0;"><span class="input-label__text" data-i18n="observation" style="white-space:nowrap;text-overflow:ellipsis;overflow:hidden;"></span>
|
|
<input class="input-label__input" type="number" name="attr_ai_observation" title="@{repeating_internal-modules_$X_ai_observation}"/>
|
|
</label>
|
|
<label class="input-label flex-box tiny-gap justify-content-space-between" style="width:100%;margin:0;"><span class="input-label__text" data-i18n="ranged combat" style="white-space:nowrap;text-overflow:ellipsis;overflow:hidden;"></span>
|
|
<input class="input-label__input" type="number" name="attr_ai_ranged_combat" title="@{repeating_internal-modules_$X_ai_ranged_combat}"/>
|
|
</label>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box Lease_Cost bottom edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Lease Cost"></h1>
|
|
<div class="border bottom"></div>
|
|
</div>
|
|
<div class="overlay bottom">
|
|
<div class="input_row">
|
|
<input name="attr_lease_cost" type="text" title="@{lease_cost}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="ship_information">
|
|
<div class="camelBox">
|
|
<h1 data-i18n="name"></h1>
|
|
<div class="input_row">
|
|
<input name="attr_character_name" type="text" title="@{character_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1 data-i18n="manufacturer"></h1>
|
|
<div class="input_row">
|
|
<input name="attr_manufacturer" type="text" title="@{manufacturer}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1 class="uppercase" data-i18n="ai"></h1>
|
|
<div class="input_row">
|
|
<input name="attr_ai" type="text" title="@{ai}"/>
|
|
</div>
|
|
</div>
|
|
<div class="left_attributes">
|
|
<input name="attr_hull" value="0" type="hidden" title="@{hull}"/>
|
|
<div class="skill_button __crew no-hover">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_crew" value="0" type="number" title="@{crew}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="crew"></h3>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button __length no-hover">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_length" value="0" type="number" title="@{length}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="length"></h3>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button __passengers no-hover">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_passengers" value="0" type="number" title="@{passengers}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="passengers"></h3>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button __hull">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_hull_max" value="0" type="number" title="@{hull|max}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="hull"></h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="right_attributes">
|
|
<div class="skill_button __signature">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_signature" value="0" type="number" title="@{signature}"/>
|
|
</label>
|
|
<button class="roller" name="roll_signature" value="@{signature_action}" type="roll">
|
|
<h3 data-i18n="signature"></h3>
|
|
</button>
|
|
<button name="act_signature-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_signature_action" type="hidden" title="@{signature_action}"/>
|
|
</div>
|
|
<div class="skill_button __ftl_rating">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_ftl_rating" value="0" type="number" title="@{ftl_rating}"/>
|
|
</label>
|
|
<button class="roller" name="roll_ftl_rating" value="@{ftl_rating_action}" type="roll">
|
|
<h3 data-i18n="ftl rating"></h3>
|
|
</button>
|
|
<button name="act_ftl-rating-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_ftl_rating_action" type="hidden" title="@{ftl_rating_action}"/>
|
|
</div>
|
|
<div class="skill_button __thrusters">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_thrusters" value="0" type="number" title="@{thrusters}"/>
|
|
</label>
|
|
<button class="roller" name="roll_thrusters" value="@{thrusters_action}" type="roll">
|
|
<h3 data-i18n="thrusters"></h3>
|
|
</button>
|
|
<button name="act_thrusters-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_thrusters_action" type="hidden" title="@{thrusters_action}"/>
|
|
</div>
|
|
<div class="skill_button __armor">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_armor" value="0" type="number" title="@{armor}"/>
|
|
</label>
|
|
<button class="roller" name="roll_armor" value="@{armor_action}" type="roll">
|
|
<h3 data-i18n="armor"></h3>
|
|
</button>
|
|
<button name="act_armor-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_armor_action" type="hidden" title="@{armor_action}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1 data-i18n="damage"></h1>
|
|
<div class="fill-left ship_damage">
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="0" checked="" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="1" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="2" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="3" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="4" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="5" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="6" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="7" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="8" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="9" type="radio" title="@{ship_damage}"/>
|
|
<input class="fill-left__radio" name="attr_ship_damage" value="10" type="radio" title="@{ship_damage}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box multibox Ships_Log">
|
|
<h1 data-i18n="ship's log"></h1>
|
|
<div class="border">
|
|
<h2 data-i18n="date"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="location"></h2>
|
|
</div>
|
|
<fieldset class="repeating_ships-log">
|
|
<div class="input_row">
|
|
<input name="attr_date" value="" placeholder="Date" type="text" title="@{date}"/>
|
|
<input name="attr_location" value="" placeholder="Location" type="text" title="@{location}"/>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div class="ship_bottom">
|
|
<div class="box multibox component_damage">
|
|
<h1 data-i18n="minor component damage"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="skill 1"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="skill 2"></h2>
|
|
</div>
|
|
<fieldset class="repeating_minor-component-damage">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_minor-component-damage_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<input class="input_row__border" name="attr_name" value="" type="text" title="@{repeating_minor-component-damage_$X_name}"/>
|
|
<div class="input-label input_row__borderless justify-self-center" style="width:fit-content">
|
|
<button class="roll_icon roller" name="roll_skill_1" value="@{skill_1_action}" type="roll">
|
|
</button>
|
|
<button name="act_skill-1-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_skill_1_action" type="hidden" title="@{repeating_minor-component-damage_$X_skill_1_action}"/>
|
|
<input class="input_row__border" name="attr_skill_1_completed" type="number" title="@{repeating_minor-component-damage_$X_skill_1_completed}"/><span>/</span>
|
|
<input class="input_row__border" name="attr_skill_1_completed_max" type="number" title="@{repeating_minor-component-damage_$X_skill_1_completed|max}"/>
|
|
</div>
|
|
<div class="input-label input_row__borderless justify-self-center" style="width:fit-content">
|
|
<button class="roll_icon roller" name="roll_skill_2" value="@{skill_2_action}" type="roll">
|
|
</button>
|
|
<button name="act_skill-2-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_skill_2_action" type="hidden" title="@{repeating_minor-component-damage_$X_skill_2_action}"/>
|
|
<input class="input_row__border" name="attr_skill_2_completed" type="number" title="@{repeating_minor-component-damage_$X_skill_2_completed}"/><span>/</span>
|
|
<input class="input_row__border" name="attr_skill_2_completed_max" type="number" title="@{repeating_minor-component-damage_$X_skill_2_completed|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="input_row expanded border">
|
|
<label class="input-label input_row__borderless"><span class="input-label__text" data-i18n="skill 1"></span>
|
|
<select class="input-label__input" name="attr_skill_1" title="@{repeating_minor-component-damage_$X_skill_1}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="heavy_machinery" data-i18n="heavy machinery">
|
|
</option>
|
|
<option value="comtech" data-i18n="comtech">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label class="input-label input_row__borderless"><span class="input-label__text" data-i18n="skill 2"></span>
|
|
<select class="input-label__input" name="attr_skill_2" title="@{repeating_minor-component-damage_$X_skill_2}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="heavy_machinery" data-i18n="heavy machinery">
|
|
</option>
|
|
<option value="comtech" data-i18n="comtech">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<div class="adaptive adaptive--text span-all input_row__border" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_effect" title="@{repeating_minor-component-damage_$X_effect}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_effect" value="" placeholder="Effect" title="@{repeating_minor-component-damage_$X_effect}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox component_damage">
|
|
<h1 data-i18n="major component damage"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="skill 1"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="skill 2"></h2>
|
|
</div>
|
|
<fieldset class="repeating_major-component-damage">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_major-component-damage_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<input class="input_row__border" name="attr_name" value="" type="text" title="@{repeating_major-component-damage_$X_name}"/>
|
|
<div class="input-label input_row__borderless justify-self-center" style="width:fit-content">
|
|
<button class="roll_icon roller" name="roll_skill_1" value="@{skill_1_action}" type="roll">
|
|
</button>
|
|
<button name="act_skill-1-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_skill_1_action" type="hidden" title="@{repeating_major-component-damage_$X_skill_1_action}"/>
|
|
<input class="input_row__border" name="attr_skill_1_completed" type="number" title="@{repeating_major-component-damage_$X_skill_1_completed}"/><span>/</span>
|
|
<input class="input_row__border" name="attr_skill_1_completed_max" type="number" title="@{repeating_major-component-damage_$X_skill_1_completed|max}"/>
|
|
</div>
|
|
<div class="input-label input_row__borderless justify-self-center" style="width:fit-content">
|
|
<button class="roll_icon roller" name="roll_skill_2" value="@{skill_2_action}" type="roll">
|
|
</button>
|
|
<button name="act_skill-2-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_skill_2_action" type="hidden" title="@{repeating_major-component-damage_$X_skill_2_action}"/>
|
|
<input class="input_row__border" name="attr_skill_2_completed" type="number" title="@{repeating_major-component-damage_$X_skill_2_completed}"/><span>/</span>
|
|
<input class="input_row__border" name="attr_skill_2_completed_max" type="number" title="@{repeating_major-component-damage_$X_skill_2_completed|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="input_row expanded border">
|
|
<label class="input-label input_row__borderless"><span class="input-label__text" data-i18n="skill 1"></span>
|
|
<select class="input-label__input" name="attr_skill_1" title="@{repeating_major-component-damage_$X_skill_1}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="heavy_machinery" data-i18n="heavy machinery">
|
|
</option>
|
|
<option value="comtech" data-i18n="comtech">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label class="input-label input_row__borderless"><span class="input-label__text" data-i18n="skill 2"></span>
|
|
<select class="input-label__input" name="attr_skill_2" title="@{repeating_major-component-damage_$X_skill_2}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="heavy_machinery" data-i18n="heavy machinery">
|
|
</option>
|
|
<option value="comtech" data-i18n="comtech">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<div class="adaptive adaptive--text span-all input_row__border" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_effect" title="@{repeating_major-component-damage_$X_effect}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_effect" value="" placeholder="Effect" title="@{repeating_major-component-damage_$X_effect}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox Upgrades short">
|
|
<h1 data-i18n="upgrades"></h1>
|
|
<div class="border">
|
|
<h2 data-i18n="quantity-abbreviation"></h2>
|
|
</div>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="effect"></h2>
|
|
</div>
|
|
<fieldset class="repeating_upgrades">
|
|
<div class="input_row">
|
|
<input name="attr_quantity" type="number" title="@{repeating_upgrades_$X_quantity}"/>
|
|
<input name="attr_name" value="" placeholder="Upgrade" type="text" title="@{repeating_upgrades_$X_name}"/>
|
|
<input name="attr_effect" value="" placeholder="Effect" type="text" title="@{repeating_upgrades_$X_effect}"/>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox Armaments edition-style">
|
|
<h1 data-i18n="armaments"></h1>
|
|
<div class="border"> </div>
|
|
<div class="border">
|
|
<h2 data-i18n="bonus"> </h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="damage"> </h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="range"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="size"></h2>
|
|
</div>
|
|
<fieldset class="repeating_armaments">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_armaments_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<div class="group flex-box input_row__borderless">
|
|
<button class="roll_icon roller" name="roll_roll" value="@{action}" type="roll">
|
|
</button>
|
|
<button name="act_action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_action" type="hidden" title="@{repeating_armaments_$X_action}"/>
|
|
<input class="input_row__border" name="attr_name" value="" data-i18n-placeholder="armament" type="text" title="@{repeating_armaments_$X_name}"/>
|
|
</div>
|
|
<input name="attr_bonus" value="" placeholder="0" type="number" title="@{repeating_armaments_$X_bonus}"/>
|
|
<input name="attr_damage" value="" placeholder="0" type="number" title="@{repeating_armaments_$X_damage}"/>
|
|
<input name="attr_range" value="" data-i18n-placeholder="range" type="text" title="@{repeating_armaments_$X_range}"/>
|
|
<input name="attr_size" value="" data-i18n-placeholder="size" type="text" title="@{repeating_armaments_$X_size}"/>
|
|
</div>
|
|
<div class="input_row border span-all expanded">
|
|
<div class="adaptive adaptive--text span-all" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_description" title="@{repeating_armaments_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" title="@{repeating_armaments_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox crew-positions span-all">
|
|
<h1 data-i18n="crew positions"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="position"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="bonus"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="notes"></h2>
|
|
</div>
|
|
<fieldset class="repeating_crew">
|
|
<div class="input_row">
|
|
<input name="attr_name" value="" data-i18n-placeholder="name" type="text" title="@{repeating_crew_$X_name}"/>
|
|
<select name="attr_position" title="@{repeating_crew_$X_position}">
|
|
<option value="" data-i18n="passenger" selected="">
|
|
</option>
|
|
<option value="captain" data-i18n="captain">
|
|
</option>
|
|
<option value="sensor operator" data-i18n="sensor operator">
|
|
</option>
|
|
<option value="pilot" data-i18n="pilot">
|
|
</option>
|
|
<option value="gunner" data-i18n="gunner">
|
|
</option>
|
|
<option value="engineer" data-i18n="engineer">
|
|
</option>
|
|
</select>
|
|
<input name="attr_bonus" type="number" title="@{repeating_crew_$X_bonus}"/>
|
|
<input name="attr_notes" value="" type="text" title="@{repeating_crew_$X_notes}"/>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--vehicle" data-container-tab="menu" data-tab="vehicle">
|
|
<div class="tab vehicle">
|
|
<div class="vehicle_top">
|
|
<div class="vehicle_information">
|
|
<div class="camelBox">
|
|
<h1>Name</h1>
|
|
<div class="input_row">
|
|
<input name="attr_character_name" type="text" title="@{character_name}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1>Length </h1>
|
|
<div class="input_row">
|
|
<input name="attr_length" type="text" title="@{length}"/>
|
|
</div>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1>Top Speed </h1>
|
|
<div class="input_row">
|
|
<input name="attr_top_speed" type="text" title="@{top_speed}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="attributes">
|
|
<div class="skill_button __passengers">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_passengers" value="0" type="number" title="@{passengers}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="passengers"></h3>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button __speed">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_speed" value="0" type="number" title="@{speed}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="speed"></h3>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button __maneuverability">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_maneuverability" value="0" type="number" title="@{maneuverability}"/>
|
|
</label>
|
|
<button class="roller" name="roll_maneuverability" value="@{maneuverability_action}" type="roll">
|
|
<h3 data-i18n="maneuverability"></h3>
|
|
</button>
|
|
<button name="act_maneuverability-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_maneuverability_action" type="hidden" title="@{maneuverability_action}"/>
|
|
</div>
|
|
<div class="skill_button __hull">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_hull" value="0" type="number" title="@{hull}"/>
|
|
</label>
|
|
<div class="button">
|
|
<h3 data-i18n="hull"></h3>
|
|
</div>
|
|
</div>
|
|
<div class="skill_button __armor">
|
|
<label class="__big">
|
|
<input class="__big" name="attr_armor" value="0" type="number" title="@{armor}"/>
|
|
</label>
|
|
<button class="roller" name="roll_armor" value="@{armor_action}" type="roll">
|
|
<h3 data-i18n="armor"></h3>
|
|
</button>
|
|
<button name="act_armor-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_armor_action" type="hidden" title="@{armor_action}"/>
|
|
</div>
|
|
<div class="camelBox">
|
|
<h1>Damage </h1>
|
|
<div class="fill-left vehicle_damage">
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="0" checked="" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="1" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="2" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="3" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="4" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="5" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="6" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="7" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="8" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="9" type="radio" title="@{vehicle_damage}"/>
|
|
<input class="fill-left__radio" name="attr_vehicle_damage" value="10" type="radio" title="@{vehicle_damage}"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box multibox component_damage">
|
|
<h1 data-i18n="component damage"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="skill 1"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="skill 2"></h2>
|
|
</div>
|
|
<fieldset class="repeating_component-damage">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_component-damage_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<input class="input_row__border" name="attr_name" value="" type="text" title="@{repeating_component-damage_$X_name}"/>
|
|
<div class="input-label input_row__borderless justify-self-center" style="width:fit-content">
|
|
<button class="roll_icon roller" name="roll_skill_1" value="@{skill_1_action}" type="roll">
|
|
</button>
|
|
<button name="act_skill-1-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_skill_1_action" type="hidden" title="@{repeating_component-damage_$X_skill_1_action}"/>
|
|
<input class="input_row__border" name="attr_skill_1_completed" type="number" title="@{repeating_component-damage_$X_skill_1_completed}"/><span>/</span>
|
|
<input class="input_row__border" name="attr_skill_1_completed_max" type="number" title="@{repeating_component-damage_$X_skill_1_completed|max}"/>
|
|
</div>
|
|
<div class="input-label input_row__borderless justify-self-center" style="width:fit-content">
|
|
<button class="roll_icon roller" name="roll_skill_2" value="@{skill_2_action}" type="roll">
|
|
</button>
|
|
<button name="act_skill-2-action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_skill_2_action" type="hidden" title="@{repeating_component-damage_$X_skill_2_action}"/>
|
|
<input class="input_row__border" name="attr_skill_2_completed" type="number" title="@{repeating_component-damage_$X_skill_2_completed}"/><span>/</span>
|
|
<input class="input_row__border" name="attr_skill_2_completed_max" type="number" title="@{repeating_component-damage_$X_skill_2_completed|max}"/>
|
|
</div>
|
|
</div>
|
|
<div class="input_row expanded border">
|
|
<label class="input-label input_row__borderless"><span class="input-label__text" data-i18n="skill 1"></span>
|
|
<select class="input-label__input" name="attr_skill_1" title="@{repeating_component-damage_$X_skill_1}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="heavy_machinery" data-i18n="heavy machinery">
|
|
</option>
|
|
<option value="comtech" data-i18n="comtech">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label class="input-label input_row__borderless"><span class="input-label__text" data-i18n="skill 2"></span>
|
|
<select class="input-label__input" name="attr_skill_2" title="@{repeating_component-damage_$X_skill_2}">
|
|
<option value="" data-i18n="select one">
|
|
</option>
|
|
<option value="heavy_machinery" data-i18n="heavy machinery">
|
|
</option>
|
|
<option value="comtech" data-i18n="comtech">
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<div class="adaptive adaptive--text span-all input_row__border" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_effect" title="@{repeating_component-damage_$X_effect}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_effect" value="" placeholder="Effect" title="@{repeating_component-damage_$X_effect}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox Armaments edition-style">
|
|
<h1 data-i18n="armaments"></h1>
|
|
<div class="border"> </div>
|
|
<div class="border">
|
|
<h2 data-i18n="bonus"> </h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="damage"> </h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="range"></h2>
|
|
</div>
|
|
<fieldset class="repeating_armaments">
|
|
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_armaments_$X_collapse}"/>
|
|
<div class="input_row">
|
|
<div class="group flex-box input_row__borderless">
|
|
<button class="roll_icon roller" name="roll_roll" value="@{action}" type="roll">
|
|
</button>
|
|
<button name="act_action" hidden="" type="action">
|
|
</button>
|
|
<input name="attr_action" type="hidden" title="@{repeating_armaments_$X_action}"/>
|
|
<input class="input_row__border" name="attr_name" value="" data-i18n-placeholder="armament" type="text" title="@{repeating_armaments_$X_name}"/>
|
|
</div>
|
|
<input name="attr_bonus" value="" placeholder="0" type="number" title="@{repeating_armaments_$X_bonus}"/>
|
|
<input name="attr_damage" value="" placeholder="0" type="number" title="@{repeating_armaments_$X_damage}"/>
|
|
<div class="flex-box tiny-gap secondedition">
|
|
<select name="attr_range" title="@{repeating_armaments_$X_range}">
|
|
<option value="Adjacent" data-i18n="a" selected="">
|
|
</option>
|
|
<option value="Short" data-i18n="s">
|
|
</option>
|
|
<option value="Medium" data-i18n="m">
|
|
</option>
|
|
<option value="Long" data-i18n="l">
|
|
</option>
|
|
<option value="Extreme" data-i18n="e">
|
|
</option>
|
|
</select><span class="slash">/</span>
|
|
<select name="attr_range_max" title="@{repeating_armaments_$X_range|max}">
|
|
<option value="Adjacent" data-i18n="a" selected="">
|
|
</option>
|
|
<option value="Short" data-i18n="s">
|
|
</option>
|
|
<option value="Medium" data-i18n="m">
|
|
</option>
|
|
<option value="Long" data-i18n="l">
|
|
</option>
|
|
<option value="Extreme" data-i18n="e">
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<input class="firstedition" name="attr_range" value="" data-i18n-placeholder="range" type="text" title="@{repeating_armaments_$X_range}"/>
|
|
</div>
|
|
<div class="input_row border span-all expanded">
|
|
<div class="adaptive adaptive--text span-all" style="justify-self:stretch;"><span class="adaptive--text__span" name="attr_description" title="@{repeating_armaments_$X_description}"></span>
|
|
<textarea class="adaptive--text__textarea" name="attr_description" title="@{repeating_armaments_$X_description}"></textarea>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="box multibox crew-positions span-all">
|
|
<h1 data-i18n="crew positions"></h1>
|
|
<div class="border"></div>
|
|
<div class="border">
|
|
<h2 data-i18n="position"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="bonus"></h2>
|
|
</div>
|
|
<div class="border">
|
|
<h2 data-i18n="notes"></h2>
|
|
</div>
|
|
<fieldset class="repeating_crew">
|
|
<div class="input_row">
|
|
<input name="attr_name" value="" data-i18n-placeholder="name" type="text" title="@{repeating_crew_$X_name}"/>
|
|
<select name="attr_position" title="@{repeating_crew_$X_position}">
|
|
<option value="" data-i18n="passenger" selected="">
|
|
</option>
|
|
<option value="captain" data-i18n="captain">
|
|
</option>
|
|
<option value="sensor operator" data-i18n="sensor operator">
|
|
</option>
|
|
<option value="pilot" data-i18n="pilot">
|
|
</option>
|
|
<option value="gunner" data-i18n="gunner">
|
|
</option>
|
|
<option value="engineer" data-i18n="engineer">
|
|
</option>
|
|
</select>
|
|
<input name="attr_bonus" type="number" title="@{repeating_crew_$X_bonus}"/>
|
|
<input name="attr_notes" value="" type="text" title="@{repeating_crew_$X_notes}"/>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs__container tabs--menu__container tabs--menu__container--initiative" data-container-tab="menu" data-tab="initiative">
|
|
<div class="tab initiative">
|
|
<div class="initiative">
|
|
<button name="roll_initiative" value="" type="roll">
|
|
<h3>Draw</h3>
|
|
</button>
|
|
<button name="roll_initiative_2" value="" type="roll">
|
|
<h3>x2</h3>
|
|
</button>
|
|
</div>
|
|
<div class="box Results edition-style">
|
|
<div class="underlay">
|
|
<h1 data-i18n="Results"></h1>
|
|
<div class="border"></div>
|
|
</div>
|
|
<div class="overlay">
|
|
<button name="roll_initiative-take" value="" type="roll">
|
|
<h3>3</h3>
|
|
</button>
|
|
<button name="roll_initiative-take_2" value="" type="roll">
|
|
<h3>8</h3>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<input name="attr_template_start" value="@{whisper}&{template:alien} {{character_name=@{character_name}}} {{push_label=^{push}}} {{character_id=@{character_id}}} {{edition=[[@{edition}]]}}" type="hidden" title="@{template_start}"/>
|
|
<script type="text/worker">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":""},"act_push":{"name":"push","type":"action","triggeredFuncs":["pushRoll"],"affects":[],"addFuncs":[],"listener":"clicked:push","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_supply":{"name":"supply","type":"action","triggeredFuncs":["supplyRoll"],"affects":[],"addFuncs":[],"listener":"clicked:supply","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_edition":{"name":"edition","type":"hidden","triggeredFuncs":["switchEdition"],"affects":[],"addFuncs":[],"listener":"change:edition","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_color_mode":{"name":"color_mode","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:color_mode","listenerFunc":"accessSheet","defaultValue":"edition","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_menu_tab":{"name":"menu_tab","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:menu_tab","listenerFunc":"accessSheet","defaultValue":"nav-tabs-menu--settings","calculation":"","initialFunc":"","formula":""},"act_roll-1d66-action":{"name":"roll-1d66-action","type":"action","triggeredFuncs":["rolld66"],"affects":[],"addFuncs":[],"listener":"clicked:roll-1d66-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_roll_1d66_action":{"name":"roll_1d66_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:roll_1d66_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--settings":{"name":"nav-tabs-menu--settings","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--settings","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--character":{"name":"nav-tabs-menu--character","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--character","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--npc":{"name":"nav-tabs-menu--npc","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--npc","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--hostile":{"name":"nav-tabs-menu--hostile","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--hostile","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--ship":{"name":"nav-tabs-menu--ship","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--ship","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--vehicle":{"name":"nav-tabs-menu--vehicle","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--vehicle","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_nav-tabs-menu--initiative":{"name":"nav-tabs-menu--initiative","type":"action","triggeredFuncs":["kSwitchTab"],"affects":[],"addFuncs":[],"listener":"clicked:nav-tabs-menu--initiative","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_sheet_type":{"name":"sheet_type","type":"select","triggeredFuncs":["characterSetup"],"affects":[],"addFuncs":[],"listener":"change:sheet_type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_whisper":{"name":"whisper","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:whisper","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_nerves_of_steel":{"name":"nerves_of_steel","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:nerves_of_steel","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_range_automation":{"name":"range_automation","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:range_automation","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_personal_agenda":{"name":"personal_agenda","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:personal_agenda","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_buddy":{"name":"buddy","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:buddy","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_rival":{"name":"rival","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:rival","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_panic-action":{"name":"panic-action","type":"action","triggeredFuncs":["rollStress"],"affects":[],"addFuncs":[],"listener":"clicked:panic-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_panic_action":{"name":"panic_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:panic_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_stress_level":{"name":"stress_level","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stress_level","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_health_level":{"name":"health_level","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:health_level","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_radiation_damage":{"name":"radiation_damage","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:radiation_damage","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_death-action":{"name":"death-action","type":"action","triggeredFuncs":["rollDeath"],"affects":[],"addFuncs":[],"listener":"clicked:death-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_death_action":{"name":"death_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:death_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_resolve":{"name":"resolve","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:resolve","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_radiation-action":{"name":"radiation-action","type":"action","triggeredFuncs":["rollRadiation"],"affects":[],"addFuncs":[],"listener":"clicked:radiation-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_radiation_action":{"name":"radiation_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:radiation_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_radiation_level":{"name":"radiation_level","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:radiation_level","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_critical_injuries":{"name":"critical_injuries","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:critical_injuries","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_starving":{"name":"starving","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:starving","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_dehydrated":{"name":"dehydrated","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:dehydrated","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_exhausted":{"name":"exhausted","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:exhausted","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_freezing":{"name":"freezing","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:freezing","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_stress-response-action":{"name":"stress-response-action","type":"action","triggeredFuncs":["stressPanicResponse"],"affects":[],"addFuncs":[],"listener":"clicked:stress-response-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_stress_response_action":{"name":"stress_response_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stress_response_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_jumpy":{"name":"jumpy","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:jumpy","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_tunnel_vision":{"name":"tunnel_vision","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:tunnel_vision","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_aggravated":{"name":"aggravated","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:aggravated","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_shakes":{"name":"shakes","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:shakes","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_frantic":{"name":"frantic","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:frantic","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_deflated":{"name":"deflated","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:deflated","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_panic-response-action":{"name":"panic-response-action","type":"action","triggeredFuncs":["stressPanicResponse"],"affects":[],"addFuncs":[],"listener":"clicked:panic-response-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_panic_response_action":{"name":"panic_response_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:panic_response_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_paranoid":{"name":"paranoid","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:paranoid","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_hesitant":{"name":"hesitant","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:hesitant","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_freeze":{"name":"freeze","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:freeze","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_seek_cover":{"name":"seek_cover","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:seek_cover","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_scream":{"name":"scream","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:scream","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_flee":{"name":"flee","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:flee","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_frenzy":{"name":"frenzy","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:frenzy","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_catatonic":{"name":"catatonic","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:catatonic","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_stress-compendium-action":{"name":"stress-compendium-action","type":"action","triggeredFuncs":["stressCompendiumResponse"],"affects":[],"addFuncs":[],"listener":"clicked:stress-compendium-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_stress_compendium_action":{"name":"stress_compendium_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stress_compendium_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_panic-compendium-action":{"name":"panic-compendium-action","type":"action","triggeredFuncs":["panicCompendiumResponse"],"affects":[],"addFuncs":[],"listener":"clicked:panic-compendium-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_panic_compendium_action":{"name":"panic_compendium_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:panic_compendium_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_air-action":{"name":"air-action","type":"action","triggeredFuncs":["consumableRoll"],"affects":[],"addFuncs":[],"listener":"clicked:air-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_air_action":{"name":"air_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:air_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_air":{"name":"air","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:air","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_food-action":{"name":"food-action","type":"action","triggeredFuncs":["consumableRoll"],"affects":[],"addFuncs":[],"listener":"clicked:food-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_food_action":{"name":"food_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:food_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_food":{"name":"food","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:food","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_power-action":{"name":"power-action","type":"action","triggeredFuncs":["consumableRoll"],"affects":[],"addFuncs":[],"listener":"clicked:power-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_power_action":{"name":"power_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:power_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_power":{"name":"power","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:power","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_water-action":{"name":"water-action","type":"action","triggeredFuncs":["consumableRoll"],"affects":[],"addFuncs":[],"listener":"clicked:water-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_water_action":{"name":"water_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:water_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_water":{"name":"water","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:water","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_career":{"name":"career","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:career","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_appearance_notes":{"name":"appearance_notes","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:appearance_notes","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_strength":{"name":"strength","type":"number","triggeredFuncs":[],"affects":["encumbrance_max"],"addFuncs":[],"listener":"change:strength","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_strength-action":{"name":"strength-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:strength-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_strength_action":{"name":"strength_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:strength_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_heavy_machinery":{"name":"heavy_machinery","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:heavy_machinery","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_heavy-machinery-action":{"name":"heavy-machinery-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:heavy-machinery-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_heavy_machinery_action":{"name":"heavy_machinery_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:heavy_machinery_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_stamina":{"name":"stamina","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stamina","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_stamina-action":{"name":"stamina-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:stamina-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_stamina_action":{"name":"stamina_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stamina_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_close_combat":{"name":"close_combat","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:close_combat","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_close-combat-action":{"name":"close-combat-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:close-combat-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_close_combat_action":{"name":"close_combat_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:close_combat_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_agility":{"name":"agility","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:agility","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_agility-action":{"name":"agility-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:agility-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_agility_action":{"name":"agility_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:agility_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ranged_combat":{"name":"ranged_combat","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ranged_combat","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_ranged-combat-action":{"name":"ranged-combat-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:ranged-combat-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ranged_combat_action":{"name":"ranged_combat_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ranged_combat_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mobility":{"name":"mobility","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mobility","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_mobility-action":{"name":"mobility-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:mobility-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_mobility_action":{"name":"mobility_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:mobility_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_piloting":{"name":"piloting","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:piloting","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_piloting-action":{"name":"piloting-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:piloting-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_piloting_action":{"name":"piloting_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:piloting_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_wits":{"name":"wits","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:wits","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_wits-action":{"name":"wits-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:wits-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_wits_action":{"name":"wits_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:wits_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_observation":{"name":"observation","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:observation","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_observation-action":{"name":"observation-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:observation-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_observation_action":{"name":"observation_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:observation_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_survival":{"name":"survival","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:survival","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_survival-action":{"name":"survival-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:survival-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_survival_action":{"name":"survival_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:survival_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_comtech":{"name":"comtech","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:comtech","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_comtech-action":{"name":"comtech-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:comtech-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_comtech_action":{"name":"comtech_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:comtech_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_empathy":{"name":"empathy","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:empathy","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_empathy-action":{"name":"empathy-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:empathy-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_empathy_action":{"name":"empathy_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:empathy_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_command":{"name":"command","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:command","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_command-action":{"name":"command-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:command-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_command_action":{"name":"command_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:command_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_medical_aid":{"name":"medical_aid","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:medical_aid","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_medical-aid-action":{"name":"medical-aid-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:medical-aid-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_medical_aid_action":{"name":"medical_aid_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:medical_aid_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_manipulation":{"name":"manipulation","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:manipulation","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_manipulation-action":{"name":"manipulation-action","type":"action","triggeredFuncs":["rollBasic"],"affects":[],"addFuncs":[],"listener":"clicked:manipulation-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_manipulation_action":{"name":"manipulation_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:manipulation_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor_collapse":{"name":"armor_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor_collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_armor-action":{"name":"armor-action","type":"action","triggeredFuncs":["rollArmor"],"affects":[],"addFuncs":[],"listener":"clicked:armor-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor_action":{"name":"armor_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor_name":{"name":"armor_name","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor_name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor":{"name":"armor","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_armor_weight":{"name":"armor_weight","type":"number","triggeredFuncs":[],"affects":["encumbrance"],"addFuncs":[],"listener":"change:armor_weight","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_armor_comment":{"name":"armor_comment","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor_comment","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_armor_description":{"name":"armor_description","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:armor_description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_encumbrance":{"name":"encumbrance","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:encumbrance","listenerFunc":"accessSheet","defaultValue":0,"calculation":"currentEncumbranceCalc","initialFunc":"","formula":""},"attr_encumbrance_max":{"name":"encumbrance_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:encumbrance_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"encumbranceCalc","initialFunc":"","formula":""},"attr_repeating_weapons_$x_collapse":{"name":"repeating_weapons_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_weapons_$x_action":{"name":"repeating_weapons_$x_action","type":"action","triggeredFuncs":["rollAttack"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_weapons:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_action":{"name":"repeating_weapons_$x_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_name":{"name":"repeating_weapons_$x_name","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_bonus":{"name":"repeating_weapons_$x_bonus","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:bonus","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_damage":{"name":"repeating_weapons_$x_damage","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:damage","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_ammo_max":{"name":"repeating_weapons_$x_ammo_max","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:ammo_max","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_ammo":{"name":"repeating_weapons_$x_ammo","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:ammo","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_use_type":{"name":"repeating_weapons_$x_use_type","type":"checkbox","triggeredFuncs":["unsetMax"],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:use_type","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":"","ammo":"ammo"},"attr_repeating_weapons_$x_quantity":{"name":"repeating_weapons_$x_quantity","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:quantity","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_type":{"name":"repeating_weapons_$x_type","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_range":{"name":"repeating_weapons_$x_range","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:range","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_range_max":{"name":"repeating_weapons_$x_range_max","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:range_max","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_weight":{"name":"repeating_weapons_$x_weight","type":"number","triggeredFuncs":[],"affects":["encumbrance"],"addFuncs":[],"listener":"change:repeating_weapons:weight","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_comment":{"name":"repeating_weapons_$x_comment","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:comment","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_weapons_$x_description":{"name":"repeating_weapons_$x_description","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_weapons:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_talent_collapse":{"name":"talent_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:talent_collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_talent_id":{"name":"talent_id","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:talent_id","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_talent_name":{"name":"talent_name","type":"text","triggeredFuncs":["saveTalent"],"affects":[],"addFuncs":[],"listener":"change:talent_name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_talent_description":{"name":"talent_description","triggeredFuncs":["saveTalent"],"affects":[],"addFuncs":[],"listener":"change:talent_description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_talent_push_twice":{"name":"talent_push_twice","type":"text","triggeredFuncs":["saveTalent"],"affects":[],"addFuncs":[],"listener":"change:talent_push_twice","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"act_add-talents":{"name":"add-talents","type":"action","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"clicked:add-talents","listenerFunc":"addItem","defaultValue":"","calculation":"","initialFunc":"","formula":""},"fieldset_repeating_talents":{"name":"repeating_talents","type":"fieldset","triggeredFuncs":["deleteTalent"],"affects":[],"addFuncs":["createTalent"],"listener":"remove:repeating_talents","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_talents_$x_active":{"name":"repeating_talents_$x_active","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_talents:active","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_talents_$x_display":{"name":"repeating_talents_$x_display","type":"action","triggeredFuncs":["loadTalent"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_talents:display","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_talents_$x_name":{"name":"repeating_talents_$x_name","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_talents:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_talents_$x_description":{"name":"repeating_talents_$x_description","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_talents:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_talents_$x_push_twice":{"name":"repeating_talents_$x_push_twice","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_talents:push_twice","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_experience_points":{"name":"experience_points","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:experience_points","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_story_points":{"name":"story_points","type":"radio","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:story_points","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_tiny_items":{"name":"tiny_items","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:tiny_items","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_signature_item":{"name":"signature_item","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:signature_item","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_collapse":{"name":"repeating_gear_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_name":{"name":"repeating_gear_$x_name","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_weight":{"name":"repeating_gear_$x_weight","type":"number","triggeredFuncs":[],"affects":["encumbrance"],"addFuncs":[],"listener":"change:repeating_gear:weight","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_power_max":{"name":"repeating_gear_$x_power_max","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:power_max","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_gear_$x_air-power-action":{"name":"repeating_gear_$x_air-power-action","type":"action","triggeredFuncs":["supplyRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_gear:air-power-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":"","rollData":{"section":"repeating_gear","attribute":"power"}},"attr_repeating_gear_$x_air_power_action":{"name":"repeating_gear_$x_air_power_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:air_power_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_power":{"name":"repeating_gear_$x_power","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:power","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_use_type":{"name":"repeating_gear_$x_use_type","type":"checkbox","triggeredFuncs":["unsetMax"],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:use_type","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":"","ammo":"power"},"attr_repeating_gear_$x_quantity":{"name":"repeating_gear_$x_quantity","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:quantity","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_effect":{"name":"repeating_gear_$x_effect","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:effect","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_gear_$x_description":{"name":"repeating_gear_$x_description","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_gear:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_title":{"name":"title","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:title","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_nickname":{"name":"nickname","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:nickname","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_age":{"name":"age","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:age","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_personality":{"name":"personality","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:personality","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_biography":{"name":"biography","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:biography","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_reveal_skills":{"name":"reveal_skills","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:reveal_skills","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_stage":{"name":"stage","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:stage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_health_max":{"name":"health_max","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:health_max","listenerFunc":"accessSheet","defaultValue":8,"calculation":"","initialFunc":"","formula":""},"attr_speed":{"name":"speed","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:speed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_information":{"name":"information","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:information","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_containment":{"name":"containment","type":"span","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:containment","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_attacks-action":{"name":"attacks-action","type":"action","triggeredFuncs":["hostileSignature"],"affects":[],"addFuncs":[],"listener":"clicked:attacks-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_attacks_action":{"name":"attacks_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:attacks_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_collapse":{"name":"repeating_signature_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_signature_$x_action":{"name":"repeating_signature_$x_action","type":"action","triggeredFuncs":["rollSignature"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_signature:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_action":{"name":"repeating_signature_$x_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_chance":{"name":"repeating_signature_$x_chance","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:chance","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_name":{"name":"repeating_signature_$x_name","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_bonus":{"name":"repeating_signature_$x_bonus","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:bonus","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_damage":{"name":"repeating_signature_$x_damage","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:damage","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_signature_$x_description":{"name":"repeating_signature_$x_description","type":"span","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_signature:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_abilities_$x_collapse":{"name":"repeating_abilities_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_abilities:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_abilities_$x_name":{"name":"repeating_abilities_$x_name","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_abilities:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_abilities_$x_description":{"name":"repeating_abilities_$x_description","type":"span","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_abilities:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_collapse":{"name":"repeating_internal-modules_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_online":{"name":"repeating_internal-modules_$x_online","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:online","listenerFunc":"accessSheet","defaultValue":1,"calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_name":{"name":"repeating_internal-modules_$x_name","type":"text","triggeredFuncs":["removeAIEffect"],"affects":["ai"],"addFuncs":[],"listener":"change:repeating_internal-modules:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_quantity":{"name":"repeating_internal-modules_$x_quantity","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:quantity","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_size":{"name":"repeating_internal-modules_$x_size","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:size","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_type":{"name":"repeating_internal-modules_$x_type","type":"select","triggeredFuncs":["removeAIEffect"],"affects":["ai"],"addFuncs":[],"listener":"change:repeating_internal-modules:type","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_ai_comtech":{"name":"repeating_internal-modules_$x_ai_comtech","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:ai_comtech","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_ai_piloting":{"name":"repeating_internal-modules_$x_ai_piloting","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:ai_piloting","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_ai_observation":{"name":"repeating_internal-modules_$x_ai_observation","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:ai_observation","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_internal-modules_$x_ai_ranged_combat":{"name":"repeating_internal-modules_$x_ai_ranged_combat","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_internal-modules:ai_ranged_combat","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_lease_cost":{"name":"lease_cost","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:lease_cost","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_manufacturer":{"name":"manufacturer","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:manufacturer","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ai":{"name":"ai","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ai","listenerFunc":"accessSheet","defaultValue":"","calculation":"setAIName","initialFunc":"","formula":""},"attr_hull":{"name":"hull","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:hull","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_crew":{"name":"crew","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:crew","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_length":{"name":"length","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:length","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_passengers":{"name":"passengers","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:passengers","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_hull_max":{"name":"hull_max","type":"number","triggeredFuncs":["setHull"],"affects":[],"addFuncs":[],"listener":"change:hull_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_signature":{"name":"signature","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:signature","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_signature-action":{"name":"signature-action","type":"action","triggeredFuncs":["sensorRoll"],"affects":[],"addFuncs":[],"listener":"clicked:signature-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_signature_action":{"name":"signature_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:signature_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ftl_rating":{"name":"ftl_rating","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ftl_rating","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_ftl-rating-action":{"name":"ftl-rating-action","type":"action","triggeredFuncs":["ftlRoll"],"affects":[],"addFuncs":[],"listener":"clicked:ftl-rating-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ftl_rating_action":{"name":"ftl_rating_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:ftl_rating_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_thrusters":{"name":"thrusters","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:thrusters","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_thrusters-action":{"name":"thrusters-action","type":"action","triggeredFuncs":["thrusterRoll"],"affects":[],"addFuncs":[],"listener":"clicked:thrusters-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_thrusters_action":{"name":"thrusters_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:thrusters_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_ship_damage":{"name":"ship_damage","type":"radio","triggeredFuncs":["setHull"],"affects":[],"addFuncs":[],"listener":"change:ship_damage","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_date":{"name":"date","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:date","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_location":{"name":"location","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:location","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_collapse":{"name":"repeating_minor-component-damage_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_name":{"name":"repeating_minor-component-damage_$x_name","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_minor-component-damage_$x_skill-1-action":{"name":"repeating_minor-component-damage_$x_skill-1-action","type":"action","triggeredFuncs":["engineerRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_minor-component-damage:skill-1-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_1_action":{"name":"repeating_minor-component-damage_$x_skill_1_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_1_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_1_completed":{"name":"repeating_minor-component-damage_$x_skill_1_completed","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_1_completed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_1_completed_max":{"name":"repeating_minor-component-damage_$x_skill_1_completed_max","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_1_completed_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_minor-component-damage_$x_skill-2-action":{"name":"repeating_minor-component-damage_$x_skill-2-action","type":"action","triggeredFuncs":["engineerRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_minor-component-damage:skill-2-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_2_action":{"name":"repeating_minor-component-damage_$x_skill_2_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_2_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_2_completed":{"name":"repeating_minor-component-damage_$x_skill_2_completed","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_2_completed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_2_completed_max":{"name":"repeating_minor-component-damage_$x_skill_2_completed_max","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_2_completed_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_1":{"name":"repeating_minor-component-damage_$x_skill_1","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_1","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_skill_2":{"name":"repeating_minor-component-damage_$x_skill_2","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:skill_2","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_minor-component-damage_$x_effect":{"name":"repeating_minor-component-damage_$x_effect","type":"span","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_minor-component-damage:effect","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_collapse":{"name":"repeating_major-component-damage_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_name":{"name":"repeating_major-component-damage_$x_name","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_major-component-damage_$x_skill-1-action":{"name":"repeating_major-component-damage_$x_skill-1-action","type":"action","triggeredFuncs":["engineerRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_major-component-damage:skill-1-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_1_action":{"name":"repeating_major-component-damage_$x_skill_1_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_1_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_1_completed":{"name":"repeating_major-component-damage_$x_skill_1_completed","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_1_completed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_1_completed_max":{"name":"repeating_major-component-damage_$x_skill_1_completed_max","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_1_completed_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_major-component-damage_$x_skill-2-action":{"name":"repeating_major-component-damage_$x_skill-2-action","type":"action","triggeredFuncs":["engineerRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_major-component-damage:skill-2-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_2_action":{"name":"repeating_major-component-damage_$x_skill_2_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_2_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_2_completed":{"name":"repeating_major-component-damage_$x_skill_2_completed","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_2_completed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_2_completed_max":{"name":"repeating_major-component-damage_$x_skill_2_completed_max","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_2_completed_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_1":{"name":"repeating_major-component-damage_$x_skill_1","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_1","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_skill_2":{"name":"repeating_major-component-damage_$x_skill_2","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:skill_2","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_major-component-damage_$x_effect":{"name":"repeating_major-component-damage_$x_effect","type":"span","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_major-component-damage:effect","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_upgrades_$x_quantity":{"name":"repeating_upgrades_$x_quantity","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_upgrades:quantity","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_upgrades_$x_name":{"name":"repeating_upgrades_$x_name","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_upgrades:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_upgrades_$x_effect":{"name":"repeating_upgrades_$x_effect","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_upgrades:effect","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_collapse":{"name":"repeating_armaments_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_armaments_$x_action":{"name":"repeating_armaments_$x_action","type":"action","triggeredFuncs":["shipAttack"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_armaments:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_action":{"name":"repeating_armaments_$x_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_name":{"name":"repeating_armaments_$x_name","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_bonus":{"name":"repeating_armaments_$x_bonus","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:bonus","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_damage":{"name":"repeating_armaments_$x_damage","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:damage","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_range":{"name":"repeating_armaments_$x_range","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:range","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_size":{"name":"repeating_armaments_$x_size","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:size","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_description":{"name":"repeating_armaments_$x_description","type":"span","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:description","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_crew_$x_name":{"name":"repeating_crew_$x_name","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_crew:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_crew_$x_position":{"name":"repeating_crew_$x_position","type":"select","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_crew:position","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_crew_$x_bonus":{"name":"repeating_crew_$x_bonus","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_crew:bonus","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_crew_$x_notes":{"name":"repeating_crew_$x_notes","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_crew:notes","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_top_speed":{"name":"top_speed","type":"text","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:top_speed","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_maneuverability":{"name":"maneuverability","type":"number","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:maneuverability","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_maneuverability-action":{"name":"maneuverability-action","type":"action","triggeredFuncs":["maneuverability"],"affects":[],"addFuncs":[],"listener":"clicked:maneuverability-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_maneuverability_action":{"name":"maneuverability_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:maneuverability_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_vehicle_damage":{"name":"vehicle_damage","type":"radio","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:vehicle_damage","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_collapse":{"name":"repeating_component-damage_$x_collapse","type":"checkbox","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:collapse","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_name":{"name":"repeating_component-damage_$x_name","type":"text","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:name","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"act_repeating_component-damage_$x_skill-1-action":{"name":"repeating_component-damage_$x_skill-1-action","type":"action","triggeredFuncs":["engineerRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_component-damage:skill-1-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_1_action":{"name":"repeating_component-damage_$x_skill_1_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_1_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_1_completed":{"name":"repeating_component-damage_$x_skill_1_completed","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_1_completed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_1_completed_max":{"name":"repeating_component-damage_$x_skill_1_completed_max","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_1_completed_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"act_repeating_component-damage_$x_skill-2-action":{"name":"repeating_component-damage_$x_skill-2-action","type":"action","triggeredFuncs":["engineerRoll"],"affects":[],"addFuncs":[],"listener":"clicked:repeating_component-damage:skill-2-action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_2_action":{"name":"repeating_component-damage_$x_skill_2_action","type":"hidden","triggeredFuncs":[],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_2_action","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_2_completed":{"name":"repeating_component-damage_$x_skill_2_completed","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_2_completed","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_2_completed_max":{"name":"repeating_component-damage_$x_skill_2_completed_max","type":"number","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_2_completed_max","listenerFunc":"accessSheet","defaultValue":0,"calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_1":{"name":"repeating_component-damage_$x_skill_1","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_1","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_skill_2":{"name":"repeating_component-damage_$x_skill_2","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:skill_2","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_component-damage_$x_effect":{"name":"repeating_component-damage_$x_effect","type":"span","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_component-damage:effect","listenerFunc":"accessSheet","defaultValue":"","calculation":"","initialFunc":"","formula":""},"attr_repeating_armaments_$x_range_max":{"name":"repeating_armaments_$x_range_max","type":"select","triggeredFuncs":["setActionCalls"],"affects":[],"addFuncs":[],"listener":"change:repeating_armaments:range_max","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:alien} {{character_name=@{character_name}}} {{push_label=^{push}}} {{character_id=@{character_id}}} {{edition=[[@{edition}]]}}","calculation":"","initialFunc":"","formula":""}};
|
|
|
|
kFuncs.cascades = cascades;
|
|
|
|
const repeatingSectionDetails = [{"section":"repeating_weapons","fields":["collapse","action","name","bonus","damage","ammo_max","ammo","use_type","quantity","type","range","range_max","weight","comment","description"]},{"section":"repeating_talents","fields":["active","name","description","push_twice"]},{"section":"repeating_gear","fields":["collapse","name","weight","power_max","air_power_action","power","use_type","quantity","effect","description"]},{"section":"repeating_signature","fields":["collapse","action","chance","name","bonus","damage","description"]},{"section":"repeating_abilities","fields":["collapse","name","description"]},{"section":"repeating_internal-modules","fields":["collapse","online","name","quantity","size","type","ai_comtech","ai_piloting","ai_observation","ai_ranged_combat"]},{"section":"repeating_minor-component-damage","fields":["collapse","name","skill_1_action","skill_1_completed","skill_1_completed_max","skill_2_action","skill_2_completed","skill_2_completed_max","skill_1","skill_2","effect"]},{"section":"repeating_major-component-damage","fields":["collapse","name","skill_1_action","skill_1_completed","skill_1_completed_max","skill_2_action","skill_2_completed","skill_2_completed_max","skill_1","skill_2","effect"]},{"section":"repeating_upgrades","fields":["quantity","name","effect"]},{"section":"repeating_armaments","fields":["collapse","action","name","bonus","damage","range","size","description","range_max"]},{"section":"repeating_crew","fields":["name","position","bonus","notes"]},{"section":"repeating_component-damage","fields":["collapse","name","skill_1_action","skill_1_completed","skill_1_completed_max","skill_2_action","skill_2_completed","skill_2_completed_max","skill_1","skill_2","effect"]}];
|
|
|
|
kFuncs.repeatingSectionDetails = repeatingSectionDetails;
|
|
|
|
const persistentTabs = ["menu_tab"];
|
|
|
|
kFuncs.persistentTabs = persistentTabs;
|
|
/**
|
|
* The K-scaffold provides several variables to allow your scripts to tap into its information flow.
|
|
* @namespace Sheetworkers.Variables
|
|
*/
|
|
/**
|
|
* This stores the name of your sheet for use in the logging functions {@link log} and {@link debug}. Accessible by `k.sheetName`
|
|
* @memberof Variables
|
|
* @var
|
|
* @type {string}
|
|
*/
|
|
let sheetName = 'kScaffold Powered Sheet';
|
|
kFuncs.sheetName = sheetName;
|
|
/**
|
|
* This stores the version of your sheet for use in the logging functions{@link log} and {@link debug}. It is also stored in the sheet_version attribute on your character sheet. Accessible via `k.version`
|
|
* @memberof Variables
|
|
* @var
|
|
* @type {number}
|
|
*/
|
|
let version = 0;
|
|
kFuncs.version = version;
|
|
/**
|
|
* A boolean flag that tells the script whether to enable or disable {@link debug} calls. If the version of the sheet is `0`, or an attribute named `debug_mode` is found on opening this is set to true for your entire session. Otherwise, it remains false.
|
|
* @memberof Variables
|
|
* @var
|
|
* @type {boolean}
|
|
*/
|
|
let debugMode = false;
|
|
kFuncs.debugMode = debugMode;
|
|
/**
|
|
* A boolean flag that tells the script whether to output verbose logs of what is being done or not when {@link debugMode} is enabled.
|
|
* @memberof Variables
|
|
* @var
|
|
* @type {boolean}
|
|
*/
|
|
let verboseMode = false;
|
|
kFuncs.verboseMode = verboseMode;
|
|
const funcs = {};
|
|
kFuncs.funcs = funcs;
|
|
const updateHandlers = {};
|
|
const openHandlers = {};
|
|
const initialSetups = {};
|
|
const allHandlers = {};
|
|
const addFuncs = {};
|
|
|
|
const kscaffoldJSVersion = '2.7.2';
|
|
const kscaffoldPUGVersion = '2.7.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){
|
|
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*/
|
|
/**
|
|
* Detailed descriptions of the arguments that are passed to functions registered with the K-scaffold.
|
|
* @namespace Sheetworkers.Function Arguments
|
|
*/
|
|
/**
|
|
* An object that stores the rowID information for each repeating section on the sheet.
|
|
* @name sections
|
|
* @memberof Function Arguments
|
|
* @var
|
|
* @property {string[]} repeating_section_name - The row IDs of a given repeating section. The repeating section name is used **with** the `repeating_` prefix (e.g. `sections['repeating_weapons']`).
|
|
*/
|
|
/**
|
|
* Object that stores the default trigger information for all attributes. Indexed by attribute, button name, or fieldset name prefixed with `attr_`, `act_`, or `fieldset_` respectively.
|
|
* @name casc
|
|
* @memberof Function Arguments
|
|
* @var
|
|
*/
|
|
/**
|
|
* Object describing the attribute that is currently being worked on. In addition to the properties described here, the properties from the Roll20 event will also be present if the attribute was the original event. Additional properties may be present if you specified them when creating the input for the attribute.
|
|
* @name trigger
|
|
* @memberof Function Arguments
|
|
* @var
|
|
* @property {string} name - The full name of the attribute.
|
|
* @property {string[]} triggeredFuncs - Array of function names that will be called when this attribute is worked on.
|
|
* @property {string} calculation - The name of the function that is used to calculate the value of this attribute.
|
|
* @property {string} formula - The macro syntax formula to use to calculate this attributes value.
|
|
* @property {string[]} affects - Array of attribute names that this attribute might affect.
|
|
* @property {string[]} addFuncs - Functions that are called when the add row button is clicked for a customControlFieldset.
|
|
* @property {string} listener - What function was used to listen for changes to this attribute. Unless you have decided to implement your own event handling, this should always be `"accessSheet"`.
|
|
* @property {string} type - What type of thing this trigger is for (e.g. number, action).
|
|
*/
|
|
//# Attribute Obj Proxy handler
|
|
/**
|
|
* A representation of the sheet's attributes. This is a proxy for the actual object and will keep track of original values and updates that have been applied. Calling an attribute directly on the attributes value will return it's current value coerced into a number if it is numeric. Setting a property on the attributes object will add it the list of updates which will be applied the next time the `set()` method is called on attributes.
|
|
* @name attributes
|
|
* @memberof Function Arguments
|
|
* @var
|
|
* @property {object} attributes - The raw original data of the character sheet.
|
|
* @property {object} updates - The raw data that will be saved to the character sheet once all operations have been completed.
|
|
* @property {function} set - Method to apply changes to the character sheet. This is called automatically at the end of the scaffold's event handling. Needs to be called manually if inside an asynchronous function, such as when using the startRoll sheetworker (or any of the scaffold aliases for startRoll). The method uses object destructuring syntax for the arguments it takes.
|
|
* @property {boolean} [set.vocal=false] - Whether the set is done silently or not. Should almost always be left at false. `attributes.set({vocal:true})`
|
|
* @property {function} [set.callback] - Callback function to be invoked once the setAttrs is complete. `attributes.set({callback(){/*do a thing}})`
|
|
* @property {any} attribute_name - Name of any attribute whose data from the character sheet you want to access. Will only return a value if the attribute was defined using the scaffold's pug mixins (e.g. +input). If the value of the attribute is numerical (e.g. `"5"`), it will be returned as a number. You can also apply changes by simply assigning a value to an attribute name (e.g. `attributes.character_name = 'New Character'`).
|
|
* @property {object} repOrders - Object showing the ordered arrays for the _reporder_ attributes for each repeating section. Indexed by repeating section name
|
|
* @property {object[]} repeating_section_name - Name of a repeating section whose data you want to access (e.g. `attributes.repeating_weapons`). The data will be returned as an array with objects describing each row in the order they are on the sheet. Objects are indexed by rowID as well. Mutating array methods are replaced by the `sort` and `move` methods. Non mutating array methods can be used as normal.
|
|
* @property {string} repeating_section_name._section - the name of the repeating section. Used internally by the scaffold. Readonly.
|
|
* @property {function} move - Method for reordering rows.
|
|
* @property {number|string} move.startingPosition - the row id or position index for the row you want to move.
|
|
* @property {number} move.destination - The position in the section where you want the row to be moved to. If the position is greater than the length of the section, the row will be moved to the last position. If the position is negative, it will be moved to the start of the section.
|
|
* @property {boolean} [move.silent=false] - Whether the reordering should trigger setSectionOrder or not.
|
|
* @property {function} sort - Alias for the default Array.sort method. Functions as the default sort method, but has an optional second argument.
|
|
* @property {function} sort.callback - The function to use for determining the sort order. See the [Array.sort documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) for details.
|
|
* @property {boolean} [sort.silent=false] - Whether to apply the sort to the display of the repeating section.
|
|
* @property {function} create - Method for creating a new row in a repeating section. Arguments for this method can be in any order. A row will not actually be created unless data is assigned to at least one attribute of the row, either at creation or later. Returns the object representing the new row.
|
|
* @property {string} [create.custom] - Custom text that replaces the starting characters of the rowID
|
|
* @property {object} [create.data] - what to set the attribute values of the row to. If not provided, the row object will be created, but no row will be created on the sheet until data is specified.
|
|
* @property {object} repeating_section_name.rowID_or_Index - Returns the object describing a row in a repeating section specified by row ID or indexed position. (e.g. `attributes.repeating_weapons[0]` returns the data for the first row in the weapons section)
|
|
* * @property {object} repeating_section_name.rowID_or_Index._id - The id of the row. Readonly.
|
|
* * @property {object} repeating_section_name.rowID_or_Index._section - The repeating section the row belongs to. Readonly.
|
|
* @property {any} repeating_section_name.rowID_or_Index.attribute_name - functions as an attribute_name call on the base attributes object. (e.g. `attributes['repeating_weapons_-jJ2soils_name']` is equivalent to `attributes.repeating_weapons['-jJ2soils'].name`).
|
|
* @type {object}
|
|
*/
|
|
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];
|
|
if(kFuncs.verboseMode){
|
|
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){
|
|
if(kFuncs.verboseMode){
|
|
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){
|
|
if(kFuncs.verboseMode){
|
|
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;
|
|
}
|
|
if(kFuncs.verboseMode){
|
|
debug({trigger});
|
|
}
|
|
if(event){
|
|
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){
|
|
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 repeatObjects = {};
|
|
const repeatTargetObjects = {};
|
|
const repeatHandler = {
|
|
get:function(obj,prop){
|
|
const row = `${obj._section}_${obj._id}`;
|
|
if(prop === '_isProxy'){
|
|
return true;
|
|
}
|
|
if(prop === 'toJSON'){
|
|
return () => {
|
|
return Object.keys(obj).reduce((o,k) => {
|
|
o[k] = attributes[`${row}_${k}`];
|
|
return o;
|
|
},{_id: obj._id,_section: obj._section});
|
|
}
|
|
}
|
|
if(prop === 'remove'){
|
|
return function(){
|
|
delete attributes[obj._section][obj._id];
|
|
}
|
|
}
|
|
return obj[prop];
|
|
},
|
|
set: function(obj,prop,value){
|
|
if(prop === '_id' || prop === '_section'){
|
|
throw new Error(`!!!Warning: cannot change the id or section of a repeating object!!!`);
|
|
}else if( prop === '_index'){
|
|
throw new Error(`!!!Warning: Cannot reorder sections by setting the _index. Sort the repeating array or use k.setSectionOrder!!!`);
|
|
}
|
|
const fullRef = `${obj._section}_${obj._id}_${prop}`;
|
|
attributes[fullRef] = value;
|
|
obj[prop] = value;
|
|
}
|
|
};
|
|
const repeatArrHandler = {
|
|
get(arr,prop){
|
|
prop = typeof prop === 'string' ?
|
|
prop.replace(/^\$/,'') :
|
|
prop;
|
|
if(prop === '_isProxy'){
|
|
return true;
|
|
}
|
|
if(
|
|
prop === 'fill' ||
|
|
prop === 'shift' ||
|
|
prop === 'pop' ||
|
|
prop === 'unshift' ||
|
|
prop === 'splice'
|
|
){
|
|
throw new Error(`The ${prop} method is not allowed on section arrays`);
|
|
}
|
|
if(prop === 'create'){
|
|
return function(){
|
|
const argArray = [...arguments];
|
|
const custom = argArray.find(e => typeof e === 'string');
|
|
const data = argArray.find(e => typeof e === 'object' && !Array.isArray(e));
|
|
|
|
const row = _generateRowID(arr._section,sections,custom);
|
|
const id = row.replace(/repeating_[^_]+_/,'');
|
|
arr[id] = createRepeatObj(arr._section,id);
|
|
arr.push(arr[id]);
|
|
if(data){
|
|
Object.entries(data).forEach(([key,value]) => {
|
|
if(arr[id].hasOwnProperty(key)){
|
|
arr[id][key] = value;
|
|
}else{
|
|
debug(`!!!Warning: no input exists in ${obj._section} for the attribute "${key}"!!!`);
|
|
}
|
|
});
|
|
}
|
|
return arr[id];
|
|
}
|
|
}
|
|
if(prop === 'move'){
|
|
return function(){
|
|
const ref = arguments[0];
|
|
const targ = arguments[1];
|
|
const vocal = !arguments[2]
|
|
// TODO: add protection for missing arguments
|
|
let id;
|
|
let index;
|
|
if(sections[arr._section].includes(ref)){
|
|
id = ref;
|
|
index = sections[arr._section].indexOf(id);
|
|
}else if(!Number.isNaN(ref)){
|
|
index = ref;
|
|
id = sections[arr._section][index];
|
|
}
|
|
if(
|
|
!Number.isNaN(index) &&
|
|
id &&
|
|
!Number.isNaN(targ)
|
|
){
|
|
const obj = arr.splice(index,1);
|
|
arr.splice(targ,0,obj);
|
|
sections[arr._section].splice(index,1);
|
|
sections[arr._section].splice(targ,0,id);
|
|
if(vocal){
|
|
_setSectionOrder(arr._section,sections[arr._section]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(prop === 'sort'){
|
|
return function(){
|
|
const callback = arguments[0];
|
|
const vocal = !arguments[1];
|
|
sections[arr._section].sort((a,b) => {
|
|
const aObj = arr[a];
|
|
const bObj = arr[b];
|
|
const sortResult = callback(aObj,bObj);
|
|
return sortResult;
|
|
});
|
|
arr.sort((a,b) => {
|
|
const aIndex = sections[arr._section].indexOf(a._id);
|
|
const bIndex = sections[arr._section].indexOf(b._id);
|
|
return aIndex - bIndex;
|
|
});
|
|
// if not a silent sort, then apply the reordered section to the sheet via setSectionOrder
|
|
if(vocal){
|
|
_setSectionOrder(arr._section,sections[arr._section]);
|
|
}
|
|
return arr;
|
|
}
|
|
}
|
|
if(arr[prop] || Number.isNaN(prop)){
|
|
return Reflect.get(...arguments);
|
|
}
|
|
if(sections[arr._section].includes(prop)){
|
|
arr[prop] = createRepeatObj(arr._section,prop);
|
|
arr.push(arr[prop]);
|
|
return arr[prop];
|
|
}
|
|
},
|
|
set(obj,prop,value){
|
|
if(prop === 'section'){
|
|
throw new Error('!!!Warning: Section property of a repeating section is readonly!!!')
|
|
}
|
|
},
|
|
deleteProperty(arr,prop){
|
|
if(
|
|
!prop.startsWith('_') &&
|
|
arr[prop] &&
|
|
arr[prop]._isProxy
|
|
){
|
|
let id;
|
|
let index;
|
|
if(typeof prop === 'string' && prop.startsWith('-')){
|
|
id = prop;
|
|
index = sections[arr._section].indexOf(id);
|
|
}else{
|
|
index = prop;
|
|
id = arr[index]._id;
|
|
}
|
|
delete arr[id];
|
|
arr.splice(index,1);
|
|
sections[arr._section].splice(index,1);
|
|
const row = `${arr._section}_${id}`;
|
|
removeRepeatingRow(row);
|
|
}
|
|
}
|
|
};
|
|
const createRepeatObj = (prop,id) => {
|
|
const row = `${prop}_${id}`;
|
|
const fields = repeatingSectionDetails.find(o => o.section === prop).fields;
|
|
const retObj = fields.reduce((o,field) => {
|
|
o[field] = attributes[`${row}_${field}`];
|
|
return o;
|
|
},{_id:id,_section: prop})
|
|
repeatTargetObjects[prop] = repeatTargetObjects[prop] || {};
|
|
repeatTargetObjects[prop][id] = retObj;
|
|
return new Proxy(retObj,repeatHandler);
|
|
}
|
|
const attrHandler = {
|
|
get:function(obj,prop){//gets the most value of the attribute.
|
|
if(prop === '_isProxy'){
|
|
return true;
|
|
}
|
|
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{
|
|
if(kFuncs.verboseMode){
|
|
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(/^repeating_[^_]+$/.test(prop)){
|
|
// if it's been lazy loaded, use it
|
|
if(!repeatObjects[prop]){
|
|
// otherwise lazy load it
|
|
const baseArr = [];
|
|
baseArr._section = prop;
|
|
repeatObjects[prop] = new Proxy(sections[prop].reduce((arr,id,i) => {
|
|
const rowObj = createRepeatObj(prop,id,i);
|
|
arr.push(rowObj);
|
|
arr[id] = rowObj;
|
|
return arr;
|
|
},baseArr),repeatArrHandler);
|
|
}
|
|
return repeatObjects[prop];
|
|
}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/.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){
|
|
let trigger = getCascObj({sourceAttribute:prop});
|
|
if(!trigger.name){
|
|
Object.assign(casc,expandCascade(cascades,sections));
|
|
trigger = getCascObj({sourceAttribute:prop});
|
|
}
|
|
if(Array.isArray(trigger.affects)){
|
|
attributes.queue.push(...trigger.affects);
|
|
}
|
|
}
|
|
const repRx = /^(repeating_[^_]+)_([^_]+)_(.+)$/;
|
|
if(repRx.test(prop)){
|
|
const [,section,rowID,field] = prop.match(repRx);
|
|
if(repeatObjects[section]){
|
|
repeatObjects[section][rowID] = repeatObjects[section][rowID] || createRepeatObj(section,rowID);
|
|
repeatTargetObjects[section][rowID][field] = value;
|
|
}
|
|
}
|
|
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]){
|
|
if(kFuncs.verboseMode){
|
|
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;
|
|
if(kFuncs.verboseMode){
|
|
debug({sheet_version:attributes.sheet_version});
|
|
}
|
|
if(!attributes.sheet_version){
|
|
Object.entries(initialSetups).forEach(([funcName,handler])=>{
|
|
if(typeof funcs[funcName] === 'function'){
|
|
if(kFuncs.verboseMode){
|
|
debug(`running ${funcName}`);
|
|
}
|
|
funcs[funcName]({attributes,sections,casc});
|
|
}else{
|
|
if(kFuncs.verboseMode){
|
|
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});
|
|
}
|
|
});
|
|
}
|
|
if(kFuncs.verboseMode){
|
|
debug({openHandlers});
|
|
}
|
|
Object.entries(openHandlers).forEach(([funcName,func])=>{
|
|
if(typeof funcs[funcName] === 'function'){
|
|
if(kFuncs.verboseMode){
|
|
debug(`running ${funcName}`);
|
|
}
|
|
funcs[funcName]({attributes,sections,casc});
|
|
}else{
|
|
if(kFuncs.verboseMode){
|
|
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){
|
|
if(kFuncs.verboseMode){
|
|
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){
|
|
if(kFuncs.verboseMode){
|
|
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);
|
|
};
|
|
// deprecation warning added to setSectionOrder
|
|
kFuncs.setSectionOrder = (section,order) => {
|
|
debug('###Deprecation: It is recommended to use the "move" method of the nested section info feature of the attributes object instead of setSectionOrder');
|
|
_setSectionOrder(section,order);
|
|
};
|
|
|
|
/**
|
|
* 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){
|
|
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);
|
|
delete attributes[section][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 = (section,sections,customText) => {
|
|
debug('###Deprecation: It is recommended to use the "create" method of the nested section info feature of the attributes object instead of k.generateRowID');
|
|
return _generateRowID(section,sections,customText);
|
|
};
|
|
|
|
/**
|
|
* 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 += ` {{${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);
|
|
if(kFuncs.verboseMode){
|
|
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);
|
|
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 = ["roll_1d66_action","panic_action","death_action","radiation_action","stress_response_action","panic_response_action","stress_compendium_action","panic_compendium_action","air_action","food_action","power_action","water_action","strength_action","heavy_machinery_action","stamina_action","close_combat_action","agility_action","ranged_combat_action","mobility_action","piloting_action","wits_action","observation_action","survival_action","comtech_action","empathy_action","command_action","medical_aid_action","manipulation_action","armor_action","repeating_weapons_$X_action","repeating_gear_$X_air_power_action","attacks_action","repeating_signature_$X_action","signature_action","ftl_rating_action","thrusters_action","repeating_minor-component-damage_$X_skill_1_action","repeating_minor-component-damage_$X_skill_2_action","repeating_major-component-damage_$X_skill_1_action","repeating_major-component-damage_$X_skill_2_action","repeating_armaments_$X_action","maneuverability_action","repeating_component-damage_$X_skill_1_action","repeating_component-damage_$X_skill_2_action"];let talentPlaceholder = '- - - -';const attributes = ["strength","agility","wits","empathy"];const skillAttributeMatch = {"heavy_machinery":"strength","stamina":"strength","close_combat":"strength","ranged_combat":"agility","mobility":"agility","piloting":"agility","observation":"wits","survival":"wits","comtech":"wits","command":"empathy","medical_aid":"empathy","manipulation":"empathy"};const moduleTypes = ["artificial intelligence","air scrubber","cargo bay","corporate suite","cryo deck","docking umbilical","emergency escape vehicle","galley","hangar","medlab","salvage crane","science lab","tractor hitch","vehicle bay"];k.version = 2.1;
|
|
k.sheetName = "Alien & Alien Evolved";
|
|
// Rollescape function from Oosh for Passthrough trick
|
|
// https://app.roll20.net/forum/post/10346883/adventures-with-startroll
|
|
// Helper - the data passed through in an action button needs these characters escaped
|
|
// I've used a mongrel escape sequence to avoid triggering anything internal in Roll20
|
|
// This may not be a complete list of characters that need escaping! If you have heavily
|
|
// punctuated text, it might break the passthrough!
|
|
const RE = {
|
|
chars: {
|
|
'"': '%quot;',
|
|
',': '%comma;',
|
|
':': '%colon;',
|
|
'}': '%rcub;',
|
|
'{': '%lcub;',
|
|
},
|
|
escape(str) {
|
|
str = (typeof(str) === 'object') ? JSON.stringify(str) : (typeof(str) === 'string') ? str : null;
|
|
return (str) ? `${str}`.replace(new RegExp(`[${Object.keys(this.chars)}]`, 'g'), (r) => this.chars[r]) : null;
|
|
},
|
|
unescape(str) {
|
|
str = `${str}`.replace(new RegExp(`(${Object.values(this.chars).join('|')})`, 'g'), (r) => Object.entries(this.chars).find(e=>e[1]===r)[0]);
|
|
return JSON.parse(str);
|
|
}
|
|
};
|
|
|
|
k.RE = RE;
|
|
/**
|
|
* Prompts the user for any bonus/penalty they have for the roll
|
|
*/
|
|
const bonusPrompt = async function({row='',attrName,attributes,passedData={}}){
|
|
const promptTransName = row ?
|
|
attributes[`${row}name`] :
|
|
getTranslationByKey(attrName.replace(/_/g,' '));
|
|
const bonusPromptTrans = k.capitalize(getTranslationByKey('dice to add/subtract for {{rollName}}')).replace(/\{\{0\}\}/g,promptTransName);
|
|
const bonusDice = +(await k.extractQueryResult(bonusPromptTrans)) || 0;
|
|
return bonusDice + (passedData.baseBonus || 0);
|
|
};const parseRow = (name) => {
|
|
const [section,rowID,specific] = k.parseTriggerName(name);
|
|
return [`${section}_${rowID}`,section,rowID,specific];
|
|
};
|
|
/**
|
|
* Filters the ship's crew members that match the indicated position. Adds the mainframe if no crew are available.
|
|
* @param {attributesProxy} attributes - The attributes of the sheet
|
|
* @param {object} sections - the sections object
|
|
* @param {string} position - the crew position to look for
|
|
* @param {boolean} [useMainframe = true] - Whether this position can be fulfilled by the mainframe
|
|
* @returns {string[]}
|
|
*/
|
|
const getCrew = (attributes,sections,position,useMainframe = true) => {
|
|
const crewRows = sections.repeating_crew.reduce((arr,crewID) => {
|
|
const crewRow = `repeating_crew_${crewID}`;
|
|
if(attributes[`${crewRow}_position`] === position){
|
|
arr.push(crewRow);
|
|
}
|
|
return arr;
|
|
},[]);
|
|
|
|
// If there are no active crew, then look for a mainframe to use
|
|
if(useMainframe && !crewRows.length){
|
|
const mainframeID = sections['repeating_internal-modules'].find(id =>
|
|
attributes[`repeating_internal-modules_${id}_type`] === 'artificial intelligence' &&
|
|
attributes[`repeating_internal-modules_${id}_online`] === 1
|
|
);
|
|
if(mainframeID){
|
|
crewRows.push(`repeating_internal-modules_${mainframeID}`);
|
|
}
|
|
}
|
|
return crewRows;
|
|
}/**
|
|
* Rolls the armament using a specific gunner's information. If there is a bonus listed, rolls using that bonus. Otherwise, calls the gunner's own ranged_attack roll button.
|
|
* @param {string} row - The row of the armament or the name of the non repeating attribute
|
|
* @param {object} rollObj - object describing the roll so far
|
|
* @param {string} crewRow - the row of the gunner details
|
|
* @param {attributesProxy} attributes - The attributes object
|
|
* @param {object} sections - The sections object
|
|
*/
|
|
const rollCrew = async (row,rollObj,crewRow,attributes,sections) => {
|
|
const attrName = crewRow.startsWith('repeating_internal-modules') ?
|
|
'ai_ranged_combat' :
|
|
'bonus';
|
|
if(
|
|
attributes[`${crewRow}_${attrName}`] ||
|
|
attributes.attributes[`${crewRow}_${attrName}`] !== ''
|
|
){
|
|
const bonus =
|
|
(attributes[`${crewRow}_${attrName}`] || 0);
|
|
const promptDice = await bonusPrompt({
|
|
row: row.startsWith('repeating') ?
|
|
`${row}_` :
|
|
'',
|
|
attrName:row.startsWith('repeating') ?
|
|
attributes[`${row}_name`] :
|
|
row,
|
|
attributes
|
|
});
|
|
const bonusDice = (promptDice || 0) + bonus;
|
|
const attrRef = row.startsWith('repeating') ?
|
|
`${row}_bonus` :
|
|
row;
|
|
Object.assign(rollObj,calcDice(attrRef,attributes,bonusDice));
|
|
const [roll,computeObj] = await executeRoll({rollObj});
|
|
finishRoll(roll.rollId,computeObj);
|
|
}else{
|
|
// Only call the crew member's sheet
|
|
await callCrew(row,rollObj,crewRow,attributes,sections);
|
|
}
|
|
};const callCrew = async (row,rollObj,crewRow,attributes,sections) => {
|
|
rollObj.character_name = '@{character_name}';
|
|
rollObj.character_id = '@{character_id}';
|
|
if(row.startsWith('repeating')){
|
|
rollObj.title = rollObj.title || attributes[`${row}_name`];
|
|
rollObj.baseBonus = attributes[`${row}_bonus`];
|
|
rollObj.base_damage = attributes[`${row}_damage`] && attributes.attributes[`${row}_damage`] !== '' ?
|
|
`[[${attributes[`${row}_damage`]}]]` :
|
|
undefined;
|
|
}else{
|
|
rollObj.title = `^{${row}}`;
|
|
rollObj.baseBonus = attributes[row];
|
|
}
|
|
const button = attributes[`${crewRow}_skill`] || rollObj.button;
|
|
delete rollObj.button;
|
|
if(!button){
|
|
return;
|
|
}
|
|
const actionCall = `%{${attributes[`${crewRow}_name`]}|${button.replace(/_|\s/g,'-')}-action||${RE.escape(rollObj)}}`;
|
|
const roll = await startRoll(actionCall);
|
|
finishRoll(roll.rollId);
|
|
};const update2e = function({trigger,attributes,sections,casc}){
|
|
attributes.edition = 1;
|
|
};
|
|
k.registerFuncs({'2':update2e},{type:['updater']});
|
|
//# sourceURL=Alien.js
|
|
|
|
/**
|
|
* Calculates how many dice to roll based on skill, attribute, and stress.
|
|
* @param {string} attrRef - The reference to the attribute including section and rowID for repeating attribute
|
|
* @param {attributeProxy} attributes - The attributes object provided by the K-scaffold
|
|
* @returns {object}
|
|
*/
|
|
const calcDice = (attrRef,attributes,bonusDice = 0,dieType = 'base') => {
|
|
const attributeName = skillAttributeMatch[attrRef] || attrRef;
|
|
const skillName = skillAttributeMatch[attrRef] ?
|
|
attrRef :
|
|
null;
|
|
let baseDice = dieType === 'base' ?
|
|
(( attributes[attributeName] || 0 ) + (attributes[skillName] || 0) + bonusDice) :
|
|
bonusDice;
|
|
let stressDice = attrRef === 'armor' ?
|
|
0 :
|
|
dieType === 'stress' ?
|
|
(( attributes[attributeName] || 0 ) + (attributes[skillName] || 0) + bonusDice) :
|
|
attributes.stress_level;
|
|
if(dieType === 'supply'){
|
|
baseDice = 0;
|
|
stressDice = Math.min(bonusDice,6);
|
|
}else if(dieType === 'death'){
|
|
baseDice = attributes[attributeName] + attributes[skillName];
|
|
stressDice = 0;
|
|
}else if(baseDice < 0){
|
|
stressDice = Math.max(0, stressDice + baseDice);
|
|
baseDice = 0;
|
|
}
|
|
const totalDice = (num,typ) =>
|
|
[...Array(num).keys()].reduce((obj,n) => {
|
|
obj[`${typ}_dice_${n+1}`] = '[[1d6]]';
|
|
return obj;
|
|
},{});
|
|
const baseObj = totalDice(baseDice,'base');
|
|
const stressObj = totalDice(stressDice,'stress');
|
|
if(Object.keys(baseObj).length || Object.keys(stressObj).length){
|
|
return {
|
|
...baseObj,
|
|
...stressObj
|
|
};
|
|
}else{
|
|
return {no_dice:true}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rolls basic attribute/skill checks
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const rollBasic = async function({trigger,attributes,sections,casc}){
|
|
const passedData = trigger.originalRollId ?
|
|
k.RE.unescape(trigger.originalRollId) :
|
|
{};
|
|
const [,,button] = k.parseTriggerName(trigger.name);
|
|
const attrName = button.replace(/-/g,'_').replace(/_action/,'');
|
|
const title = `^{${attrName.replace(/_/g,' ')}}`;
|
|
|
|
const bonusDice = await bonusPrompt({row:'',attrName,attributes,passedData})
|
|
|
|
const rollObj = {
|
|
title,
|
|
...calcDice(attrName,attributes,bonusDice),
|
|
...passedData
|
|
};
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections});
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({rollBasic});
|
|
|
|
/**
|
|
* Assembles the roll string from the roll object
|
|
* @param {object} rollObj - object describing the roll
|
|
* @param {string} [rollStart = '@{template_start}'] - The string to start the roll with.
|
|
* @returns {string}
|
|
*/
|
|
const assembleRoll = (rollObj,rollStart = '@{template_start} {{successes=[[0[computed value]]]}} {{panic=[[0[computed value]]]}} {{push_label=^{push}}} {{push_through=[[0[computed value]]]}}') => {
|
|
return Object.entries(rollObj).reduce((str,[field,content])=>{
|
|
return str += content ?
|
|
` {{${field}=${content}}}` :
|
|
'';
|
|
},`${rollStart}`);
|
|
};
|
|
|
|
/**
|
|
* Assembles and encodes the push data.
|
|
* @param {object} results - The results details
|
|
* @param {object} rollObj - The object detailing the roll that was sent.
|
|
*/
|
|
const assemblePushData = (results,rollObj) => {
|
|
const pushObj = Object.entries(rollObj).reduce((memo,[key,val]) => {
|
|
if(/(?:base|stress)_dice/.test(key)){
|
|
memo[key] = results[key].result === 6 ?
|
|
'[[6]]' :
|
|
`[[${results[key].expression}]]`;
|
|
}else if(
|
|
key !== 'successes' &&
|
|
key !== 'panic' &&
|
|
key !== 'push_through'
|
|
){
|
|
memo[key] = val
|
|
}
|
|
return memo;
|
|
},{});
|
|
const pushString = RE.escape(pushObj);
|
|
return pushString;
|
|
};
|
|
|
|
/**
|
|
* calculates the number of successes/panics in a roll result
|
|
* @param {object} results - The results object.
|
|
* @returns
|
|
*/
|
|
const calcSuccessPanic = (results = {},rollObj) => {
|
|
const successPanic = Object.entries(results).reduce((memo,[key,obj]) => {
|
|
if(/(?:base|stress)_dice/.test(key)){
|
|
if(obj.result === 1 && /stress/.test(key)){
|
|
memo.panic++;
|
|
}else if(obj.result === 6){
|
|
memo.successes++;
|
|
}
|
|
}
|
|
return memo;
|
|
},{successes:0,panic:0});
|
|
if(!successPanic.panic){
|
|
successPanic.push_through = assemblePushData(results,rollObj);
|
|
}
|
|
return successPanic;
|
|
};
|
|
|
|
/**
|
|
* Executes the roll. Uses a callback if any computations are required.
|
|
* @param {object} rollObj - Object describing the roll fields to be used
|
|
* @param {object} attributes - The character attributes
|
|
* @param {object[]} sections - The sections array
|
|
* @returns {Promise<object[]>} - Resolves to array with index 0 being the roll results object and index 1 being the computeObj with success/panics precalculated.
|
|
*/
|
|
const executeRoll = async ({rollObj,customString,attributes,sections}) => {
|
|
const rollString = assembleRoll(rollObj,customString);
|
|
const roll = await startRoll(rollString);
|
|
const computeObj = (roll.results.panic || roll.results.successes) ? calcSuccessPanic(roll.results,rollObj) : {};
|
|
return [roll, computeObj];
|
|
};/**
|
|
* Processes the push information and constructs the roll to be pushed.
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const pushRoll = async function({trigger,attributes,sections,casc}){
|
|
if(!trigger.originalRollId) return;
|
|
k.debug('pushing');
|
|
const pushData = RE.unescape(trigger.originalRollId);
|
|
debugger;
|
|
let stressDie = 0;
|
|
Object.keys(pushData).forEach(k =>{
|
|
if(/stress_dice/.test(k)){
|
|
stressDie++;
|
|
}
|
|
});
|
|
stressDie++;
|
|
pushData[`stress_dice_${stressDie}`] = `[[1d6]]`;
|
|
if(attributes.edition === 2 && attributes.jumpy){
|
|
stressDie++;
|
|
pushData[`stress_dice_${stressDie}`] = `[[1d6]]`;
|
|
}
|
|
attributes.stress_level = Math.min(stressDie, 10);
|
|
const [roll,computeObj] = await executeRoll({rollObj:pushData,customString:'@{template_start} {{successes=[[0[computed value]]]}} {{panic=[[0[computed value]]]}}',attributes,sections});
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({pushRoll});/**
|
|
* Rolls an attack for a weapon
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const rollAttack = async function({trigger,attributes,sections,casc}){
|
|
const [row] = parseRow(trigger.name);
|
|
const skill = attributes[`${row}_type`];
|
|
let promptDice;
|
|
if(
|
|
attributes.edition === 2 &&
|
|
attributes.range_automation === 'query' &&
|
|
attributes[`${row}_range_max`] !== 'Adjacent'
|
|
){
|
|
const ranges = ['Adjacent','Short','Medium','Long','Extreme'];
|
|
const maxRangeIndex = ranges.indexOf(attributes[`${row}_range_max`]);
|
|
const rangeOptions = ranges
|
|
.slice(0,maxRangeIndex + 1)
|
|
.map(r => `${k.capitalize(k.getTranslationByKey(r))},${r}`)
|
|
.join('|');
|
|
const range = await k.extractQueryResult(`${k.getTranslationByKey('Range to target')}|${rangeOptions}`);
|
|
promptDice = await bonusPrompt({row:`${row}_`,attrName:attributes[`${row}_name`],attributes});
|
|
const rangeMod = Math.min(
|
|
0,
|
|
ranges.indexOf(range) - ranges.indexOf(attributes[`${row}_range`])
|
|
);
|
|
promptDice += rangeMod * 2;
|
|
}else{
|
|
promptDice = await bonusPrompt({row:`${row}_`,attrName:attributes[`${row}_name`],attributes});
|
|
}
|
|
const bonusDice = (promptDice || 0) + attributes[`${row}_bonus`];
|
|
const rollObj = {
|
|
title:attributes[`${row}_name`],
|
|
...calcDice(skill,attributes,bonusDice),
|
|
base_damage: `[[${attributes[`${row}_damage`]}]]`,
|
|
comment: attributes[`${row}_description`]
|
|
};
|
|
if(attributes.edition === 2 && attributes[`${row}_ammo`] > 0){
|
|
rollObj.supply_roll = '[[0[computed roll]]]';
|
|
rollObj.supply_label = '^{ammo}';
|
|
}
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections});
|
|
if(attributes.edition === 2 && rollObj.supply_roll){
|
|
computeObj.supply_roll = k.escape({name:attributes[`${row}_name`],rating:attributes[`${row}_ammo`],attribute:`${row}_ammo`});
|
|
}
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({rollAttack});/**
|
|
* Rolls armor checks
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const rollArmor = async function({trigger,attributes,sections,casc}){
|
|
const bonusDice = await bonusPrompt({attrName:'armor',attributes});
|
|
const rollObj = {
|
|
title: attributes.armor_name || '^{armor}',
|
|
...calcDice('armor',attributes,bonusDice)
|
|
};
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start} {{successes=[[0[computed value]]]}}'});
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({rollArmor});/**
|
|
* Rolls an attack roll for a ship.
|
|
* @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 shipAttack = async function({trigger,attributes,sections,casc}){
|
|
const [row] = parseRow(trigger.name);
|
|
const rollObj = {
|
|
title:attributes[`${row}_name`],
|
|
description: attributes[`${row}_description`]
|
|
};
|
|
// Get the active gunners
|
|
const gunnerRows = getCrew(attributes,sections,'gunner');
|
|
|
|
// If there are no gunners and no mainframe, output an error message to chat
|
|
if(!gunnerRows.length){
|
|
rollObj.description = '^{no-assigned-crew}';
|
|
const [roll,computeObj] = await executeRoll({rollObj});
|
|
finishRoll(roll.rollId,computeObj);
|
|
return;
|
|
}
|
|
rollObj.base_damage = `[[${attributes[`${row}_damage`]}]]`;
|
|
// Otherwise, continue figuring out what type of weapon roll to make
|
|
if(gunnerRows.length === 1){
|
|
await rollCrew(row,rollObj,gunnerRows[0],attributes,sections);
|
|
return;
|
|
}else{
|
|
const queryMsg = `${k.capitalize(getTranslationByKey('multiple-gunner-query'))}|${gunnerRows.map((r,i) => `${attributes[`${r}_name`]},${i}`).join('|')}`;
|
|
const gunnerIndex = await k.extractQueryResult(queryMsg);
|
|
await rollCrew(row,rollObj,gunnerRows[gunnerIndex],attributes,sections);
|
|
}
|
|
};
|
|
k.registerFuncs({shipAttack});/**
|
|
* Rolls piloting checks for the ship modified by the thruster rating
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const thrusterRoll = async function({trigger,attributes,sections,casc}){
|
|
const attrName = trigger.name.replace(/-action$/,'');
|
|
const rollObj = {
|
|
title: `^{${attrName}}`
|
|
};
|
|
const pilotRows = getCrew(attributes,sections,'pilot');
|
|
// If there are no gunners and no mainframe, output an error message to chat
|
|
if(!pilotRows.length){
|
|
rollObj.description = '^{no-assigned-crew}';
|
|
const [roll,computeObj] = await executeRoll({rollObj});
|
|
finishRoll(roll.rollId,computeObj);
|
|
return;
|
|
}
|
|
if(pilotRows.length === 1){
|
|
await rollCrew('thrusters',rollObj,pilotRows[0],attributes,sections);
|
|
return;
|
|
}else{
|
|
const queryMsg = `${k.capitalize(getTranslationByKey('multiple-pilot-query'))}|${pilotRows.map((r,i) => `${attributes[`${r}_name`]},${i}`).join('|')}`;
|
|
const pilotIndex = await k.extractQueryResult(queryMsg);
|
|
await rollCrew('thrusters',rollObj,pilotRows[pilotIndex],attributes,sections);
|
|
}
|
|
};
|
|
k.registerFuncs({thrusterRoll});/**
|
|
* Rolls piloting checks for the ship modified by the thruster rating
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const engineerRoll = async function({trigger,attributes,sections,casc}){
|
|
const [row,,,buttonName] = parseRow(trigger.name);
|
|
const skillSelect = buttonName
|
|
.replace(/-action$/,'')
|
|
.replace(/-/g,'_');
|
|
|
|
const skillButton = attributes[`${row}_${skillSelect}`];
|
|
if(!skillButton) return;
|
|
const rollObj = {
|
|
title: `${attributes[`${row}_name`]}: ^{${skillButton.replace(/_/g,' ')}}`
|
|
};
|
|
const crewRows = getCrew(attributes,sections,'engineer',false);
|
|
// If there are no engineers, output an error message to chat
|
|
if(!crewRows.length){
|
|
rollObj.description = '^{no-assigned-crew}';
|
|
const [roll,computeObj] = await executeRoll({rollObj});
|
|
finishRoll(roll.rollId,computeObj);
|
|
return;
|
|
}
|
|
rollObj.button = skillButton;
|
|
if(crewRows.length === 1){
|
|
await rollCrew(row,rollObj,crewRows[0],attributes,sections);
|
|
return;
|
|
}else{
|
|
const queryMsg = `${k.capitalize(getTranslationByKey('multiple-engineer-query'))}|${crewRows.map((r,i) => `${attributes[`${r}_name`]},${i}`).join('|')}`;
|
|
const pilotIndex = await k.extractQueryResult(queryMsg);
|
|
await rollCrew(row ,rollObj,crewRows[pilotIndex],attributes,sections);
|
|
}
|
|
};
|
|
k.registerFuncs({engineerRoll});/**
|
|
* Calculates how long the journey will take.
|
|
* @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 ftlRoll = async function({trigger,attributes,sections,casc}){
|
|
const distance = await k.extractQueryResult(k.capitalize(getTranslationByKey('ftl-trip-query')));
|
|
const rollObj = {
|
|
title:'^{ftl trip}',
|
|
description: `days: [[${distance}[${k.capitalize(getTranslationByKey('distance'))}] * ${attributes.ftl_rating}[${k.capitalize(getTranslationByKey('ftl rating'))}]]]`
|
|
};
|
|
const [roll] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'})
|
|
finishRoll(roll.rollId);
|
|
};
|
|
k.registerFuncs({ftlRoll});/**
|
|
* Rolls for the sensor checks on a ship.
|
|
* @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 sensorRoll = async function({trigger,attributes,sections,casc}){
|
|
const rollObj = {};
|
|
const crewRows = getCrew(attributes,sections,'sensor operator');
|
|
if(!crewRows.length){
|
|
rollObj.description = '^{no-assigned-crew}';
|
|
const [roll,computeObj] = await executeRoll({rollObj});
|
|
finishRoll(roll.rollId,computeObj);
|
|
return;
|
|
}
|
|
|
|
if(crewRows.length === 1){
|
|
await rollCrew('comtech',rollObj,crewRows[0],attributes,sections);
|
|
return;
|
|
}else{
|
|
const queryMsg = `${k.capitalize(getTranslationByKey('multiple-so-query'))}|${crewRows.map((r,i) => `${attributes[`${r}_name`]},${i}`).join('|')}`;
|
|
const crewIndex = await k.extractQueryResult(queryMsg);
|
|
await rollCrew('comtech' ,rollObj,crewRows[crewIndex],attributes,sections);
|
|
}
|
|
};
|
|
k.registerFuncs({sensorRoll});/**
|
|
* Rolls for which signature attack to use.
|
|
* @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 hostileSignature = async function({trigger,attributes,sections,casc}){
|
|
if(!sections.repeating_signature.length){
|
|
const roll = await startRoll(`@{template_start} {{title=^{hostile signature}}} {{description=^{no-signature-moves}}}`);
|
|
finishRoll(roll.rollId);
|
|
return;
|
|
}
|
|
const sigTable = sections.repeating_signature.reduce((arr,id) => {
|
|
[...Array(attributes[`repeating_signature_${id}_weight`]).keys()].forEach(n => arr.push(`repeating_signature_${id}`))
|
|
return arr;
|
|
},[]);
|
|
const roll = await startRoll(`!{{signature=[[1d${sigTable.length}]]}}`);
|
|
const selRow = sigTable[roll.results.signature.result - 1];
|
|
finishRoll(roll.rollId);
|
|
rollSignature({trigger:{name:`${selRow}_action`},attributes,sections,casc});
|
|
};
|
|
k.registerFuncs({hostileSignature});/**
|
|
* Rolls the details for a given signature roll
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const rollSignature = async function({trigger,attributes,sections,casc}){
|
|
const [row,section,rowID] = parseRow(trigger.name);
|
|
const rollObj = {
|
|
title:attributes[`${row}_name`],
|
|
base_damage:`[[${attributes[`${row}_damage`]}]]`,
|
|
description:attributes[`${row}_description`]
|
|
};
|
|
const bonusDice = +(await bonusPrompt({
|
|
row,
|
|
attrName:attributes[`${row}_name`],
|
|
attributes
|
|
})) || 0;
|
|
const dice = calcDice(`${row}_bonus`,attributes,bonusDice);
|
|
|
|
Object.assign(rollObj,dice);
|
|
const [roll,computeObj] = await executeRoll({rollObj,customString:'@{template_start} {{successes=[[0[computed value]]]}}'});
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({rollSignature});/**
|
|
* Roll consumable rolls
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const consumableRoll = async function({trigger,attributes,sections,casc}){
|
|
const [,,button] = k.parseTriggerName(trigger.name);
|
|
const attrName = button.replace(/-/g,'_').replace(/_action/,'');
|
|
const title = `^{${attrName.replace(/_/g,' ')}}`;
|
|
if(attributes.edition === 2){
|
|
const supplyTrigger = {
|
|
...trigger,
|
|
rollData: {
|
|
name: title,
|
|
rating: attributes[attrName],
|
|
attribute:attrName
|
|
}
|
|
};
|
|
await supplyRoll({trigger:supplyTrigger,attributes,sections,casc})
|
|
return;
|
|
}
|
|
const bonusDice = await bonusPrompt({attrName,attributes});
|
|
const rollObj = {
|
|
title,
|
|
...calcDice(attrName,attributes,bonusDice,'stress')
|
|
};
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start} {{successes=[[0[computed value]]]}} {{panic=[[0[computed value]]]}}'});
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({consumableRoll});/**
|
|
* Rolls the d66 roll according to the rules for Alien
|
|
* @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 rolld66 = async function({trigger,attributes,sections,casc}){
|
|
const rollObj = {
|
|
title:'^{generic 1d66}',
|
|
d66:'[[0[computed value]]]',
|
|
tens:'[[1d6]]',
|
|
ones:'[[1d6]]'
|
|
};
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
computeObj.d66 = `${roll.results.tens.result}${roll.results.ones.result}`;
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({rolld66});/**
|
|
* Rolls the stress dice and applies results of stress 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 rollStress = async function({trigger,attributes,sections,casc}){
|
|
const [row,section,rowID,attr] = parseRow(trigger.name);
|
|
const rollObj = {
|
|
title:'^{stress}',
|
|
stress_roll:`[[1d6 + ${attributes.stress_level - attributes.nerves_of_steel}]]`
|
|
};
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
finishRoll(roll.rollId,computeObj);
|
|
const applyStress = {
|
|
'7':increaseStress,
|
|
'10':increaseStress,
|
|
'11':decreaseStress,
|
|
'12':decreaseStress,
|
|
'13':decreaseStress
|
|
}
|
|
applyStress[roll.results.stress_roll.result] &&
|
|
applyStress[roll.results.stress_roll.result](attributes);
|
|
attributes.set({attributes,sections,casc});
|
|
};
|
|
k.registerFuncs({rollStress});
|
|
|
|
const increaseStress = (attributes) => attributes.stress_level = Math.min(10,attributes.stress_level + 1);
|
|
|
|
const decreaseStress = (attributes) => attributes.stress_level = Math.max(attributes.stress_level - 1,0);/**
|
|
* Rolls the stress dice and applies results of stress 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 rollRadiation = async function({trigger,attributes,sections,casc}){
|
|
const [row,section,rowID,attr] = parseRow(trigger.name);
|
|
const rollObj = {
|
|
title:'^{radiation}',
|
|
...calcDice('radiation_level',attributes,attributes.radiation_level,dieType = 'armor')
|
|
};
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
finishRoll(roll.rollId,computeObj);
|
|
const applyStress = {
|
|
'7':increaseStress,
|
|
'10':increaseStress,
|
|
'11':decreaseStress,
|
|
'12':decreaseStress,
|
|
'13':decreaseStress
|
|
}
|
|
applyStress[roll.results.stress_roll.result] &&
|
|
applyStress[roll.results.stress_roll.result](attributes);
|
|
attributes.set({attributes,sections,casc});
|
|
};
|
|
k.registerFuncs({rollRadiation});/**
|
|
*
|
|
* @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 supplyRoll = async function({trigger,attributes,sections,casc}){
|
|
if(!trigger.rollData) return;
|
|
const data = {...trigger.rollData};
|
|
const [section,rowID,btnName] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${rowID}`;
|
|
if(data.section && !data.name){
|
|
data.attribute = `${row}_${data.attribute}`
|
|
data.name = attributes[`${row}_name`];
|
|
}
|
|
if(!data.hasOwnProperty('rating')){
|
|
data.rating = attributes[data.attribute];
|
|
}
|
|
const rollObj = {
|
|
title: data.name ? `^{supply}: ${data.name}` : `^{supply roll}`,
|
|
...calcDice(null,attributes,data.rating,'supply')
|
|
};
|
|
const [roll] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
finishRoll(roll.rollId);
|
|
|
|
if(!data.attribute) return;
|
|
|
|
const decrease = Object.entries(roll.results).reduce((total,[key,obj]) => {
|
|
if(
|
|
key.startsWith('stress_dice_') &&
|
|
obj.result === 1
|
|
){
|
|
total++;
|
|
}
|
|
return total;
|
|
},0);
|
|
attributes[data.attribute] = Math.max(0,attributes[data.attribute]-decrease) ;
|
|
attributes.set();
|
|
};
|
|
k.registerFuncs({supplyRoll});/**
|
|
*
|
|
* @param {object} trigger - The trigger that caused the function to be called
|
|
* @param {object} attributes - The attribute values of the character
|
|
* @param {object[]} sections - All the repeating section IDs
|
|
* @param {object} casc - Expanded cascade object
|
|
*/
|
|
const rollDeath = async function({trigger,attributes,sections,casc}){
|
|
const rollObj = {
|
|
title: '^{death roll}',
|
|
...calcDice('stamina',attributes,0,'death')
|
|
}
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start} {{successes=[[0[computed value]]]}}'});
|
|
finishRoll(roll.rollId,computeObj);
|
|
};
|
|
k.registerFuncs({rollDeath});
|
|
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
|
/*jshint -W014,-W084,-W030,-W033*/
|
|
const maxAttr = ['health','resolve','hull'];
|
|
|
|
const convertAttributeNames = (key) => {
|
|
key = key.replace(/^(?:data-)?cs(?:list)?-/,'');
|
|
const conversionChart = {
|
|
armor_rating:'armor'
|
|
};
|
|
return conversionChart[key] || key;
|
|
}
|
|
|
|
const handleCompendiumDrop = function({attributes,sections,casc}){
|
|
let data = parseDropData(attributes.drop_data);
|
|
if(!data) return;
|
|
data = (data['data-Ships'] && data['data-Ships'][0]) ||
|
|
(data['data-Hostiles'] && data['data-Hostiles'][0]) ||
|
|
(data['data-Vehicles'] && data['data-Vehicles'][0]) ||
|
|
(data['data-NPCs'] && data['data-NPCs'][0]) ||
|
|
data;
|
|
k.debug({data});
|
|
clearDropAttributes();
|
|
compendiumLookup({
|
|
origBlock:data,
|
|
attributes,sections,casc,
|
|
callback: async (lookupObj)=>{
|
|
let isFull = false;
|
|
if(/Ships|Hostiles|Vehicles|NPCs/.test(data.Category)){
|
|
isFull = npcHandler(data,attributes,sections,casc)
|
|
}else if(data.Category === 'Armor'){
|
|
attributes.armor_description = '';
|
|
attributes.armor_comment = '';
|
|
attributes.armor_weight = 0;
|
|
attributes.armor = 0;
|
|
attributes.armor_name = '';
|
|
}
|
|
k.debug({parsedData:lookupObj});
|
|
const sectionsToQuery = [];
|
|
processDropData({data:lookupObj,attributes,sections,casc,sectionsToQuery});
|
|
const protoQueue = Object.keys(attributes.updates)
|
|
.flatMap( key => {
|
|
const cascRef = key.replace(/(repeating_[^_]+)_[^_]+_(.+)/,'$1_\$X_$2');
|
|
casc[`attr_${cascRef}`] = casc[`attr_${cascRef}`] || k.cascades[`attr_${cascRef}`];
|
|
return k.cascades[`attr_${cascRef}`] ?
|
|
casc[`attr_${cascRef}`].affects
|
|
: [];
|
|
});
|
|
if(isFull){
|
|
sections.repeating_gear.forEach(gearID => {
|
|
const gearRow = `repeating_gear_${gearID}`;
|
|
if(
|
|
sections.repeating_weapons.some(weapID => {
|
|
const weapRow = `repeating_weapons_${weapID}`;
|
|
return attributes[`${weapRow}_name`] === attributes[`${gearRow}_name`];
|
|
})
|
|
){
|
|
k.removeRepeatingRow(gearRow,attributes,sections);
|
|
}
|
|
})
|
|
}
|
|
k.setActionCalls({attributes,sections});
|
|
k.callFunc('kTabOnOpen',{attributes});
|
|
attributes.queue.push(...[...new Set(protoQueue)]);
|
|
k.debug('Drop processing complete');
|
|
k.debug({updates:attributes.updates});
|
|
attributes.set({attributes,sections,casc});
|
|
}
|
|
});
|
|
};
|
|
k.registerFuncs({handleCompendiumDrop});
|
|
|
|
const parseDropData = function(drop_data){
|
|
k.debug('parsing drop data');
|
|
k.debug({drop_data:`"${drop_data}"`});
|
|
try{
|
|
let data = JSON.parse(drop_data);
|
|
data = Object.entries(data)
|
|
.reduce((memo,[key,val])=>{
|
|
if(val){
|
|
if(typeof val === 'string' && val.startsWith('[{')){
|
|
val = JSON.parse(val);
|
|
}
|
|
memo[key] = val;
|
|
}
|
|
return memo;
|
|
},{});
|
|
if(data.Category !== 'NPCs' && data.Category !== 'Vehicles' && data.Category !== 'Armor'){
|
|
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});
|
|
});
|
|
}
|
|
}
|
|
return data;
|
|
}catch(err){
|
|
k.debug({'Invalid Drop Data! Drop aborted. Error:':err,drop_data},true);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const clearSheet = function(attributes,sections,casc){
|
|
Object.entries(sections).forEach(([section,idArray])=>{
|
|
idArray.forEach((id)=>{
|
|
k.removeRepeatingRow(`${section}_${id}`,attributes,sections);
|
|
});
|
|
});
|
|
Object.keys(attributes.attributes).forEach((attr)=>{
|
|
if(casc[`attr_${attr}`]){
|
|
attributes.updates[attr] = casc[`attr_${attr}`].hasOwnProperty('defaultValue') && casc[`attr_${attr}`].defaultValue !== 0 ?
|
|
casc[`attr_${attr}`].defaultValue :
|
|
'';
|
|
}
|
|
});
|
|
};
|
|
|
|
const clearDropAttributes = function(){
|
|
k.setAttrs({drop_name:'',drop_data:''});
|
|
};
|
|
|
|
const processDropData = function({data, attributes, sections, casc,sectionsToQuery,section=''}){
|
|
const repeatProcessors = {
|
|
Talents:genericDrop,
|
|
Weapons:weaponDrop,
|
|
Gear:genericDrop,
|
|
Signature:genericDrop,
|
|
Armaments:genericDrop,
|
|
Internal:genericDrop,
|
|
'Internal-modules':genericDrop,
|
|
Upgrades:upgradeDrop,
|
|
Component:componentDrop,
|
|
Abilities:genericDrop,
|
|
"Rollable Tables": tableDrop,
|
|
"Rollable":tableDrop,
|
|
"rollable":tableDrop,
|
|
"rollable tables":tableDrop
|
|
};
|
|
section = section ? `${section}_` : '';
|
|
if(/Ships|Hostiles|Vehicles|NPCs/.test(data.Category)){
|
|
const tokenSize = 70;
|
|
const tokenObj = {
|
|
width:tokenSize,
|
|
height:tokenSize,
|
|
};
|
|
setDefaultToken(tokenObj);
|
|
}
|
|
const worker = (queue) => {
|
|
let [key,val] = queue.shift();
|
|
try{
|
|
const setKey = convertAttributeNames(key);
|
|
if(typeof val === 'string' && val.startsWith('[{')){
|
|
val = JSON.parse(val);
|
|
}
|
|
if(!Array.isArray(val) && (key.startsWith('cs-') || key.startsWith('data-cs-'))){
|
|
attributes[`${section}${setKey}`] = val;
|
|
if(maxAttr.includes(setKey)){
|
|
attributes[`${section}${setKey}_max`] = val;
|
|
}
|
|
}else if(Array.isArray(val) && key.startsWith('data-')){
|
|
let lookupKey = k.capitalize(key.replace(/data-(?:cs(?:list)?-)?/,''));
|
|
k.debug({lookupKey});
|
|
if(repeatProcessors[lookupKey]){
|
|
repeatProcessors[lookupKey](lookupKey,val,attributes,sections,casc,sectionsToQuery);
|
|
}else if(key.startsWith('data-cslist-')){
|
|
attributes[`${section}${setKey}`] = val.map((o)=>o.name).join(', ');
|
|
}else if(key === 'data-content'){
|
|
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+$/,'');
|
|
}else if(Array.isArray(val)){
|
|
val.forEach(v=>{
|
|
queue.push(...Object.entries(v));
|
|
})
|
|
}
|
|
}
|
|
}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 sectionLookup = {
|
|
Internal:'internal-modules'
|
|
};
|
|
|
|
/**
|
|
* 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]});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 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 = function(lookupKey,arr,sections,casc,callback){
|
|
const type = sectionLookup[lookupKey] || lookupKey.toLowerCase();
|
|
const worker = (queue)=>{
|
|
const itemObj = queue.shift();
|
|
itemObj['data-cs-collapse'] = 1;
|
|
const section = k.generateRowID(type,sections);
|
|
addRowToCasc(section,casc);
|
|
callback(itemObj,section);
|
|
if(queue.length){
|
|
return worker(queue);
|
|
}else{
|
|
return true;
|
|
}
|
|
};
|
|
return worker([...arr]);
|
|
}/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
|
/*jshint -W014,-W084,-W030,-W033*/
|
|
//Initiate a compendium lookup
|
|
const specialCategories = {
|
|
'Internal':'Internal Modules',
|
|
'internal-modules':'Internal Modules',
|
|
'Component':'Component Damage',
|
|
'component-damage':'Component Damage'
|
|
};
|
|
//These categories are the part after the data- in a bestiary entry. E.g. a monster has a data-Armors JSON, but the actual compendium category is "Armor". These are converted to the proper compendium category via the categoryLookup Proxy
|
|
const itemCategories = [
|
|
'Internal','internal-modules','Internal Modules',
|
|
'Component','component-damage','Component Damage',
|
|
'Armaments','Gear','Talents','Upgrades','Weapons'];
|
|
|
|
//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}`] || statblock[`data-${type}`.toLowerCase()]){
|
|
let searchNames = (
|
|
statblock[`data-${type}`] ||
|
|
statblock[`data-${type}`.toLowerCase()]
|
|
).map((obj) => obj.name || obj['data-cs-name'] || '')
|
|
.join('|')
|
|
.replace(/\|{2,}/g,'')
|
|
.replace(/\|$/,'');
|
|
if(searchNames.length > 0){
|
|
let searchString = `Category:${searchType} data-cs-name:${searchNames}`;
|
|
m.push(searchString);
|
|
}
|
|
}
|
|
return m;
|
|
}, searchArray);
|
|
k.debug({searchArray});
|
|
if(searchArray.length){
|
|
lookupBurndown(statblock, searchArray, callback, origBlock, attributes, sections, casc,pass);
|
|
}else{
|
|
callback(origBlock);
|
|
}
|
|
});
|
|
};
|
|
|
|
//Actually queries the compendium to get details on the items in each category using the searchArray assembled in compendiumLookup
|
|
//ARGUMENTS
|
|
//statblock (object): the original object dropped from the compendium
|
|
//callback (function): A function that will use the parsed compendium lookup data to finish the drag and drop of the item
|
|
//The callback function receives the parsed statblock as an argument
|
|
const lookupBurndown = function(statblock, searchArray, callback, origBlock, attributes, sections, casc,pass) {
|
|
getCompendiumQuery(searchArray, (dataArr) => {
|
|
k.debug({dataArr});
|
|
const expansionIDs = dataArr
|
|
.reduce( (arr,obj)=>{
|
|
arr.push(k.value(obj.data.Expansion));
|
|
return arr;
|
|
},[])
|
|
.sort((a,b) => b - a);
|
|
itemCategories.forEach((category) => {
|
|
if (statblock[`data-${category}`] || statblock[`data-${category}`.toLowerCase()]) {
|
|
const statRef = statblock[`data-${category}`] ?
|
|
category :
|
|
category.toLowerCase();
|
|
origBlock[`data-${statRef}`] = statblock[`data-${statRef}`].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;
|
|
};/**
|
|
* Generic drop function for repeating sections that don't need any special processing.
|
|
* @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 genericDrop = function(lookupKey,arr,attributes,sections,casc,sectionsToQuery){
|
|
if(!Array.isArray(arr)){
|
|
k.debug({'Invalid section details passed. Exiting. Object passed was:':arr},true);
|
|
return;
|
|
}
|
|
return repeatWorker(lookupKey,arr,sections,casc,(itemObj,section)=>{
|
|
processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
|
|
});
|
|
};/**
|
|
* Generic drop function for repeating sections that don't need any special processing.
|
|
* @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 = function(lookupKey,arr,attributes,sections,casc,sectionsToQuery){
|
|
if(!Array.isArray(arr)){
|
|
k.debug({'Invalid section details passed. Exiting. Object passed was:':arr},true);
|
|
return;
|
|
}
|
|
const weaponArr = arr.map( o => {
|
|
return Object.entries(o)
|
|
.reduce( (m,[k,v]) => {
|
|
if(!/(?:weight|cost)$/.test(k)){
|
|
m[k] = v;
|
|
}
|
|
return m;
|
|
},{});
|
|
});
|
|
const gearArr = arr.map( o => {
|
|
return Object.entries(o)
|
|
.reduce( (m,[k,v]) => {
|
|
if(/(?:name|description|weight|cost|)$/.test(k)){
|
|
m[k] = v;
|
|
}
|
|
return m;
|
|
},{});
|
|
});
|
|
repeatWorker('Weapons',weaponArr,sections,casc,(itemObj,section)=>{
|
|
processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
|
|
});
|
|
|
|
repeatWorker('Gear',gearArr,sections,casc,(itemObj,section)=>{
|
|
processDropData({data:itemObj,attributes,sections,casc,sectionsToQuery,section});
|
|
});
|
|
};/**
|
|
* Generic drop function for repeating sections that don't need any special processing.
|
|
* @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 upgradeDrop = function(lookupKey,arr,attributes,sections,casc,sectionsToQuery){
|
|
if(!Array.isArray(arr)){
|
|
k.debug({'Invalid section details passed. Exiting. Object passed was:':arr},true);
|
|
return;
|
|
}
|
|
arr.forEach( o => {
|
|
o['data-cs-quantity'] = o['data-cs-quantity'] || 1;
|
|
});
|
|
genericDrop(lookupKey,arr,attributes,sections,casc,sectionsToQuery);
|
|
};/**
|
|
* Generic drop function for repeating sections that don't need any special processing.
|
|
* @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 componentDrop = function(lookupKey,arr,attributes,sections,casc,sectionsToQuery){
|
|
if(!Array.isArray(arr)){
|
|
k.debug({'Invalid section details passed. Exiting. Object passed was:':arr},true);
|
|
return;
|
|
}
|
|
const vehicleArr = [];
|
|
const minorArr = [];
|
|
const majorArr = [];
|
|
arr.forEach( o => {
|
|
const type = o['data-cs-type'];
|
|
delete o['data-cs-type'];
|
|
[1,2].forEach(num => {
|
|
if(o[`data-cs-skill_${num}_completed_max`]){
|
|
o[`data-cs-skill_${num}_completed`] = o[`data-cs-skill_${num}_completed`] || 0;
|
|
}
|
|
})
|
|
switch(type){
|
|
case 'minor':
|
|
minorArr.push(o);
|
|
break;
|
|
case 'major':
|
|
majorArr.push(o);
|
|
break;
|
|
case 'vehicle':
|
|
vehicleArr.push(o);
|
|
}
|
|
});
|
|
if(vehicleArr.length){
|
|
genericDrop('component-damage',vehicleArr,attributes,sections,casc,sectionsToQuery);
|
|
}else if(minorArr.length){
|
|
genericDrop('minor-component-damage',minorArr,attributes,sections,casc,sectionsToQuery);
|
|
}else if(majorArr.length){
|
|
genericDrop('major-component-damage',majorArr,attributes,sections,casc,sectionsToQuery);
|
|
}
|
|
};const npcHandler = function(data,attributes,sections,casc){
|
|
clearSheet(attributes,sections,casc);
|
|
if(+data.Expansion > 19398){
|
|
attributes.edition = 2;
|
|
}
|
|
attributes.queue.push('character_name','menu_tab');
|
|
attributes.character_name = data['data-cs-character_name'] ||
|
|
data['data-cs-name'];
|
|
attributes.reveal_skills = 0;
|
|
delete data['data-cs-name'];
|
|
delete data['data-cs-character_name'];
|
|
|
|
attributes.sheet_type = data.Category
|
|
.toLowerCase()
|
|
.replace(/s$/,'');
|
|
attributes['menu_tab'] = `nav-tabs-menu--${attributes.sheet_type}`;
|
|
return true;
|
|
}/**
|
|
* Generic drop function for repeating sections that don't need any special processing.
|
|
* @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 tableDrop = async function (lookupKey, arr, attributes, sections, casc, sectionsToQuery) {
|
|
const data = arr[0];
|
|
const predefinedHandlers = {
|
|
"Panic Responses": panicCompendiumResponse,
|
|
"Stress Responses": stressCompendiumResponse,
|
|
"Neurological Distortion Disorder": NDDResponse
|
|
};
|
|
if (predefinedHandlers[data['data-cs-name']]) {
|
|
await k.pseudoQuery();
|
|
predefinedHandlers[data['data-cs-name']]({ attributes, sections, casc, data });
|
|
} else {
|
|
const die = data['data-dice'].replace(/stress|resolve/g, (match) => attributes[match]);
|
|
await rollTable(die, data['data-cs-name'], data['data-table'], attributes, sections, casc);
|
|
}
|
|
};
|
|
|
|
const rollTable = async function (die, tableName, table, attributes, sections, casc) {
|
|
die = die.replace(/d66/g,'[[d6]][[d6]]');
|
|
const rollObj = {
|
|
title: tableName,
|
|
tableResult: `[[${die}[computed result]]]`,
|
|
};
|
|
const [roll, computeObj] = await executeRoll({ rollObj, attributes, sections, customString: '@{template_start}' });
|
|
const tableIndex = Math.max(0, Math.min(table.length - 1, roll.results.tableResult.result));
|
|
const numResult = roll.results.tableResult.result;
|
|
const result = table.find(o => (new RegExp(`≤?${numResult}\\+?`)).test(`${o.die}`));
|
|
let conditionName
|
|
if(result.label){
|
|
conditionName = result.label.toLowerCase();
|
|
computeObj.tableResult = `${conditionName.toUpperCase()} ${result.response}`;
|
|
}else{
|
|
computeObj.tableResult = Object
|
|
.entries(result)
|
|
.reduce((t,[key,value]) => {
|
|
if(key !== 'die'){
|
|
t.push(`${key}: ${value}`)
|
|
}
|
|
return t;
|
|
},[])
|
|
.join('\n');
|
|
}
|
|
finishRoll(roll.rollId, computeObj);
|
|
return [computeObj.tableResult,conditionName,result.response];
|
|
}
|
|
|
|
const NDDResponse = async function ({ attributes, sections, casc, data }) {
|
|
const days = Math.max(0,+(await k.extractQueryResult(`${k.getTranslationByKey('NDD Prompt')}`)) - 1);
|
|
rollTable(`1d6 + ${days}`,data['data-cs-name'],data['data-table'],attributes,sections,casc);
|
|
}
|
|
/**
|
|
* Switches the active state of all row IDs to be appropriate to their state. Only a single row should have an active state.
|
|
* @param {string} newID - The row ID of the new row
|
|
* @param {AttributesProxy} attributes - The K-scaffolds Attribute object
|
|
* @param {object} sections - The K-scaffold sections object
|
|
*/
|
|
const switchActiveTalent = (newID,attributes,sections) => {
|
|
sections.repeating_talents.forEach(id => {
|
|
attributes[`repeating_talents_${id}_active`] = id ===
|
|
newID ?
|
|
1 :
|
|
0;
|
|
})
|
|
}/**
|
|
* Deletes the currently displayed talent info when the corresponding repeating item is deleted.
|
|
* @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 deleteTalent = function({trigger,attributes,sections,casc}){
|
|
const attr = Object.keys(trigger.removedInfo)[0];
|
|
if(!attr) return;
|
|
const [ ,rowID ] = k.parseTriggerName(attr);
|
|
if(rowID && rowID.toLowerCase() === attributes.talent_id.toLowerCase()){
|
|
attributes.talent_name = '';
|
|
attributes.talent_description = '';
|
|
attributes.talent_id = '';
|
|
}
|
|
};
|
|
k.registerFuncs({deleteTalent});/**
|
|
* Loads a talent's information into the edit interface
|
|
* @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 loadTalent = function({trigger,attributes,sections,casc}){
|
|
const [section,rowID] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${rowID}`;
|
|
|
|
switchActiveTalent(rowID,attributes,sections);
|
|
|
|
attributes.talent_id = rowID;
|
|
attributes[`${row}_active`] = 1;
|
|
attributes.talent_name = attributes[`${row}_name`] === talentPlaceholder ?
|
|
'' :
|
|
attributes[`${row}_name`];
|
|
attributes.talent_description = attributes[`${row}_description`];
|
|
attributes.talent_push_twice = attributes[`${row}_push_twice`];
|
|
};
|
|
k.registerFuncs({loadTalent});/**
|
|
* Does the setup for adding a new talent
|
|
* @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 createTalent = function({trigger,attributes,sections,casc,newRow}){
|
|
attributes.talent_name = '';
|
|
attributes.talent_description = '';
|
|
attributes.talent_push_twice = '';
|
|
const [,rowID] = k.parseRepeatName(newRow);
|
|
attributes.talent_id = rowID;
|
|
switchActiveTalent(rowID,attributes,sections);
|
|
attributes[`${newRow}_name`] = talentPlaceholder;
|
|
};
|
|
k.registerFuncs({createTalent});/**
|
|
* Saves talent information to the repeating section.
|
|
* @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 saveTalent = function({trigger,attributes,sections,casc}){
|
|
const target = trigger.name.replace(/talent_/,'');
|
|
const row = attributes.talent_id ?
|
|
`repeating_talents_${attributes.talent_id}` :
|
|
k.generateRowID('repeating_talents',sections);
|
|
const [,rowID] = k.parseRepeatName(row);
|
|
attributes[`${row}_${target}`] = attributes[trigger.name];
|
|
attributes.talent_id = rowID;
|
|
};
|
|
k.registerFuncs({saveTalent});
|
|
/**
|
|
*
|
|
* @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 encumbranceCalc = function({trigger,attributes,sections,casc}){
|
|
return attributes.strength * 2;
|
|
};
|
|
k.registerFuncs({encumbranceCalc});/**
|
|
* Calculates the current weight of items
|
|
* @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 currentEncumbranceCalc = function({trigger,attributes,sections,casc}){
|
|
let weight2e = 0;
|
|
if(attributes.edition === 2){
|
|
weight2e = sections.repeating_weapons.reduce((total,id) => {
|
|
const row = `repeating_weapons_${id}`;
|
|
return total += attributes[`${row}_weight`];
|
|
},0)
|
|
}
|
|
return sections.repeating_gear.reduce((total,id) => {
|
|
const row = `repeating_gear_${id}`;
|
|
return total += attributes[`${row}_weight`] * attributes[`${row}_quantity`];
|
|
},attributes.armor_weight + weight2e);
|
|
};
|
|
k.registerFuncs({currentEncumbranceCalc});/**
|
|
* Determines if the changed internal module attribute should update the ai name and applies that update if it does.
|
|
* @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 removeAIEffect = function({trigger,attributes,sections,casc}){
|
|
const [section,rowID] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${rowID}`;
|
|
if(attributes[`${row}_type`] === 'artificial intelligence'){
|
|
trigger.affects = trigger.affects.filter(str => str !== 'ai');
|
|
}
|
|
};
|
|
k.registerFuncs({removeAIEffect});/**
|
|
* Assembles the AI name based on the internal modules
|
|
* @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 setAIName = function({trigger,attributes,sections,casc}){
|
|
const aiID = sections['repeating_internal-modules']
|
|
.find(id =>
|
|
attributes[`repeating_internal-modules_${id}_type`] === 'artificial intelligence')
|
|
|
|
const row = `repeating_internal-modules_${aiID}`;
|
|
return attributes[`${row}_name`];
|
|
};
|
|
k.registerFuncs({setAIName});/**
|
|
* Controls the reactions to the character type changing. Adjusts the whisper type and invokes `characterDisplay` to add/remove classes to control the display of nav buttons.
|
|
* @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 characterSetup = function({trigger,attributes,sections,casc}){
|
|
attributes.whisper = attributes.sheet_type === 'npc' ?
|
|
attributes.whisper = '/w gm ' :
|
|
'';
|
|
characterDisplay({attributes});
|
|
};
|
|
k.registerFuncs({characterSetup});/**
|
|
* Controls the classes of the nav buttons to control their display.
|
|
* @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 characterDisplay = function({attributes}){
|
|
const validTabs = {
|
|
'character':['character','character2e'],
|
|
'npc':['npc','character','npc2e','character2e'],
|
|
'hostile':['hostile','hostile2e'],
|
|
'ship':['ship','ship2e'],
|
|
'vehicle':['vehicle','vehicle2e'],
|
|
'party screen': ['initiative']
|
|
}
|
|
$20('.tabs__button:not(.tabs--menu__button--settings)').addClass('disabled');
|
|
validTabs[attributes.sheet_type].forEach( t => {
|
|
$20(`.tabs__button.tabs--menu__button--${t}`).removeClass('disabled');
|
|
})
|
|
};
|
|
k.registerFuncs({characterDisplay},{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 compendiumCheck = function({trigger,attributes,sections,casc}){
|
|
// 'Rollable Tables:Stress Responses'
|
|
getCompendiumPage('Rollable Tables:Stress Responses',data => {
|
|
$20('.no-compendium').addClass('disabled');
|
|
$20('.compendium-required').addClass('active');
|
|
});
|
|
};
|
|
k.registerFuncs({compendiumCheck},{type:['opener']});
|
|
|
|
|
|
/**
|
|
* unsets the max value when single shot/use is selected
|
|
* @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 unsetMax = function({trigger,attributes,sections,casc}){
|
|
if(attributes.attributes[trigger.name] !== 'single') return;
|
|
const [section,rowID] = k.parseTriggerName(trigger.name);
|
|
const row = `${section}_${rowID}`;
|
|
attributes[`${row}_${trigger.ammo}_max`] = '';
|
|
};
|
|
k.registerFuncs({unsetMax});
|
|
|
|
|
|
const switchEdition = function({trigger,attributes,sections,casc}){
|
|
const [action1e,action2e] = attributes.edition === 1 ?
|
|
['removeClass','addClass']:
|
|
['addClass','removeClass'];
|
|
|
|
$20('.secondedition')[action2e]('edition-disabled');
|
|
$20('.edition-style')[action1e]('style-2e');
|
|
$20('.charactersheet')[action1e]('style-2e');
|
|
|
|
$20('.firstedition')[action1e]('edition-disabled');
|
|
$20('.edition-style')[action2e]('style-1e');
|
|
$20('.charactersheet')[action2e]('style-1e');
|
|
};
|
|
k.registerFuncs({switchEdition},{type:['opener']});
|
|
|
|
|
|
// no compendium roll for stress/panic
|
|
const stressPanicResponse = async function({trigger,attributes,sections,casc}){
|
|
const responseType = trigger.name.replace(/-response-action/,'');
|
|
const rollObj = {
|
|
title: `^{${responseType} response}`,
|
|
results: `[[1d6 + ${attributes.stress_level} - ${attributes.resolve}]]`
|
|
};
|
|
|
|
const [roll] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
finishRoll(roll.rollId);
|
|
};
|
|
k.registerFuncs({stressPanicResponse});
|
|
|
|
const stressCompendiumResponse = function({trigger,attributes,sections,casc}){
|
|
getCompendiumPage('Rollable Tables:Stress Responses',async data => {
|
|
const rollObj = {
|
|
title: '^{stress response}',
|
|
tableResult: `[[1d6 + ${attributes.stress_level} - ${attributes.resolve}[computed result]]]`
|
|
}
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
const tableIndex = Math.max(0,Math.min(7,roll.results.tableResult.result));
|
|
const conditionName = data.data['data-table'][tableIndex].label.toLowerCase();
|
|
computeObj.tableResult = `${conditionName.toUpperCase()} ${data.data['data-table'][tableIndex].response}`;
|
|
finishRoll(roll.rollId,computeObj);
|
|
if(attributes.attributes.hasOwnProperty(conditionName)){
|
|
attributes[conditionName.replace(/\s+/g,'_')] = 1;
|
|
if(
|
|
conditionName === 'deflated' ||
|
|
(conditionName === 'jumpy' && attributes.deflated)
|
|
){
|
|
attributes.jumpy = 0;
|
|
}
|
|
}
|
|
attributes.set();
|
|
});
|
|
};
|
|
k.registerFuncs({stressCompendiumResponse});
|
|
|
|
const panicCompendiumResponse = function({trigger,attributes,sections,casc}){
|
|
getCompendiumPage('Rollable Tables:Panic Responses',async data => {
|
|
const rollObj = {
|
|
title: '^{panic response}',
|
|
tableResult: `[[1d6 + ${attributes.stress_level} - ${attributes.resolve}[computed result]]]`
|
|
}
|
|
const [roll,computeObj] = await executeRoll({rollObj,attributes,sections,customString:'@{template_start}'});
|
|
const tableIndex = Math.max(0,Math.min(12,roll.results.tableResult.result));
|
|
const conditionName = data.data['data-table'][tableIndex].label.toLowerCase();
|
|
computeObj.tableResult = `${conditionName.toUpperCase()} ${data.data['data-table'][tableIndex].response}`;
|
|
finishRoll(roll.rollId,computeObj);
|
|
if(attributes.attributes.hasOwnProperty(conditionName.replace(/\s+/g,'_'))){
|
|
attributes[conditionName.replace(/\s+/g,'_')] = 1;
|
|
}else if(conditionName === 'spooked'){
|
|
attributes.stress_level = Math.min(10,attributes.stress_level + 1)
|
|
}
|
|
attributes.set();
|
|
});
|
|
};
|
|
k.registerFuncs({panicCompendiumResponse});
|
|
</script>
|
|
|