mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-09-04 22:22:28 +00:00
2279 lines
174 KiB
HTML
2279 lines
174 KiB
HTML
|
||
<input name="attr_template_start" value="@{whisper}&{template:utn} {{character_name=@{character_name}}} {{character_id=@{character_id}}}" type="hidden" title="@{template_start}"/>
|
||
<input name="attr_sheet_version" value="0" type="hidden" title="@{sheet_version}"/>
|
||
<input name="attr_sheet_state" value="settings" type="hidden" title="@{sheet_state}"/>
|
||
<input name="attr_collapsed" value="" type="hidden" title="@{collapsed}"/>
|
||
<main id="main">
|
||
<nav class="sheet-nav" id="main-nav">
|
||
<div class="basic-moves span-all character-type character-type--character character-type--mon">
|
||
<button class="styled-button basic-roll roller" name="roll_see_into_their_heart" data-i18n="see into their heart" value="@{see_into_their_heart_action}" title="%{see_into_their_heart}" type="roll">
|
||
</button>
|
||
<button name="act_see-into-their-heart-action" hidden="" type="action" title="%{see-into-their-heart-action}">
|
||
</button>
|
||
<input name="attr_see_into_their_heart_action" type="hidden" title="@{see_into_their_heart_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_help_somebody" data-i18n="help somebody" value="@{help_somebody_action}" title="%{help_somebody}" type="roll">
|
||
</button>
|
||
<button name="act_help-somebody-action" hidden="" type="action" title="%{help-somebody-action}">
|
||
</button>
|
||
<input name="attr_help_somebody_action" type="hidden" title="@{help_somebody_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_touch_the_other_side" data-i18n="touch the other side" value="@{touch_the_other_side_action}" title="%{touch_the_other_side}" type="roll">
|
||
</button>
|
||
<button name="act_touch-the-other-side-action" hidden="" type="action" title="%{touch-the-other-side-action}">
|
||
</button>
|
||
<input name="attr_touch_the_other_side_action" type="hidden" title="@{touch_the_other_side_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_understand" data-i18n="understand" value="@{understand_action}" title="%{understand}" type="roll">
|
||
</button>
|
||
<button name="act_understand-action" hidden="" type="action" title="%{understand-action}">
|
||
</button>
|
||
<input name="attr_understand_action" type="hidden" title="@{understand_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_take_a_swing" data-i18n="take a swing" value="@{take_a_swing_action}" title="%{take_a_swing}" type="roll">
|
||
</button>
|
||
<button name="act_take-a-swing-action" hidden="" type="action" title="%{take-a-swing-action}">
|
||
</button>
|
||
<input name="attr_take_a_swing_action" type="hidden" title="@{take_a_swing_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_take_action" data-i18n="take action" value="@{take_action_action}" title="%{take_action}" type="roll">
|
||
</button>
|
||
<button name="act_take-action-action" hidden="" type="action" title="%{take-action-action}">
|
||
</button>
|
||
<input name="attr_take_action_action" type="hidden" title="@{take_action_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_sneak" data-i18n="sneak" value="@{sneak_action}" title="%{sneak}" type="roll">
|
||
</button>
|
||
<button name="act_sneak-action" hidden="" type="action" title="%{sneak-action}">
|
||
</button>
|
||
<input name="attr_sneak_action" type="hidden" title="@{sneak_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_keep_your_cool" data-i18n="keep your cool" value="@{keep_your_cool_action}" title="%{keep_your_cool}" type="roll">
|
||
</button>
|
||
<button name="act_keep-your-cool-action" hidden="" type="action" title="%{keep-your-cool-action}">
|
||
</button>
|
||
<input name="attr_keep_your_cool_action" type="hidden" title="@{keep_your_cool_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_convince_somebody" data-i18n="convince somebody" value="@{convince_somebody_action}" title="%{convince_somebody}" type="roll">
|
||
</button>
|
||
<button name="act_convince-somebody-action" hidden="" type="action" title="%{convince-somebody-action}">
|
||
</button>
|
||
<input name="attr_convince_somebody_action" type="hidden" title="@{convince_somebody_action}"/>
|
||
<button class="styled-button basic-roll roller" name="roll_another_move" data-i18n="another move" value="@{another_move_action}" title="%{another_move}" type="roll">
|
||
</button>
|
||
<button name="act_another-move-action" hidden="" type="action" title="%{another-move-action}">
|
||
</button>
|
||
<input name="attr_another_move_action" type="hidden" title="@{another_move_action}"/>
|
||
<button class="styled-button basic-roll initiative roller" name="roll_initiative" data-i18n="initiative" value="@{initiative_action}" title="%{initiative}" type="roll">
|
||
</button>
|
||
<button name="act_initiative-action" hidden="" type="action" title="%{initiative-action}">
|
||
</button>
|
||
<input name="attr_initiative_action" type="hidden" title="@{initiative_action}"/>
|
||
</div>
|
||
<div class="roll-options character-type character-type--character character-type--mon">
|
||
<label class="input-label double-label">
|
||
<input class="styled-button-control" name="attr_double" hidden="" value="1" type="checkbox" title="@{double}"/><span class="styled-button styled-button--controlled" data-i18n="double"></span>
|
||
</label>
|
||
<label class="input-label">
|
||
<input class="styled-button-control" name="attr_advantage" hidden="" type="radio" value="[[3+@{double}]]d6kh2" title="@{advantage}"/><span class="styled-button styled-button--controlled" data-i18n="advantage"></span>
|
||
</label>
|
||
<label class="input-label">
|
||
<input class="styled-button-control" name="attr_advantage" hidden="" type="radio" value="2d6" checked="" title="@{advantage}"/><span class="styled-button styled-button--controlled" data-i18n="normal"></span>
|
||
</label>
|
||
<label class="input-label">
|
||
<input class="styled-button-control" name="attr_advantage" hidden="" type="radio" value="[[3+@{double}]]d6kl2" title="@{advantage}"/><span class="styled-button styled-button--controlled" data-i18n="disadvantage"></span>
|
||
</label>
|
||
<label class="input-label">
|
||
<input class="styled-button-control" name="attr_advantage" hidden="" type="radio" value="?{Roll with|Double Advantage,4d6kh2|Advantage,3d6kh2|Normal,2d6|Disadvantage,3d6kl2|Double Disadvantage,4d6kl2}" title="@{advantage}"/><span class="styled-button styled-button--controlled" data-i18n="query"></span>
|
||
</label>
|
||
<input class="styled-button-control" name="attr_generic_bonus" value="" type="hidden" title="@{generic_bonus}"/>
|
||
<label class="input-label styled-button styled-button--controlled"><span class="input-label__text" data-i18n="bonus"></span>
|
||
<input class="input-label__input" name="attr_generic_bonus" type="number" title="@{generic_bonus}"/>
|
||
</label>
|
||
</div>
|
||
<button class="pictos active sheet-nav__tab settings" name="act_nav-settings" data-i18n-title="open the settings page" role="heading" aria-level="5" type="action" title="%{nav-settings}">y
|
||
</button>
|
||
<button class="pictos sheet-nav__tab character character-type character-type--character character-type--mon" name="act_nav-character" data-i18n-title="open the character sheet" role="heading" aria-level="5" type="action" title="%{nav-character}">N
|
||
</button>
|
||
<button class="pictos sheet-nav__tab gamescreen character-type character-type--gamescreen" name="act_nav-gamescreen" data-i18n-title="open the confrontation sheet" role="heading" aria-level="5" type="action" title="%{nav-gamescreen}">N
|
||
</button>
|
||
</nav>
|
||
<article class="character navigable-section navigable-section--character character-type character-type--character character-type--mon" id="character">
|
||
<header class="header span-all" id="character-header"><img class="header-image" src="https://s3.amazonaws.com/files.d20.io/images/277217218/yuDLFwlFjVStADz6M5aNLg/original.png" data-i18n-alt="Under the Neighborhood by Kyle Decker" role="heading" aria-level="1"/>
|
||
<div class="sentence character-type character-type--character" data-i18n-list="character sentence order">
|
||
<div class="adaptive adaptive--input character-name"><span class="adaptive--input__span" name="attr_character_name" title="@{character_name}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_character_name" type="text" role="heading" aria-level="2" title="@{character_name}"/>
|
||
</div>
|
||
<div class="input-label"><span data-i18n="sentence the" data-list-item="the"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_playbook" title="@{playbook}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_playbook" type="text" data-list-item="playbook" data-i18n-placeholder="playbook placeholder" title="@{playbook}"/>
|
||
</div>
|
||
</div>
|
||
<div class="input-label"><span data-i18n="sentence who" data-list-item="who"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_descriptor" title="@{descriptor}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_descriptor" type="text" data-list-item="descriptor" data-i18n-placeholder="descriptor placeholder" title="@{descriptor}"/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="character-summary character-type character-type--character">
|
||
<div class="generic-details span-all">
|
||
<div class="input-label"><span role="heading" aria-level="5" data-i18n="pronouns"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_pronouns" title="@{pronouns}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_pronouns" type="text" title="@{pronouns}"/>
|
||
</div>
|
||
</div>
|
||
<div class="input-label"><span role="heading" aria-level="5" data-i18n="age"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_age" title="@{age}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_age" type="text" title="@{age}"/>
|
||
</div>
|
||
</div>
|
||
<div class="input-label span-2"><span role="heading" aria-level="5" data-i18n="appearance"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_appearance" title="@{appearance}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_appearance" type="text" title="@{appearance}"/>
|
||
</div>
|
||
</div>
|
||
<div class="input-label span-2"><span role="heading" aria-level="5" data-i18n="homeworld"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_homeworld" title="@{homeworld}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_homeworld" type="text" title="@{homeworld}"/>
|
||
</div>
|
||
</div>
|
||
<div class="input-label span-2"><span role="heading" aria-level="5" data-i18n="want"></span>
|
||
<div class="adaptive adaptive--input"><span class="adaptive--input__span" name="attr_want" title="@{want}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_want" type="text" title="@{want}"/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="headed-textarea arc">
|
||
<h5 data-i18n="character arc/flaw"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_arc_flaw" title="@{arc_flaw}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_arc_flaw" title="@{arc_flaw}"></textarea>
|
||
</div>
|
||
</div>
|
||
<label class="input-label stacked ap adventure-points"><span class="input-label__text" data-i18n="adventure points" role="heading" aria-level="4"></span>
|
||
<input class="underlined input-label__input" name="attr_ap" type="number" title="@{ap}"/>
|
||
</label>
|
||
</div>
|
||
<div class="character-summary character-type character-type--mon">
|
||
<div class="adaptive adaptive--input character-name"><span class="adaptive--input__span" name="attr_character_name" title="@{character_name}"></span>
|
||
<input class="underlined adaptive--input__input" name="attr_character_name" type="text" role="heading" aria-level="2" title="@{character_name}"/>
|
||
</div>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="signature stat" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_signature_stat" title="@{signature_stat}">
|
||
<option value="" data-i18n="select one">
|
||
</option>
|
||
<option class="heart" value="heart" data-i18n="heart">
|
||
</option>
|
||
<option class="books" value="books" data-i18n="books">
|
||
</option>
|
||
<option class="fierce" value="fierce" data-i18n="fierce">
|
||
</option>
|
||
<option class="slick" value="slick" data-i18n="slick">
|
||
</option>
|
||
<option class="weird" value="weird" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<div class="input-label"><span data-i18n="element" role="heading" aria-level="4"></span>
|
||
<input class="underlined" name="attr_element" type="text" title="@{element}"/>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
<section class="attributes" id="attributes">
|
||
<h3 class="header" data-i18n="stats"></h3>
|
||
<div class="input-label input-label--button heart">
|
||
<button class="roller" name="roll_heart" role="heading" aria-level="4" data-i18n="heart" value="@{heart_action}" title="%{heart}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_heart" type="number" value="0" min="-3" max="3" title="@{heart}"/>
|
||
</div>
|
||
<button name="act_heart-action" hidden="" type="action" title="%{heart-action}">
|
||
</button>
|
||
<input name="attr_heart_action" type="hidden" title="@{heart_action}"/>
|
||
<div class="input-label input-label--button books">
|
||
<button class="roller" name="roll_books" role="heading" aria-level="4" data-i18n="books" value="@{books_action}" title="%{books}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_books" type="number" value="0" min="-3" max="3" title="@{books}"/>
|
||
</div>
|
||
<button name="act_books-action" hidden="" type="action" title="%{books-action}">
|
||
</button>
|
||
<input name="attr_books_action" type="hidden" title="@{books_action}"/>
|
||
<div class="input-label input-label--button fierce">
|
||
<button class="roller" name="roll_fierce" role="heading" aria-level="4" data-i18n="fierce" value="@{fierce_action}" title="%{fierce}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_fierce" type="number" value="0" min="-3" max="3" title="@{fierce}"/>
|
||
</div>
|
||
<button name="act_fierce-action" hidden="" type="action" title="%{fierce-action}">
|
||
</button>
|
||
<input name="attr_fierce_action" type="hidden" title="@{fierce_action}"/>
|
||
<div class="input-label input-label--button slick">
|
||
<button class="roller" name="roll_slick" role="heading" aria-level="4" data-i18n="slick" value="@{slick_action}" title="%{slick}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_slick" type="number" value="0" min="-3" max="3" title="@{slick}"/>
|
||
</div>
|
||
<button name="act_slick-action" hidden="" type="action" title="%{slick-action}">
|
||
</button>
|
||
<input name="attr_slick_action" type="hidden" title="@{slick_action}"/>
|
||
<div class="input-label input-label--button weird">
|
||
<button class="roller" name="roll_weird" role="heading" aria-level="4" data-i18n="weird" value="@{weird_action}" title="%{weird}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_weird" type="number" value="0" min="-3" max="3" title="@{weird}"/>
|
||
</div>
|
||
<button name="act_weird-action" hidden="" type="action" title="%{weird-action}">
|
||
</button>
|
||
<input name="attr_weird_action" type="hidden" title="@{weird_action}"/>
|
||
</section>
|
||
<section class="span-2--if-wide" aria-labelledby="skill-header">
|
||
<div class="skills repeating-container" id="skills">
|
||
<h3 class="header" data-i18n="skills and inabilities" id="skill-header"></h3>
|
||
<div class="repeat-column">
|
||
<h4 data-i18n="skill"></h4>
|
||
<h4 data-i18n="inability"></h4>
|
||
</div>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-skill" type="action" title="%{add-skill}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-skill" type="action" title="%{edit-skill}">
|
||
</button>
|
||
<fieldset class="repeating_skill">
|
||
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_skill_$X_collapse}"/>
|
||
<div class="input-label input-label--button">
|
||
<button class="roller" name="roll_roll" value="@{action}" title="%{repeating_skill_$X_roll}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_name" type="text" title="@{repeating_skill_$X_name}"/>
|
||
</div>
|
||
<button name="act_action" hidden="" type="action" title="%{repeating_skill_$X_action}">
|
||
</button>
|
||
<input name="attr_action" type="hidden" title="@{repeating_skill_$X_action}"/>
|
||
<div class="input-label input-label--button">
|
||
<button class="roller" name="roll_inability" value="@{inability_action}" title="%{repeating_skill_$X_inability}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_inability" type="text" title="@{repeating_skill_$X_inability}"/>
|
||
</div>
|
||
<button name="act_inability-action" hidden="" type="action" title="%{repeating_skill_$X_inability-action}">
|
||
</button>
|
||
<input name="attr_inability_action" type="hidden" title="@{repeating_skill_$X_inability_action}"/>
|
||
<div class="expanded">
|
||
<label class="input-label"><span class="input-label__text" data-i18n="stat" role="heading" aria-level="5"></span>
|
||
<select class="underlined input-label__input" name="attr_skill_stat" title="@{repeating_skill_$X_skill_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query" selected="">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label expanded super"><span class="input-label__text" data-i18n="super" role="heading" aria-level="5"></span>
|
||
<input class="underlined input-label__input" name="attr_super" type="checkbox" value="1" title="@{repeating_skill_$X_super}"/>
|
||
</label>
|
||
</div>
|
||
<div class="expanded">
|
||
<label class="input-label"><span class="input-label__text" data-i18n="stat" role="heading" aria-level="5"></span>
|
||
<select class="underlined input-label__input" name="attr_inability_stat" title="@{repeating_skill_$X_inability_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query" selected="">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label expanded super"><span class="input-label__text" data-i18n="super" role="heading" aria-level="5"></span>
|
||
<input class="underlined input-label__input" name="attr_inability_super" type="checkbox" value="1" title="@{repeating_skill_$X_inability_super}"/>
|
||
</label>
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
<div class="signature-item repeating-container character-type character-type--character" id="signature-item">
|
||
<h4 data-i18n="signature item"></h4>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-signature" type="action" title="%{add-signature}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-signature" type="action" title="%{edit-signature}">
|
||
</button>
|
||
<fieldset class="repeating_signature">
|
||
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_signature_$X_collapse}"/>
|
||
<div class="input-label input-label--button">
|
||
<button class="roller" name="roll_roll" role="heading" value="@{action}" title="%{repeating_signature_$X_roll}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_name" type="text" title="@{repeating_signature_$X_name}"/>
|
||
</div>
|
||
<button name="act_action" hidden="" type="action" title="%{repeating_signature_$X_action}">
|
||
</button>
|
||
<input name="attr_action" type="hidden" title="@{repeating_signature_$X_action}"/>
|
||
<div class="expanded">
|
||
<label class="input-label"><span class="input-label__text" data-i18n="stat" role="heading" aria-level="5"></span>
|
||
<select class="underlined input-label__input" name="attr_stat" title="@{repeating_signature_$X_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query" selected="">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label expanded super"><span class="input-label__text" data-i18n="super" role="heading" aria-level="5"></span>
|
||
<input class="underlined input-label__input" name="attr_super" type="checkbox" value="1" title="@{repeating_signature_$X_super}"/>
|
||
</label>
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
</section>
|
||
<section class="playbook repeating-container span-2--if-wide character-type character-type--character" id="playbook">
|
||
<h3 class="header" data-i18n="character moves"></h3>
|
||
<div class="repeat-column">
|
||
<h4 data-i18n="name"></h4>
|
||
<h4 data-i18n="cost"></h4>
|
||
<h4 data-i18n="source"></h4>
|
||
</div>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-move" type="action" title="%{add-move}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-move" type="action" title="%{edit-move}">
|
||
</button>
|
||
<fieldset class="repeating_move">
|
||
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_move_$X_collapse}"/>
|
||
<div class="input-label input-label--button">
|
||
<button class="roller" name="roll_roll" value="@{action}" title="%{repeating_move_$X_roll}" type="roll">
|
||
</button>
|
||
<input class="underlined input-label__input" name="attr_name" type="text" role="heading" aria-level="5" title="@{repeating_move_$X_name}"/>
|
||
</div>
|
||
<button name="act_action" hidden="" type="action" title="%{repeating_move_$X_action}">
|
||
</button>
|
||
<input name="attr_action" type="hidden" title="@{repeating_move_$X_action}"/>
|
||
<input class="underlined" name="attr_cost" type="text" title="@{repeating_move_$X_cost}"/>
|
||
<select class="underlined" name="attr_source" title="@{repeating_move_$X_source}">
|
||
<option value="" data-i18n="select one">
|
||
</option>
|
||
<option value="playbook" data-i18n="playbook">
|
||
</option>
|
||
<option value="descriptor" data-i18n="descriptor">
|
||
</option>
|
||
<option value="arc" data-i18n="arc">
|
||
</option>
|
||
</select>
|
||
<div class="collapse-container expanded span-all">
|
||
<input class="collapse text-collapse__check" name="attr_result_collapse" value="1" checked="" hidden="" type="checkbox" title="@{repeating_move_$X_result_collapse}"/>
|
||
<label class="text-collapse">
|
||
<input class="text-collapse__check" name="attr_result_collapse" hidden="" value="1" checked="" type="checkbox" title="@{repeating_move_$X_result_collapse}"/>
|
||
<h5 class="text-collapse__text" data-i18n="customize results"></h5>
|
||
</label>
|
||
<div class="headed-textarea expanded span-all">
|
||
<h5 data-i18n="critical success"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_critical_success" title="@{repeating_move_$X_critical_success}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_critical_success" title="@{repeating_move_$X_critical_success}"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="headed-textarea expanded span-all">
|
||
<h5 data-i18n="full success"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_full_success" title="@{repeating_move_$X_full_success}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_full_success" title="@{repeating_move_$X_full_success}"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="headed-textarea expanded span-all">
|
||
<h5 data-i18n="mixed success"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_mixed_success" title="@{repeating_move_$X_mixed_success}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_mixed_success" title="@{repeating_move_$X_mixed_success}"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="headed-textarea expanded span-all">
|
||
<h5 data-i18n="failure"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_failure" title="@{repeating_move_$X_failure}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_failure" title="@{repeating_move_$X_failure}"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="headed-textarea expanded span-all">
|
||
<h5 data-i18n="critical failure"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_critical_failure" title="@{repeating_move_$X_critical_failure}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_critical_failure" title="@{repeating_move_$X_critical_failure}"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="headed-textarea description expanded span-all">
|
||
<h5 data-i18n="description">
|
||
</h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_move_$X_description}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_description" title="@{repeating_move_$X_description}"></textarea>
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
</section>
|
||
<section class="compatibility repeating-container" id="compatibility">
|
||
<h3 data-i18n="compatibility scores"></h3>
|
||
<div class="repeat-column">
|
||
<h4 class="character" data-i18n="character"></h4>
|
||
<h4 class="score" data-i18n="score"></h4>
|
||
</div>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-compatibility" type="action" title="%{add-compatibility}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-compatibility" type="action" title="%{edit-compatibility}">
|
||
</button>
|
||
<fieldset class="repeating_compatibility">
|
||
<div class="input-label">
|
||
<input name="attr_activate" value="1" type="checkbox" title="@{repeating_compatibility_$X_activate}"/>
|
||
<input class="underlined" name="attr_name" role="heading" aria-level="5" type="text" title="@{repeating_compatibility_$X_name}"/>
|
||
</div>
|
||
<input class="underlined" name="attr_score" type="number" title="@{repeating_compatibility_$X_score}"/>
|
||
</fieldset>
|
||
<label class="input-label">
|
||
<input name="attr_interference" value="1" type="checkbox" title="@{interference}"/>
|
||
<h5 class="underlined underlined--invisible" data-i18n="interference"></h5>
|
||
</label>
|
||
</section>
|
||
<section class="meter span-2--if-wide repeating-container" aria-labelledby="meter-header" id="meter">
|
||
<h3 class="header" data-i18n="meters" id="meter-header"></h3>
|
||
<div class="repeat-column">
|
||
<h4 data-i18n="name"></h4>
|
||
<h4>1</h4>
|
||
<h4>2</h4>
|
||
<h4>3</h4>
|
||
<h4>4</h4>
|
||
<h4>5</h4>
|
||
<h4>6</h4>
|
||
<h4>7</h4>
|
||
<h4>8</h4>
|
||
<h4>9</h4>
|
||
<h4>10</h4>
|
||
</div>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-meter" type="action" title="%{add-meter}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-meter" type="action" title="%{edit-meter}">
|
||
</button>
|
||
<fieldset class="repeating_meter">
|
||
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_meter_$X_collapse}"/>
|
||
<input class="underlined" name="attr_name" role="heading" aria-level="5" type="text" title="@{repeating_meter_$X_name}"/>
|
||
<input class="fill-left__max-control" name="attr_value_max" value="10" type="hidden" title="@{repeating_meter_$X_value|max}"/>
|
||
<div class="fill-left">
|
||
<input class="square fill-left__radio fill-left__radio--clearer" name="attr_value" value="0" checked="" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="1" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="2" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="3" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="4" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="5" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="6" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="7" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="8" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="9" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
<input class="square fill-left__radio" name="attr_value" value="10" type="radio" title="@{repeating_meter_$X_value}"/>
|
||
</div>
|
||
<h5 class="expanded" data-i18n="max"></h5>
|
||
<div class="fill-left expanded no-fill">
|
||
<input class="square fill-left__radio" name="attr_value_max" value="1" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="2" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="3" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="4" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="5" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="6" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="7" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="8" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="9" data-i18n-title="set the meter's maximum value." type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
<input class="square fill-left__radio" name="attr_value_max" value="10" data-i18n-title="set the meter's maximum value." checked="" type="radio" title="@{repeating_meter_$X_value|max}"/>
|
||
</div>
|
||
<div class="headed-textarea description expanded span-all">
|
||
<h5 data-i18n="description">
|
||
</h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_meter_$X_description}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_description" title="@{repeating_meter_$X_description}"></textarea>
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
</section>
|
||
<section class="repeating-container" aria-labelledby="modifier-header" id="modifiers">
|
||
<h3 data-i18n="roll modifiers" id="modifier-header"></h3>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-modifier" type="action" title="%{add-modifier}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-modifier" type="action" title="%{edit-modifier}">
|
||
</button>
|
||
<fieldset class="repeating_modifier">
|
||
<input class="collapse" name="attr_collapse" value="1" type="checkbox" title="@{repeating_modifier_$X_collapse}"/>
|
||
<input name="attr_activate" value="1" type="checkbox" title="@{repeating_modifier_$X_activate}"/>
|
||
<input class="underlined" name="attr_name" type="text" title="@{repeating_modifier_$X_name}"/>
|
||
<div class="headed-textarea description expanded span-all">
|
||
<h5 data-i18n="effects"></h5>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_effect" title="@{repeating_modifier_$X_effect}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_effect" title="@{repeating_modifier_$X_effect}"></textarea>
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
</section>
|
||
<section class="advancement span-all character-type character-type--character" id="advancement">
|
||
<h3 data-i18n="advancements"></h3>
|
||
<div class="repeating-container">
|
||
<h4 class="header" data-i18n="basic"></h4>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-basic-advancement" type="action" title="%{add-basic-advancement}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-basic-advancement" type="action" title="%{edit-basic-advancement}">
|
||
</button>
|
||
<fieldset class="repeating_basic-advancement">
|
||
<input class="boxed ratio1-1" name="attr_picked" type="checkbox" title="@{repeating_basic-advancement_$X_picked}"/>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_basic-advancement_$X_description}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_description" title="@{repeating_basic-advancement_$X_description}"></textarea>
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
<div class="repeating-container">
|
||
<h4 class="header" data-i18n="super"></h4>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-super-advancement" type="action" title="%{add-super-advancement}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-super-advancement" type="action" title="%{edit-super-advancement}">
|
||
</button>
|
||
<fieldset class="repeating_super-advancement">
|
||
<input class="boxed ratio1-1" name="attr_picked" type="checkbox" title="@{repeating_super-advancement_$X_picked}"/>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_super-advancement_$X_description}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_description" title="@{repeating_super-advancement_$X_description}"></textarea>
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
<div class="repeating-container">
|
||
<h4 class="header" data-i18n="ultra"></h4>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-ultra-advancement" type="action" title="%{add-ultra-advancement}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-ultra-advancement" type="action" title="%{edit-ultra-advancement}">
|
||
</button>
|
||
<fieldset class="repeating_ultra-advancement">
|
||
<input class="boxed ratio1-1" name="attr_picked" type="checkbox" title="@{repeating_ultra-advancement_$X_picked}"/>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_ultra-advancement_$X_description}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_description" title="@{repeating_ultra-advancement_$X_description}"></textarea>
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
</section>
|
||
</article>
|
||
<article class="gamescreen navigable-section navigable-section--gamescreen character-type character-type--gamescreen" id="gamescreen">
|
||
<header class="header span-all" id="character-header"><img class="header-image" src="https://s3.amazonaws.com/files.d20.io/images/277217218/yuDLFwlFjVStADz6M5aNLg/original.png" data-i18n-alt="Under the Neighborhood by Kyle Decker" role="heading" aria-level="1"/>
|
||
</header>
|
||
<section class="lifeslice span-all repeating-container" aria-labelledby="lifesliceheader" id="lifeslice">
|
||
<h3 data-i18n="slice of life complications" id="lifesliceheader"></h3>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-complication" type="action" title="%{add-complication}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-complication" type="action" title="%{edit-complication}">
|
||
</button>
|
||
<fieldset class="repeating_complication">
|
||
<input name="attr_activate" value="1" type="checkbox" title="@{repeating_complication_$X_activate}"/>
|
||
<div class="adaptive adaptive--text"><span class="adaptive--text__span" name="attr_description" title="@{repeating_complication_$X_description}"></span>
|
||
<textarea class="underlined adaptive--text__textarea" name="attr_description" title="@{repeating_complication_$X_description}"></textarea>
|
||
</div>
|
||
</fieldset>
|
||
</section>
|
||
<section class="clock span-2--if-wide repeating-container" aria-labelledby="clock-header" id="clock">
|
||
<h3 class="header" data-i18n="clocks" id="clock-header"></h3>
|
||
<button class="repcontrol-button repcontrol-button--add" name="act_add-clock" type="action" title="%{add-clock}">
|
||
</button>
|
||
<button class="repcontrol-button repcontrol-button--edit" name="act_edit-clock" type="action" title="%{edit-clock}">
|
||
</button>
|
||
<fieldset class="repeating_clock">
|
||
<input class="clock-control--current" name="attr_value" value="0" type="hidden" title="@{repeating_clock_$X_value}"/>
|
||
<input class="clock-control--max" name="attr_value_max" value="10" type="hidden" title="@{repeating_clock_$X_value|max}"/>
|
||
<div class="clock-progress"></div>
|
||
<div class="clock-label">
|
||
<input class="clear-x" name="attr_value" value="0" type="radio" title="@{repeating_clock_$X_value}"/>
|
||
<input name="attr_value" value="0" type="number" title="@{repeating_clock_$X_value}"/><span class="slash">/</span>
|
||
<input name="attr_value_max" value="10" min="2" max="10" type="number" title="@{repeating_clock_$X_value|max}"/>
|
||
</div>
|
||
<input class="underlined" name="attr_name" role="heading" aria-level="5" type="text" title="@{repeating_clock_$X_name}"/>
|
||
</fieldset>
|
||
</section>
|
||
</article>
|
||
<article class="settings navigable-section navigable-section--settings active" id="settings">
|
||
<h1 data-i18n="settings"></h1>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="sheet type" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_sheet_type" title="@{sheet_type}">
|
||
<option value="character" data-i18n="character" selected="">
|
||
</option>
|
||
<option value="mon" data-i18n="mon">
|
||
</option>
|
||
<option value="gamescreen" data-i18n="game screen">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="is weird" role="heading" aria-level="4"></span>
|
||
<input class="input-label__input" name="attr_is_weird" type="checkbox" value="1" title="@{is_weird}"/>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="use initiative" role="heading" aria-level="4"></span>
|
||
<input class="input-label__input" name="attr_use_initiative" type="checkbox" value="1" title="@{use_initiative}"/>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="has arc/flaw" role="heading" aria-level="4"></span>
|
||
<input class="input-label__input" name="attr_has_arc" type="checkbox" value="1" title="@{has_arc}"/>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="use roll modifiers" role="heading" aria-level="4"></span>
|
||
<input class="input-label__input" name="attr_use_roll_modifiers" type="checkbox" value="1" checked="" title="@{use_roll_modifiers}"/>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="use physical dice" role="heading" aria-level="4"></span>
|
||
<input class="input-label__input" name="attr_use_physical_dice" type="checkbox" value="1" title="@{use_physical_dice}"/>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="skills use moves" role="heading" aria-level="4"></span>
|
||
<input class="input-label__input" name="attr_skill_basic_move" type="checkbox" value="1" checked="" title="@{skill_basic_move}"/>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="whisper to gm" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_whisper" title="@{whisper}">
|
||
<option value="" data-i18n="never" selected="">
|
||
</option>
|
||
<option value="/w gm" data-i18n="always">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<div class="span-all move-stats">
|
||
<h2 class="span-all" data-i18n="basic move stats"></h2>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="see into their heart" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_see_into_their_heart_stat" title="@{see_into_their_heart_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart" selected="">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="help somebody" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_help_somebody_stat" title="@{help_somebody_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart" selected="">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="touch the other side" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_touch_the_other_side_stat" title="@{touch_the_other_side_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books" selected="">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="understand" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_understand_stat" title="@{understand_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books" selected="">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="take a swing" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_take_a_swing_stat" title="@{take_a_swing_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce" selected="">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="take action" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_take_action_stat" title="@{take_action_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce" selected="">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="sneak" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_sneak_stat" title="@{sneak_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick" selected="">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="keep your cool" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_keep_your_cool_stat" title="@{keep_your_cool_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick" selected="">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="convince somebody" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_convince_somebody_stat" title="@{convince_somebody_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query" selected="">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label"><span class="input-label__text" data-i18n="another move" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_another_move_stat" title="@{another_move_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query" selected="">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label class="input-label initiative"><span class="input-label__text" data-i18n="initiative" role="heading" aria-level="4"></span>
|
||
<select class="underlined input-label__input" name="attr_initiative_stat" title="@{initiative_stat}">
|
||
<option value="?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}" data-i18n="query">
|
||
</option>
|
||
<option value="@{heart}" data-i18n="heart">
|
||
</option>
|
||
<option value="@{books}" data-i18n="books">
|
||
</option>
|
||
<option value="@{fierce}" data-i18n="fierce" selected="">
|
||
</option>
|
||
<option value="@{slick}" data-i18n="slick">
|
||
</option>
|
||
<option value="@{weird}" data-i18n="weird">
|
||
</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
</article>
|
||
</main>
|
||
<rolltemplate class="sheet-rolltemplate-utn">
|
||
<div class="template utn">
|
||
<div class="header">{{#header}}
|
||
<h3>{{header}}</h3>{{/header}}{{#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}}
|
||
</div>
|
||
<div class="content">{{#roll}}
|
||
<div class="template-row center">{{#roll_name}}
|
||
<h5>{{roll_name}}</h5>{{/roll_name}}{{^roll_name}}
|
||
<h5 data-i18n="roll"></h5>{{/roll_name}}{{#rollGreater() computed::result 0}}<span class="crit">{{roll}}</span>{{/rollGreater() computed::result 0}}{{#rollLess() computed::result 0}}<span class="fumble">{{roll}}</span>{{/rollLess() computed::result 0}}{{#rollBetween() computed::result 0 0}}<span class="regular-roll">{{roll}}</span>{{/rollBetween() computed::result 0 0}}
|
||
</div>{{#result}}
|
||
<div class="template-row">{{#rollLess() roll 7}}{{#rollLess() computed::result 0}}
|
||
<h5 class="critical failure" data-i18n="critical failure"></h5>{{#fumble_result}}<span>{{fumble_result}}</span>{{/fumble_result}}{{^fumble_result}}<span>{{failure_result}}</span>{{/fumble_result}}{{/rollLess() computed::result 0}}{{#^rollLess() computed::result 0}}
|
||
<h5 class="failure" data-i18n="failure"></h5><span>{{failure_result}}</span>{{/^rollLess() computed::result 0}}{{/rollLess() roll 7}}{{#rollBetween() roll 7 9}}
|
||
<h5 data-i18n="mixed success"></h5><span>{{mixed_result}}</span>{{/rollBetween() roll 7 9}}{{#rollGreater() roll 9}}{{#rollGreater() computed::result 0}}
|
||
<h5 class="critical success" data-i18n="critical success"></h5>{{#critical_result}}<span>{{critical_result}}</span>{{/critical_result}}{{^critical_result}}<span>{{success_result}}</span>{{/critical_result}}{{/rollGreater() computed::result 0}}{{#^rollGreater() computed::result 0}}
|
||
<h5 class="success" data-i18n="full success"></h5><span>{{success_result}}</span>{{/^rollGreater() computed::result 0}}{{/rollGreater() roll 9}}
|
||
</div>{{/result}}{{/roll}}{{#description}}
|
||
<div class="template-row">
|
||
<h5 data-i18n="description"></h5><span>{{description}}</span>
|
||
</div>{{/description}}{{#allprops() header character_name character_id roll_name roll result fumble_result failure_result mixed_result success_result critical_result description}}
|
||
<div class="template-row">
|
||
<h5>{{key}}</h5><span>{{value}}</span>
|
||
</div>{{/allprops() header character_name character_id roll_name roll result fumble_result failure_result mixed_result success_result critical_result description}}
|
||
</div>
|
||
</div>
|
||
</rolltemplate>
|
||
<script type="text/worker">
|
||
const k = (function(){
|
||
const kFuncs = {};
|
||
const document = false;
|
||
|
||
const cascades = {"attr_character_name":{"name":"character_name","type":"text","defaultValue":"","affects":[],"triggeredFuncs":["setActionCalls"],"listenerFunc":"accessSheet","listener":"change:character_name"},"attr_template_start":{"name":"template_start","type":"hidden","defaultValue":"@{whisper}&{template:utn} {{character_name=@{character_name}}} {{character_id=@{character_id}}}","triggeredFuncs":[],"affects":[]},"attr_sheet_version":{"name":"sheet_version","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_sheet_state":{"name":"sheet_state","type":"hidden","defaultValue":"settings","triggeredFuncs":[],"affects":[]},"attr_collapsed":{"name":"collapsed","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_see-into-their-heart-action":{"triggeredFuncs":["rollBasicMove"],"name":"see-into-their-heart-action","listener":"clicked:see-into-their-heart-action","listenerFunc":"accessSheet","type":"action"},"attr_see_into_their_heart_action":{"name":"see_into_their_heart_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_help-somebody-action":{"triggeredFuncs":["rollBasicMove"],"name":"help-somebody-action","listener":"clicked:help-somebody-action","listenerFunc":"accessSheet","type":"action"},"attr_help_somebody_action":{"name":"help_somebody_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_touch-the-other-side-action":{"triggeredFuncs":["rollBasicMove"],"name":"touch-the-other-side-action","listener":"clicked:touch-the-other-side-action","listenerFunc":"accessSheet","type":"action"},"attr_touch_the_other_side_action":{"name":"touch_the_other_side_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_understand-action":{"triggeredFuncs":["rollBasicMove"],"name":"understand-action","listener":"clicked:understand-action","listenerFunc":"accessSheet","type":"action"},"attr_understand_action":{"name":"understand_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_take-a-swing-action":{"triggeredFuncs":["rollBasicMove"],"name":"take-a-swing-action","listener":"clicked:take-a-swing-action","listenerFunc":"accessSheet","type":"action"},"attr_take_a_swing_action":{"name":"take_a_swing_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_take-action-action":{"triggeredFuncs":["rollBasicMove"],"name":"take-action-action","listener":"clicked:take-action-action","listenerFunc":"accessSheet","type":"action"},"attr_take_action_action":{"name":"take_action_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_sneak-action":{"triggeredFuncs":["rollBasicMove"],"name":"sneak-action","listener":"clicked:sneak-action","listenerFunc":"accessSheet","type":"action"},"attr_sneak_action":{"name":"sneak_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_keep-your-cool-action":{"triggeredFuncs":["rollBasicMove"],"name":"keep-your-cool-action","listener":"clicked:keep-your-cool-action","listenerFunc":"accessSheet","type":"action"},"attr_keep_your_cool_action":{"name":"keep_your_cool_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_convince-somebody-action":{"triggeredFuncs":["rollBasicMove"],"name":"convince-somebody-action","listener":"clicked:convince-somebody-action","listenerFunc":"accessSheet","type":"action"},"attr_convince_somebody_action":{"name":"convince_somebody_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_another-move-action":{"triggeredFuncs":["rollBasicMove"],"name":"another-move-action","listener":"clicked:another-move-action","listenerFunc":"accessSheet","type":"action"},"attr_another_move_action":{"name":"another_move_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_initiative-action":{"triggeredFuncs":["rollInitiative"],"name":"initiative-action","listener":"clicked:initiative-action","listenerFunc":"accessSheet","type":"action"},"attr_initiative_action":{"name":"initiative_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_double":{"name":"double","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_advantage":{"name":"advantage","type":"radio","defaultValue":"[[3+@{double}]]d6kh2","triggeredFuncs":[],"affects":[]},"attr_generic_bonus":{"defaultValue":0,"name":"generic_bonus","type":"hidden","triggeredFuncs":[],"affects":[]},"act_nav-settings":{"triggeredFuncs":["navigateSheet"],"name":"nav-settings","listener":"clicked:nav-settings","listenerFunc":"accessSheet","type":"action"},"act_nav-character":{"triggeredFuncs":["navigateSheet"],"name":"nav-character","listener":"clicked:nav-character","listenerFunc":"accessSheet","type":"action"},"act_nav-gamescreen":{"triggeredFuncs":["navigateSheet"],"name":"nav-gamescreen","listener":"clicked:nav-gamescreen","listenerFunc":"accessSheet","type":"action"},"attr_playbook":{"name":"playbook","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_descriptor":{"name":"descriptor","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_pronouns":{"name":"pronouns","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_age":{"name":"age","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_appearance":{"name":"appearance","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_homeworld":{"name":"homeworld","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_want":{"name":"want","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_arc_flaw":{"name":"arc_flaw","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_ap":{"name":"ap","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_signature_stat":{"name":"signature_stat","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_element":{"name":"element","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_heart":{"affects":["heart_mod"],"name":"heart","listener":"change:heart","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"act_heart-action":{"triggeredFuncs":["rollStat"],"name":"heart-action","listener":"clicked:heart-action","listenerFunc":"accessSheet","type":"action"},"attr_heart_action":{"name":"heart_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_books":{"affects":["books_mod"],"name":"books","listener":"change:books","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"act_books-action":{"triggeredFuncs":["rollStat"],"name":"books-action","listener":"clicked:books-action","listenerFunc":"accessSheet","type":"action"},"attr_books_action":{"name":"books_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_fierce":{"affects":["fierce_mod"],"name":"fierce","listener":"change:fierce","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"act_fierce-action":{"triggeredFuncs":["rollStat"],"name":"fierce-action","listener":"clicked:fierce-action","listenerFunc":"accessSheet","type":"action"},"attr_fierce_action":{"name":"fierce_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_slick":{"affects":["slick_mod"],"name":"slick","listener":"change:slick","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"act_slick-action":{"triggeredFuncs":["rollStat"],"name":"slick-action","listener":"clicked:slick-action","listenerFunc":"accessSheet","type":"action"},"attr_slick_action":{"name":"slick_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_weird":{"affects":["weird_mod"],"name":"weird","listener":"change:weird","listenerFunc":"accessSheet","type":"number","defaultValue":0,"triggeredFuncs":[]},"act_weird-action":{"triggeredFuncs":["rollStat"],"name":"weird-action","listener":"clicked:weird-action","listenerFunc":"accessSheet","type":"action"},"attr_weird_action":{"name":"weird_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-skill":{"listenerFunc":"addItem","name":"add-skill","listener":"clicked:add-skill","type":"action"},"act_edit-skill":{"listenerFunc":"editSection","name":"edit-skill","listener":"clicked:edit-skill","type":"action"},"attr_repeating_skill_$X_collapse":{"name":"repeating_skill_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_skill_$X_name":{"name":"repeating_skill_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_skill_$X_action":{"triggeredFuncs":["rollSkill"],"name":"repeating_skill_$X_action","listener":"clicked:repeating_skill:action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_skill_$X_action":{"name":"repeating_skill_$X_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_skill_$X_inability":{"name":"repeating_skill_$X_inability","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_skill_$X_inability-action":{"triggeredFuncs":["rollSkill"],"name":"repeating_skill_$X_inability-action","listener":"clicked:repeating_skill:inability-action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_skill_$X_inability_action":{"name":"repeating_skill_$X_inability_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_skill_$X_skill_stat":{"name":"repeating_skill_$X_skill_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_repeating_skill_$X_super":{"name":"repeating_skill_$X_super","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_skill_$X_inability_stat":{"name":"repeating_skill_$X_inability_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_repeating_skill_$X_inability_super":{"name":"repeating_skill_$X_inability_super","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_add-signature":{"listenerFunc":"addItem","name":"add-signature","listener":"clicked:add-signature","type":"action"},"act_edit-signature":{"listenerFunc":"editSection","name":"edit-signature","listener":"clicked:edit-signature","type":"action"},"attr_repeating_signature_$X_collapse":{"name":"repeating_signature_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_signature_$X_name":{"name":"repeating_signature_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_signature_$X_action":{"triggeredFuncs":["rollSkill"],"name":"repeating_signature_$X_action","listener":"clicked:repeating_signature:action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_signature_$X_action":{"name":"repeating_signature_$X_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_signature_$X_stat":{"name":"repeating_signature_$X_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_repeating_signature_$X_super":{"name":"repeating_signature_$X_super","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_add-move":{"listenerFunc":"addItem","name":"add-move","listener":"clicked:add-move","type":"action"},"act_edit-move":{"listenerFunc":"editSection","name":"edit-move","listener":"clicked:edit-move","type":"action"},"attr_repeating_move_$X_collapse":{"name":"repeating_move_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_name":{"name":"repeating_move_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_repeating_move_$X_action":{"triggeredFuncs":["rollCharacterMove"],"name":"repeating_move_$X_action","listener":"clicked:repeating_move:action","listenerFunc":"accessSheet","type":"action"},"attr_repeating_move_$X_action":{"name":"repeating_move_$X_action","type":"hidden","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_cost":{"name":"repeating_move_$X_cost","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_source":{"name":"repeating_move_$X_source","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_result_collapse":{"name":"repeating_move_$X_result_collapse","type":"checkbox","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_critical_success":{"name":"repeating_move_$X_critical_success","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_full_success":{"name":"repeating_move_$X_full_success","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_mixed_success":{"name":"repeating_move_$X_mixed_success","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_failure":{"name":"repeating_move_$X_failure","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_critical_failure":{"name":"repeating_move_$X_critical_failure","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_move_$X_description":{"name":"repeating_move_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-compatibility":{"listenerFunc":"addItem","name":"add-compatibility","listener":"clicked:add-compatibility","type":"action"},"act_edit-compatibility":{"listenerFunc":"editSection","name":"edit-compatibility","listener":"clicked:edit-compatibility","type":"action"},"attr_repeating_compatibility_$X_activate":{"name":"repeating_compatibility_$X_activate","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_compatibility_$X_name":{"name":"repeating_compatibility_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_compatibility_$X_score":{"name":"repeating_compatibility_$X_score","type":"number","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_interference":{"name":"interference","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"act_add-meter":{"listenerFunc":"addItem","name":"add-meter","listener":"clicked:add-meter","type":"action"},"act_edit-meter":{"listenerFunc":"editSection","name":"edit-meter","listener":"clicked:edit-meter","type":"action"},"attr_repeating_meter_$X_collapse":{"name":"repeating_meter_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_meter_$X_name":{"name":"repeating_meter_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_meter_$X_value_max":{"name":"repeating_meter_$X_value_max","type":"hidden","defaultValue":10,"triggeredFuncs":[],"affects":["repeating_meter_$X_value"],"listener":"change:repeating_meter:value_max","listenerFunc":"accessSheet"},"attr_repeating_meter_$X_value":{"calculation":"limitMeterValue","name":"repeating_meter_$X_value","type":"radio","defaultValue":0,"triggeredFuncs":[],"affects":[],"listener":"change:repeating_meter:value","listenerFunc":"accessSheet"},"attr_repeating_meter_$X_description":{"name":"repeating_meter_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-modifier":{"listenerFunc":"addItem","name":"add-modifier","listener":"clicked:add-modifier","type":"action"},"act_edit-modifier":{"listenerFunc":"editSection","name":"edit-modifier","listener":"clicked:edit-modifier","type":"action"},"attr_repeating_modifier_$X_collapse":{"name":"repeating_modifier_$X_collapse","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_modifier_$X_activate":{"name":"repeating_modifier_$X_activate","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_modifier_$X_name":{"name":"repeating_modifier_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_repeating_modifier_$X_effect":{"name":"repeating_modifier_$X_effect","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-basic-advancement":{"listenerFunc":"addItem","name":"add-basic-advancement","listener":"clicked:add-basic-advancement","type":"action"},"act_edit-basic-advancement":{"listenerFunc":"editSection","name":"edit-basic-advancement","listener":"clicked:edit-basic-advancement","type":"action"},"attr_repeating_basic-advancement_$X_picked":{"name":"repeating_basic-advancement_$X_picked","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_basic-advancement_$X_description":{"name":"repeating_basic-advancement_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-super-advancement":{"listenerFunc":"addItem","name":"add-super-advancement","listener":"clicked:add-super-advancement","type":"action"},"act_edit-super-advancement":{"listenerFunc":"editSection","name":"edit-super-advancement","listener":"clicked:edit-super-advancement","type":"action"},"attr_repeating_super-advancement_$X_picked":{"name":"repeating_super-advancement_$X_picked","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_super-advancement_$X_description":{"name":"repeating_super-advancement_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-ultra-advancement":{"listenerFunc":"addItem","name":"add-ultra-advancement","listener":"clicked:add-ultra-advancement","type":"action"},"act_edit-ultra-advancement":{"listenerFunc":"editSection","name":"edit-ultra-advancement","listener":"clicked:edit-ultra-advancement","type":"action"},"attr_repeating_ultra-advancement_$X_picked":{"name":"repeating_ultra-advancement_$X_picked","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_ultra-advancement_$X_description":{"name":"repeating_ultra-advancement_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-complication":{"listenerFunc":"addItem","name":"add-complication","listener":"clicked:add-complication","type":"action"},"act_edit-complication":{"listenerFunc":"editSection","name":"edit-complication","listener":"clicked:edit-complication","type":"action"},"attr_repeating_complication_$X_activate":{"name":"repeating_complication_$X_activate","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_complication_$X_description":{"name":"repeating_complication_$X_description","type":"span","defaultValue":"","triggeredFuncs":[],"affects":[]},"act_add-clock":{"listenerFunc":"addItem","name":"add-clock","listener":"clicked:add-clock","type":"action"},"act_edit-clock":{"listenerFunc":"editSection","name":"edit-clock","listener":"clicked:edit-clock","type":"action"},"attr_repeating_clock_$X_value":{"name":"repeating_clock_$X_value","type":"hidden","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_repeating_clock_$X_value_max":{"name":"repeating_clock_$X_value_max","type":"hidden","defaultValue":10,"triggeredFuncs":[],"affects":[]},"attr_repeating_clock_$X_name":{"name":"repeating_clock_$X_name","type":"text","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_sheet_type":{"triggeredFuncs":["characterDisplay"],"name":"sheet_type","listener":"change:sheet_type","listenerFunc":"accessSheet","type":"select","defaultValue":"character","affects":[]},"attr_is_weird":{"triggeredFuncs":["sectionDisplay"],"name":"is_weird","listener":"change:is_weird","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_use_initiative":{"triggeredFuncs":["sectionDisplay"],"name":"use_initiative","listener":"change:use_initiative","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_has_arc":{"triggeredFuncs":["sectionDisplay"],"name":"has_arc","listener":"change:has_arc","listenerFunc":"accessSheet","type":"checkbox","defaultValue":0,"affects":[]},"attr_use_roll_modifiers":{"triggeredFuncs":["modifierDisplay"],"name":"use_roll_modifiers","listener":"change:use_roll_modifiers","listenerFunc":"accessSheet","type":"checkbox","defaultValue":1,"affects":[]},"attr_use_physical_dice":{"name":"use_physical_dice","type":"checkbox","defaultValue":0,"triggeredFuncs":[],"affects":[]},"attr_skill_basic_move":{"name":"skill_basic_move","type":"checkbox","defaultValue":1,"triggeredFuncs":[],"affects":[]},"attr_whisper":{"name":"whisper","type":"select","defaultValue":"","triggeredFuncs":[],"affects":[]},"attr_see_into_their_heart_stat":{"name":"see_into_their_heart_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_help_somebody_stat":{"name":"help_somebody_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_touch_the_other_side_stat":{"name":"touch_the_other_side_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_understand_stat":{"name":"understand_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_take_a_swing_stat":{"name":"take_a_swing_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_take_action_stat":{"name":"take_action_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_sneak_stat":{"name":"sneak_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_keep_your_cool_stat":{"name":"keep_your_cool_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_convince_somebody_stat":{"name":"convince_somebody_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_another_move_stat":{"name":"another_move_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]},"attr_initiative_stat":{"name":"initiative_stat","type":"select","defaultValue":"?{Which Stat|Heart,@{heart}|Books,@{books}|Fierce,@{fierce}|Slick,@{slick}|Weird,@{weird}}","triggeredFuncs":[],"affects":[]}};
|
||
|
||
kFuncs.cascades = cascades;
|
||
|
||
const repeatingSectionDetails = [{"section":"repeating_skill","fields":["collapse","name","action","inability","inability_action","skill_stat","super","inability_stat","inability_super"]},{"section":"repeating_signature","fields":["collapse","name","action","stat","super"]},{"section":"repeating_move","fields":["collapse","name","action","cost","source","result_collapse","critical_success","full_success","mixed_success","failure","critical_failure","description"]},{"section":"repeating_compatibility","fields":["activate","name","score"]},{"section":"repeating_meter","fields":["collapse","name","value_max","value","description"]},{"section":"repeating_modifier","fields":["collapse","activate","name","effect"]},{"section":"repeating_basic-advancement","fields":["picked","description"]},{"section":"repeating_super-advancement","fields":["picked","description"]},{"section":"repeating_ultra-advancement","fields":["picked","description"]},{"section":"repeating_complication","fields":["activate","description"]},{"section":"repeating_clock","fields":["value","value_max","name"]}];
|
||
|
||
kFuncs.repeatingSectionDetails = repeatingSectionDetails;
|
||
|
||
const docs = {"js":{},"pug":{"trigger":{"type":"argument","description":"Many of the K-scaffold's mixins utilize the scaffold's trigger system. Triggers can be passed in any mixin that creates an attribute backed element, which is any element that you would give the `name` property to. The trigger is passed as a property of the object that defines the attribute backed element. See the [input mixin](#input) below for a simple example.\nTriggers are how the K-scaffold connects the attributes created in the html of the sheet with the javscript listeners to trigger sheetworker code. When accessed from a sheetworker, a trigger has all of the below properties. When passing a trigger into a mixin, it should only have any or all of the first four properties; `affects`,`initialFunc`, `calculation`, `triggeredFuncs`, and `listenerFunc`. Note that except for `listenerFunc`, the function that is called is passed arguments using the [destructuring assignment pattern](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). This means that the functions referenced in ,`initialFunc`, `calculation`, and `triggeredFuncs` must be passed in an object associated with a key named as indicated in the arguments below.","arguments":[{"type":"Array","name":"affects","description":"An array of attribute names that this attribute might affect. As an example, the `strength` attribute in a 5e based sheet would have `strength_mod` in its affects array."},{"type":"string","name":"initialFunc","description":"The name of a function that has been registered with the K-scaffold using [k.registerFuncs](https://github.com/Kurohyou/Roll20-Snippets/blob/main/K_Scaffold/readme_docs/k_scaffold_js_documentation.md#registerFuncs). This function will only be called if the change to the attribute is directly caused by the user as opposed to being changed by the sheetworkers.\nThe K-scaffold sends this function the following arguments:\n- `trigger`: The trigger object for the attribute that is being changed\n- `attributes`: the attributes object containing the entire state of the sheet.\n- `sections`: An object containing the row IDs of all the repeating sections, indexed by section name (e.g. repeating_equipment)."},{"type":"string","name":"calculation","description":"The name of a function that has been registered with the K-scaffold using [k.registerFuncs](https://github.com/Kurohyou/Roll20-Snippets/blob/main/K_Scaffold/readme_docs/k_scaffold_js_documentation.md#registerFuncs). This function must return the calculated value of the attribute it is for, and is only called if the attribute is not changed directly by the user. Ideally, this function should be written as a pure function, reacting only to the arguments it is passed, and returning a value without modifying any of the arguments it is passed.\nThe K-scaffold sends this function the following arguments:\n- `trigger`: The trigger object for the attribute that is being changed\n- `attributes`: the attributes object containing the entire state of the sheet.\n- `sections`: An object containing the row IDs of all the repeating sections, indexed by section name (e.g. repeating_equipment)."},{"type":"Array","name":"triggeredFuncs","description":"An array of function names that have been registered with the K-scaffold using [k.registerFuncs](https://github.com/Kurohyou/Roll20-Snippets/blob/main/K_Scaffold/readme_docs/k_scaffold_js_documentation.md#registerFuncs). These functions are called any time an attribute is changed, regardless of the source of the change, do not return any values, and will likely modify the arguments that are passed to them. These functions are used for doing complex logic to determine what should be done in response to a change.\nThe K-scaffold sends these functions the following arguments:\n- `trigger`: The trigger object for the attribute that is being changed\n- `attributes`: the attributes object containing the entire state of the sheet.\n- `sections`: An object containing the row IDs of all the repeating sections, indexed by section name (e.g. repeating_equipment), and in the order that they appear on the sheet."},{"type":"string","name":"listenerFunc","description":"The name of a function that has been registered with the K-scaffold using [k.registerFuncs](https://github.com/Kurohyou/Roll20-Snippets/blob/main/K_Scaffold/readme_docs/k_scaffold_js_documentation.md#registerFuncs). This function will be called directly from the event listener for this attribute instead of the default [accessSheet](https://github.com/Kurohyou/Roll20-Snippets/blob/main/K_Scaffold/readme_docs/k_scaffold_js_documentation.md#accesssheet) listener function. If a `listenerFunc` is specified, the automated handling of the rest of the previous trigger properties will be disabled. You can still use these properties, but will need to code that handling yourself.\nThe K-scaffold sends this function the following argument:\n- `event`: The event information object that is passed to the callback in the [sheet worker event listener](https://wiki.roll20.net/Sheet_Worker_Scripts#Event_listener). This is **NOT** passed using the object destructuring pattern, unlike the previous three function types."},{"type":"string","name":"name","description":"The name of the attribute. When accessed from inside the default function cascade of the K-scaffold, or the callback of [getAllAttrs](https://github.com/Kurohyou/Roll20-Snippets/blob/main/K_Scaffold/readme_docs/k_scaffold_js_documentation.md#getAllAttrs), repeating attributes will include their specific row id for that instance of the attribute."},{"type":"string","name":"type","description":"What type of attribute is this. This is determined by the type of element that first created the trigger. Can be `text`,`number`,`checkbox`,`select`,or `radio`, but will usually be `text` or `number` based on the type of default value that is assigned to the attribute."},{"type":"string|number","name":"defaultValue","description":"What the default value of the attribute is. The k-scaffold uses this to return the default value in the event the value of the attribute becomes corrupted. For checkboxes and radios, this is determined based on the check state of the element. For selects, this is determined by which option has the `selected` property."}]},"input":{"type":"mixin","description":"A generic mixin to create an input. The mixin will replace spaces in the attribute name with underscores and will add a title property if one isn't supplied that will inform the user what the attribute call for the attribute is.","arguments":[{"type":"object","name":"obj","description":"An object containing all of the properties to apply to the element. Must have the properties; `name` and `type`. Can have any property that is valid for an input element. May also have a [trigger](#trigger) property"},{"type":"string","name":"obj.name"}],"example":[["+input({name:'my attribute',type:'text',class:'some-class',trigger:{affects:['other_attribute']}})'","<input name=\"attr_my_attribute\" type=\"text\" class=\"some-class\">'"]]},"text":{"type":"mixin","description":"Alias for [input](#input) that makes a text input.","example":[["+text({name:'my text',class:'some-class',trigger:{affects:['other_attribute']}})","<input type=\"text\" name=\"attr_my_text\" class=\"some-class\">"]]},"checkbox":{"type":"mixin","description":"Alias for [input](#input) that makes a checkbox input.","example":[["+checkbox({name:'my checkbox',class:'some-class',trigger:{affects:['other_attribute']}})","<input type=\"checkbox\" name=\"attr_my_checkbox\" class=\"some-class\">"]]},"collapse":{"type":"mixin","description":"Alias for [checkbox](#checkbox) that creates a checkbox for use in collapsing/expanding a section. Sets the checkbox to unchecked with a checked value of `1` and a class of `collapse`. Additional classes/ids can be applied by applying them inline to the mixin call.","arguments":[{"type":"string","name":"name","description":"The name to assign to the collapse button. Defaults to `collapse`"}]},"radio":{"type":"mixin","description":"Alias for [input](#input) that makes a radio input.","example":[["+radio({name:'my radio',class:'some-class',trigger:{affects:['other_attribute']}})","<input type=\"radio\" name=\"attr_my_radio\" class=\"some-class\">"]]},"number":{"type":"mixin","description":"Alias for [input](#input) that makes a number input.","example":[["+number({name:'my number',class:'some-class',trigger:{affects:['other_attribute']}})","<input type=\"number\" name=\"attr_my_number\" class=\"some-class\">"]]},"range":{"type":"mixin","description":"Alias for [input](#input) that makes a range input.","example":[["+range({name:'my range',class:'some-class',trigger:{affects:['other_attribute']}})","<input type=\"range\" name=\"attr_my_range\" class=\"some-class\">"]]},"hidden":{"type":"mixin","description":"Alias for [input](#input) that makes a hidden input.","example":[["+hidden({name:'my hidden',class:'some-class',trigger:{affects:['other_attribute']}})","<input type=\"hidden\" name=\"attr_my_hidden\" class=\"some-class\">"]]},"fillLeft":{"type":"mixin","description":"A mixin that creates a construction that can be used to recreate sheet mechanics that fill to the left. Will apply BEM style classes in addition to the classes specified. BEM classes that can be applied are\n - `fill-left`: The class for the fill-left container.\n - `fill-left__radio`: The class applied to all the radio buttons in the container\n - `fill-left__radio--clearer`: The class applied to the clear value radio button","arguments":[{"type":"object","name":"radioObj","description":"The object containing the details of the radio input to create. Similar to the [radio mixin](#radio), but the value property passed is used as the default checked value."},{"type":"object","name":"divObj","description":"Optional object containing any details of the div to be applied such as class, id, or other properties. Class and ID can also be supplied by attaching them to the mixin invocation just like with a regular div."},{"type":"array","name":"valueArray","description":"Array containing the values to be used for the fill to left construction. These should be in the order that they should be displayed left to right."},{"name":"noClear","type":"boolean","description":"Optional argument that tells the mixin whether or not to apply the `fill-left__radio--clearer` class to the first radio button value. If falsy (or not passed), the class is applied. If truthy, the class is not applied."}],"example":[["+fillLeft({radioObj:{name:'track',class:'some-class',value:\"0\"},valueArray:[0,1,2]})","<div class=\"fill-left\">\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio fill-left__radio--clearer\" value=\"0\" checked>\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"1\">\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"2\">\n</div>"],["+fillLeft({radioObj:{name:'track',class:'some-class',value:\"0\"},valueArray:[0,1,2],noClear:true})","<div class=\"fill-left\">\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"0\" checked>\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"1\">\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"2\">\n</div>"],["+fillLeft({radioObj:{name:'track',class:'some-class',value:\"0\"},valueArray:[0,1,2],divObj:{'aria-label':'Accessible tracker'}}).custom-tracker-class","<div class=\"fill-left custom-tracker-class\" aria-label:\"Accessible tracker\">\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio fill-left__radio--clearer\" value=\"0\" checked>\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"1\">\n <input type=\"radio\" name=\"attr_track\" class=\"some-class fill-left__radio\" value=\"2\">\n</div>"]]},"textarea":{"type":"mixin","description":"Functions like [input](#input), but creates a textarea instead.","example":[["+textarea({name:'my hidden',class:'some-class',placeholder:'Placeholder text',trigger:{affects:['other_attribute']}})","<textarea type=\"hidden\" name=\"attr_my_hidden\" class=\"some-class\">Placeholder text</textarea>"]]},"option":{"type":"mixin","description":"Creates an option attribute. Also stores the trigger for the select that the option is part of. See [select](#select) for example uses."},"select":{"type":"mixin","description":"Functions like [input](#input), but creates a select instead.","example":[["+select({name:'my select',class:'some-class'})\n +option({value:'option 1','data-i18n':'some-text',trigger:{affects:['some-attribute']}})\n +option({value:'option 2','data-i18n':'other-text'})","<select name=\"attr_my_select\" class=\"some-class\">\n <option value=\"option 1\" data-i18n=\"some-text\"></option>\n <option value=\"option 2\" data-i18n=\"other-text\"></option>\n</select>"]]},"img":{"type":"mixin","description":"Functions like [input](#input), but creates a span instead. The name property is optional.","example":[["+span({name:'my span',class:'some-class'})","<span name=\"attr_my_span\" class=\"some-class\"></span>"]]},"datalist":{"type":"mixin","description":"Functions like [input](#input), but creates a datalist instead. Note that an ID should never be put inside a repeating section, although you can reference one from inside the repeating section.","example":[["+select({name:'my select',list:'my-data'})\n+datalist({id:'my-data'})\n +option({value:'option 1','data-i18n':'some-text',trigger:{affects:['some-attribute']}})\n +option({value:'option 2','data-i18n':'other-text'})","<select name=\"attr_my_select\" class=\"some-class\"></select><datalist id=\"my-data\">\n <option value=\"option 1\" data-i18n=\"some-text\"></option>\n <option value=\"option 2\" data-i18n=\"other-text\"></option>\n</datalist>"]]},"button":{"type":"mixin","description":"Creates a button element. Valid types are `roll` or `action`. If a type is not specified in the object argument, a roll button is created. If an action button is created, spaces in the name are replaced with dashes instead of underscores.","example":[["+button({name:'my button',value:'/r 3d10'})","<button type=\"roll\" name=\"roll_my_button\" value=\"/r 3d10\"></button>"],["+button({name:'my button',type:'action','data-i18n':'action button'})","<button type=\"action\" name=\"act_my-button\" data-i18n=\"action button\"></button>"]]},"action":{"type":"mixin","description":"Alias for [button](#button) that creates a button element with a type of `action`. Spaces in the name are replaced with dashes instead of underscores.","example":[["+action({name:'my button','data-i18n':'action button'})","<button type=\"action\" name=\"act_my-button\" data-i18n=\"action button\"></button>"]]},"navButton":{"type":"mixin","description":"Alias for [button](#button) that creates a combination roll button and action button element to get around the limitation that action buttons cannot be dragged to the macro quickbar. Requires sheetworker infrastructure to work, which should be triggered `on(sheet:opened)` and `on(\"change:character_name\")`.","example":[["+roller({name:'my roll'})","<button type=\"roll\" name=\"roll_my_roll\" value=\"@{my_roll_action}\"></button>\n<button type=\"action\" name=\"act_my-roll-action\" hidden></button>\n<input type=\"hidden\" name=\"attr_my_roll_action\" value=\"\">"]]},"customControlFieldset":{"type":"mixin","description":"Alias for [fieldset](#fieldset) that creates to custom action buttons to add/remove rows to the repeating section. Useful when you need to trigger a sheetworker when a row is added. This also prevents the occassional error of a new row disappearing immediately after the user has clicked the button to create one. Proper use of this will require css to hide the default buttons that fieldsets create automatically. Note that currently this assumes the existence of an addItem and editSection sheetworker function.","arguments":[{"name":"name","type":"string","description":"The name of the repeating section. Will be prefixed with `repeating_` and spaces will be replaced with dashes (`-`)."},{"name":"trigger","type":"object","description":"Trigger that defines how to handle the removal of a row from the fieldset. `Optional`"},{"name":"addClass","type":"string","description":"Any additional classes that should be used for the repeating section. Note that these are not added to the fieldset itself as adding additional classes to the fieldset itself interferes with calling action buttons from chat, but are added to a span that precedes the fieldset. This allows styling of the repcontainer via a css declaration like `.bonus-class + fieldset + .repcontainer`."}],"example":[["+customControlFieldset({name:'equipment'})\n +text({name:'name',class:'underlined'})","<button type=\"action\" name=\"add-equipment\" class=\"repcontrol-button repcontrol-button--add\"></button>\n<button type=\"action\" name=\"edit-equipment\" class=\"repcontrol-button repcontrol-button--edit\"></button>\n<fieldset class=\"repeating_equipment\">\n <input type=\"text\" name=\"attr_name\" title=\"@{repeating_equipment_$x_name}\">\n</fieldset>"]]},"fieldset":{"type":"mixin","description":"A mixin that creates a fieldset for the creation of a repeating section. The mixin prefixes the name with `repeating_` and replaces problem characters (e.g. spaces are replaced with dashes). Additionally, the auto-generated title properties from the K-scaffold's mixins will include the proper repeating section information.","arguments":[{"name":"name","type":"string","description":"The name of the repeating section. Will be prefixed with `repeating_` and spaces will be replaced with dashes (`-`)."},{"name":"trigger","type":"object","description":"Trigger that defines how to handle the removal of a row from the fieldset. `Optional`"},{"name":"addClass","type":"string","description":"Any additional classes that should be used for the repeating section. Note that these are not added to the fieldset itself as adding additional classes to the fieldset itself interferes with calling action buttons from chat, but are added to a span that precedes the fieldset. This allows styling of the repcontainer via a css declaration like `.bonus-class + fieldset + .repcontainer`."}],"example":[["+fieldset({name:'equipment'})\n +text({name:'name',class:'underlined'})","<fieldset class=\"repeating_equipment\"></fieldset><div class=\"repcontainer\" data-groupname=\"repeating_equipment\">\n <input type=\"text\" name=\"attr_name\" title=\"@{repeating_equipment_$x_name}\">\n</div>"],["+fieldset({name:'equipment',trigger:{listenerFunc:'handleDeletedRow'},addClass:'class-1 class-2'})\n +text({name:'name',class:'underlined'})","<span hidden class=\"class-1 class-2\"></span>\n<fieldset class=\"repeating_equipment\"></fieldset><div class=\"repcontainer\" data-groupname=\"repeating_equipment\">\n <input type=\"text\" name=\"attr_name\" title=\"@{repeating_equipment_$x_name}\">\n</div>"]]},"pseudo-button":{"type":"mixin","description":"A mixin for creating pseudo buttons of paired checkboxes/radios and spans such as those that had to be used to create [tabbed sheets](https://wiki.roll20.net/CSS_Wizardry#Show.2FHide_Areas) before action buttons were introduced.","arguments":[{"name":"label","type":"string","description":"The `data-i18n` translation key to use for the displayed text."},{"name":"inputObj","type":"object","description":"An object describing the input to be paired with the span. This is the same object that you would pass to [input](#input)."}],"example":[["+pseudo-button('page 1',{name:'page',type:'radio',value:1,trigger:{triggeredFuncs:['changePage']}})","<input type=\"hidden\" name=\"attr_page\" title=\"@{page} value=\"1\">\n<label class=\"pseudo-button\"><span data-i8n=\"page 1\" class=\"pseudo-button__span\"></span>\n <input type=\"radio\" name=\"attr_page\" value=\"1\"></label>"]]},"button-label":{"type":"mixin","description":"A mixin to create a combined button and input that are within the same container. Similar to [input-label](#input-label), but does not use a label.","arguments":[{"name":"inputObj","type":"object","description":"An object describing the input to be paired with the button. This is the same object that you would pass to [input](#input)."},{"name":"buttonObj","type":"object","description":"An object describing the button to be paired with the input. This is the same object that you would pass to [button](#button)."},{"name":"divObj","type":"object","description":"An object describing the container div. Similar to the first two objects, but will most likely only have a `class` property if it is passed at all."}],"example":[["+button-label({inputObj:{name:'strength',type:'number',class:'underlined',value:10,trigger:{affects:['athletics']}},buttonObj:{name:'strength_roll',type:'roll',value:'/r 1d20+@{strength}'},divObj:{class:'strength'}})","<div class=\"input-label input-label--button strength\">\n <button name=\"roll_strength_roll\" type=\"roll\" value=\"/r 1d20+@strength\">\n <input name=\"attr_strength\" type=\"number\" value=\"10\">\n</div"]]},"roller-label":{"type":"mixin","description":"Similar to the construction created by [button-label](#button-label), except that it creates a [roller](#roller) construction instead of just a straight button.","arguments":[{"name":"inputObj","type":"object","description":"An object describing the input to be paired with the button. This is the same object that you would pass to [input](#input)."},{"name":"buttonObj","type":"object","description":"An object describing the button to be paired with the input. This is the same object that you would pass to [roller](#roller)."},{"name":"divObj","type":"object","description":"An object describing the container div. Similar to the first two objects, but will most likely only have a `class` property if it is passed at all."}]},"action-label":{"type":"mixin","description":"Similar to the construction created by [button-label](#button-label), except that it specifcally creates an [action button](https://wiki.roll20.net/Button#Action_Button) as per [action](#action).","arguments":[{"name":"inputObj","type":"object","description":"An object describing the input to be paired with the button. This is the same object that you would pass to [input](#input)."},{"name":"buttonObj","type":"object","description":"An object describing the button to be paired with the input. This is the same object that you would pass to [action](#action)."},{"name":"divObj","type":"object","description":"An object describing the container div. Similar to the first two objects, but will most likely only have a `class` property if it is passed at all."}]},"select-label":{"type":"mixin","description":"Similar to the construction created by [input-label](#input-label), except that the input is replaced with a select.","arguments":[{"name":"label","type":"string","description":"The `data-i18n` translation key to add to the span in the label."},{"name":"inputObj","type":"object","description":"An object describing the select to be paired with the button. This is the same object that you would pass to [select](#select)."},{"name":"divObj","type":"object","description":"An object describing the container label. Similar to the inputObj, but will most likely only have a `class` property if it is passed at all."},{"name":"spanObj","type":"object","description":"An object describing the span to be paired with the input. This is the same object that you would pass to [span](#span)."},{"name":"block","type":"block","description":"The mixin uses the pug block as the content of the select."}],"example":[["+select-label('Whisper to GM',{name:'whisper'},{class:'div-class'},{class:'span-class'})\n +option({value:'','data-i18n':'never'})\n +option({value:'/w gm ','data-i18n':'always'})","<label class=\"input-label div-class\"><span data-i18n=\"Whisper to GM\" class=\"input-label__text span-class\"></span>\n <select name=\"attr_whisper\" class=\"input-label__input\">\n <option value=\"\" data-i18n=\"never\"></option>\n <option value=\"/w gm \" data-i18n=\"always\"></option>\n </select>\n</label>"]]},"input-label":{"type":"mixin","description":"Creates a construction that nests the input and span in a label so that they are connected. This is beneficial for screen readers as well as making it easier to interact with the input via mouse by clicking on the text associated with it.","arguments":[{"name":"label","type":"string","description":"The `data-i18n` translation key to add to the span in the label."},{"name":"inputObj","type":"object","description":"An object describing the input to be paired with the button. This is the same object that you would pass to [input](#input)."},{"name":"divObj","type":"object","description":"An object describing the container label. Similar to the inputObj, but will most likely only have a `class` property if it is passed at all."},{"name":"spanObj","type":"object","description":"An object describing the span to be paired with the input. This is the same object that you would pass to [span](#span)."},{"name":"block","type":"block","description":"The mixin uses the pug block as the content of the select."}],"example":[["+input-label({label:'strength',inputObj:{name:'strength',type:'number'},divObj:{class:'div-class'},spanObj:{class:'span-class'}})","<label class=\"input-label div-class\"><span data-i18n=\"Whisper to GM\" class=\"input-label__text span-class\"></span>\n <input name=\"attr_strength\" type=\"number\" class=\"input-label__input\">\n</label>"]]},"headedTextarea":{"type":"mixin","description":"Creates a construction for pairing a header with a textarea. Currently is locked to creating an `h3`. This mixin also accepts classes and IDs appended directly to it (see the second example)","arguments":[{"name":"textObj","type":"object","description":"The object describing the textarea as per [textarea](#textarea)"},{"name":"header","type":"string","description":"The `data-i18n` translation key to use for the header"}],"example":[["+headedTextarea({textObj:{name:'character description','data-i18n-placeholder':'The description of your character'},header:'description'})","<div class=\"headed-textarea\">\n <h3 data-i18n=\"description\"></h3>\n <textarea name=\"attr_character_description\" data-i18n-placeholder:\"The description of your character\"></textarea>\n</div>"],["+headedTextarea({textObj:{name:'character description','data-i18n-placeholder':'The description of your character'},header:'description'}).character-description","<div class=\"headed-textarea character-description\">\n <h3 data-i18n=\"description\"></h3>\n <textarea name=\"attr_character_description\" data-i18n-placeholder:\"The description of your character\"></textarea>\n</div>"]]},"script":{"type":"mixin","description":"Creates a generic [Roll20 script block](https://wiki.roll20.net/Building_Character_Sheets#JavaScript_2) for use with the sheetworker system."},"adaptiveTextarea":{"type":"mixin","description":"Creates an html construction for creating a [content-scaled](https://wiki.roll20.net/CSS_Wizardry#Content-scaled_Inputs) textarea.","arguments":[{"name":"textObj","type":"object","description":"The object describing the textarea as per the [textarea](#textarea) mixin. You can apply classes and IDs to the container div by appending them to the mixin call (see the second example)."}],"example":[["+adaptiveTextarea({name:'character description'})","<div class=\"adaptive adaptive--text\"><span name:\"attr_character_description\" class=\"adaptive--text__span\"></span>\n <textarea name=\"attr_character_description\" class=\"adaptive--text__textarea\"></textarea>\n</div>"],["+adaptiveTextarea({name:'character description'}).custom-class","<div class=\"adaptive adaptive--text custom-class\"><span name:\"attr_character_description\" class=\"adaptive--text__span\"></span>\n <textarea name=\"attr_character_description\" class=\"adaptive--text__textarea\"></textarea>\n</div>"]]},"compendiumAttributes":{"type":"mixin","description":"Creates a set of compendium drop target attributes. Defaults to creating target attributes for the `Name` and `data` compendium attributes.","arguments":[{"name":"prefix","type":"string","description":"A prefix to attach to the default attribute names."},{"name":"lookupAttributes","type":"array","description":"An array of the lookup attributes to create targets for. The target attributes are named based on the compendium attribute they are for. lookupAttributes defaults to `[\"Name\",\"data\"]`."},{"name":"triggerAccept","type":"string","description":"The compendium attribute that should trigger the sheetworkers to handle the compendium drop."},{"name":"trigger","type":"object","description":"The trigger object. Defaults to `{listenerFunc:\"handleCompendiumDrop\"}`"}],"example":[["+compendiumAttributes({})","<input name=\"attr_drop_name\" accept=\"Name\" value=\"\" type=\"hidden\" title=\"@{drop_name}\"/>\n<input name=\"attr_drop_data\" accept=\"data\" value=\"\" type=\"hidden\" title=\"@{drop_data}\"/>"],["+compendiumAttributes({prefix:'prefix'})","<input name=\"attr_prefix_drop_name\" accept=\"Name\" value=\"\" type=\"hidden\" title=\"@{prefix_drop_name}\"/>\n<input name=\"attr_prefix_drop_data\" accept=\"data\" value=\"\" type=\"hidden\" title=\"@{prefix_drop_data}\"/>"],["+compendiumAttributes({lookupAttributes:['Name','data','Category'],prefix:'prefix})","<input name=\"attr_prefix_drop_name\" accept=\"Name\" value=\"\" type=\"hidden\" title=\"@{prefix_drop_name}\"/>\n<input name=\"attr_prefix_drop_data\" accept=\"data\" value=\"\" type=\"hidden\" title=\"@{prefix_drop_data}\"/>\n<input name=\"attr_prefix_drop_category\" accept=\"Category\" value=\"\" type=\"hidden\" title=\"@{prefix_drop_category}\"/>"]]},"attrTitle":{"type":"function","description":"Converts an attribute name into an attribute call for that attribute. Converts `_max` attribute names to the proper attribute call syntax for `_max` attributes (see second example). If called from inside the block of a [fieldset](#fieldset) mixin, will also add the appropriate information for calling a repeating attribute.","arguments":[{"name":"attrName","type":"string","description":"The attribute name to create an attribute call for."}],"example":[["- attrTitle('strength') => \"@{strength}\""],["- attrTitle('hp_max') => \"@{hp|max}\""],["+fieldset({name:'equipment'})\n - attrTitle('weight') => \"@{repeating_equipment_$X_weight}\""]],"retValue":{"type":"string"}},"kscript":{"type":"mixin","description":"Similar to [script](#script), but includes the K-scaffold's javascript function library."},"buttonTitle":{"type":"function","description":"Converts an ability name into an ability call for that attribute. If called from inside the block of a [fieldset](#fieldset) mixin, will also add the appropriate information for calling a repeating attribute.","arguments":[{"name":"abilityName","type":"string","description":"The ability name to create an attribute call for."}],"example":[["- buttonTitle('strength') => \"%{strength}\""],["+fieldset({name:'equipment'})\n - buttonTitle('use') => \"%{repeating_equipment_$X_use}\""]],"retValue":{"type":"string"}},"replaceSpaces":{"type":"function","description":"Replaces spaces in a string with underscores (`_`).","arguments":[{"name":"string","type":"string","description":"The string to work on"}],"example":[["- replaceSpaces('attribute name') => \"attribute_name\""]],"retValue":{"type":"string"}},"replaceProblems":{"type":"function","description":"Escapes problem characters in a string for use as a regex.","arguments":[{"name":"string","type":"string","description":"The string to work on"}],"example":[["- replaceProblems(\"Here's a problem => [\") => \"Here's a problem => [\""]],"retValue":{"type":"string"}},"capitalize":{"type":"function","description":"Capitalizes the first let of words in a string.","arguments":[{"name":"string","type":"string","description":"The string to apply capitalization to."}],"retValue":{"type":"string"}}}};
|
||
|
||
kFuncs.docs = docs;
|
||
/**
|
||
* This stores the name of your sheet for use in the logging functions {@link log} and {@link debug}
|
||
* * @var
|
||
* @type {string}
|
||
*/
|
||
docs.js['k.sheetName'] = {
|
||
type:'string',
|
||
description:'This stores the name of your sheet for use in the logging functions [k.log](#klog) and [k.debug](#kdebug).'
|
||
};
|
||
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.
|
||
* @var
|
||
* @type {number}
|
||
*/
|
||
docs.js['k.version'] = {
|
||
type:'number',
|
||
description:'This stores the version of your sheet for use in the logging functions [k.log](#klog) and [k.debug](#kdebug), and in the K-scaffolds sheet versioning handling. It is also stored in the sheet_version attribute on your character sheet.'
|
||
};
|
||
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.
|
||
* @var
|
||
* @type {boolean}
|
||
*/
|
||
docs.js['k.debugMode'] = {
|
||
type:'boolean',
|
||
description:'A boolean flag that tells the script whether to enable or disable [k.debug](#kdebug) 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 all sheets you open from that point on. Otherwise, it remains false.'
|
||
};
|
||
let debugMode = false;
|
||
kFuncs.debugMode = debugMode;
|
||
const funcs = {};
|
||
kFuncs.funcs = funcs;
|
||
const updateHandlers = {};
|
||
const openHandlers = {};
|
||
const initialSetups = {};
|
||
const addFuncs = {};
|
||
|
||
const kscaffoldJSVersion = 0.30;
|
||
const kscaffoldPUGVersion = 0.30;
|
||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
docs.js['k.sanitizeForRegex'] = {
|
||
type:'function',
|
||
invocation:`k.sanitizeForRegex(text)`,
|
||
description:'Replaces problem characters to use a string as a regex.',
|
||
arguments:[
|
||
{type:'string',name:'text',description:'The text to replace characters in.'}
|
||
]
|
||
};
|
||
const sanitizeForRegex = function(text){
|
||
return text.replace(/\.|\||\(|\)|\[|\]|\-|\+|\?|\/|\{|\}|\^|\$|\*/g,'\\$&');
|
||
};
|
||
kFuncs.sanitizeForRegex = sanitizeForRegex;
|
||
|
||
docs.js['k.value'] = {
|
||
type:'function',
|
||
invocation:`k.value(val,def)`,
|
||
description:'Converts a value to a number, it\'s default value, or `0` if no default value passed.',
|
||
arguments:[
|
||
{type:'any',name:'val',description:'The value to coerce into a number.'},
|
||
{type:'number',name:'def',description:'A default value to use, if not passed, 0 is used instead.'}
|
||
]
|
||
};
|
||
const value = function(val,def){
|
||
return (+val||def||0);
|
||
};
|
||
kFuncs.value = value;
|
||
|
||
docs.js['k.parseRepeatName'] = {
|
||
type:'function',
|
||
invocation:`k.parseRepeatName(string)`,
|
||
description:'Extracts the section (e.g. `repeating_equipment`), rowID (e.g `-;lkj098J:LKj`), and field name (e.g. `bulk`) from a repeating attribute name.',
|
||
arguments:[
|
||
{type:'string',name:'string',description:'The attribute name to parse.'}
|
||
],
|
||
retValue:{
|
||
type:'array',
|
||
description:'For a repeating attribute named `repeating_equipment_-LKJhpoi98;lj_weight`, the array will be `[\'repeating_equipment\',\'-LKJhpoi98;lj\',\'weight\']`.'
|
||
}
|
||
};
|
||
const parseRepeatName = function(string){
|
||
let match = string.match(/(repeating_[^_]+)_([^_]+)(?:_(.+))?/);
|
||
match.shift();
|
||
return match;
|
||
};
|
||
kFuncs.parseRepeatName = parseRepeatName;
|
||
|
||
docs.js['k.parseTriggerName'] = {
|
||
type:'function',
|
||
invocation:`k.parseTriggerName(string)`,
|
||
description:'Parses out the components of a trigger name similar to [parseRepeatName](#parserepeatname). Aliases: parseClickTrigger.\n\nAliases: `k.parseClickTrigger`',
|
||
arguments:[
|
||
{type:'string',name:'string',description:'The triggerName property of the [event](https://wiki.roll20.net/Sheet_Worker_Scripts#eventInfo_Object).'}
|
||
],
|
||
retValue:{
|
||
type:'array',
|
||
description:'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\']`'
|
||
}
|
||
};
|
||
const parseTriggerName = function(string){
|
||
let match = string.replace(/^clicked:/,'').match(/(?:(repeating_[^_]+)_([^_]+)_)?(.+)/);
|
||
match.shift();
|
||
return match;
|
||
};
|
||
kFuncs.parseTriggerName = parseTriggerName;
|
||
const parseClickTrigger = parseTriggerName;
|
||
kFuncs.parseClickTrigger = parseClickTrigger;
|
||
|
||
docs.js['k.parseHTMLName'] = {
|
||
type:'function',
|
||
invocation:`k.parseHTMLName(string)`,
|
||
description:'Parses out the attribute name from the htmlattribute name.',
|
||
arguments:[
|
||
{type:'string',name:'string',description:'The triggerName property of the [event](https://wiki.roll20.net/Sheet_Worker_Scripts#eventInfo_Object).'}
|
||
],
|
||
retValue:{
|
||
type:'array',
|
||
description:'For a repeating button named `act_repeating_equipment_-LKJhpoi98;lj_roll`, the array will be `[\'repeating_equipment\',\'-LKJhpoi98;lj\',\'roll\']`. For a non repeating button named `act_roll`, the array will be `[undefined,undefined,\'roll\']`'
|
||
}
|
||
};
|
||
const parseHTMLName = function(string){
|
||
let match = string.match(/(?:attr|act|roll)_(.+)/);
|
||
match.shift();
|
||
return match[0];
|
||
};
|
||
kFuncs.parseHTMLName = parseHTMLName;
|
||
|
||
docs.js['k.capitalize'] = {
|
||
type:'function',
|
||
invocation:`k.capitalize(string)`,
|
||
description:'Capitalize each word in a string.',
|
||
arguments:[
|
||
{type:'string',name:'string',description:'The string to capitalize'},
|
||
],
|
||
retValue:{
|
||
type:'string',
|
||
description:'The capitalized string'
|
||
}
|
||
};
|
||
const capitalize = function(string){
|
||
return string.replace(/(?:^|\s+|\/)[a-z]/ig,(letter)=>letter.toUpperCase());
|
||
};
|
||
kFuncs.capitalize = capitalize;
|
||
|
||
docs.js['k.extractQueryResult'] = {
|
||
type:'function',
|
||
invocation:`k.extractQueryResult(section,sections,customText)`,
|
||
description:'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).',
|
||
arguments:[
|
||
{type:'string',name:'query',description:'The query should be just the text as the `?{` and `}` at the start/end of the query are added by the function.'}
|
||
],
|
||
retValue:{
|
||
type:'string',
|
||
description:'The selected value from the roll query'
|
||
}
|
||
};
|
||
const extractQueryResult = async function(query){
|
||
debug('entering extractQueryResult');
|
||
let queryRoll = await startRoll(`!{{query=[[0[response=?{${query}}]]]}}`);
|
||
finishRoll(queryRoll.rollId);
|
||
return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,'');
|
||
};
|
||
kFuncs.extractQueryResult = extractQueryResult;
|
||
|
||
docs.js['k.pseudoQuery'] = {
|
||
type:'function',
|
||
invocation:`k.pseudoQuery(section,sections,customText)`,
|
||
description:'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.',
|
||
arguments:[
|
||
{type:'number|string',name:'value',description:'The value to return. Optional.'}
|
||
],
|
||
retValue:{
|
||
type:'string',
|
||
description:'The `value` passed to the function is returned after startRoll resolves.'
|
||
}
|
||
};
|
||
const pseudoQuery = async function(value){
|
||
debug('entering pseudoQuery');
|
||
let queryRoll = await startRoll(`!{{query=[[0[response=${value}]]]}}`);
|
||
finishRoll(queryRoll.rollId);
|
||
return queryRoll.results.query.expression.replace(/^.+?response=|\]$/g,'');
|
||
};
|
||
kFuncs.pseudoQuery = pseudoQuery;
|
||
|
||
docs.js['k.log'] = {
|
||
type:'function',
|
||
invocation:`k.log(msg)`,
|
||
description:'An alias for console.log.',
|
||
arguments:[
|
||
{type:'string|object|array',name:'msg',description:'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;
|
||
|
||
docs.js['k.debug'] = {
|
||
type:'function',
|
||
invocation:`k.debug(msg,force)`,
|
||
description:'Alias for console.log that only triggers when debug mode is enabled or when the sheet\'s version is `0`.',
|
||
arguments:[
|
||
{type:'string',name:'setObj',description:'See [k.log](#klog)'},
|
||
{type:'boolean',name:'force',description:'Pass as a truthy value to force the debug output to be output to the console regardless of debug mode.'}
|
||
]
|
||
};
|
||
const debug = function(msg,force){
|
||
if(!kFuncs.debugMode && !force && kFuncs.version > 0) return;
|
||
if(typeof msg === 'string'){
|
||
console.log(`%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.log(`%c${kFuncs.sheetName} DEBUG| ${m}: ${msg[m]}`,"background-color:tan;color:red;");
|
||
}else{
|
||
console.log(`%c${kFuncs.sheetName} DEBUG| ${typeof msg[m]} ${m}`,"background-color:tan;color:red;font-weight:bold;");
|
||
console.table(msg[m]);
|
||
}
|
||
});
|
||
}
|
||
};
|
||
kFuncs.debug = debug;
|
||
|
||
docs.js['k.orderSections'] = {
|
||
type:'function',
|
||
invocation:`k.orderSections(attributes,sections)`,
|
||
description:'Orders the section id arrays for all sections in the `sections` object to match the repOrder attribute.',
|
||
arguments:[
|
||
{type:'object',name:'attributes',description:'The attributes object that must have a value for the reporder for each section.'},
|
||
{type:'object',name:'sections',description:'Object containing the IDs for the repeating sections, indexed by repeating section name.'}
|
||
]
|
||
};
|
||
const orderSections = function(attributes,sections){
|
||
Object.keys(sections).forEach((section)=>{
|
||
attributes.attributes[`_reporder_${section}`] = commaArray(attributes[`_reporder_${section}`]);
|
||
orderSection(attributes.attributes[`_reporder_${section}`],sections[section]);
|
||
});
|
||
};
|
||
kFuncs.orderSections = orderSections;
|
||
|
||
docs.js['k.orderSection'] = {
|
||
type:'function',
|
||
invocation:`k.orderSection(repOrder,IDs)`,
|
||
description:'Orders a single ID array.',
|
||
arguments:[
|
||
{type:'array',name:'setObj',description:'Array of IDs in the order they are in on the sheet.'},
|
||
{type:'array',name:'vocal',description:'Array of IDs to be ordered.'}
|
||
]
|
||
};
|
||
const orderSection = function(repOrder,IDs=[]){
|
||
IDs.sort((a,b)=>{
|
||
return repOrder.indexOf(a.toLowerCase()) - repOrder.indexOf(b.toLowerCase());
|
||
});
|
||
};
|
||
kFuncs.orderSection = orderSection;
|
||
|
||
/**
|
||
* Splits a comma delimited string into an array
|
||
* @param {string} [string='']
|
||
* @returns {string[]}
|
||
*/
|
||
docs.js['k.commaArray'] = {
|
||
type:'function',
|
||
invocation:`k.commaArray(string)`,
|
||
description:'Splits a comma delimited string into an array',
|
||
arguments:[
|
||
{type:'string',name:'setObj',description:'The string to split.'}
|
||
],
|
||
retValue:{
|
||
type:'array',
|
||
description:'The string segments of the comma delimited list.'
|
||
}
|
||
};
|
||
const commaArray = function(string=''){
|
||
return string.toLowerCase().split(/\s*,\s*/);
|
||
};
|
||
kFuncs.commaArray = commaArray;/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
//# Attribute Obj Proxy handler
|
||
const createAttrProxy = function(attrs){
|
||
//creates a proxy for the attributes object so that values can be worked with more easily.
|
||
const getCascObj = function(event,casc){
|
||
const eventName = event.triggerName || event.sourceAttribute;
|
||
let typePrefix = eventName.startsWith('clicked:') ?
|
||
'act_' :
|
||
event.removedInfo ?
|
||
'fieldset_' :
|
||
'attr_';
|
||
let cascName = `${typePrefix}${eventName.replace(/clicked:/,'')}`;
|
||
let cascObj = casc[cascName];
|
||
return cascObj;
|
||
};
|
||
|
||
const triggerFunctions = function(obj,attributes,sections){
|
||
if(obj.triggeredFuncs && obj.triggeredFuncs.length){
|
||
debug(`triggering functions for ${obj.name}`);
|
||
obj.triggeredFuncs && obj.triggeredFuncs.forEach(func=>funcs[func] ?
|
||
funcs[func]({trigger:obj,attributes,sections}) :
|
||
debug(`!!!Warning!!! no function named ${func} found. Triggered function not called for ${obj.name}`,true));
|
||
}
|
||
};
|
||
|
||
const initialFunction = function(obj,attributes,sections){
|
||
if(obj.initialFunc){
|
||
debug(`initial functions for ${obj.name}`);
|
||
funcs[obj.initialFunc] ?
|
||
funcs[obj.initialFunc]({trigger:obj,attributes,sections}) :
|
||
debug(`!!!Warning!!! no function named ${obj.initialFunc} found. Initial function not called for ${obj.name}`,true);
|
||
}
|
||
};
|
||
const processChange = function({event,trigger,attributes,sections,casc}){
|
||
debug({trigger});
|
||
if(event && !trigger){
|
||
debug('initial change detected. No trigger found');
|
||
return;
|
||
}
|
||
if(!attributes || !sections || !casc){
|
||
debug(`!!! Insufficient arguments || attributes > ${!!attributes} | sections > ${!!sections} | casc > ${!!casc} !!!`);
|
||
return;
|
||
}
|
||
//store the queue in attributes.
|
||
if(event){
|
||
debug('checking for initial functions');
|
||
initialFunction(trigger,attributes,sections);//functions that should only be run if the attribute was the thing changed by the user
|
||
}
|
||
if(trigger){
|
||
debug(`processing ${trigger.name}`);
|
||
triggerFunctions(trigger,attributes,sections);
|
||
if(!event && trigger.calculation && funcs[trigger.calculation]){
|
||
attributes[trigger.name] = funcs[trigger.calculation]({trigger,attributes,sections,casc});
|
||
}else if(trigger.calculation && !funcs[trigger.calculation]){
|
||
debug(`K-Scaffold Error: No function named ${trigger.calculation} found`);
|
||
}
|
||
if(Array.isArray(trigger.affects)){
|
||
attributes.queue.push(...trigger.affects);
|
||
}
|
||
}
|
||
attributes.set({attributes,sections,casc});
|
||
};
|
||
const attrTarget = {
|
||
updates:{},
|
||
attributes:{...attrs},
|
||
repOrders:{},
|
||
queue: [],
|
||
casc:{},
|
||
processChange,
|
||
triggerFunctions,
|
||
initialFunction,
|
||
getCascObj
|
||
};
|
||
const attrHandler = {
|
||
get:function(obj,prop){//gets the most value of the attribute.
|
||
//If it is a repeating order, returns the array, otherwise returns the update value or the original value
|
||
if(prop === 'set'){
|
||
return function(){
|
||
let {attributes,sections,casc,callback,vocal} = arguments[0] ? arguments[0] : {};
|
||
if(attributes && attributes.queue.length && sections && casc){
|
||
let triggerName = attributes.queue.shift();
|
||
let trigger = getCascObj({sourceAttribute:triggerName},casc);
|
||
attributes.processChange({trigger,attributes,sections,casc});
|
||
}else{
|
||
debug({updates:obj.updates});
|
||
let trueCallback = Object.keys(obj.repOrders).length ?
|
||
function(){
|
||
Object.entries(obj.repOrders).forEach(([section,order])=>{
|
||
_setSectionOrder(section,order,)
|
||
});
|
||
callback && callback();
|
||
}:
|
||
callback;
|
||
Object.keys(obj.updates).forEach((key)=>obj.attributes[key] = obj.updates[key]);
|
||
const update = obj.updates;
|
||
obj.updates = {};
|
||
set(update,vocal,trueCallback);
|
||
}
|
||
}
|
||
}else if(Object.keys(obj).some(key=>key===prop)){
|
||
return Reflect.get(...arguments)
|
||
}else{
|
||
let retValue;
|
||
switch(true){
|
||
case obj.repOrders.hasOwnProperty(prop):
|
||
retValue = obj.repOrders[prop];
|
||
break;
|
||
case obj.updates.hasOwnProperty(prop):
|
||
retValue = obj.updates[prop];
|
||
break;
|
||
default:
|
||
retValue = obj.attributes[prop];
|
||
break;
|
||
}
|
||
let cascRef = `attr_${prop.replace(/(repeating_[^_]+_)[^_]+/,'$1\$X')}`;
|
||
let numRetVal = +retValue;
|
||
if(!Number.isNaN(numRetVal) && retValue !== ''){
|
||
retValue = numRetVal;
|
||
}else if(cascades[cascRef] && (typeof cascades[cascRef].defaultValue === 'number' || cascades[cascRef].type === 'number')){
|
||
retValue = cascades[cascRef].defaultValue;
|
||
}
|
||
return retValue;
|
||
}
|
||
},
|
||
set:function(obj,prop,value){
|
||
//Sets the value. Also verifies that the value is a valid attribute value
|
||
//e.g. not undefined, null, or NaN
|
||
if(value || value===0 || value===''){
|
||
if(/reporder|^repeating_[^_]+$/.test(prop)){
|
||
let section = prop.replace(/_reporder_/,'');
|
||
obj.repOrders[section] = value;
|
||
}else if(`${obj.attributes}` !== `${value}` ||
|
||
(obj.updates[prop] && `${obj.updates}` !== `${value}`)
|
||
){
|
||
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()];
|
||
});
|
||
}
|
||
};
|
||
return new Proxy(attrTarget,attrHandler);
|
||
};
|
||
|
||
/**
|
||
* 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.
|
||
* @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.
|
||
*/
|
||
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,
|
||
'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;
|
||
|
||
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;
|
||
|
||
/**
|
||
* Function to call a function previously registered to the funcs object. May not be used that much. Either returns the function or null if no function exists.
|
||
* @param {string} funcName - The name of the function to invoke.
|
||
* @param {...any} args - The arguments to call the function with.
|
||
* @returns {any}
|
||
*/
|
||
const callFunc = function(funcName,...args){
|
||
if(funcs[funcName]){
|
||
debug(`calling ${funcName}`);
|
||
return funcs[funcName](...args);
|
||
}else{
|
||
debug(`Invalid function name: ${funcName}`);
|
||
return null;
|
||
}
|
||
};
|
||
kFuncs.callFunc = callFunc;/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
//Sheet Updaters and styling functions
|
||
/**
|
||
* An object to store your update functions in. Functions should be index by the version they are for (e.g. the update handler for version 1.01 would be indexed to '1.01'). These update functions will be iterated through based on the previous version of the sheet (as stored in the `sheet_version` attribute of the sheet) and the new version of the sheet (as stored in {@link k.version}).
|
||
* @type {object}
|
||
*/
|
||
const updateSheet = function(){
|
||
log('updating sheet');
|
||
getAllAttrs({props:['debug_mode',...baseGet],callback:(attributes,sections,casc)=>{
|
||
kFuncs.debugMode = kFuncs.debugMode || !!attributes.debug_mode;
|
||
debug({sheet_version:attributes.sheet_version});
|
||
if(!attributes.sheet_version){
|
||
Object.entries(initialSetups).forEach(([funcName,handler])=>{
|
||
if(typeof funcs[funcName] === 'function'){
|
||
debug(`running ${funcName}`);
|
||
funcs[funcName]({attributes,sections,casc});
|
||
}else{
|
||
debug(`!!!Warning!!! no function named ${funcName} found. Initial sheet setup not performed.`);
|
||
}
|
||
});
|
||
}else{
|
||
Object.entries(updateHandlers).forEach(([ver,handler])=>{
|
||
if(attributes.version < +ver){
|
||
handler({attributes,sections,casc});
|
||
}
|
||
});
|
||
}
|
||
Object.entries(openHandlers).forEach(([funcName,func])=>{
|
||
if(typeof funcs[funcName] === 'function'){
|
||
debug(`running ${funcName}`);
|
||
funcs[funcName]({attributes,sections,casc});
|
||
}else{
|
||
debug(`!!!Warning!!! no function named ${funcName} found. Sheet open handling not performed.`);
|
||
}
|
||
});
|
||
setActionCalls({attributes,sections});
|
||
attributes.sheet_version = kFuncs.version;
|
||
log(`Sheet Update applied. Current Sheet Version ${kFuncs.version}`);
|
||
if(document){
|
||
['pug','js'].forEach((type)=>{
|
||
log(docGen(type));
|
||
});
|
||
}
|
||
attributes.set();
|
||
log('Sheet ready for use');
|
||
}});
|
||
};
|
||
|
||
const docGen = function(language){
|
||
debug(`generating documentation for ${language}`);
|
||
let docHead = [`# K Scaffold ${language.toUpperCase()} documentation`];
|
||
Object.keys(docs[language])
|
||
.sort((nameA,nameB) => nameA.localeCompare(nameB))
|
||
.forEach((funcName)=>{
|
||
docHead.push(`- [${funcName}](#${funcName.replace(/\./g,'').replace(/\s/g,'-')})`);
|
||
});
|
||
return Object.entries(docs[language])
|
||
.sort(([nameA,docObjA],[nameB,docObjB]) => nameA.localeCompare(nameB))
|
||
.reduce((text,[name,docObj]) => {
|
||
let type = docObj.type;
|
||
text.push(`## ${docObj.name || name}`,`\`${type}\`\n`);
|
||
if(docObj.invocation){
|
||
text.push(`\`\`\`js\n${docObj.invocation}\n\`\`\``);
|
||
}
|
||
if(docObj.description){
|
||
text.push(docObj.description);
|
||
}
|
||
let args = Array.isArray(docObj.arguments) ? docObj.arguments : [];
|
||
if(args.length){
|
||
text.push('|Argument|type|description|','|---|---|---|')
|
||
}
|
||
args.forEach((a)=>{
|
||
text.push(`|${a.name}|\`${a.type}\`|${a.description || ''}|`)
|
||
});
|
||
if(args.length){
|
||
text.push('\n')
|
||
}
|
||
let example = Array.isArray(docObj.example) ? docObj.example : [];
|
||
if(example.length){
|
||
text.push(`### Example${example.length > 1 ? 's' : ''}`);
|
||
}
|
||
example.forEach((eArr)=>{
|
||
text.push(
|
||
`**${language.toUpperCase()}**`,
|
||
`\`\`\`js`,
|
||
eArr[0],
|
||
`\`\`\``
|
||
);
|
||
if(type === 'mixin'){
|
||
text.push(
|
||
'**HTML**',
|
||
`\`\`\`html`,
|
||
eArr[1],
|
||
`\`\`\``
|
||
);
|
||
}
|
||
});
|
||
if(docObj.retValue){
|
||
text.push(`returns \`${docObj.retValue.type}\` ${
|
||
docObj.retValue.description ?
|
||
`- ${docObj.retValue.description}` :
|
||
''
|
||
}`
|
||
);
|
||
}
|
||
return text;
|
||
},docHead).join('\n');
|
||
};
|
||
|
||
const initialSetup = function(attributes,sections){
|
||
debug('Initial sheet setup');
|
||
};
|
||
|
||
/**
|
||
* This is the default listener function for attributes that the K-Scaffold uses. It utilizes the `triggerFuncs`, `listenerFunc`, `calculation`, and `affects` properties of the K-scaffold trigger object (see the Pug section of the scaffold for more details).
|
||
* @param {Roll20Event} event
|
||
* @returns {void}
|
||
*/
|
||
const accessSheet = function(event){
|
||
debug({funcs:Object.keys(funcs)});
|
||
debug({event});
|
||
getAllAttrs({event,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,attributes){
|
||
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,attributes);
|
||
}else if(key){//for non repeating attributes do this logic
|
||
expandNormal(memo,key,cascade,sections);
|
||
}
|
||
return memo;
|
||
},{});
|
||
};
|
||
|
||
const expandRepeating = function(memo,key,cascade,sections,attributes){
|
||
key.replace(/((?:attr|act)_)(repeating_[^_]+)_[^_]+?_(.+)/,(match,type,section,field)=>{
|
||
(sections[section]||[]).forEach((id)=>{
|
||
memo[`${type}${section}_${id}_${field}`]=_.clone(cascade[key]);//clone the details so that each row's attributes have correct ids
|
||
memo[`${type}${section}_${id}_${field}`].name = `${section}_${id}_${field}`;
|
||
if(key.startsWith('attr_')){
|
||
memo[`${type}${section}_${id}_${field}`].affects = memo[`${type}${section}_${id}_${field}`].affects.reduce((m,affected)=>{
|
||
if(section === affected){//otherwise if the affected attribute is in the same section, simply set the affected attribute to have the same row id.
|
||
m.push(applyID(affected,id));
|
||
}else if(/repeating/.test(affected)){//If the affected attribute isn't in the same repeating section but is still a repeating attribute, add all the rows of that section
|
||
addAllRows(affected,m,sections);
|
||
}else{//otherwise the affected attribute is a non repeating attribute. Simply add it to the computed affected array
|
||
m.push(affected);
|
||
}
|
||
return m;
|
||
},[]);
|
||
}
|
||
});
|
||
});
|
||
};
|
||
|
||
const applyID = function(affected,id){
|
||
return affected.replace(/(repeating_[^_]+_)[^_]+(.+)/,`$1${id}$2`);
|
||
};
|
||
|
||
const expandNormal = function(memo,key,cascade,sections){
|
||
memo[key] = _.clone(cascade[key]);
|
||
if(key.startsWith('attr_')){
|
||
memo[key].affects = memo[key].affects || [];
|
||
memo[key].affects = memo[key].affects.reduce((m,a)=>{
|
||
if(/^repeating/.test(a)){
|
||
addAllRows(a,m,sections);
|
||
}else{
|
||
m.push(a);
|
||
}
|
||
return m;
|
||
},[]);
|
||
}
|
||
};
|
||
|
||
const addAllRows = function(affected,memo,sections){
|
||
affected.replace(/(repeating_[^_]+?)_[^_]+?_(.+)/,(match,section,field)=>{
|
||
sections[section].forEach(id=>memo.push(`${section}_${id}_${field}`));
|
||
});
|
||
};/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
/**
|
||
* 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.
|
||
* @name setSectionOrder
|
||
* @param {string} section
|
||
* @param {string[]} order
|
||
* @returns {void}
|
||
*/
|
||
docs.js['k.setSectionOrder'] = {
|
||
type:'function',
|
||
description:'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.',
|
||
arguments:[
|
||
{type:'string',name:'section',description:'The name of the section to change the order in. Accepts the section name with or without the `repeating_` prefix.'},
|
||
{type:'[\'string\']',name:'order',description:'Array of the row ids in the order that the rows need to be placed.'}
|
||
]
|
||
};
|
||
const _setSectionOrder = function(section,order){
|
||
let trueSection = section.replace(/repeating_/,'');
|
||
setSectionOrder(trueSection,order);
|
||
};
|
||
kFuncs.setSectionOrder = _setSectionOrder;
|
||
|
||
/**
|
||
* Alias for [removeRepeatingRow](https://wiki.roll20.net/Sheet_Worker_Scripts#removeRepeatingRow.28_RowID_.29) that also removes the row from the current object of attribute values and array of section IDs to ensure that erroneous updates are not issued.
|
||
* @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}
|
||
*/
|
||
docs.js['k.removeRepeatingRow'] = {
|
||
type:'function',
|
||
description:'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.',
|
||
arguments:[
|
||
{type:'string',name:'row',description:'The row id including the section name, e.g. `repeating_equipment_-oiuLKJ987ulkj`.'},
|
||
{type:'object',name:'attributes',description:'The attributes object passed to the callback in [k.getAllAttrs()](#getAllAttrs), [k.getAttrs()](#getAttrs), or [getAttrs()](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29)'},
|
||
{type:'object',name:'sections',description:'Object that contains arrays of all the IDs in sections on the sheet indexed by repeating name.'}
|
||
]
|
||
};
|
||
const _removeRepeatingRow = function(row,attributes,sections){
|
||
debug(`removing ${row}`);
|
||
Object.keys(attributes.attributes).forEach((key)=>{
|
||
if(key.startsWith(row)){
|
||
delete attributes[key];
|
||
}
|
||
});
|
||
let [,section,rowID] = row.match(/(repeating_[^_]+)_(.+)/,'');
|
||
sections[section] = sections[section].filter((id)=>id!==rowID);
|
||
removeRepeatingRow(row);
|
||
};
|
||
kFuncs.removeRepeatingRow = _removeRepeatingRow;
|
||
|
||
/**
|
||
* Alias for [getAttrs()](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29) that converts the default object of attribute values into an {@link attributesProxy} and passes that back to the callback function.
|
||
* @name getAttrs
|
||
* @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 {function(attributesProxy)} args.callback - The function to call after the attribute values have been gotten. An {@link attributesProxy} is passed to the callback.
|
||
*/
|
||
docs.js['k.getAttrs'] = {
|
||
type:'function',
|
||
invocation:`k.getAttrs({props,callback})`,
|
||
description:'Alias for [getAttrs](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28_RowID_.29) that converts the default object of attribute values into a K-scaffold attributes object and passes that back to the callback function.',
|
||
arguments:[
|
||
{type:'array',name:'props',description:'Array of attribute names to get the values of as per the [getAttrs() sheetworker](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29). If not passed, gets all the attributes contained in the cascades object.'},
|
||
{type:'function',name:'callback',description:'The function to call after the attribute values have been gotten. Works the same as the callback for the [getAttrs() sheetworker](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29).'}
|
||
]
|
||
};
|
||
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.
|
||
* @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}.
|
||
*/
|
||
docs.js['k.getAllAttrs'] = {
|
||
type:'function',
|
||
invocation:`k.getAllAttrs({props,sectionDetails,callback})`,
|
||
description:'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 a K-scaffold attributes object. ',
|
||
arguments:[
|
||
{type:'array',name:'props',description:'Array of attribute names to get the values of as per the [getAttrs() sheetworker](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29).'},
|
||
{type:'array',name:'sectionDetails',description:'An array of objects that contain the details on how to handle a given repeating section. See [k.getSections](#getSections) for more details.'},
|
||
{type:'function',name:'callback(attributes,sections,casc)',description:'The function to call after the attribute values have been gotten. Three arguments are passed to the callback; `attributes`, `sections`, and `casc`. `sections` is an object that holds arrays of row ids, indexed by repeating section name. `casc` is the expanded version of the cascades object with repeating attributes including their row IDs.'}
|
||
]
|
||
};
|
||
const getAllAttrs = function({props=baseGet,sectionDetails=repeatingSectionDetails,callback}){
|
||
getSections(sectionDetails,(repeats,sections)=>{
|
||
getAttrs([...props,...repeats],(values)=>{
|
||
const attributes = createAttrProxy(values);
|
||
orderSections(attributes,sections);
|
||
const casc = expandCascade(cascades,sections,attributes);
|
||
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.
|
||
* @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}.
|
||
* @returns {void}
|
||
*/
|
||
docs.js['k.getSections'] = {
|
||
type:'function',
|
||
invocation:`k.getSections(sectionDetails,callback)`,
|
||
description:'Alias for [getSectionIDs()](https://wiki.roll20.net/Sheet_Worker_Scripts#getSectionIDs.28section_name.2Ccallback.29) that allows you to iterate through several sections at once. Also assembles an array of repeating attributes to get.',
|
||
arguments:[
|
||
{type:'array',name:'props',description:'Array of attribute names to get the values of as per the [getAttrs() sheetworker](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29).'},
|
||
{type:'array',name:'sectionDetails',description:'An array of objects that contain the details on how to handle a given repeating section. See [k.repeatingSectionDetails](#krepeatingsectiondetails) for more details.'},
|
||
{type:'function',name:'callback(repeatAttrs,sections)',description:'The function to call after the attribute values have been gotten. Two arguments are passed to the callback; `repeatAttrs` and `sections`. `repeatAttrs` is an array of repeating attributes ready to be used in a [getAttrs](https://wiki.roll20.net/Sheet_Worker_Scripts#getAttrs.28attributeNameArray.2C_callback.29), or [k.getAttrs](#kgetattrs) call. `sections` is an object that holds arrays of row ids, indexed by repeating section name.'}
|
||
]
|
||
};
|
||
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.
|
||
* @name 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.
|
||
* @returns {void}
|
||
*/
|
||
docs.js['k.setAttrs'] = {
|
||
type:'function',
|
||
invocation:`k.setAttrs(setObj,vocal,callback)`,
|
||
description:'Alias for [setAttrs()](https://wiki.roll20.net/Sheet_Worker_Scripts#setAttrs.28values.2Coptions.2Ccallback.29) that sets silently by default.',
|
||
arguments:[
|
||
{type:'object',name:'setObj',description:'Object with key/value pairs of attributes to set on the sheet. See [the wiki page](https://wiki.roll20.net/Sheet_Worker_Scripts#setAttrs.28values.2Coptions.2Ccallback.29) for more information.'},
|
||
{type:'boolean',name:'vocal',description:'Whether to set silently (default value) or not.'},
|
||
{type:'function',name:'callback()',description:'The callback function to invoke after the setting has been completed. No arguments are passed to the callback function.'}
|
||
]
|
||
};
|
||
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.
|
||
* @name generateRowID
|
||
* @param {string} section - The section name to create an ID for. The `repeating_` prefix is optional so both `repeating_equipment` and `equipment` are valid.
|
||
* @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 {any}
|
||
*/
|
||
docs.js['k.generateRowID'] = {
|
||
type:'function',
|
||
invocation:`k.generateRowID(section,sections,customText)`,
|
||
description:'Alias for generateRowID that adds the new id to the sections object. Also allows for creation of custom IDs that conform to the section ID requirements.',
|
||
arguments:[
|
||
{type:'string',name:'setObj',description:'The section name to create an ID for. The `repeating_` prefix is optional so both `repeating_equipment` and `equipment` are valid.'},
|
||
{type:'object',name:'vocal',description:'Object containing the IDs for the repeating sections, indexed by repeating section name.'},
|
||
{type:'string',name:'customText',description:'Custom text to start the ID with. This text should not be longer than the standard repeating section ID format.'}
|
||
]
|
||
};
|
||
const _generateRowID = function(section,sections,customText){
|
||
let rowID = customText ?
|
||
generateCustomID(customText) :
|
||
generateRowID();
|
||
section = section.match(/^repeating_[^_]+$/) ?
|
||
section :
|
||
`repeating_${section}`;
|
||
sections[section] = sections[section] || [];
|
||
sections[section].push(rowID);
|
||
return `${section}_${rowID}`;
|
||
};
|
||
kFuncs.generateRowID = _generateRowID;/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
const listeners = {};
|
||
const baseGet = Object.entries(cascades).reduce((memo,[attrName,detailObj])=>{
|
||
if(!/repeating/.test(attrName) && detailObj.type !== 'action'){
|
||
memo.push(detailObj.name);
|
||
}
|
||
if(detailObj.listener){
|
||
listeners[detailObj.listener] = detailObj.listenerFunc;
|
||
}
|
||
return memo;
|
||
},[]);
|
||
kFuncs.baseGet = baseGet;
|
||
const registerEventHandlers = function(){
|
||
on('sheet:opened',updateSheet);
|
||
debug({funcKeys:Object.keys(funcs),funcs});
|
||
//Roll20 change and click listeners
|
||
Object.entries(listeners).forEach(([event,funcName])=>{
|
||
if(funcs[funcName]){
|
||
on(event,funcs[funcName]);
|
||
}else{
|
||
debug(`!!!Warning!!! no function named ${funcName} found. No listener created for ${event}`,true);
|
||
}
|
||
});
|
||
log(`kScaffold Loaded`);
|
||
};
|
||
setTimeout(registerEventHandlers,0);//Delay the execution of event registration to ensure all event properties are present.
|
||
|
||
const addItem = function(event){
|
||
let [,,section] = parseClickTrigger(event.triggerName);
|
||
section = section.replace(/add-/,'');
|
||
getAllAttrs({
|
||
callback:(attributes,sections,casc) => {
|
||
let row = _generateRowID(section,sections);
|
||
debug({row});
|
||
attributes[`${row}_name`] = '';
|
||
setActionCalls({attributes,sections});
|
||
const trigger = cascades[`fieldset_repeating_${section}`];
|
||
if(trigger && trigger.addFuncs){
|
||
trigger.addFuncs.forEach((funcName) => {
|
||
if(funcs[funcName]){
|
||
funcs[funcName]({attributes,sections,casc,trigger});
|
||
}
|
||
});
|
||
}
|
||
attributes.set({attributes,sections,casc});
|
||
}
|
||
});
|
||
};
|
||
funcs.addItem = addItem;
|
||
|
||
const editSection = function(event){
|
||
let [,,section] = parseClickTrigger(event.triggerName);
|
||
section = section.replace(/edit-/,'');
|
||
let target = `fieldset.repeating_${section} + .repcontainer`;
|
||
$20(target).toggleClass('ui-sortable');
|
||
$20(target).toggleClass('editmode');
|
||
};
|
||
registerFuncs({editSection});return kFuncs;
|
||
}());
|
||
const actionAttributes = ["see_into_their_heart_action","help_somebody_action","touch_the_other_side_action","understand_action","take_a_swing_action","take_action_action","sneak_action","keep_your_cool_action","convince_somebody_action","another_move_action","initiative_action","heart_action","books_action","fierce_action","slick_action","weird_action","repeating_skill_$X_action","repeating_skill_$X_inability_action","repeating_signature_$X_action","repeating_move_$X_action"];const attributeNames = ["heart","books","fierce","slick","weird"];const basicMoves = {"see into their heart":{"stat":"heart","success":"see into their heart success result","mixed":"see into their heart mixed result","failure":"see into their heart failure result"},"help somebody":{"stat":"heart","success":"help somebody success result","mixed":"help somebody mixed result","failure":"help somebody failure result"},"touch the other side":{"stat":"books","success":"touch the other side success result","mixed":"touch the other side mixed result","failure":"touch the other side failure result"},"understand":{"stat":"books","success":"understand success result","mixed":"understand mixed result","failure":"understand failure result"},"take a swing":{"stat":"fierce","success":"take a swing success result","mixed":"take a swing mixed result","failure":"take a swing failure result"},"take action":{"stat":"fierce","success":"take action success result","mixed":"take action mixed result","failure":"take action failure result"},"sneak":{"stat":"slick","success":"sneak success result","mixed":"sneak mixed result","failure":"sneak failure result"},"keep your cool":{"stat":"slick","success":"keep your cool success result","mixed":"keep your cool mixed result","failure":"keep your cool failure result"},"convince somebody":{"stat":null,"success":"convince somebody success result","mixed":"convince somebody mixed result","failure":"convince somebody failure result"},"another move":{"stat":null,"critical":"basic critical result","success":"basic success result","mixed":"basic mixed result","failure":"basic failure result","fumble":"basic fumble result"}};const advantageTypes = {"double advantage":"4d6kh2","advantage":"3d6kh2","normal":"2d6","disadvantage":"3d6kl2","double disadvantage":"4d6kl2"};const meterValues = [0,1,2,3,4,5,6,7,8,9,10];
|
||
/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
k.version = 0.1;
|
||
k.sheetName = 'Under the Neighborhood';
|
||
const systemDefaults = {
|
||
'repeating_basic-advancement':[
|
||
{description:'Increase a stat by 1 (max:+3)'},
|
||
{description:'Increase a stat by 1 (max:+3)'},
|
||
{description:'Increase a stat by 1 (max:+3)'},
|
||
{description:'Increase a stat by 1 (max:+3)'},
|
||
{description:'Add Another Skill'},
|
||
{description:'Add Another Signature Item'},
|
||
{description:'Add a Move from your Playbook'},
|
||
{description:'Add a Move from your Playbook'},
|
||
{description:'Add a Move from your Playbook Or a different Playbook'},
|
||
{description:'Add a Move from your Playbook Or a different Playbook'}
|
||
],
|
||
'repeating_super-advancement':[
|
||
{description:'Upgrade two Playbook Moves to advanced'},
|
||
{description:'Upgrade two Playbook Moves to advanced'},
|
||
{description:'Upgrade one Descriptor to advanced'},
|
||
{description:'Upgrade two Skills into Super Skills'},
|
||
{description:'Add Another Descriptor'},
|
||
{description:'Increase the Maximum number of AP stored between adventures by 1'},
|
||
],
|
||
'repeating_ultra-advancement':[
|
||
{description:'Increase a stat by 1 (max:+4)'},
|
||
{description:'Increase the Weird stat by 2 (max:+1)'},
|
||
{description:'Upgrade all remaining Playbook Moves to Advanced'},
|
||
{description:'Upgrade all remaining Descriptors to Advanced'},
|
||
{description:'Add Another Skill'}
|
||
]
|
||
}/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
const setupSheet = function({attributes,sections}){
|
||
Object.entries(systemDefaults).forEach(([section,fields])=>{
|
||
fields.forEach((fieldObj)=>{
|
||
Object.entries(fieldObj).forEach(([field,content])=>{
|
||
const row = k.generateRowID(section,sections);
|
||
k.debug({row,fields});
|
||
attributes[`${row}_${field}`] = content;
|
||
});
|
||
});
|
||
});
|
||
};
|
||
k.registerFuncs({setupSheet},{type:['new']});/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
const limitMeterValue = function({trigger,attributes,sections}){
|
||
const [section,id,field] = k.parseTriggerName(trigger.name);
|
||
return Math.min(attributes[`${section}_${id}_${field}`],attributes[`${section}_${id}_${field}_max`])
|
||
};
|
||
k.registerFuncs({limitMeterValue});/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
const navigateSheet = function({trigger,attributes}){
|
||
k.debug('navigating sheet');
|
||
let triggerName = trigger ?
|
||
trigger.name :
|
||
attributes.sheet_state;
|
||
let target = triggerName.replace(/clicked:|nav-/g,'');
|
||
k.debug({target});
|
||
$20('.navigable-section,.sheet-nav__tab').removeClass('active');
|
||
$20(`.sheet-nav__tab.${target},.navigable-section--${target}`).addClass('active');
|
||
attributes.sheet_state = target;
|
||
};
|
||
k.registerFuncs({navigateSheet},{type:['opener']});
|
||
|
||
const characterDisplay = function({attributes}){
|
||
$20('.character-type').addClass('character-type--inactive');
|
||
k.debug({sheet_type:attributes.sheet_type})
|
||
const target = `.character-type--${attributes.sheet_type}`;
|
||
k.debug({target});
|
||
$20(target).removeClass('character-type--inactive');
|
||
}
|
||
k.registerFuncs({characterDisplay},{type:['opener']})
|
||
|
||
const sectionDisplay = function({trigger,attributes}){
|
||
const fieldSwitch = {
|
||
is_weird:'weird',
|
||
mon_trainer:'mon',
|
||
use_initiative:'initiative',
|
||
has_arc:'arc'
|
||
};
|
||
k.debug({trigger});
|
||
let fields;
|
||
if(trigger){
|
||
let[,,attr] = k.parseTriggerName(trigger.name);
|
||
fields = [attr];
|
||
}else{
|
||
fields = Object.keys(fieldSwitch);
|
||
}
|
||
fields.forEach((field)=>{
|
||
const action = attributes[field] ?
|
||
'remove' :
|
||
'add';
|
||
$20(`.${fieldSwitch[field]}`)[`${action}Class`]('inactive');
|
||
});
|
||
}
|
||
k.registerFuncs({sectionDisplay},{type:['opener']});
|
||
|
||
const modifierDisplay = function({attributes}){
|
||
if(attributes.use_roll_modifiers){
|
||
$20('#modifiers').removeClass('inactive');
|
||
$20('.roll-options').addClass('inactive');
|
||
attributes.advantage = '2d6';
|
||
attributes.double = 0;
|
||
}else{
|
||
$20('#modifiers').addClass('inactive');
|
||
$20('.roll-options').removeClass('inactive');
|
||
}
|
||
};
|
||
k.registerFuncs({modifierDisplay},{type:['opener']})/*jshint esversion: 11, laxcomma:true, eqeqeq:true*/
|
||
/*jshint -W014,-W084,-W030,-W033*/
|
||
//Roll Listeners
|
||
const rollBasicMove = async function({trigger,attributes,sections}){
|
||
const [,,field,activeEffects,rollObj,dice] = await baseRollInfo({trigger,attributes,sections});
|
||
let statRef = getMoveResults(field.replace(/-/g,' '),rollObj,attributes);
|
||
rollObj.roll = assembleRoll(dice,statRef,activeEffects,attributes.is_weird);
|
||
executeRoll({rollObj});
|
||
};
|
||
k.registerFuncs({rollBasicMove});
|
||
|
||
const getMoveResults = function(move,rollObj,attributes){
|
||
const possibleResults = basicMoves[move];
|
||
['critical','success','mixed','failure','fumble'].forEach((result)=>{
|
||
if(result !== 'stat'){
|
||
rollObj[`${result}_result`] = possibleResults[result] ?
|
||
`^{${possibleResults[result]}}` :
|
||
'';
|
||
}
|
||
});
|
||
return attributes[`${move.replace(/\s+/g,'_')}_stat`];
|
||
};
|
||
|
||
const rollStat = async function({trigger,attributes,sections}){
|
||
const [,,field,activeEffects,rollObj,dice] = await baseRollInfo({trigger,attributes,sections});
|
||
rollObj.roll = assembleRoll(dice,`@{${field}}`,activeEffects,attributes.is_weird);
|
||
executeRoll({rollObj});
|
||
};
|
||
k.registerFuncs({rollStat});
|
||
|
||
const rollSkill = async function({trigger,attributes,sections}){
|
||
const [section,rowID,field,activeEffects,rollObj,dice] = await baseRollInfo({trigger,attributes,sections,isSkill:true});
|
||
let statRef;
|
||
rollObj.header = attributes[`${section}_${rowID}_${field === 'inability' ? field : 'name'}`];
|
||
if(attributes.skill_basic_move){
|
||
const query = k.capitalize(getTranslationByKey('move query'));
|
||
const options = Object.keys(basicMoves)
|
||
.map((key) => {
|
||
return `${k.capitalize(getTranslationByKey(key))},${key}`
|
||
})
|
||
.join('|');
|
||
const move = await k.extractQueryResult(`${query}|${options}`);
|
||
statRef = getMoveResults(move,rollObj,attributes);
|
||
}else{
|
||
await k.pseudoQuery('');
|
||
statRef = section === 'repeating_skill' ?
|
||
(/inability/.test(field) ?
|
||
'inability_stat' :
|
||
'skill_stat'
|
||
) :
|
||
'stat';
|
||
statRef = attributes[`${section}_${rowID}_${statRef}`];
|
||
}
|
||
k.debug({section,rowID,field});
|
||
|
||
rollObj.roll = assembleRoll(dice,statRef,activeEffects,attributes.is_weird);
|
||
k.debug({skillObj:rollObj});
|
||
executeRoll({rollObj});
|
||
};
|
||
k.registerFuncs({rollSkill});
|
||
|
||
const rollHelpFriend = async function({trigger,attributes,sections}){
|
||
const [section,rowID,field,activeEffects,rollObj,dice] = await baseRollInfo({trigger,attributes,sections});
|
||
const relationScore = attributes[`${section}_${rowID}_score`];
|
||
rollObj.header = getTranslationByKey('help a friend roll header').replace('{{0}}',attributes[`${section}_${rowID}_name`]);
|
||
k.debug({activeEffects});
|
||
rollObj.roll = assembleRoll(dice,relationScore,activeEffects,attributes.is_weird);
|
||
executeRoll({rollObj});
|
||
};
|
||
k.registerFuncs({rollHelpFriend});
|
||
|
||
const rollCharacterMove = async function({trigger,attributes,sections}){
|
||
const [section,rowID,field,activeEffects,rollObj,dice] = await baseRollInfo({trigger,attributes,sections});
|
||
rollObj.roll = assembleRoll(dice,'?{query}',activeEffects,attributes.is_weird);
|
||
const fieldSwitch = {
|
||
critical_result:attributes[`${section}_${rowID}_critical_success`] || attributes[`${section}_${rowID}_full_success`] || basicMoves['another move'].critical,
|
||
success_result:attributes[`${section}_${rowID}_full_success`] || basicMoves['another move'].success,
|
||
mixed_result:attributes[`${section}_${rowID}_mixed_success`] || basicMoves['another move'].mixed,
|
||
failure_result:attributes[`${section}_${rowID}_failure`] || basicMoves['another move'].failure,
|
||
fumble_result:attributes[`${section}_${rowID}_critical_failure`] || attributes[`${section}_${rowID}_failure`] || basicMoves['another move'].fumble
|
||
};
|
||
rollObj.header = attributes[`${section}_${rowID}_name`];
|
||
Object.entries(fieldSwitch).forEach(([fieldName,content])=>{
|
||
rollObj[fieldName] = content;
|
||
});
|
||
executeRoll({rollObj});
|
||
};
|
||
k.registerFuncs({rollCharacterMove});
|
||
|
||
const rollInitiative = async function({trigger,attributes,sections}){
|
||
const [section,rowID,field,activeEffects,rollObj,dice] = await baseRollInfo({trigger,attributes,sections});
|
||
rollObj.roll = assembleRoll(dice,attributes.fierce,activeEffects,attributes.is_weird)
|
||
.replace(/\]\]/,'&{tracker}]]');
|
||
executeRoll({rollObj});
|
||
};
|
||
k.registerFuncs({rollInitiative});
|
||
|
||
//Parse Functions
|
||
const baseRollInfo = async function({trigger,attributes,sections,isSkill}){
|
||
const [section,rowID,button] = k.parseTriggerName(trigger.name);
|
||
const field = button.replace(/-?action/,'');
|
||
const baseEffects = {advantage:0,bonus:0,text:[]};
|
||
if(isSkill){
|
||
baseEffects.advantage = field === 'inability' ?
|
||
-1 - attributes[`${section}_${rowID}_${field}_super`] :
|
||
1 + attributes[`${section}_${rowID}_super`];
|
||
}
|
||
const activeEffects = await countEffects(attributes,sections,baseEffects);
|
||
const rollObj = {
|
||
header:`^{${field.replace(/-/g,' ')}}`,
|
||
result:`[[0[computed value]]]`
|
||
};
|
||
if(baseEffects.text?.length){
|
||
rollObj.description = baseEffects.text.map((text)=>`^{${text}}`).join('\n');
|
||
}
|
||
Object.entries(basicMoves['another move']).forEach(([result,effect])=>{
|
||
if(result !== 'stat'){
|
||
rollObj[`${result}_result`] = `^{${effect}}`;
|
||
}
|
||
});
|
||
const dice = await parseAdvantage(attributes.advantage,activeEffects,attributes,rollObj);
|
||
return [section,rowID,field,activeEffects,rollObj,dice];
|
||
};
|
||
|
||
/*
|
||
The Compatibility Scores and their effects are as follows:
|
||
-1 (Frenemies)
|
||
The other PC rolls with Disadvantage. Each of you gains 1 AP.
|
||
|
||
+0 (Acquaintances)
|
||
The other PC gets +1 on their roll.
|
||
|
||
+1 (Friends)
|
||
CHOOSE 1
|
||
The other PC gets +1 on their roll.
|
||
The consequences of the other PC’s actions are “bigger” (Full Successes come with a small bonus, Failures come with an extra complication).
|
||
|
||
+2 (Good Friends)
|
||
CHOOSE 1
|
||
The other PC gets +2 on their roll.
|
||
The other PC rolls with Advantage.
|
||
The consequences of the other PC’s actions are “bigger” (Full Successes come with a small bonus, Failures come with an extra complication).
|
||
|
||
+3 (Family)
|
||
CHOOSE UP TO 2
|
||
The other PC gets +2 on their roll.
|
||
The other PC rolls with Advantage.
|
||
The consequences of the other PC’s move are “bigger” (Full Successes come with a small bonus, Failures come with an extra complication).
|
||
*/
|
||
const compatibilityQuery = async function(baseEffects,attributes,sections){
|
||
const compatibleEffects = {
|
||
'-1':{optNum:1,options:['disadvantage']},
|
||
'0':{optNum:1,options:['+1']},
|
||
'1':{optNum:1,options:['+1','bigger consequences']},
|
||
'2':{optNum:1,options:['+1','advantage','bigger consequences']},
|
||
'3':{optNum:2,options:['+2','advantage','bigger consequences']}
|
||
}
|
||
const activeID = sections.repeating_compatibility.reduce((memo,id)=>{
|
||
return attributes[`repeating_compatibility_${id}_activate`] &&
|
||
(!memo || attributes[`repeating_compatibility_${id}_score`] < attributes[`repeating_compatibility_${id}_score`]) ?
|
||
id :
|
||
memo;
|
||
},'');
|
||
const ordinals = {
|
||
'1':'1st',
|
||
'2':'2nd'
|
||
}
|
||
if(activeID){
|
||
const activeEffect = compatibleEffects[attributes[`repeating_compatibility_${activeID}_score`]];
|
||
k.debug({activeID,[`compatibleEffects[${attributes[`repeating_compatibility_${activeID}_score`]}]`]:activeEffect})
|
||
const selectedEffects = [];
|
||
if(activeEffect.options.length > 1){
|
||
const effectWorker = async (iteration = 1)=>{
|
||
const availableOptions = activeEffect.options.filter((opt)=>selectedEffects.indexOf(opt) === -1);
|
||
const promptKey = activeEffect.optNum === 1 ?
|
||
'Which compatibility effect' :
|
||
`${ordinals[iteration]} compatible effect`;
|
||
const selectedOption = await k.extractQueryResult(`${getTranslationByKey(promptKey)}|${availableOptions.map((opt)=>`${getTranslationByKey(`compatibility prompt ${opt}`)},${opt}`).join('|')}`);
|
||
k.debug({selectedOption});
|
||
selectedOption.replace(/\+?(.+)/,(match,effect)=>{
|
||
if(+effect){
|
||
baseEffects.bonus += +effect;
|
||
}else if(/dis/.test(effect)){
|
||
baseEffects.advantage--;
|
||
}else if(/advantage/.test(effect)){
|
||
baseEffects.advantage++;
|
||
}else{
|
||
baseEffects.text.push(effect);
|
||
}
|
||
});
|
||
selectedEffects.push(selectedOption);
|
||
iteration++;
|
||
if(iteration > activeEffect.optNum){
|
||
return true;
|
||
}else{
|
||
return effectWorker(iteration);
|
||
}
|
||
}
|
||
await effectWorker();
|
||
}else{
|
||
selectedEffects.push(activeEffect.options[0]);
|
||
await k.pseudoQuery();
|
||
}
|
||
}else{
|
||
if(attributes.interference){
|
||
baseEffects.advantage--;
|
||
baseEffects.text.push('interference roll message');
|
||
}
|
||
await k.pseudoQuery();
|
||
}
|
||
};
|
||
|
||
const countEffects = async function(attributes,sections,effectObj = {advantage:0,bonus:0}){
|
||
let idArray;
|
||
const baseEffects = {...effectObj};
|
||
if(attributes.use_roll_modifiers){
|
||
idArray = sections.repeating_modifier;
|
||
}else{
|
||
idArray = [];
|
||
baseEffects.bonus = attributes.generic_bonus;
|
||
}
|
||
await compatibilityQuery(baseEffects,attributes,sections);
|
||
k.debug({baseEffects});
|
||
return idArray.reduce((memo,id)=>{
|
||
k.debug({[`attributes[repeating_modifier_${id}_activate]`]:attributes[`repeating_modifier_${id}_activate`]});
|
||
if(attributes[`repeating_modifier_${id}_activate`]){
|
||
const effect = attributes[`repeating_modifier_${id}_effect`];
|
||
k.debug({effect});
|
||
const advs = effect.match(/(?:^|\s)(?:super )?advantage/ig) || [];
|
||
const disadvs = effect.match(/(?:super )?disadvantage/ig) || [];
|
||
const bonuses = effect.match(/(?:[+\-]\s*)?\d+/g) || [];
|
||
k.debug({advs,disadvs,bonuses});
|
||
memo.advantage = advs.reduce((total,adv)=>total += /super/.test(adv) ? 2 : 1,memo.advantage);
|
||
memo.advantage = disadvs.reduce((total,adv)=>total -= /super/.test(adv) ? 2 : 1,memo.advantage);
|
||
memo.bonus = bonuses.reduce((total,bonus)=>{
|
||
const val = +bonus.replace(/\+/,'').trim();
|
||
return total += val;
|
||
},memo.bonus);
|
||
}
|
||
return memo;
|
||
},{...baseEffects});
|
||
};
|
||
|
||
const parseAdvantage = async function(advantageState,activeEffects,attributes,rollObj){
|
||
if(attributes.use_physical_dice){
|
||
const result = +(await k.extractQueryResult(getTranslationByKey('physical roll query')));
|
||
if(result === 12){
|
||
rollObj.result = '[[1]]';
|
||
}else if(result === 2){
|
||
rollObj.result = '[[-1]]';
|
||
}else{
|
||
rollObj.result = '[[0]]';
|
||
}
|
||
return result;
|
||
}else{
|
||
await k.pseudoQuery('');
|
||
if(advantageState.startsWith('?{')){
|
||
//If the advantage state is a query, translate the query.
|
||
const options = Object.entries(advantageTypes).map(([aType,aValue])=>{
|
||
return `${k.capitalize(getTranslationByKey(`${aType} option`))},${aValue}`;
|
||
}).join('|');
|
||
return `?{${k.capitalize(getTranslationByKey('roll'))}|${options}}`;
|
||
}else{
|
||
//otherwise, just use the advantage as is.
|
||
return activeEffects.advantage ?
|
||
(() => {
|
||
const diceNum = 2 + Math.abs(activeEffects.advantage);
|
||
const keep = activeEffects.advantage > 0 ?
|
||
'kh' :
|
||
'kl';
|
||
return `${diceNum}d6${keep}2`;
|
||
})() :
|
||
advantageState;
|
||
}
|
||
}
|
||
};
|
||
|
||
const assembleRoll = function(dice,chosenStat,activeEffects,isWeird){
|
||
let stat;
|
||
k.debug({chosenStat,activeEffects});
|
||
if(`${chosenStat}`.startsWith('?{')){
|
||
//If the advantage state is a query, translate the query.
|
||
const options = attributeNames.map((attr)=>{
|
||
if(attr !== 'weird' || isWeird){
|
||
return `${k.capitalize(getTranslationByKey(attr))},@{${attr}}`;
|
||
}else{
|
||
return null;
|
||
}
|
||
})
|
||
.filter((a)=>a)
|
||
.join('|');
|
||
stat = `+ ?{${k.capitalize(getTranslationByKey('which stat'))}|${options}}`;
|
||
}else{
|
||
//otherwise, just use the advantage as is.
|
||
stat = `+ ${chosenStat}`;
|
||
}
|
||
const bonus = stringifyBonus(activeEffects.bonus);
|
||
return `[[${dice}${stat}${bonus}]]`;
|
||
};
|
||
|
||
const stringifyBonus = function(bonus){
|
||
k.debug({bonus});
|
||
return bonus < 0 ?
|
||
bonus :
|
||
`+ ${bonus}`.replace(/\+ 0/,'');
|
||
};
|
||
|
||
const executeRoll = async function({rollObj}){
|
||
k.debug({toExecute:rollObj});
|
||
let message = `@{template_start} ${Object.entries(rollObj).map(([field,content])=>`{{${field}=${content}}}`).join('')}`;
|
||
k.debug({message});
|
||
const rolled = await startRoll(message);
|
||
const computeObj = {};
|
||
if(rolled.results.roll && rolled.results.result && /computed value/.test(rollObj.result)){
|
||
const expression = rolled.results.roll.expression;
|
||
let rollState;
|
||
let rollQuant = 2;
|
||
expression.replace(/d6k([hl])(\d+)/,(match,target,num)=>{
|
||
rollState = target;
|
||
rollQuant = +num || 2;
|
||
});
|
||
const diceRoll = rolled.results.roll.rolls[0];
|
||
const rollTotal = diceRoll.results.sort((a,b)=>{
|
||
if(rollState === 'l'){
|
||
return a - b;
|
||
}else if(rollState === 'h'){
|
||
return b - a;
|
||
}else{
|
||
return 0;
|
||
}
|
||
})
|
||
.slice(0,rollQuant);
|
||
k.debug({rollTotal});
|
||
const uniqueRolls = [...new Set(rollTotal)];
|
||
if(uniqueRolls.length === 1){
|
||
if(uniqueRolls[0] === 6){
|
||
computeObj.result = 1;
|
||
}else if(uniqueRolls[0] === 1){
|
||
computeObj.result = -1;
|
||
}
|
||
}
|
||
}
|
||
finishRoll(rolled.rollId,computeObj);
|
||
};
|
||
</script>
|
||
|
||
|
||
|
||
|