Files
roll20-character-sheets-tester/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html
T
Michael Smith e946e95647 BattleTech - A Time of War - splitting out sheet worker code, adding unit tests and build process (#8670)
* 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.
2021-04-08 10:18:31 -04:00

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>