* BTATOW Start to split up code to allow writing unit tests. * BTATOW Add .idea folder to .gitignore file for BTATOW sheet. * BTATOW Fix .gitignore for .idea folder. * BTATOW Start to split out skills code and write tests. Also fix exports from attributes file. * Added pre-commit scripts and README with development instructions.
1807 lines
73 KiB
HTML
1807 lines
73 KiB
HTML
<input type="radio" name="attr_tab" class="tab tab1" value="1" title="Personal Data" checked="checked"/>
|
|
<input type="radio" name="attr_tab" class="tab tab2" value="2" title="Combat Data"/>
|
|
<input type="radio" name="attr_tab" class="tab tab3" value="3" title="Skills"/>
|
|
<input type="radio" name="attr_tab" class="tab tab4" value="4" title="Inventory"/>
|
|
|
|
<input type="hidden" name="attr_btatow_sheet_version" value="1"/>
|
|
|
|
<div class="tab-content tab1"><!-- Personal Data -->
|
|
<h1>Personal Data</h1>
|
|
<div class="wrapper">
|
|
<div class="section">
|
|
<div class="input-field2">
|
|
Name <br><input type="text" name="attr_name" style="width:450px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Affiliation <br><input type="text" name="attr_affiliation" style="width:200px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Height (cm)<br><input type="text" name="attr_Height" style="width:150px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Weight (KG) <br><input type="text" name="attr_Weight" style="width:150px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Hair <br><input type="text" name="attr_Hair" style="width:150px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Eyes <br><input type="text" name="attr_Eyes" style="width:150px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Description <br><input type="text" name="attr_description" style="width:475px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
Age <br><input type="number" name="attr_age" style="width:50px;">
|
|
</div>
|
|
<div class="sheet-input-field2">
|
|
C-Bills <br><input type="number" name="attr_cbills" style="width:100px;">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="sheet-input-field" style="width:695px;margin-top:8px;padding-top:10px;background-color:#698888">
|
|
<span style="font-size:large; padding-right:470px">Traits</span>
|
|
<fieldset class="repeating_traits">
|
|
<table class="sheet-section-table2">
|
|
<tr>
|
|
<th>Trait</th>
|
|
<th>TP</th>
|
|
<th>Page Ref.</th>
|
|
<th>XP</th>
|
|
<th>Notes</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:200px;" type="text" name="attr_trait">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_traittp"
|
|
value="floor(@{traitxp}/100)" disabled="true">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_traitpr">
|
|
</td>
|
|
<td>
|
|
<input style="width:75px;" type="number" name="attr_traitxp">
|
|
</td>
|
|
<td>
|
|
<input style="width:225px;" type="text" name="attr_traitnotes">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="sheet-input-field" style="width:695px;margin-top:8px;padding-top:10px;background-color:#AD855C">
|
|
<span style="font-size:large">Biography</span><br>
|
|
<fieldset class="repeating_Bio">
|
|
<table class="sheet-section-table2">
|
|
<tr>
|
|
<th>Life Module</th>
|
|
<th>Notes</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:250px;" type="text" name="attr_lifemod">
|
|
</td>
|
|
<td>
|
|
<input style="width:400px;" type="text" name="attr_lifenote">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-content tab2"><!-- Combat Data -->
|
|
<h1>Combat Data</h1>
|
|
<div class="wrapper">
|
|
<div class="section">
|
|
<div class="col">
|
|
<div class="input-field" style="width:328px;margin-top:8px;padding-top:10px;">
|
|
<span style="font-size:large">Attributes</span><br>
|
|
<table class="section-table">
|
|
<tr>
|
|
<th>Attribute</th>
|
|
<th>Score</th>
|
|
<th>Link</th>
|
|
<th>XP</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_strength_check"
|
|
title=%{CharName|strength_check}
|
|
value='Strength Check
|
|
Margin of Success: [[2d6 + @{strength}[MOD] - 12[TN]]]'
|
|
>
|
|
STR
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_strength" title="@{strength}"></span>
|
|
<input type="hidden" name="attr_strength" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_strength_link" title="@{strength_link}"></span>
|
|
<input type="hidden" name="attr_strength_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_strength_xp" value="100" title="@{strength_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_body_check"
|
|
title=%{CharName|body_check}
|
|
value='Body Check
|
|
Margin of Success: [[2d6 + @{body}[MOD] - 12[TN]]]'
|
|
>
|
|
BOD
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_body" title="@{body}"></span>
|
|
<input type="hidden" name="attr_body" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_body_link" title="@{body_link}"></span>
|
|
<input type="hidden" name="attr_body_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_body_xp" value="100" title="@{body_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_reflex_check"
|
|
title=%{CharName|reflex_check}
|
|
value='Reflex Check
|
|
Margin of Success: [[2d6 + @{reflex}[MOD] - 12[TN]]]'
|
|
>
|
|
RFL
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_reflex" title="@{reflex}"></span>
|
|
<input type="hidden" name="attr_reflex" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_reflex_link" title="@{reflex_link}"></span>
|
|
<input type="hidden" name="attr_reflex_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_reflex_xp" value="100" title="@{reflex_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_dexterity_check"
|
|
title=%{CharName|dexterity_check}
|
|
value='Dexterity Check
|
|
Margin of Success: [[2d6 + @{dexterity}[MOD] - 12[TN]]]'
|
|
>
|
|
DEX
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_dexterity" title="@{dexterity}"></span>
|
|
<input type="hidden" name="attr_dexterity" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_dexterity_link" title="@{dexterity_link}"></span>
|
|
<input type="hidden" name="attr_dexterity_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_dexterity_xp" value="100" title="@{dexterity_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_intelligence_check"
|
|
title=%{CharName|intelligence_check}
|
|
value='Intelligence Check
|
|
Margin of Success: [[2d6 + @{intelligence}[MOD] - 12[TN]]]'
|
|
>
|
|
INT
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_intelligence" title="@{intelligence}"></span>
|
|
<input type="hidden" name="attr_intelligence" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_intelligence_link" title="@{intelligence_link}"></span>
|
|
<input type="hidden" name="attr_intelligence_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_intelligence_xp" value="100" title="@{intelligence_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_will_check"
|
|
title=%{CharName|will_check}
|
|
value='Will Check
|
|
Margin of Success: [[2d6 + @{will}[MOD] - 12[TN]]]'
|
|
>
|
|
WIL
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_will" title="@{will}"></span>
|
|
<input type="hidden" name="attr_will" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_will_link" title="@{will_link}"></span>
|
|
<input type="hidden" name="attr_will_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_will_xp" value="100" title="@{will_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_charisma_check"
|
|
title=%{CharName|charisma_check}
|
|
value='Charisma Check
|
|
Margin of Success: [[2d6 + @{charisma}[MOD] - 12[TN]]]'
|
|
>
|
|
CHA
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_charisma" title="@{charisma}"></span>
|
|
<input type="hidden" name="attr_charisma" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_charisma_link" title="@{charisma_link}"></span>
|
|
<input type="hidden" name="attr_charisma_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_charisma_xp" value="100" title="@{charisma_xp}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="background-color:#303030;color:white">
|
|
<button
|
|
type="roll"
|
|
class="blank-roll-button"
|
|
name="roll_edge_check"
|
|
title=%{CharName|edge_check}
|
|
value='Edge Check
|
|
Margin of Success: [[2d6 + @{edge}[MOD] - 12[TN]]]'
|
|
>
|
|
EDG
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<span name="attr_edge" title="@{edge}"></span>
|
|
<input type="hidden" name="attr_edge" value="1">
|
|
</td>
|
|
<td>
|
|
<span name="attr_edge_link" title="@{edge_link}"></span>
|
|
<input type="hidden" name="attr_edge_link" value="-2">
|
|
</td>
|
|
<td>
|
|
<input type="number" name="attr_edge_xp" value="100" title="@{edge_xp}">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="input-field" style="width:328px;margin-top:8px;padding-top:10px;">
|
|
<span style="font-size:large">Condition Monitor</span><br>
|
|
<table class="section-table">
|
|
<tr>
|
|
<th>Standard Damage</th>
|
|
<th>Fatigue Damage</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_smaxhealth"
|
|
value="@{body}*2" disabled="true">
|
|
/<input style="width:50px;" type="number" name="attr_sdamage">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_fmaxhealth"
|
|
value="@{will}*2" disabled="true">
|
|
/<input style="width:50px;" type="number" name="attr_fdamage">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Max Standard Damage = BOD x 2
|
|
</td>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Max Fatigue Damage = WIL x 2
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="input-field" style="width:328px;margin-top:8px;padding-top:10px;">
|
|
<span style="font-size:large">Movement MP (Meters per Turn)</span><br>
|
|
<table class="section-table">
|
|
<tr>
|
|
<th>Walk (MP)</th>
|
|
<th>Run/Evade</th>
|
|
<th>Sprint</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_MP"
|
|
value="@{strength}+@{reflex}" disabled="true">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_run">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_sprint"
|
|
value="@{run}*2" disabled="true">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Walk = STR + RFL
|
|
</td>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Run = 10 + STR + RFL + Running Skill Level
|
|
</td>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Sprint = Run MP x 2
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Climb</th>
|
|
<th>Crawl</th>
|
|
<th>Swim</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_climb">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_crawl"
|
|
value="floor((@{strength}+@{reflex})/4)" disabled="true">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_swim">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Climb = MP / 2 + Climbing Skill Level
|
|
</td>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Crawl = MP / 4
|
|
</td>
|
|
<td class="info" style="background-color: #DBDBDB;">
|
|
Swim = MP + Swimming Skill Level
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="input-field"
|
|
style="width:695px;margin-top:8px;padding-top:10px;background-color:#855C33">
|
|
<span style="font-size:large">Armor</span><br>
|
|
<fieldset class="repeating_armor">
|
|
<table class="section-table2">
|
|
<tr>
|
|
<th>Personal Armor</th>
|
|
<th>Location</th>
|
|
<th>Armor Type</th>
|
|
<th>BAR (M/B/E/X)</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:120px;" type="text" name="attr_Armor1">
|
|
</td>
|
|
<td>
|
|
<input style="width:120px;" type="text" name="attr_ArmorLoc1">
|
|
</td>
|
|
<td>
|
|
<input style="width:115px;" type="text" name="attr_ArmorType1">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_ArmorBAR1">
|
|
/<input style="width:50px;" type="number" name="attr_ArmorBAR2">
|
|
/<input style="width:50px;" type="number" name="attr_ArmorBAR3">
|
|
/<input style="width:50px;" type="number" name="attr_ArmorBAR4">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="info2" style="background-color: #DBDBDB;">
|
|
Example: Jacket
|
|
</td>
|
|
<td class="info2" style="background-color: #DBDBDB;">
|
|
Example: Torso, Arms
|
|
</td>
|
|
<td class="info2" style="background-color: #DBDBDB;">
|
|
Example: Flak
|
|
</td>
|
|
<td class="info2" style="background-color: #DBDBDB;">
|
|
Example: 1/5/1/3
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
<div class="input-field"
|
|
style="width:695px;margin-top:8px;padding-top:10px;background-color:#CF2929">
|
|
<span style="font-size:large">Weapon</span><br>
|
|
<fieldset class="repeating_weapon">
|
|
<table class="section-table2">
|
|
<tr>
|
|
<th>Weapon</th>
|
|
<th>Ammo</th>
|
|
<th>AP/BD</th>
|
|
<th>Range</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:200px;" type="text" name="attr_Weapon">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_WeaponAmmo">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="text" name="attr_WeaponAP">
|
|
/<input style="width:50px;" type="text" name="attr_WeaponBD">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_WeaponR1">
|
|
/<input style="width:50px;" type="number" name="attr_WeaponR2">
|
|
/<input style="width:50px;" type="number" name="attr_WeaponR3">
|
|
/<input style="width:50px;" type="number" name="attr_WeaponR4">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<table class="section-table2">
|
|
<tr>
|
|
<th>Skill</th>
|
|
<th>TN</th>
|
|
<th>Notes</th>
|
|
<th>Check</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_WeaponSk">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_WeaponTN">
|
|
</td>
|
|
<td>
|
|
<input style="width:480px;" type="text" name="attr_ArmorWeaponNotes">
|
|
</td>
|
|
<td>
|
|
<button type='roll' name="roll_weaponcheck" style="text-align:left" value='
|
|
Attacks with @{Weapon}
|
|
Margin of Success: [[2d6 + @{WeaponSk} - @{WeaponTN}]]
|
|
Weapon Damage: @{WeaponAP}/@{WeaponBD} '/>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SKILLS -->
|
|
<div class="tab-content tab3 main">
|
|
<h3>Skills</h3>
|
|
<input type="radio" value="-1" name="attr_learning_speed" class="skills-labels">Fast Learner</input>
|
|
<input type="radio" value="1" name="attr_learning_speed" class="skills-labels">Slow Learner</input>
|
|
<input type="radio" value="0" name="attr_learning_speed" checked="true" class="skills-labels">None</input>
|
|
<div class="skills-headings skills-container">
|
|
<span class="skills skill skills-headings left">Skill</span>
|
|
<span class="skills skills-skill-level">Lvl</span>
|
|
<span class="skills skills-linked-attributes">Links</span>
|
|
<span class="skills skills-modifier">Mod</span>
|
|
<span class="skills skills-tnc">TN/C</span>
|
|
<span class="skills skills-xp">XP</span>
|
|
<span class="skills skill-roll"></span>
|
|
</div>
|
|
<fieldset class="repeating_skills">
|
|
<div class="skills-container">
|
|
<select name="attr_skill" class="skills skill content" title="@{repeating_skills_$id_skill}">
|
|
<option value="acrobatics_free_fall">Acrobatics/Free-Fall</option>
|
|
<option value="acrobatics_gymnastics">Acrobatics/Gymnastics</option>
|
|
<option value="acting">Acting</option>
|
|
<option value="administration">Administration</option>
|
|
<option value="animal_handling_herding">Animal Handling/Herding</option>
|
|
<option value="animal_handling_riding">Animal Handling/Riding</option>
|
|
<option value="animal_handling_training">Animal Handling/Training</option>
|
|
<option value="appraisal">Appraisal</option>
|
|
<option value="archery">Archery</option>
|
|
<option value="art">Art</option>
|
|
<option value="artillery">Artillery</option>
|
|
<option value="career">Career</option>
|
|
<option value="climbing">Climbing</option>
|
|
<option value="communications_black_box">Communications/Black Box</option>
|
|
<option value="communications_conventional">Communications/Conventional (EM)</option>
|
|
<option value="communications_hyperpulse_generator">Communications/Hyperpulse Generator</option>
|
|
<option value="computers">Computers</option>
|
|
<option value="cryptography">Cryptography</option>
|
|
<option value="demolitions">Demolitions</option>
|
|
<option value="disguise">Disguise</option>
|
|
<option value="driving_ground_vehicles">Driving/Ground Vehicles</option>
|
|
<option value="driving_rail_vehicles">Driving/Rail Vehicles</option>
|
|
<option value="driving_sea_vehicles">Driving/Sea Vehicles</option>
|
|
<option value="escape_artist">Escape Artist</option>
|
|
<option value="forgery">Forgery</option>
|
|
<option value="gunnery_aerospace">Gunnery/Aerospace</option>
|
|
<option value="gunnery_air_vehicle">Gunnery/Air Vehicle</option>
|
|
<option value="gunnery_battlesuit">Gunnery/Battlesuit</option>
|
|
<option value="gunnery_ground_vehicle">Gunnery/Ground Vehicle</option>
|
|
<option value="gunnery_mech">Gunnery/'Mech</option>
|
|
<option value="gunnery_protomech">Gunnery/ProtoMech</option>
|
|
<option value="gunnery_sea_vehicle">Gunnery/Sea Vehicle</option>
|
|
<option value="gunnery_spacecraft">Gunnery/Spacecraft</option>
|
|
<option value="gunnery_turret">Gunnery/Turret</option>
|
|
<option value="interest">Interest</option>
|
|
<option value="interrogation">Interrogation</option>
|
|
<option value="investigation">Investigation</option>
|
|
<option value="language">Language</option>
|
|
<option value="leadership">Leadership</option>
|
|
<option value="martial_arts">Martial Arts</option>
|
|
<option value="medtech_general">MedTech/General</option>
|
|
<option value="medtech_veterinary">MedTech/Veterinary</option>
|
|
<option value="melee_weapons">Melee Weapons</option>
|
|
<option value="navigation_air">Navigation/Air</option>
|
|
<option value="navigation_ground">Navigation/Ground</option>
|
|
<option value="navigation_kf_jump">Navigation/K-F Jump</option>
|
|
<option value="navigation_sea">Navigation/Sea</option>
|
|
<option value="navigation_space">Navigation/Space</option>
|
|
<option value="negotiation">Negotiation</option>
|
|
<option value="perception">Perception</option>
|
|
<option value="piloting_aerospace">Piloting/Aerospace</option>
|
|
<option value="piloting_air_vehicle">Piloting/Air Vehicle</option>
|
|
<option value="piloting_battlesuit">Piloting/Battlesuit</option>
|
|
<option value="piloting_ground_vehicle">Piloting/Ground Vehicle</option>
|
|
<option value="piloting_mech">Piloting/'Mech</option>
|
|
<option value="piloting_protomech">Piloting/ProtoMech</option>
|
|
<option value="piloting_rail_vehicle">Piloting/Rail Vehicle</option>
|
|
<option value="piloting_sea_vehicle">Piloting/Sea Vehicle</option>
|
|
<option value="piloting_spacecraft">Piloting/Spacecraft</option>
|
|
<option value="prestidigitation_pick_pocket">Prestidigitation/Pick Pocket</option>
|
|
<option value="prestidigitation_quickdraw">Prestidigitation/Quickdraw</option>
|
|
<option value="prestidigitation_sleight_of_hand">Prestidigitation/Sleight of Hand</option>
|
|
<option value="protocol">Protocol</option>
|
|
<option value="running">Running</option>
|
|
<option value="science">Science</option>
|
|
<option value="security_systems_electronic">Security Systems/Electronic</option>
|
|
<option value="security_systems_mechanical">Security Systems/Mechanical</option>
|
|
<option value="sensor_operations">Sensor Operations</option>
|
|
<option value="small_arms">Small Arms</option>
|
|
<option value="stealth">Stealth</option>
|
|
<option value="strategy">Strategy</option>
|
|
<option value="streetwise">Streetwise</option>
|
|
<option value="support_weapons">Support Weapons</option>
|
|
<option value="surgery_general">Surgery/General</option>
|
|
<option value="surgery_veterinary">Surgery/Veterinary</option>
|
|
<option value="survival">Survival</option>
|
|
<option value="swimming">Swimming</option>
|
|
<option value="tactics_air">Tactics/Air</option>
|
|
<option value="tactics_infantry">Tactics/Infantry</option>
|
|
<option value="tactics_land">Tactics/Land</option>
|
|
<option value="tactics_sea">Tactics/Sea</option>
|
|
<option value="tactics_space">Tactics/Space</option>
|
|
<option value="technician_aeronautics">Technician/Aeronautics</option>
|
|
<option value="technician_cybernetics">Technician/Cybernetics</option>
|
|
<option value="technician_electronics">Technician/Electronics</option>
|
|
<option value="technician_jets">Technician/Jets</option>
|
|
<option value="technician_mechanical">Technician/Mechanical</option>
|
|
<option value="technician_myomer">Technician/Myomer</option>
|
|
<option value="technician_nuclear">Technician/Nuclear</option>
|
|
<option value="technician_weapons">Technician/Weapons</option>
|
|
<option value="thrown_weapons_blades">Thrown Weapons/Blades</option>
|
|
<option value="thrown_weapons_blunt_weapons">Thrown Weapons/Blunt Weapons</option>
|
|
<option value="tracking_urban">Tracking/Urban</option>
|
|
<option value="tracking_wilds">Tracking/Wilds</option>
|
|
<option value="training">Training</option>
|
|
<option value="zero_g_operations">Zero-G Operations</option>
|
|
</select>
|
|
<input type="text" name="attr_sub_skill" class="skills skill content" title="@{repeating_skills_$id_sub_skill}">
|
|
<span name="attr_skill_level" class="skills content skills-labels skills-skill-level" title="@{repeating_skills_$id_skill_level}"></span>
|
|
<input type="hidden" name="attr_skill_level">
|
|
<span name="attr_skill_linked_attributes" class="skills content skills-labels skills-linked-attributes" title="@{repeating_skills_$id_skill_linked_attributes}"></span>
|
|
<input type="hidden" name="attr_skill_linked_attributes">
|
|
<span name="attr_skill_modifier" class="skills content skills-labels skills-modifier" title="@{repeating_skills_$id_skill_modifier}"></span>
|
|
<input type="hidden" name="attr_skill_modifier">
|
|
<span name="attr_skill_tnc" class="skills content skills-labels skills-tnc" title="@{repeating_skills_$id_skill_tnc}"></span>
|
|
<input type="hidden" name="attr_skill_tnc">
|
|
<input type="hidden" name="attr_target_number">
|
|
<input type="number" name="attr_skill_xp" class="skills content skills-labels skills-xp" title="@{repeating_skills_$id_skill_xp}">
|
|
<input type="hidden" name="attr_skill_roll_value" value="Acrobatics/Free-Fall Skill Check
|
|
Margin of Success: [[2d6 + @{skill_modifier}[MOD] - @{target_number}[TN]]]">
|
|
<span class="skills skills-labels">
|
|
<button type="roll" name="roll_skill_check" value="@{skill_roll_value}" class="skill-roll skills-labels d6" title="@{repeating_skills_$id_skill_check}">l</button>
|
|
</span>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="sheet-tab-content sheet-tab4">
|
|
<h1>Inventory</h1>
|
|
<div class="sheet-wrapper">
|
|
<div class="sheet-section">
|
|
<div>
|
|
<div class="sheet-input-field"
|
|
style="width:695px;margin-top:8px;padding-top:10px;background-color:#7A7A52">
|
|
<span style="font-size:large">Encumbrance</span><br>
|
|
<table class="sheet-section-table2">
|
|
<tr>
|
|
<th>Gear Weight (kg)</th>
|
|
<th>STR</th>
|
|
<th>Encumbered (kg)</th>
|
|
<th>Very Encumbered (kg)</th>
|
|
<th>Overloaded (kg)</th>
|
|
<th>Notes</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_gearweight">
|
|
</td>
|
|
<td>
|
|
<input style="width:35px;" type="number" name="attr_encombstr"
|
|
value="floor(@{strength_xp}/100)" disabled="true">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_encumb">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_veryencumb">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="number" name="attr_overload">
|
|
</td>
|
|
<td>
|
|
<input style="width:200px;" type="text" name="attr_encombnotes">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="sheet-input-field"
|
|
style="width:695px;margin-top:8px;padding-top:10px;background-color:#FFA319">
|
|
<span style="font-size:large">Inventory</span><br>
|
|
<fieldset class="repeating_inventory">
|
|
<table class="sheet-section-table2">
|
|
<tr>
|
|
<th>Item</th>
|
|
<th>Location</th>
|
|
<th>Weight (kg)</th>
|
|
<th>Data</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:200px;" type="text" name="attr_item">
|
|
</td>
|
|
<td>
|
|
<input style="width:100px;" type="text" name="attr_itemloc">
|
|
</td>
|
|
<td>
|
|
<input style="width:50px;" type="text" name="attr_itemweight">
|
|
</td>
|
|
<td>
|
|
<input style="width:275px;" type="text" name="attr_itemdata">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
<div class="sheet-input-field"
|
|
style="width:695px;margin-top:8px;padding-top:10px;background-color:#CC3300">
|
|
<span style="font-size:large">Vehicle Data</span><br>
|
|
<fieldset class="repeating_vehicle">
|
|
<table class="sheet-section-table2">
|
|
<tr>
|
|
<th>Vehicle Model/Name</th>
|
|
<th>Type</th>
|
|
<th>Mass</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:405px;" type="text" name="attr_vehname">
|
|
</td>
|
|
<td>
|
|
<input style="width:150px;" type="text" name="attr_vehtype">
|
|
</td>
|
|
<td>
|
|
<input style="width:75px;" type="number" name="attr_vehmass">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<table class="sheet-section-table2">
|
|
<tr>
|
|
<th>Vehicle Traits</th>
|
|
<th>Notes</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input style="width:400px;" type="text" name="attr_vehtrait">
|
|
</td>
|
|
<td>
|
|
<input style="width:250px;" type="text" name="attr_vehnotes">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/worker">
|
|
'use strict';
|
|
|
|
const STRENGTH_XP = "strength_xp";
|
|
const BODY_XP = "body_xp";
|
|
const REFLEX_XP = "reflex_xp";
|
|
const DEXTERITY_XP = "dexterity_xp";
|
|
const INTELLIGENCE_XP = "intelligence_xp";
|
|
const WILL_XP = "will_xp";
|
|
const CHARISMA_XP = "charisma_xp";
|
|
const EDGE_XP = "edge_xp";
|
|
|
|
const STRENGTH_LINK = "strength_link";
|
|
const BODY_LINK = "body_link";
|
|
const REFLEX_LINK = "reflex_link";
|
|
const DEXTERITY_LINK = "dexterity_link";
|
|
const INTELLIGENCE_LINK = "intelligence_link";
|
|
const WILL_LINK = "will_link";
|
|
const CHARISMA_LINK = "charisma_link";
|
|
const EDGE_LINK = "edge_link";
|
|
|
|
const linkedAttributeDisplayNames = {
|
|
STRENGTH_LINK: "STR",
|
|
BODY_LINK: "BOD",
|
|
REFLEX_LINK: "RFL",
|
|
DEXTERITY_LINK: "DEX",
|
|
INTELLIGENCE_LINK: "INT",
|
|
WILL_LINK: "WIL",
|
|
CHARISMA_LINK: "CHA",
|
|
EDGE_LINK: "EDG",
|
|
};
|
|
|
|
const calculateAbilityScore = ({
|
|
sourceAttribute,
|
|
newValue
|
|
}) => {
|
|
if (typeof newValue !== "number") {
|
|
console.error("Expected numerical value for attribute [ " + sourceAttribute + " ] but got [ " + newValue + " ]");
|
|
return undefined
|
|
}
|
|
|
|
const attributeValue = Math.floor(newValue / 100);
|
|
const attributeLinkedValue = calculateLinkedAttributeValue(attributeValue);
|
|
|
|
let attribute;
|
|
|
|
switch (sourceAttribute) {
|
|
case STRENGTH_XP:
|
|
attribute = {
|
|
name: "strength",
|
|
value: attributeValue,
|
|
linkName: STRENGTH_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case BODY_XP:
|
|
attribute = {
|
|
name: "body",
|
|
value: attributeValue,
|
|
linkName: BODY_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case REFLEX_XP:
|
|
attribute = {
|
|
name: "reflex",
|
|
value: attributeValue,
|
|
linkName: REFLEX_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case DEXTERITY_XP:
|
|
attribute = {
|
|
name: "dexterity",
|
|
value: attributeValue,
|
|
linkName: DEXTERITY_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case INTELLIGENCE_XP:
|
|
attribute = {
|
|
name: "intelligence",
|
|
value: attributeValue,
|
|
linkName: INTELLIGENCE_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case WILL_XP:
|
|
attribute = {
|
|
name: "will",
|
|
value: attributeValue,
|
|
linkName: WILL_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case CHARISMA_XP:
|
|
attribute = {
|
|
name: "charisma",
|
|
value: attributeValue,
|
|
linkName: CHARISMA_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
case EDGE_XP:
|
|
attribute = {
|
|
name: "edge",
|
|
value: attributeValue,
|
|
linkName: EDGE_LINK,
|
|
linkValue: attributeLinkedValue,
|
|
};
|
|
break
|
|
default:
|
|
console.error("unknown attribute type passed in to basic attribute on change function");
|
|
}
|
|
|
|
return attribute
|
|
};
|
|
|
|
const calculateLinkedAttributeValue = attribute => {
|
|
if (attribute > 10) {
|
|
return Math.floor(attribute / 3)
|
|
} else {
|
|
if (attribute < 1)
|
|
return -4
|
|
else if (attribute < 2)
|
|
return -2
|
|
else if (attribute < 4)
|
|
return -1
|
|
else if (attribute < 7)
|
|
return 0
|
|
else if (attribute < 10)
|
|
return 1
|
|
else
|
|
return 2
|
|
}
|
|
};
|
|
|
|
const skillsList = {
|
|
"acrobatics": {
|
|
"linkedAttributes": [REFLEX_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"acrobatics_free_fall": "Acrobatics/Free-Fall",
|
|
"acrobatics_gymnastics": "Acrobatics/Gymnastics",
|
|
},
|
|
},
|
|
"acting": {
|
|
"linkedAttributes": [CHARISMA_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"acting": "Acting",
|
|
},
|
|
},
|
|
"administration": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"administration": "Administration",
|
|
},
|
|
},
|
|
"animal": {
|
|
"linkedAttributes": [WILL_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"animal_handling_herding": "Animal Handling/Herding",
|
|
"animal_handling_riding": "Animal Handling/Riding",
|
|
"animal_handling_training": "Animal Handling/Training",
|
|
},
|
|
},
|
|
"appraisal": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"appraisal": "Appraisal",
|
|
},
|
|
},
|
|
"archery": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"archery": "Archery",
|
|
},
|
|
},
|
|
"artillery": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"artillery": "Artillery",
|
|
},
|
|
},
|
|
"career": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"career": "Career",
|
|
},
|
|
},
|
|
"climbing": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"climbing": "Climbing",
|
|
},
|
|
},
|
|
"communications": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"communications_black_box": "Communications/Black Box",
|
|
"communications_conventional_em": "Communications/Conventional (EM)",
|
|
"communications_hyperpulse_generator": "Communications/Hyperpulse Generator",
|
|
},
|
|
},
|
|
"cryptography": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"cryptography": "Cryptography",
|
|
},
|
|
},
|
|
"demolitions": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"demolitions": "Demolitions",
|
|
},
|
|
},
|
|
"disguise": {
|
|
"linkedAttributes": [CHARISMA_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"disguise": "Disguise",
|
|
},
|
|
},
|
|
"driving": {
|
|
"linkedAttributes": [REFLEX_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"driving_ground_vehicles": "Driving/Ground Vehicles",
|
|
"driving_rail_vehicles": "Driving/Rail Vehicles",
|
|
"driving_sea_vehicles": "Driving/Sea Vehicles",
|
|
},
|
|
},
|
|
"escape": {
|
|
"linkedAttributes": [STRENGTH_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"escape_artist": "Escape Artist",
|
|
},
|
|
},
|
|
"forgery": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"forgery": "Forgery",
|
|
},
|
|
},
|
|
"gunnery": {
|
|
"linkedAttributes": [REFLEX_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"gunnery_aerospace": "Gunnery/Aerospace",
|
|
"gunnery_air_vehicle": "Gunnery/Air Vehicle",
|
|
"gunnery_battlesuit": "Gunnery/Battlesuit",
|
|
"gunnery_ground_vehicle": "Gunnery/Ground Vehicle",
|
|
"gunnery_mech": "Gunnery/'Mech",
|
|
"gunnery_protomech": "Gunnery/ProtoMech",
|
|
"gunnery_sea_vehicle": "Gunnery/Sea Vehicle",
|
|
"gunnery_spacecraft": "Gunnery/Spacecraft",
|
|
"gunnery_turret": "Gunnery/Turret",
|
|
},
|
|
},
|
|
"interrogation": {
|
|
"linkedAttributes": [WILL_LINK, CHARISMA_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"interrogation": "Interrogation",
|
|
},
|
|
},
|
|
"investigation": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"investigation": "Investigation",
|
|
},
|
|
},
|
|
"language": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, CHARISMA_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"language": "Language",
|
|
},
|
|
},
|
|
"leadership": {
|
|
"linkedAttributes": [WILL_LINK, CHARISMA_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"leadership": "Leadership",
|
|
},
|
|
},
|
|
"medtech": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"medtech_general": "MedTech/General",
|
|
"medtech_veterinary": "MedTech/Veterinary",
|
|
},
|
|
},
|
|
"navigation": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"navigation_air": "Navigation/Air",
|
|
"navigation_ground": "Navigation/Ground",
|
|
"navigation_kf_jump": "Navigation/K-F Jump",
|
|
"navigation_sea": "Navigation/Sea",
|
|
"navigation_space": "Navigation/Space",
|
|
},
|
|
},
|
|
"negotiation": {
|
|
"linkedAttributes": [CHARISMA_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"negotiation": "Negotiation",
|
|
},
|
|
},
|
|
"perception": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"perception": "Perception",
|
|
},
|
|
},
|
|
"piloting": {
|
|
"linkedAttributes": [REFLEX_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"piloting_aerospace": "Piloting/Aerospace",
|
|
"piloting_air_vehicle": "Piloting/Air Vehicle",
|
|
"piloting_battlesuit": "Piloting/Battlesuit",
|
|
"piloting_ground_vehicle": "Piloting/Ground Vehicle",
|
|
"piloting_mech": "Piloting/'Mech",
|
|
"piloting_protomech": "Piloting/ProtoMech",
|
|
"piloting_rail_vehicle": "Piloting/Rail Vehicle",
|
|
"piloting_sea_vehicle": "Piloting/Sea Vehicle",
|
|
"piloting_spacecraft": "Piloting/Spacecraft",
|
|
},
|
|
},
|
|
"protocol": {
|
|
"linkedAttributes": [WILL_LINK, CHARISMA_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"protocol": "Protocol",
|
|
},
|
|
},
|
|
"running": {
|
|
"linkedAttributes": [REFLEX_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"running": "Running",
|
|
},
|
|
},
|
|
"science": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"science": "Science",
|
|
},
|
|
},
|
|
"security": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"security_systems_electronic": "Security Systems/Electronic",
|
|
"security_systems_mechanical": "Security Systems/Mechanical",
|
|
},
|
|
},
|
|
"sensor": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"sensor_operations": "Sensor Operations",
|
|
},
|
|
},
|
|
"small": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"small_arms": "Small Arms",
|
|
},
|
|
},
|
|
"stealth": {
|
|
"linkedAttributes": [REFLEX_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"stealth": "Stealth",
|
|
},
|
|
},
|
|
"strategy": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"strategy": "Strategy",
|
|
},
|
|
},
|
|
"streetwise": {
|
|
"linkedAttributes": [CHARISMA_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"streetwise": "Streetwise",
|
|
},
|
|
},
|
|
"support": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"support_weapons": "Support Weapons",
|
|
},
|
|
},
|
|
"surgery": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"surgery_general": "Surgery/General",
|
|
"surgery_veterinary": "Surgery/Veterinary",
|
|
},
|
|
},
|
|
"survival": {
|
|
"linkedAttributes": [BODY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"survival": "Survival",
|
|
},
|
|
},
|
|
"swimming": {
|
|
"linkedAttributes": [STRENGTH_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"swimming": "Swimming",
|
|
},
|
|
},
|
|
"tactics": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"tactics_air": "Tactics/Air",
|
|
"tactics_infantry": "Tactics/Infantry",
|
|
"tactics_land": "Tactics/Land",
|
|
"tactics_sea": "Tactics/Sea",
|
|
"tactics_space": "Tactics/Space",
|
|
},
|
|
},
|
|
"technician": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"technician_aeronautics": "Technician/Aeronautics",
|
|
"technician_cybernetics": "Technician/Cybernetics",
|
|
"technician_electronic": "Technician/Electronic",
|
|
"technician_jets": "Technician/Jets",
|
|
"technician_mechanical": "Technician/Mechanical",
|
|
"technician_myomer": "Technician/Myomer",
|
|
"technician_nuclear": "Technician/Nuclear",
|
|
"technician_weapons": "Technician/Weapons",
|
|
},
|
|
},
|
|
"thrown": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"thrown_weapons_blades": "Thrown Weapons/Blades",
|
|
"thrown_weapons_blunt_weapons": "Thrown Weapons/Blunt Weapons",
|
|
},
|
|
},
|
|
"tracking": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"tracking_urban": "Tracking/Urban",
|
|
"tracking_wilds": "Tracking/Wilds",
|
|
},
|
|
},
|
|
"training": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, CHARISMA_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"training": "Training",
|
|
},
|
|
},
|
|
"zero": {
|
|
"linkedAttributes": [REFLEX_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"zero_g_operations": "Zero-G Operations",
|
|
},
|
|
},
|
|
};
|
|
|
|
const tieredSkillsBasic = {
|
|
"art": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"art": "Art",
|
|
},
|
|
},
|
|
"computers": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"computers": "Computers",
|
|
},
|
|
},
|
|
"interest": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "CB",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"interest": "Interest",
|
|
},
|
|
},
|
|
"martial": {
|
|
"linkedAttributes": [REFLEX_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"martial_arts": "Martial Arts",
|
|
},
|
|
},
|
|
"melee": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"melee_weapons": "Melee Weapons",
|
|
},
|
|
},
|
|
"prestidigitation": {
|
|
"linkedAttributes": [DEXTERITY_LINK, ],
|
|
"targetNumber": 7,
|
|
"complexity": "SB",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"prestidigitation_pick_pocket": "Prestidigitation/Pick Pocket",
|
|
"prestidigitation_quickdraw": "Prestidigitation/Quickdraw",
|
|
"prestidigitation_sleight_of_hand": "Prestidigitation/Sleight of Hand",
|
|
},
|
|
},
|
|
};
|
|
|
|
const tieredSkillsAdvanced = {
|
|
"art": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"art": "Art",
|
|
},
|
|
},
|
|
"computers": {
|
|
"linkedAttributes": [DEXTERITY_LINK, INTELLIGENCE_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"computers": "Computers",
|
|
},
|
|
},
|
|
"interest": {
|
|
"linkedAttributes": [INTELLIGENCE_LINK, WILL_LINK, ],
|
|
"targetNumber": 9,
|
|
"complexity": "CA",
|
|
"subSkills": true,
|
|
"displayName": {
|
|
"interest": "Interest",
|
|
},
|
|
},
|
|
"martial": {
|
|
"linkedAttributes": [REFLEX_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"martial_arts": "Martial Arts",
|
|
},
|
|
},
|
|
"melee": {
|
|
"linkedAttributes": [REFLEX_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"melee_weapons": "Melee Weapons",
|
|
},
|
|
},
|
|
"prestidigitation": {
|
|
"linkedAttributes": [REFLEX_LINK, DEXTERITY_LINK, ],
|
|
"targetNumber": 8,
|
|
"complexity": "SA",
|
|
"subSkills": false,
|
|
"displayName": {
|
|
"prestidigitation_pick_pocket": "Prestidigitation/Pick Pocket",
|
|
"prestidigitation_quickdraw": "Prestidigitation/Quickdraw",
|
|
"prestidigitation_sleight_of_hand": "Prestidigitation/Sleight of Hand",
|
|
},
|
|
},
|
|
};
|
|
|
|
const tieredSkills = [
|
|
"art",
|
|
"computers",
|
|
"interest",
|
|
"martial",
|
|
"melee",
|
|
"prestidigitation",
|
|
];
|
|
|
|
const calculateSkillLevel = (skillXP, learningSpeedModifier) => {
|
|
const learningSpeedPercentageModifier = 1 + 0.2 * learningSpeedModifier;
|
|
|
|
if (skillXP < 20 * learningSpeedPercentageModifier) {
|
|
return -1
|
|
}
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
if (skillXP < getXPForLevel(i + 1) * learningSpeedPercentageModifier)
|
|
return i
|
|
}
|
|
|
|
return 10
|
|
};
|
|
|
|
const getXPForLevel = level => {
|
|
let total = 0;
|
|
|
|
while (level > 0) {
|
|
total += level * 10;
|
|
level--;
|
|
}
|
|
|
|
return total + 20
|
|
};
|
|
|
|
const getSkillDisplayName = (skill, skillDisplayNameKey, subSkill) => {
|
|
if (skill.subSkills === true) {
|
|
return skill.displayName[skillDisplayNameKey] + "/" + subSkill
|
|
}
|
|
|
|
if (typeof subSkill === "string" && subSkill != "") {
|
|
return skill.displayName[skillDisplayNameKey] + " (" + subSkill + ")"
|
|
}
|
|
|
|
return skill.displayName[skillDisplayNameKey]
|
|
};
|
|
|
|
const getSkill = (skillName, skillLevel, tieredSkill) => {
|
|
if (tieredSkill) {
|
|
if (skillLevel <= 3) {
|
|
return tieredSkillsBasic[skillName]
|
|
} else {
|
|
return tieredSkillsAdvanced[skillName]
|
|
}
|
|
} else {
|
|
return skillsList[skillName]
|
|
}
|
|
};
|
|
|
|
const sheetOpened = () => {
|
|
sheetMigration();
|
|
|
|
getAttrs(["btatow_sheet_version", ], ({
|
|
btatow_sheet_version
|
|
}) => {
|
|
if (btatow_sheet_version >= 3) {
|
|
recalculateSkills();
|
|
}
|
|
});
|
|
};
|
|
|
|
// run any data migrations
|
|
on("sheet:opened", sheetOpened);
|
|
|
|
const recalculateSkills = () => {
|
|
getSectionIDs("skills", ids =>
|
|
ids.forEach(
|
|
id => getAttrs(["repeating_skills_" + id + "_skill_xp", ],
|
|
values =>
|
|
skillXPChanged({
|
|
newValue: values["repeating_skills_" + id + "_skill_xp"],
|
|
id,
|
|
})
|
|
)
|
|
)
|
|
);
|
|
};
|
|
|
|
// calculate stat values when XP amount changes
|
|
on("change:strength_xp change:body_xp change:reflex_xp change:dexterity_xp change:intelligence_xp change:will_xp change:charisma_xp change:edge_xp", calculateAbilityScore);
|
|
|
|
on("change:repeating_skills:skill change:repeating_skills:sub_skill", _ => {
|
|
getAttrs(["repeating_skills_skill_xp", ], ({
|
|
repeating_skills_skill_xp
|
|
}) => {
|
|
skillXPChanged({
|
|
newValue: repeating_skills_skill_xp,
|
|
});
|
|
});
|
|
});
|
|
|
|
const skillXPChanged = ({
|
|
id,
|
|
newValue
|
|
}) => {
|
|
// When the sheet is opened, or data migrations are run, the skills are retrieved via ID, and thus must have their
|
|
// ID included in the attribute name when setting attributes.
|
|
const skillId = id !== undefined ? id + "_" : "";
|
|
|
|
const skill = "repeating_skills_" + skillId + "skill";
|
|
const skillLevel = "repeating_skills_" + skillId + "skill_level";
|
|
const subSkillAttrName = "repeating_skills_" + skillId + "sub_skill";
|
|
|
|
getAttrs([skill, subSkillAttrName, "learning_speed", ], values => {
|
|
const skillName = values[skill];
|
|
const skillNameLookupKey = skillName.split("_")[0];
|
|
const subSkill = values[subSkillAttrName];
|
|
|
|
let skillAttributesToSet = {};
|
|
|
|
skillAttributesToSet[skillLevel] = calculateSkillLevel(Number(newValue), values.learning_speed);
|
|
|
|
const skillData = getSkill(
|
|
skillNameLookupKey,
|
|
skillAttributesToSet[skillLevel],
|
|
tieredSkills.includes(skillNameLookupKey)
|
|
);
|
|
|
|
skillAttributesToSet["repeating_skills_" + skillId + "skill_tnc"] = skillData.targetNumber + "/" + skillData.complexity;
|
|
skillAttributesToSet["repeating_skills_" + skillId + "target_number"] = skillData.targetNumber;
|
|
|
|
getAttrs(skillData.linkedAttributes, values => {
|
|
skillAttributesToSet["repeating_skills_" + skillId + "skill_modifier"] = Object.values(values)
|
|
.reduce((total, num) => Number(total) + Number(num)) + Number(skillAttributesToSet[skillLevel]);
|
|
|
|
skillAttributesToSet["repeating_skills_" + skillId + "skill_linked_attributes"] = skillData.linkedAttributes
|
|
.map(linkAtr => linkedAttributeDisplayNames[linkAtr] + " (" + values[linkAtr] + ")")
|
|
.join(" + ");
|
|
|
|
skillAttributesToSet["repeating_skills_" + skillId + "skill_roll_value"] =
|
|
getSkillDisplayName(skillData, skillName, subSkill) + " Skill Check:\n" +
|
|
"Margin of Success: [[2d6 + @{skill_modifier}[MOD] - @{target_number}[TN]]]";
|
|
|
|
setAttrs(skillAttributesToSet, {}, () => {});
|
|
});
|
|
});
|
|
};
|
|
|
|
// calculate skill modifiers when skill xp changes
|
|
on("change:repeating_skills:skill_xp", skillXPChanged);
|
|
|
|
// recalculate all skills when learning speed modifier changes
|
|
on("change:learning_speed", recalculateSkills);
|
|
|
|
const sheetMigration = () => {
|
|
console.log("Running sheet data migration");
|
|
|
|
let sheetVersionAttributeName = "btatow_sheet_version";
|
|
let currentVersion = 3;
|
|
|
|
getAttrs([sheetVersionAttributeName, ], sheetVersionAttribute => {
|
|
let sheetVersion = Number(sheetVersionAttribute[sheetVersionAttributeName]);
|
|
// Check if we should do the migration
|
|
if (isNaN(sheetVersion)) {
|
|
console.error("No sheet version defined, unable to determine if sheet data needs to be migrated.");
|
|
return
|
|
}
|
|
|
|
if (sheetVersion === currentVersion) {
|
|
console.log("No migration needed");
|
|
return
|
|
}
|
|
|
|
switch (sheetVersion) {
|
|
case 1:
|
|
migrateFrom1To2();
|
|
break
|
|
case 2:
|
|
migrateFrom2To3();
|
|
break
|
|
}
|
|
});
|
|
};
|
|
|
|
// Migrate attribute data from version 1 to version 2
|
|
const migrateFrom1To2 = () => {
|
|
const oldAttributeNames = [
|
|
"STRXP",
|
|
"BODXP",
|
|
"RFLXP",
|
|
"DEXXP",
|
|
"INTXP",
|
|
"WILXP",
|
|
"CHAXP",
|
|
"EDGXP",
|
|
];
|
|
const newAttributeNames = [
|
|
"strength_xp",
|
|
"body_xp",
|
|
"reflex_xp",
|
|
"dexterity_xp",
|
|
"intelligence_xp",
|
|
"will_xp",
|
|
"charisma_xp",
|
|
"edge_xp",
|
|
];
|
|
|
|
let newAttributes = {};
|
|
|
|
console.log("Starting migration from version 1 to version 2.");
|
|
|
|
getAttrs(oldAttributeNames, attributes => {
|
|
console.debug("Attributes fetched: " + JSON.stringify(attributes));
|
|
for (let i = 0; i < oldAttributeNames.length; i++) {
|
|
if (attributes[oldAttributeNames[i]] !== undefined) {
|
|
console.debug("Attributes[" + oldAttributeNames[i] + "]: " + attributes[oldAttributeNames[i]]);
|
|
newAttributes[newAttributeNames[i]] = attributes[oldAttributeNames[i]];
|
|
}
|
|
}
|
|
|
|
console.debug("New attributes: " + JSON.stringify(newAttributes));
|
|
|
|
setAttrs(newAttributes, {}, () => {
|
|
setAttrs({
|
|
btatow_sheet_version: "2",
|
|
}, {}, () => {
|
|
console.log("Sheet data migration completed");
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
// Migrate skills data from version 2 to version 3
|
|
const migrateFrom2To3 = () => {
|
|
console.log("Starting migration from version 2 to version 3.");
|
|
|
|
getSectionIDs("skills", ids => {
|
|
let skillsUpdated = 0;
|
|
|
|
ids.forEach(id => {
|
|
const oldSkillDataNames = {
|
|
skill: "repeating_skills_" + id + "_skill",
|
|
subSkill: "repeating_skills_" + id + "_skillNotes",
|
|
xp: "repeating_skills_" + id + "_skillXP",
|
|
};
|
|
const newSkillDataNames = {
|
|
skill: "repeating_skills_" + id + "_skill",
|
|
subSkill: "repeating_skills_" + id + "_sub_skill",
|
|
xp: "repeating_skills_" + id + "_skill_xp",
|
|
};
|
|
getAttrs(Object.values(oldSkillDataNames), oldSkillValues => {
|
|
const oldSkillName = oldSkillValues[oldSkillDataNames.skill];
|
|
const oldSkillSubSkillName = oldSkillValues[oldSkillDataNames.subSkill];
|
|
|
|
if (oldSkillName === undefined || oldSkillValues[oldSkillDataNames.xp] === undefined) {
|
|
console.error("Old skill data is missing values, unable to migrate.\n" + JSON.stringify(oldSkillValues));
|
|
skillsUpdated++;
|
|
return
|
|
}
|
|
|
|
let parsedSkillName = oldSkillName.toLowerCase()
|
|
.replace(" ", "_")
|
|
.replace("-", "_");
|
|
|
|
const skillFirstName = parsedSkillName.split("_")[0];
|
|
|
|
let skillData = {};
|
|
const newSkillValues = {};
|
|
|
|
if (skillFirstName in skillsList) {
|
|
skillData = skillsList[skillFirstName];
|
|
} else if (skillFirstName in tieredSkillsBasic) {
|
|
skillData = tieredSkillsBasic[skillFirstName];
|
|
} else if (skillFirstName.substring(0, skillFirstName.length - 1) in tieredSkillsBasic) {
|
|
skillData = tieredSkillsBasic[skillFirstName.substring(0, skillFirstName.length - 1)];
|
|
parsedSkillName = parsedSkillName.substring(0, parsedSkillName.length - 1);
|
|
} else {
|
|
console.error("Unable to migrate skill data. Old values are: " + JSON.stringify(oldSkillValues));
|
|
skillsUpdated++;
|
|
return
|
|
}
|
|
|
|
let skillName = "";
|
|
let displaySubSkill = true;
|
|
|
|
if (parsedSkillName in skillData.displayName) {
|
|
skillName = parsedSkillName;
|
|
} else if (parsedSkillName.substring(0, parsedSkillName.length - 1) in skillData.displayName) {
|
|
skillName = parsedSkillName.substring(0, parsedSkillName.length - 1);
|
|
} else if (oldSkillSubSkillName === undefined) {
|
|
console.error("Unable to identify skill. Old skill name: " + oldSkillName);
|
|
skillsUpdated++;
|
|
return
|
|
} else {
|
|
const parsedSubSkillName = oldSkillSubSkillName.trim()
|
|
.replace("'", "")
|
|
.replace("`", "")
|
|
.replace("-", "_")
|
|
.replace("/", "_")
|
|
.toLowerCase();
|
|
|
|
const skillWithSubSkill = parsedSkillName + "_" + parsedSubSkillName;
|
|
|
|
if (skillWithSubSkill in skillData.displayName) {
|
|
skillName = skillWithSubSkill;
|
|
displaySubSkill = false;
|
|
} else {
|
|
console.error("Unable to identify skill. Old skill name and notes: " + oldSkillName + " " + oldSkillSubSkillName);
|
|
skillsUpdated++;
|
|
return
|
|
}
|
|
}
|
|
|
|
newSkillValues[newSkillDataNames.skill] = skillName;
|
|
if (displaySubSkill && oldSkillSubSkillName !== undefined) {
|
|
newSkillValues[newSkillDataNames.subSkill] = oldSkillSubSkillName;
|
|
}
|
|
newSkillValues[newSkillDataNames.xp] = oldSkillValues[oldSkillDataNames.xp];
|
|
|
|
setAttrs(newSkillValues, {}, () => {
|
|
skillsUpdated++;
|
|
|
|
if (skillsUpdated === ids.length) {
|
|
setAttrs({
|
|
btatow_sheet_version: 3,
|
|
}, {}, () => {
|
|
console.log("Sheet migrated from version 2 to version 3.");
|
|
recalculateSkills();
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
</script>
|