mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-08-30 03:40:32 +00:00
Made sure the files were .HTML and .CSS this is a new sheet for Final Fantasy 5e which is a system i have made.
4135 lines
167 KiB
HTML
4135 lines
167 KiB
HTML
<div class="ff7-shell">
|
|
|
|
<input type="hidden" name="attr_sheet_mode" class="sheet-mode" value="character">
|
|
<input type="hidden" name="attr_sheet_tab" class="sheet-tab" value="overview">
|
|
|
|
<div class="ff7-header">
|
|
<div class="logo-panel">
|
|
<span class="logo-text">FINAL FANTASY 5E</span>
|
|
<span class="sub-text">Roll20 Tactical Sheet</span>
|
|
</div>
|
|
|
|
<div class="mode-buttons">
|
|
<button type="action" name="act_mode_character">Character</button>
|
|
<button type="action" name="act_mode_monster">Monster</button>
|
|
<button type="action" name="act_mode_vehicle">Vehicle</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
CHARACTER MODE
|
|
========================== -->
|
|
|
|
<div class="mode-character">
|
|
|
|
<div class="tab-buttons character-tabs">
|
|
<button type="action" name="act_tab_overview">Overview</button>
|
|
<button type="action" name="act_tab_cp">CP Engine</button>
|
|
<button type="action" name="act_tab_combat">Combat</button>
|
|
<button type="action" name="act_tab_magic">Magic</button>
|
|
<button type="action" name="act_tab_equipment">Equipment</button>
|
|
<button type="action" name="act_tab_status">Status</button>
|
|
<button type="action" name="act_tab_bio">Bio</button>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
CHARACTER OVERVIEW TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-overview">
|
|
|
|
<div class="top-summary-grid">
|
|
|
|
<div class="ff7-card identity-card">
|
|
<h2>Character</h2>
|
|
|
|
<div class="identity-top-grid">
|
|
<div>
|
|
<label>Name</label>
|
|
<input type="text" name="attr_character_name" placeholder="Character Name">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Total Level</label>
|
|
<input type="number" name="attr_level" value="1" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Primary Job Level</label>
|
|
<input type="number" name="attr_primary_job_level" value="1">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Secondary Job Level</label>
|
|
<input type="number" name="attr_secondary_job_level" value="0">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="job-grid">
|
|
<div>
|
|
<label>Primary Job / Class</label>
|
|
<select name="attr_primary_job">
|
|
<option value="Freelancer">Freelancer</option>
|
|
<option value="Warrior">Warrior</option>
|
|
<option value="Fighter">Fighter</option>
|
|
<option value="Barbarian">Barbarian</option>
|
|
<option value="Paladin">Paladin</option>
|
|
<option value="Dark Knight">Dark Knight</option>
|
|
<option value="Gunbreaker">Gunbreaker</option>
|
|
<option value="Samurai">Samurai</option>
|
|
<option value="Monk">Monk</option>
|
|
<option value="Dragoon">Dragoon</option>
|
|
<option value="Reaper">Reaper</option>
|
|
<option value="Viper">Viper</option>
|
|
<option value="Rogue">Rogue</option>
|
|
<option value="Thief">Thief</option>
|
|
<option value="Ninja">Ninja</option>
|
|
<option value="Ranger">Ranger</option>
|
|
<option value="Archer">Archer</option>
|
|
<option value="Sniper">Sniper</option>
|
|
<option value="Machinist">Machinist</option>
|
|
<option value="Engineer">Engineer</option>
|
|
<option value="Artificer">Artificer</option>
|
|
<option value="Bard">Bard</option>
|
|
<option value="Dancer">Dancer</option>
|
|
<option value="Black Mage">Black Mage</option>
|
|
<option value="White Mage">White Mage</option>
|
|
<option value="Red Mage">Red Mage</option>
|
|
<option value="Blue Mage">Blue Mage</option>
|
|
<option value="Time Mage">Time Mage</option>
|
|
<option value="Green Mage">Green Mage</option>
|
|
<option value="Geomancer">Geomancer</option>
|
|
<option value="Summoner">Summoner</option>
|
|
<option value="Scholar">Scholar</option>
|
|
<option value="Sage">Sage</option>
|
|
<option value="Astrologian">Astrologian</option>
|
|
<option value="Wizard">Wizard</option>
|
|
<option value="Sorcerer">Sorcerer</option>
|
|
<option value="Warlock">Warlock</option>
|
|
<option value="Cleric">Cleric</option>
|
|
<option value="Druid">Druid</option>
|
|
<option value="Alchemist">Alchemist</option>
|
|
<option value="Chemist">Chemist</option>
|
|
<option value="Beastmaster">Beastmaster</option>
|
|
<option value="Puppetmaster">Puppetmaster</option>
|
|
<option value="Corsair">Corsair</option>
|
|
<option value="Gambler">Gambler</option>
|
|
<option value="Mime">Mime</option>
|
|
<option value="Oracle">Oracle</option>
|
|
<option value="Necromancer">Necromancer</option>
|
|
<option value="Berserker">Berserker</option>
|
|
<option value="Mystic Knight">Mystic Knight</option>
|
|
<option value="Rune Knight">Rune Knight</option>
|
|
<option value="Pictomancer">Pictomancer</option>
|
|
<option value="Onion Knight">Onion Knight</option>
|
|
<option value="Custom">Custom</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Secondary Job / Class</label>
|
|
<select name="attr_secondary_job">
|
|
<option value="">None</option>
|
|
<option value="Freelancer">Freelancer</option>
|
|
<option value="Warrior">Warrior</option>
|
|
<option value="Fighter">Fighter</option>
|
|
<option value="Barbarian">Barbarian</option>
|
|
<option value="Paladin">Paladin</option>
|
|
<option value="Dark Knight">Dark Knight</option>
|
|
<option value="Gunbreaker">Gunbreaker</option>
|
|
<option value="Samurai">Samurai</option>
|
|
<option value="Monk">Monk</option>
|
|
<option value="Dragoon">Dragoon</option>
|
|
<option value="Reaper">Reaper</option>
|
|
<option value="Viper">Viper</option>
|
|
<option value="Rogue">Rogue</option>
|
|
<option value="Thief">Thief</option>
|
|
<option value="Ninja">Ninja</option>
|
|
<option value="Ranger">Ranger</option>
|
|
<option value="Archer">Archer</option>
|
|
<option value="Sniper">Sniper</option>
|
|
<option value="Machinist">Machinist</option>
|
|
<option value="Engineer">Engineer</option>
|
|
<option value="Artificer">Artificer</option>
|
|
<option value="Bard">Bard</option>
|
|
<option value="Dancer">Dancer</option>
|
|
<option value="Black Mage">Black Mage</option>
|
|
<option value="White Mage">White Mage</option>
|
|
<option value="Red Mage">Red Mage</option>
|
|
<option value="Blue Mage">Blue Mage</option>
|
|
<option value="Time Mage">Time Mage</option>
|
|
<option value="Green Mage">Green Mage</option>
|
|
<option value="Geomancer">Geomancer</option>
|
|
<option value="Summoner">Summoner</option>
|
|
<option value="Scholar">Scholar</option>
|
|
<option value="Sage">Sage</option>
|
|
<option value="Astrologian">Astrologian</option>
|
|
<option value="Wizard">Wizard</option>
|
|
<option value="Sorcerer">Sorcerer</option>
|
|
<option value="Warlock">Warlock</option>
|
|
<option value="Cleric">Cleric</option>
|
|
<option value="Druid">Druid</option>
|
|
<option value="Alchemist">Alchemist</option>
|
|
<option value="Chemist">Chemist</option>
|
|
<option value="Beastmaster">Beastmaster</option>
|
|
<option value="Puppetmaster">Puppetmaster</option>
|
|
<option value="Corsair">Corsair</option>
|
|
<option value="Gambler">Gambler</option>
|
|
<option value="Mime">Mime</option>
|
|
<option value="Oracle">Oracle</option>
|
|
<option value="Necromancer">Necromancer</option>
|
|
<option value="Berserker">Berserker</option>
|
|
<option value="Mystic Knight">Mystic Knight</option>
|
|
<option value="Rune Knight">Rune Knight</option>
|
|
<option value="Pictomancer">Pictomancer</option>
|
|
<option value="Onion Knight">Onion Knight</option>
|
|
<option value="Custom">Custom</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="job-info-grid">
|
|
<div>
|
|
<label>Primary Role</label>
|
|
<input type="text" name="attr_primary_role" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Primary Casting</label>
|
|
<input type="text" name="attr_job_spellcasting" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Secondary Role</label>
|
|
<input type="text" name="attr_secondary_role" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Secondary Casting</label>
|
|
<input type="text" name="attr_secondary_spellcasting" readonly>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ff7-card exp-card">
|
|
<h2>EXP Tracker</h2>
|
|
|
|
<div class="exp-grid">
|
|
<div>
|
|
<label>Current EXP</label>
|
|
<input type="number" name="attr_exp_current" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Next Level EXP</label>
|
|
<input type="number" name="attr_exp_next" value="300">
|
|
</div>
|
|
|
|
<div>
|
|
<label>EXP to Next</label>
|
|
<input type="number" name="attr_exp_remaining" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>EXP Status</label>
|
|
<input type="text" name="attr_exp_status" readonly>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource-adjust exp-adjust">
|
|
<input type="number" name="attr_exp_adjust" value="0" placeholder="EXP Amount">
|
|
<button type="action" name="act_exp_subtract">- EXP</button>
|
|
<button type="action" name="act_exp_add">+ EXP</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="resource-bar">
|
|
|
|
<div class="resource hp">
|
|
<label>HP</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_hp_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_hp_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_hp_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_hp_subtract">- HP</button>
|
|
<button type="action" name="act_hp_add">+ HP</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource mp">
|
|
<label>MP</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_mp_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_mp_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_mp_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_mp_subtract">- MP</button>
|
|
<button type="action" name="act_mp_add">+ MP</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource limit">
|
|
<label>Limit</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_limit_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_limit_max" value="100">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_limit_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_limit_subtract">- Limit</button>
|
|
<button type="action" name="act_limit_add">+ Limit</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="overview-grid">
|
|
|
|
<div class="ff7-card">
|
|
<h2>Lineage</h2>
|
|
|
|
<label>Race</label>
|
|
<select name="attr_race">
|
|
<option value="Hume">Hume</option>
|
|
<option value="Miqo'te">Miqo'te</option>
|
|
<option value="Elezen">Elezen</option>
|
|
<option value="Lalafell">Lalafell</option>
|
|
<option value="Roegadyn">Roegadyn</option>
|
|
<option value="Viera">Viera</option>
|
|
<option value="Au Ra">Au Ra</option>
|
|
<option value="Hrothgar">Hrothgar</option>
|
|
<option value="Moogle">Moogle</option>
|
|
<option value="Bangaa">Bangaa</option>
|
|
<option value="Al Bhed">Al Bhed</option>
|
|
<option value="Cetra">Cetra</option>
|
|
<option value="Burmecian">Burmecian</option>
|
|
<option value="Guado">Guado</option>
|
|
<option value="Nu Mou">Nu Mou</option>
|
|
<option value="Dwarf">Dwarf</option>
|
|
<option value="Garlean">Garlean</option>
|
|
<option value="Hybrid">Hybrid / Custom Lineage</option>
|
|
</select>
|
|
|
|
<label>Race Variant / Clan</label>
|
|
<select name="attr_race_variant">
|
|
<option value="">None / Default</option>
|
|
<option value="Midlander">Hume - Midlander</option>
|
|
<option value="Highlander">Hume - Highlander</option>
|
|
<option value="Seeker">Miqo'te - Seeker of the Sun</option>
|
|
<option value="Keeper">Miqo'te - Keeper of the Moon</option>
|
|
<option value="Wildwood">Elezen - Wildwood</option>
|
|
<option value="Duskwight">Elezen - Duskwight</option>
|
|
<option value="Rava">Viera - Rava</option>
|
|
<option value="Veena">Viera - Veena</option>
|
|
<option value="Raen">Au Ra - Raen</option>
|
|
<option value="Xaela">Au Ra - Xaela</option>
|
|
<option value="Tholl">Dwarf - Tholl Clan</option>
|
|
<option value="Gogg">Dwarf - Gogg Clan</option>
|
|
</select>
|
|
|
|
<div class="choice-grid">
|
|
<div>
|
|
<label>Bonus Choice 1</label>
|
|
<select name="attr_race_choice_1">
|
|
<option value="">None</option>
|
|
<option value="strength">STR</option>
|
|
<option value="dexterity">DEX</option>
|
|
<option value="constitution">CON</option>
|
|
<option value="intelligence">INT</option>
|
|
<option value="wisdom">WIS</option>
|
|
<option value="charisma">CHA</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Bonus Choice 2</label>
|
|
<select name="attr_race_choice_2">
|
|
<option value="">None</option>
|
|
<option value="strength">STR</option>
|
|
<option value="dexterity">DEX</option>
|
|
<option value="constitution">CON</option>
|
|
<option value="intelligence">INT</option>
|
|
<option value="wisdom">WIS</option>
|
|
<option value="charisma">CHA</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Race Features</label>
|
|
<textarea name="attr_race_features" placeholder="Race features, custom lineage notes, homebrew edits, or DM rulings."></textarea>
|
|
|
|
<label>Row</label>
|
|
<select name="attr_row_position">
|
|
<option value="vanguard">Vanguard</option>
|
|
<option value="rearguard">Rearguard</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Attributes</h2>
|
|
|
|
<div class="stat-grid">
|
|
<div>
|
|
<label>STR Base</label>
|
|
<input type="number" name="attr_strength" value="10">
|
|
<span name="attr_strength_mod"></span>
|
|
</div>
|
|
|
|
<div>
|
|
<label>DEX Base</label>
|
|
<input type="number" name="attr_dexterity" value="10">
|
|
<span name="attr_dexterity_mod"></span>
|
|
</div>
|
|
|
|
<div>
|
|
<label>CON Base</label>
|
|
<input type="number" name="attr_constitution" value="10">
|
|
<span name="attr_constitution_mod"></span>
|
|
</div>
|
|
|
|
<div>
|
|
<label>INT Base</label>
|
|
<input type="number" name="attr_intelligence" value="10">
|
|
<span name="attr_intelligence_mod"></span>
|
|
</div>
|
|
|
|
<div>
|
|
<label>WIS Base</label>
|
|
<input type="number" name="attr_wisdom" value="10">
|
|
<span name="attr_wisdom_mod"></span>
|
|
</div>
|
|
|
|
<div>
|
|
<label>CHA Base</label>
|
|
<input type="number" name="attr_charisma" value="10">
|
|
<span name="attr_charisma_mod"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hidden effective totals still exist for automation, but are not displayed. -->
|
|
<input type="hidden" name="attr_strength_total">
|
|
<input type="hidden" name="attr_dexterity_total">
|
|
<input type="hidden" name="attr_constitution_total">
|
|
<input type="hidden" name="attr_intelligence_total">
|
|
<input type="hidden" name="attr_wisdom_total">
|
|
<input type="hidden" name="attr_charisma_total">
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Derived Stats</h2>
|
|
|
|
<div class="derived-grid">
|
|
<div>
|
|
<label>Proficiency</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_proficiency_bonus" value="2">
|
|
<span name="attr_proficiency_bonus"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Armor Class</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_ac">
|
|
<span name="attr_ac"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Speed</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_speed">
|
|
<span name="attr_speed"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Fly Speed</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_fly_speed" readonly>
|
|
<span name="attr_fly_speed"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Chassis</label>
|
|
<input type="text" name="attr_chassis">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Hit Die</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_hit_die">
|
|
<span>d<span name="attr_hit_die"></span></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Initiative</label>
|
|
<div class="initiative-row">
|
|
<input type="number" name="attr_initiative">
|
|
|
|
<button type="roll" name="roll_character_initiative" value="!ff5e-card-init "@{character_id}" "@{character_name}" "Character" @{initiative}">
|
|
Roll Initiative
|
|
</button>
|
|
</div>
|
|
|
|
<label>Aetherial Ineptitude</label>
|
|
<input type="text" name="attr_aetherial_ineptitude" readonly>
|
|
|
|
<label>Limit Ready?</label>
|
|
<input type="text" name="attr_limit_ready" readonly>
|
|
</div>
|
|
|
|
<div class="ff7-card checks-card">
|
|
<h2>Checks, Saves & Skills</h2>
|
|
|
|
<h3>Ability Checks</h3>
|
|
|
|
<p class="sheet-help">
|
|
Ability checks can now use proficiency or expertise. This is useful for custom job features, tools, lore checks, or special campaign rules.
|
|
</p>
|
|
|
|
<div class="ability-check-grid">
|
|
|
|
<div class="ability-check-row header-row">
|
|
<span>Check</span>
|
|
<span>Prof</span>
|
|
<span>Expert</span>
|
|
<span>Misc</span>
|
|
<span>Total</span>
|
|
<span>Roll</span>
|
|
</div>
|
|
|
|
<div class="ability-check-row">
|
|
<span>STR Check</span>
|
|
<label><input type="checkbox" name="attr_check_strength_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_check_strength_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_check_strength_bonus" value="0">
|
|
<input type="number" name="attr_check_strength_total" readonly>
|
|
<button type="roll" name="roll_strength_check" value="!ff5e-card-d20 "@{character_name}" "Strength Check" "Ability Check" @{check_strength_total} "Strength ability check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="ability-check-row">
|
|
<span>DEX Check</span>
|
|
<label><input type="checkbox" name="attr_check_dexterity_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_check_dexterity_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_check_dexterity_bonus" value="0">
|
|
<input type="number" name="attr_check_dexterity_total" readonly>
|
|
<button type="roll" name="roll_dexterity_check" value="!ff5e-card-d20 "@{character_name}" "Dexterity Check" "Ability Check" @{check_dexterity_total} "Dexterity ability check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="ability-check-row">
|
|
<span>CON Check</span>
|
|
<label><input type="checkbox" name="attr_check_constitution_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_check_constitution_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_check_constitution_bonus" value="0">
|
|
<input type="number" name="attr_check_constitution_total" readonly>
|
|
<button type="roll" name="roll_constitution_check" value="!ff5e-card-d20 "@{character_name}" "Constitution Check" "Ability Check" @{check_constitution_total} "Constitution ability check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="ability-check-row">
|
|
<span>INT Check</span>
|
|
<label><input type="checkbox" name="attr_check_intelligence_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_check_intelligence_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_check_intelligence_bonus" value="0">
|
|
<input type="number" name="attr_check_intelligence_total" readonly>
|
|
<button type="roll" name="roll_intelligence_check" value="!ff5e-card-d20 "@{character_name}" "Intelligence Check" "Ability Check" @{check_intelligence_total} "Intelligence ability check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="ability-check-row">
|
|
<span>WIS Check</span>
|
|
<label><input type="checkbox" name="attr_check_wisdom_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_check_wisdom_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_check_wisdom_bonus" value="0">
|
|
<input type="number" name="attr_check_wisdom_total" readonly>
|
|
<button type="roll" name="roll_wisdom_check" value="!ff5e-card-d20 "@{character_name}" "Wisdom Check" "Ability Check" @{check_wisdom_total} "Wisdom ability check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="ability-check-row">
|
|
<span>CHA Check</span>
|
|
<label><input type="checkbox" name="attr_check_charisma_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_check_charisma_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_check_charisma_bonus" value="0">
|
|
<input type="number" name="attr_check_charisma_total" readonly>
|
|
<button type="roll" name="roll_charisma_check" value="!ff5e-card-d20 "@{character_name}" "Charisma Check" "Ability Check" @{check_charisma_total} "Charisma ability check."">Roll</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<h3>Saving Throws</h3>
|
|
|
|
<div class="save-grid">
|
|
<div class="save-row header-row">
|
|
<span>Save</span>
|
|
<span>Prof</span>
|
|
<span>Misc</span>
|
|
<span>Total</span>
|
|
<span>Roll</span>
|
|
</div>
|
|
|
|
<div class="save-row">
|
|
<span>STR Save</span>
|
|
<label><input type="checkbox" name="attr_save_strength_prof" value="1"> Prof</label>
|
|
<input type="number" name="attr_save_strength_bonus" value="0">
|
|
<input type="number" name="attr_save_strength_total" readonly>
|
|
<button type="roll" name="roll_strength_save" value="!ff5e-card-d20 "@{character_name}" "Strength Save" "Saving Throw" @{save_strength_total} "Strength saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div class="save-row">
|
|
<span>DEX Save</span>
|
|
<label><input type="checkbox" name="attr_save_dexterity_prof" value="1"> Prof</label>
|
|
<input type="number" name="attr_save_dexterity_bonus" value="0">
|
|
<input type="number" name="attr_save_dexterity_total" readonly>
|
|
<button type="roll" name="roll_dexterity_save" value="!ff5e-card-d20 "@{character_name}" "Dexterity Save" "Saving Throw" @{save_dexterity_total} "Dexterity saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div class="save-row">
|
|
<span>CON Save</span>
|
|
<label><input type="checkbox" name="attr_save_constitution_prof" value="1"> Prof</label>
|
|
<input type="number" name="attr_save_constitution_bonus" value="0">
|
|
<input type="number" name="attr_save_constitution_total" readonly>
|
|
<button type="roll" name="roll_constitution_save" value="!ff5e-card-d20 "@{character_name}" "Constitution Save" "Saving Throw" @{save_constitution_total} "Constitution saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div class="save-row">
|
|
<span>INT Save</span>
|
|
<label><input type="checkbox" name="attr_save_intelligence_prof" value="1"> Prof</label>
|
|
<input type="number" name="attr_save_intelligence_bonus" value="0">
|
|
<input type="number" name="attr_save_intelligence_total" readonly>
|
|
<button type="roll" name="roll_intelligence_save" value="!ff5e-card-d20 "@{character_name}" "Intelligence Save" "Saving Throw" @{save_intelligence_total} "Intelligence saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div class="save-row">
|
|
<span>WIS Save</span>
|
|
<label><input type="checkbox" name="attr_save_wisdom_prof" value="1"> Prof</label>
|
|
<input type="number" name="attr_save_wisdom_bonus" value="0">
|
|
<input type="number" name="attr_save_wisdom_total" readonly>
|
|
<button type="roll" name="roll_wisdom_save" value="!ff5e-card-d20 "@{character_name}" "Wisdom Save" "Saving Throw" @{save_wisdom_total} "Wisdom saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div class="save-row">
|
|
<span>CHA Save</span>
|
|
<label><input type="checkbox" name="attr_save_charisma_prof" value="1"> Prof</label>
|
|
<input type="number" name="attr_save_charisma_bonus" value="0">
|
|
<input type="number" name="attr_save_charisma_total" readonly>
|
|
<button type="roll" name="roll_charisma_save" value="!ff5e-card-d20 "@{character_name}" "Charisma Save" "Saving Throw" @{save_charisma_total} "Charisma saving throw."">Roll</button>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Skills</h3>
|
|
|
|
<p class="sheet-help">
|
|
Skill totals update from the ability modifier, proficiency bonus, proficiency checkbox, expertise checkbox, and misc bonus.
|
|
</p>
|
|
|
|
<div class="skill-auto-grid">
|
|
|
|
<div class="skill-auto-row header-row">
|
|
<span>Skill</span>
|
|
<span>Prof</span>
|
|
<span>Expert</span>
|
|
<span>Misc</span>
|
|
<span>Total</span>
|
|
<span>Roll</span>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Acrobatics <small>DEX</small></span>
|
|
<label><input type="checkbox" name="attr_skill_acrobatics_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_acrobatics_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_acrobatics_bonus" value="0">
|
|
<input type="number" name="attr_skill_acrobatics" readonly>
|
|
<button type="roll" name="roll_skill_acrobatics" value="!ff5e-card-d20 "@{character_name}" "Acrobatics" "Skill Check" @{skill_acrobatics} "Dexterity skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Animal Handling <small>WIS</small></span>
|
|
<label><input type="checkbox" name="attr_skill_animal_handling_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_animal_handling_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_animal_handling_bonus" value="0">
|
|
<input type="number" name="attr_skill_animal_handling" readonly>
|
|
<button type="roll" name="roll_skill_animal_handling" value="!ff5e-card-d20 "@{character_name}" "Animal Handling" "Skill Check" @{skill_animal_handling} "Wisdom skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Arcana <small>INT</small></span>
|
|
<label><input type="checkbox" name="attr_skill_arcana_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_arcana_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_arcana_bonus" value="0">
|
|
<input type="number" name="attr_skill_arcana" readonly>
|
|
<button type="roll" name="roll_skill_arcana" value="!ff5e-card-d20 "@{character_name}" "Arcana" "Skill Check" @{skill_arcana} "Intelligence skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Athletics <small>STR</small></span>
|
|
<label><input type="checkbox" name="attr_skill_athletics_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_athletics_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_athletics_bonus" value="0">
|
|
<input type="number" name="attr_skill_athletics" readonly>
|
|
<button type="roll" name="roll_skill_athletics" value="!ff5e-card-d20 "@{character_name}" "Athletics" "Skill Check" @{skill_athletics} "Strength skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Deception <small>CHA</small></span>
|
|
<label><input type="checkbox" name="attr_skill_deception_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_deception_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_deception_bonus" value="0">
|
|
<input type="number" name="attr_skill_deception" readonly>
|
|
<button type="roll" name="roll_skill_deception" value="!ff5e-card-d20 "@{character_name}" "Deception" "Skill Check" @{skill_deception} "Charisma skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>History <small>INT</small></span>
|
|
<label><input type="checkbox" name="attr_skill_history_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_history_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_history_bonus" value="0">
|
|
<input type="number" name="attr_skill_history" readonly>
|
|
<button type="roll" name="roll_skill_history" value="!ff5e-card-d20 "@{character_name}" "History" "Skill Check" @{skill_history} "Intelligence skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Insight <small>WIS</small></span>
|
|
<label><input type="checkbox" name="attr_skill_insight_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_insight_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_insight_bonus" value="0">
|
|
<input type="number" name="attr_skill_insight" readonly>
|
|
<button type="roll" name="roll_skill_insight" value="!ff5e-card-d20 "@{character_name}" "Insight" "Skill Check" @{skill_insight} "Wisdom skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Intimidation <small>CHA</small></span>
|
|
<label><input type="checkbox" name="attr_skill_intimidation_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_intimidation_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_intimidation_bonus" value="0">
|
|
<input type="number" name="attr_skill_intimidation" readonly>
|
|
<button type="roll" name="roll_skill_intimidation" value="!ff5e-card-d20 "@{character_name}" "Intimidation" "Skill Check" @{skill_intimidation} "Charisma skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Investigation <small>INT</small></span>
|
|
<label><input type="checkbox" name="attr_skill_investigation_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_investigation_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_investigation_bonus" value="0">
|
|
<input type="number" name="attr_skill_investigation" readonly>
|
|
<button type="roll" name="roll_skill_investigation" value="!ff5e-card-d20 "@{character_name}" "Investigation" "Skill Check" @{skill_investigation} "Intelligence skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Medicine <small>WIS</small></span>
|
|
<label><input type="checkbox" name="attr_skill_medicine_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_medicine_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_medicine_bonus" value="0">
|
|
<input type="number" name="attr_skill_medicine" readonly>
|
|
<button type="roll" name="roll_skill_medicine" value="!ff5e-card-d20 "@{character_name}" "Medicine" "Skill Check" @{skill_medicine} "Wisdom skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Nature <small>INT</small></span>
|
|
<label><input type="checkbox" name="attr_skill_nature_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_nature_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_nature_bonus" value="0">
|
|
<input type="number" name="attr_skill_nature" readonly>
|
|
<button type="roll" name="roll_skill_nature" value="!ff5e-card-d20 "@{character_name}" "Nature" "Skill Check" @{skill_nature} "Intelligence skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Perception <small>WIS</small></span>
|
|
<label><input type="checkbox" name="attr_skill_perception_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_perception_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_perception_bonus" value="0">
|
|
<input type="number" name="attr_skill_perception" readonly>
|
|
<button type="roll" name="roll_skill_perception" value="!ff5e-card-d20 "@{character_name}" "Perception" "Skill Check" @{skill_perception} "Wisdom skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Performance <small>CHA</small></span>
|
|
<label><input type="checkbox" name="attr_skill_performance_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_performance_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_performance_bonus" value="0">
|
|
<input type="number" name="attr_skill_performance" readonly>
|
|
<button type="roll" name="roll_skill_performance" value="!ff5e-card-d20 "@{character_name}" "Performance" "Skill Check" @{skill_performance} "Charisma skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Persuasion <small>CHA</small></span>
|
|
<label><input type="checkbox" name="attr_skill_persuasion_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_persuasion_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_persuasion_bonus" value="0">
|
|
<input type="number" name="attr_skill_persuasion" readonly>
|
|
<button type="roll" name="roll_skill_persuasion" value="!ff5e-card-d20 "@{character_name}" "Persuasion" "Skill Check" @{skill_persuasion} "Charisma skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Religion <small>INT</small></span>
|
|
<label><input type="checkbox" name="attr_skill_religion_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_religion_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_religion_bonus" value="0">
|
|
<input type="number" name="attr_skill_religion" readonly>
|
|
<button type="roll" name="roll_skill_religion" value="!ff5e-card-d20 "@{character_name}" "Religion" "Skill Check" @{skill_religion} "Intelligence skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Sleight of Hand <small>DEX</small></span>
|
|
<label><input type="checkbox" name="attr_skill_sleight_of_hand_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_sleight_of_hand_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_sleight_of_hand_bonus" value="0">
|
|
<input type="number" name="attr_skill_sleight_of_hand" readonly>
|
|
<button type="roll" name="roll_skill_sleight_of_hand" value="!ff5e-card-d20 "@{character_name}" "Sleight of Hand" "Skill Check" @{skill_sleight_of_hand} "Dexterity skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Stealth <small>DEX</small></span>
|
|
<label><input type="checkbox" name="attr_skill_stealth_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_stealth_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_stealth_bonus" value="0">
|
|
<input type="number" name="attr_skill_stealth" readonly>
|
|
<button type="roll" name="roll_skill_stealth" value="!ff5e-card-d20 "@{character_name}" "Stealth" "Skill Check" @{skill_stealth} "Dexterity skill check."">Roll</button>
|
|
</div>
|
|
|
|
<div class="skill-auto-row">
|
|
<span>Survival <small>WIS</small></span>
|
|
<label><input type="checkbox" name="attr_skill_survival_prof" value="1"> Prof</label>
|
|
<label><input type="checkbox" name="attr_skill_survival_expert" value="1"> Expert</label>
|
|
<input type="number" name="attr_skill_survival_bonus" value="0">
|
|
<input type="number" name="attr_skill_survival" readonly>
|
|
<button type="roll" name="roll_skill_survival" value="!ff5e-card-d20 "@{character_name}" "Survival" "Skill Check" @{skill_survival} "Wisdom skill check."">Roll</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
CP ENGINE TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-cp">
|
|
<div class="ff7-card">
|
|
<h2>Customization Points</h2>
|
|
|
|
<div class="cp-grid">
|
|
<div>
|
|
<label>Baseline CP</label>
|
|
<input type="number" name="attr_cp_baseline" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Racial CP Bonus</label>
|
|
<input type="number" name="attr_racial_cp_bonus" value="0" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Chassis CP Bonus</label>
|
|
<input type="number" name="attr_chassis_cp_bonus" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Defect CP Bonus</label>
|
|
<input type="number" name="attr_defect_cp_bonus" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Total CP</label>
|
|
<input type="number" name="attr_cp_total" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Spent CP</label>
|
|
<input type="number" name="attr_cp_spent" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Remaining CP</label>
|
|
<input type="number" name="attr_cp_remaining" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>CP Warning</label>
|
|
<input type="text" name="attr_cp_warning" readonly>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Purchased Attributes</h3>
|
|
|
|
<fieldset class="repeating_attributes">
|
|
<div class="repeat-row three">
|
|
<input type="text" name="attr_attribute_name" placeholder="Attribute Name">
|
|
<input type="number" name="attr_attribute_rank" placeholder="Rank">
|
|
<input type="number" name="attr_attribute_cost" placeholder="CP Cost">
|
|
<textarea name="attr_attribute_notes" placeholder="Attribute notes, upgrades, restrictions, or reminders."></textarea>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<h3>Defects</h3>
|
|
|
|
<fieldset class="repeating_defects">
|
|
<div class="repeat-row three">
|
|
<input type="text" name="attr_defect_name" placeholder="Defect Name">
|
|
<input type="number" name="attr_defect_rank" placeholder="Rank">
|
|
<input type="number" name="attr_defect_cp_gain" placeholder="CP Gain">
|
|
<textarea name="attr_defect_notes" placeholder="Defect notes and roleplay reminders."></textarea>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
COMBAT TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-combat">
|
|
<div class="ff7-card">
|
|
<h2>Weapon Attacks</h2>
|
|
|
|
<fieldset class="repeating_attacks">
|
|
<div class="repeat-row combat">
|
|
<input type="text" name="attr_attack_name" placeholder="Attack Name">
|
|
|
|
<select name="attr_attack_stat">
|
|
<option value="strength_mod">STR</option>
|
|
<option value="dexterity_mod">DEX</option>
|
|
<option value="intelligence_mod">INT</option>
|
|
<option value="wisdom_mod">WIS</option>
|
|
<option value="charisma_mod">CHA</option>
|
|
</select>
|
|
|
|
<select name="attr_attack_proficient">
|
|
<option value="1">Proficient</option>
|
|
<option value="0">Not Proficient</option>
|
|
</select>
|
|
|
|
<input type="number" name="attr_attack_weapon_bonus" placeholder="Weapon Bonus" value="0">
|
|
<input type="number" name="attr_attack_total_bonus" placeholder="Total Bonus" readonly>
|
|
<input type="text" name="attr_attack_damage" placeholder="Damage Dice">
|
|
|
|
<input type="text" name="attr_attack_damage_type" placeholder="Damage Type / Notes">
|
|
<input type="text" name="attr_attack_element" placeholder="Element / Tags">
|
|
<textarea name="attr_attack_notes" placeholder="Attack description, effects, properties, ammo, crit notes, or special rules."></textarea>
|
|
|
|
<button type="roll" name="roll_weapon_attack" value="!ff5e-card-attack "@{character_name}" "@{attack_name}" "Weapon Attack" @{attack_total_bonus} "@{attack_damage}" 0 "@{attack_notes}"">
|
|
Attack
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Techniques</h2>
|
|
|
|
<fieldset class="repeating_techniques">
|
|
<div class="repeat-row technique">
|
|
<input type="text" name="attr_tech_name" placeholder="Technique Name">
|
|
<input type="text" name="attr_tech_job" placeholder="Job">
|
|
<input type="number" name="attr_tech_cp_rank" placeholder="Rank">
|
|
<input type="text" name="attr_tech_cost" placeholder="Cost">
|
|
<input type="text" name="attr_tech_roll" placeholder="Roll Formula">
|
|
<textarea name="attr_tech_description" placeholder="Technique description, timing, target rules, upgrades, and effects."></textarea>
|
|
|
|
<button type="roll" name="roll_technique" value="!ff5e-card-power "@{character_name}" "@{tech_name}" "Technique" "@{tech_roll}" "@{tech_cost}" "Technique Effect" "@{tech_description}"">
|
|
Use
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Limit Breaks</h2>
|
|
|
|
<fieldset class="repeating_limits">
|
|
<div class="repeat-row technique">
|
|
<input type="text" name="attr_limit_name" placeholder="Limit Break Name">
|
|
|
|
<select name="attr_limit_type">
|
|
<option value="Offensive">Offensive</option>
|
|
<option value="Defensive">Defensive</option>
|
|
<option value="Healing">Healing</option>
|
|
<option value="Summon">Summon</option>
|
|
<option value="Transformation">Transformation</option>
|
|
</select>
|
|
|
|
<input type="number" name="attr_limit_cost" placeholder="Gauge Cost" value="100">
|
|
<input type="text" name="attr_limit_roll" placeholder="Roll Formula">
|
|
<textarea name="attr_limit_description" placeholder="Limit Break effects, targeting, duration, and cinematic description."></textarea>
|
|
|
|
<button type="roll" name="roll_limit_break" value="!ff5e-card-power "@{character_name}" "@{limit_name}" "@{limit_type} Limit Break" "@{limit_roll}" "@{limit_cost} Limit" "Limit Effect" "@{limit_description}"">
|
|
LIMIT
|
|
</button>
|
|
|
|
<button type="roll" name="roll_limit_api" value="!ff5e-limit-use @{selected|token_id} "@{limit_name}" @{limit_cost}">
|
|
Spend
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
<!-- =========================
|
|
MAGIC / MATERIA / SUMMONS TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-magic">
|
|
|
|
<div class="ff7-card">
|
|
<h2>Spellcasting</h2>
|
|
|
|
<div class="spellcasting-grid">
|
|
<div>
|
|
<label>Spellcasting Ability</label>
|
|
<select name="attr_spellcasting_ability">
|
|
<option value="intelligence_mod">Intelligence</option>
|
|
<option value="wisdom_mod">Wisdom</option>
|
|
<option value="charisma_mod">Charisma</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Spellcasting Modifier</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_spellcasting_mod" readonly>
|
|
<span name="attr_spellcasting_mod"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Spell Attack Bonus</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_spell_attack_bonus" readonly>
|
|
<span name="attr_spell_attack_bonus"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Spell Save DC</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_spell_save_dc" readonly>
|
|
<span name="attr_spell_save_dc"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Racial MP Bonus</label>
|
|
<input type="number" name="attr_racial_mp_bonus" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Materia MP Bonus</label>
|
|
<input type="number" name="attr_materia_mp_bonus" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Total MP Bonus</label>
|
|
<input type="number" name="attr_total_mp_bonus" readonly>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Spells</h2>
|
|
|
|
<fieldset class="repeating_spells">
|
|
<div class="repeat-row spell">
|
|
<input type="text" name="attr_spell_name" placeholder="Spell Name">
|
|
|
|
<select name="attr_spell_source">
|
|
<option value="Job">Job</option>
|
|
<option value="Materia">Materia</option>
|
|
<option value="Race">Race</option>
|
|
<option value="Summon">Summon</option>
|
|
<option value="Item">Item</option>
|
|
<option value="Other">Other</option>
|
|
</select>
|
|
|
|
<input type="number" name="attr_spell_mp_cost" placeholder="MP Cost" value="0">
|
|
<input type="text" name="attr_spell_element" placeholder="Element / Detail">
|
|
<input type="text" name="attr_spell_range" placeholder="Range / Area">
|
|
<input type="text" name="attr_spell_roll" placeholder="Damage / Healing / Effect Roll">
|
|
|
|
<select name="attr_spell_roll_type">
|
|
<option value="Spell Effect">Spell Effect</option>
|
|
<option value="Spell Attack">Spell Attack</option>
|
|
<option value="Spell Save">Spell Save</option>
|
|
<option value="Healing">Healing</option>
|
|
<option value="Buff">Buff</option>
|
|
<option value="Debuff">Debuff</option>
|
|
</select>
|
|
|
|
<input type="text" name="attr_spell_save" placeholder="Save / DC">
|
|
<input type="text" name="attr_spell_linked_materia" placeholder="Linked Materia">
|
|
<input type="text" name="attr_spell_unlocked" placeholder="Unlocked?" readonly>
|
|
|
|
<textarea name="attr_spell_description" placeholder="Spell description, upcast effects, conditions, targeting, and special notes."></textarea>
|
|
|
|
<div class="button-strip">
|
|
<button type="roll" name="roll_spell" value="!ff5e-card-power "@{character_name}" "@{spell_name}" "@{spell_roll_type}" "@{spell_roll}" "@{spell_mp_cost}" "@{spell_element} | @{spell_save} | @{spell_range}" "@{spell_description}"">
|
|
Card
|
|
</button>
|
|
|
|
<button type="roll" name="roll_spell_attack_card" value="!ff5e-card-attack "@{character_name}" "@{spell_name}" "Spell Attack" @{spell_attack_bonus} "@{spell_roll}" @{spell_mp_cost} "@{spell_description}"">
|
|
Attack
|
|
</button>
|
|
|
|
<button type="roll" name="roll_spell_spend_mp" value="!ff5e-mp spend @{selected|token_id} @{spell_mp_cost}">
|
|
Spend MP
|
|
</button>
|
|
|
|
<button type="roll" name="roll_spell_full_api" value="!ff5e-cast @{selected|token_id} "@{spell_name}" @{spell_mp_cost} "@{spell_element}" "@{spell_roll}"">
|
|
Cast
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Materia Slots</h2>
|
|
|
|
<p class="sheet-help">
|
|
Equipped Materia can grant spells, MP bonuses, stat bonuses, linked effects, and support effects.
|
|
</p>
|
|
|
|
<fieldset class="repeating_materia">
|
|
<div class="repeat-row materia-advanced">
|
|
<input type="text" name="attr_materia_name" placeholder="Materia Name">
|
|
|
|
<select name="attr_materia_type">
|
|
<option value="Magic">Magic</option>
|
|
<option value="Command">Command</option>
|
|
<option value="Support">Support</option>
|
|
<option value="Independent">Independent</option>
|
|
<option value="Summon">Summon</option>
|
|
</select>
|
|
|
|
<select name="attr_materia_equipped">
|
|
<option value="1">Equipped</option>
|
|
<option value="0">Not Equipped</option>
|
|
</select>
|
|
|
|
<input type="text" name="attr_materia_slot" placeholder="Slot ID">
|
|
<input type="text" name="attr_materia_linked_slot" placeholder="Linked Slot ID">
|
|
|
|
<input type="number" name="attr_materia_level" placeholder="Level" value="1">
|
|
<input type="number" name="attr_materia_ap" placeholder="Current AP" value="0">
|
|
<input type="number" name="attr_materia_next_ap" placeholder="Next Level AP" value="100">
|
|
|
|
<input type="text" name="attr_materia_grants_spell" placeholder="Granted Spell">
|
|
<input type="number" name="attr_materia_mp_bonus" placeholder="MP Bonus" value="0">
|
|
|
|
<input type="number" name="attr_materia_str_bonus" placeholder="STR Bonus" value="0">
|
|
<input type="number" name="attr_materia_dex_bonus" placeholder="DEX Bonus" value="0">
|
|
<input type="number" name="attr_materia_con_bonus" placeholder="CON Bonus" value="0">
|
|
<input type="number" name="attr_materia_int_bonus" placeholder="INT Bonus" value="0">
|
|
<input type="number" name="attr_materia_wis_bonus" placeholder="WIS Bonus" value="0">
|
|
<input type="number" name="attr_materia_cha_bonus" placeholder="CHA Bonus" value="0">
|
|
|
|
<input type="text" name="attr_materia_link_effect" placeholder="Linked Effect">
|
|
<textarea name="attr_materia_effect" placeholder="Materia effect, linked effect, AP notes, upgrades, and restrictions."></textarea>
|
|
|
|
<button type="roll" name="roll_materia_effect" value="!ff5e-card-power "@{character_name}" "@{materia_name}" "Materia Effect" "0" "0" "@{materia_type} | Level @{materia_level}" "@{materia_effect}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Summons</h2>
|
|
|
|
<fieldset class="repeating_summons">
|
|
<div class="repeat-row summon">
|
|
<input type="text" name="attr_summon_name" placeholder="Summon Name">
|
|
<input type="number" name="attr_summon_mp_cost" placeholder="MP Cost" value="0">
|
|
<input type="text" name="attr_summon_element" placeholder="Element / Detail">
|
|
<input type="number" name="attr_summon_duration_rounds" placeholder="Duration Rounds" value="3">
|
|
<input type="text" name="attr_summon_roll" placeholder="Signature Roll / Damage">
|
|
<input type="text" name="attr_summon_range" placeholder="Range / Area">
|
|
|
|
<textarea name="attr_summon_description" placeholder="Summon description, signature attack, passive aura, duration rules, and exit effect."></textarea>
|
|
|
|
<div class="button-strip">
|
|
<button type="roll" name="roll_summon" value="!ff5e-card-power "@{character_name}" "@{summon_name}" "Summon" "@{summon_roll}" "@{summon_mp_cost}" "@{summon_element} | Duration @{summon_duration_rounds} rounds | @{summon_range}" "@{summon_description}"">
|
|
Card
|
|
</button>
|
|
|
|
<button type="roll" name="roll_summon_attack_card" value="!ff5e-card-attack "@{character_name}" "@{summon_name}" "Summon Attack" @{spell_attack_bonus} "@{summon_roll}" @{summon_mp_cost} "@{summon_description}"">
|
|
Attack
|
|
</button>
|
|
|
|
<button type="roll" name="roll_summon_api" value="!ff5e-summon-cast @{selected|token_id} "@{summon_name}" @{summon_mp_cost} @{summon_duration_rounds}">
|
|
Cast
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
EQUIPMENT TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-equipment">
|
|
<div class="ff7-card">
|
|
<h2>Armor</h2>
|
|
|
|
<div class="equipment-grid">
|
|
<div>
|
|
<label>Armor Type</label>
|
|
<select name="attr_armor_type">
|
|
<option value="unarmored">Unarmored</option>
|
|
<option value="light">Light</option>
|
|
<option value="medium">Medium</option>
|
|
<option value="heavy">Heavy</option>
|
|
<option value="natural">Natural Armor</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Armor Base AC</label>
|
|
<input type="number" name="attr_armor_base_ac" value="10">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Natural AC Base</label>
|
|
<input type="number" name="attr_natural_ac_base" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Armor Bonus</label>
|
|
<input type="number" name="attr_armor_bonus" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Shield Bonus</label>
|
|
<input type="number" name="attr_shield_bonus" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Gear AC Bonus</label>
|
|
<input type="number" name="attr_gear_ac_bonus" value="0">
|
|
</div>
|
|
</div>
|
|
|
|
<label>Armor Notes</label>
|
|
<textarea name="attr_armor_notes" placeholder="Armor properties, shield rules, upgrades, resistance notes, or reminders."></textarea>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Weapons</h2>
|
|
|
|
<fieldset class="repeating_weapons">
|
|
<div class="repeat-row weapon">
|
|
<input type="text" name="attr_weapon_name" placeholder="Weapon Name">
|
|
<input type="text" name="attr_weapon_type" placeholder="Weapon Type">
|
|
<input type="text" name="attr_weapon_damage" placeholder="Damage Dice">
|
|
<input type="text" name="attr_weapon_element" placeholder="Element / Notes">
|
|
<input type="number" name="attr_weapon_bonus" placeholder="Bonus" value="0">
|
|
|
|
<textarea name="attr_weapon_notes" placeholder="Weapon properties, ammunition, materia slots, upgrades, special rules, and notes."></textarea>
|
|
|
|
<button type="roll" name="roll_weapon_info_card" value="!ff5e-card-power "@{character_name}" "@{weapon_name}" "Weapon Info" "0" "0" "@{weapon_type} | Bonus @{weapon_bonus} | Damage @{weapon_damage}" "@{weapon_notes}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Accessories</h2>
|
|
|
|
<fieldset class="repeating_accessories">
|
|
<div class="repeat-row accessory">
|
|
<input type="text" name="attr_accessory_name" placeholder="Accessory">
|
|
<input type="text" name="attr_accessory_slot" placeholder="Slot">
|
|
<input type="text" name="attr_accessory_effect" placeholder="Effect">
|
|
|
|
<textarea name="attr_accessory_notes" placeholder="Accessory rules, charges, passive effects, upgrades, and restrictions."></textarea>
|
|
|
|
<button type="roll" name="roll_accessory_card" value="!ff5e-card-power "@{character_name}" "@{accessory_name}" "Accessory" "0" "0" "@{accessory_slot} | @{accessory_effect}" "@{accessory_notes}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Inventory</h2>
|
|
|
|
<fieldset class="repeating_inventory">
|
|
<div class="repeat-row inventory">
|
|
<input type="text" name="attr_item_name" placeholder="Item">
|
|
<input type="number" name="attr_item_qty" placeholder="Qty" value="1">
|
|
<input type="text" name="attr_item_type" placeholder="Type">
|
|
|
|
<textarea name="attr_item_notes" placeholder="Item effect, value, weight, crafting use, charges, or notes."></textarea>
|
|
|
|
<button type="roll" name="roll_item_card" value="!ff5e-card-power "@{character_name}" "@{item_name}" "Item" "0" "0" "Qty @{item_qty} | @{item_type}" "@{item_notes}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
STATUS / ELEMENTS TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-status">
|
|
<div class="ff7-card">
|
|
<h2>Elemental Affinities</h2>
|
|
|
|
<div class="element-grid">
|
|
<div class="element-row header">
|
|
<span>Element</span>
|
|
<span>Affinity</span>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Fire</label>
|
|
<select name="attr_affinity_fire">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Ice</label>
|
|
<select name="attr_affinity_ice">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Lightning</label>
|
|
<select name="attr_affinity_lightning">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Water</label>
|
|
<select name="attr_affinity_water">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Wind</label>
|
|
<select name="attr_affinity_wind">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Earth</label>
|
|
<select name="attr_affinity_earth">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Holy</label>
|
|
<select name="attr_affinity_holy">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Dark</label>
|
|
<select name="attr_affinity_dark">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Poison</label>
|
|
<select name="attr_affinity_poison">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Affinity Notes</label>
|
|
<textarea name="attr_affinity_notes" placeholder="Elemental rules, conditional weaknesses, resist changes, or campaign-specific notes."></textarea>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Status Effects</h2>
|
|
|
|
<div class="status-grid">
|
|
<label><input type="checkbox" name="attr_status_poison"> Poison</label>
|
|
<label><input type="checkbox" name="attr_status_silence"> Silence</label>
|
|
<label><input type="checkbox" name="attr_status_blind"> Blind</label>
|
|
<label><input type="checkbox" name="attr_status_berserk"> Berserk</label>
|
|
<label><input type="checkbox" name="attr_status_doom"> Doom</label>
|
|
<label><input type="checkbox" name="attr_status_slow"> Slow</label>
|
|
<label><input type="checkbox" name="attr_status_stop"> Stop</label>
|
|
<label><input type="checkbox" name="attr_status_petrify"> Petrify</label>
|
|
<label><input type="checkbox" name="attr_status_sleep"> Sleep</label>
|
|
<label><input type="checkbox" name="attr_status_confuse"> Confuse</label>
|
|
|
|
<label><input type="checkbox" name="attr_status_protect"> Protect</label>
|
|
<label><input type="checkbox" name="attr_status_shell"> Shell</label>
|
|
<label><input type="checkbox" name="attr_status_haste"> Haste</label>
|
|
<label><input type="checkbox" name="attr_status_regen"> Regen</label>
|
|
<label><input type="checkbox" name="attr_status_reflect"> Reflect</label>
|
|
<label><input type="checkbox" name="attr_status_float"> Float</label>
|
|
<label><input type="checkbox" name="attr_status_brave"> Brave</label>
|
|
<label><input type="checkbox" name="attr_status_faith"> Faith</label>
|
|
</div>
|
|
|
|
<label>Status Notes</label>
|
|
<textarea name="attr_status_notes" placeholder="Current conditions, remaining duration, concentration notes, status immunity, or reminders."></textarea>
|
|
|
|
<h3>Timed Status Helper</h3>
|
|
|
|
<fieldset class="repeating_statustimers">
|
|
<div class="repeat-row status-timer">
|
|
<input type="text" name="attr_timer_status_name" placeholder="Status Name">
|
|
<input type="number" name="attr_timer_rounds" placeholder="Rounds" value="1">
|
|
|
|
<button type="roll" name="roll_status_timer_api" value="!ff5e-status add @{selected|token_id} @{timer_status_name} @{timer_rounds}">
|
|
Timer
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
BIO TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-bio">
|
|
<div class="ff7-card">
|
|
<h2>Biography</h2>
|
|
|
|
<div class="bio-grid">
|
|
<div>
|
|
<label>Origin</label>
|
|
<input type="text" name="attr_origin">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Faction</label>
|
|
<input type="text" name="attr_faction">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Renown</label>
|
|
<input type="number" name="attr_renown">
|
|
</div>
|
|
</div>
|
|
|
|
<label>Languages</label>
|
|
<textarea name="attr_languages" placeholder="Languages, dialects, secret codes, regional speech, and translation notes."></textarea>
|
|
|
|
<label>Character Notes</label>
|
|
<textarea name="attr_character_notes" placeholder="Backstory, personality, bonds, flaws, goals, reputation, allies, enemies, and story hooks."></textarea>
|
|
|
|
<button type="roll" name="roll_bio_card" value="!ff5e-card-power "@{character_name}" "Character Bio" "Biography" "0" "0" "@{origin} | @{faction} | Renown @{renown}" "@{character_notes}"">
|
|
Bio Card
|
|
</button>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Holdings / Base</h2>
|
|
|
|
<div class="bio-grid">
|
|
<div>
|
|
<label>Holding Name</label>
|
|
<input type="text" name="attr_holding_name">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Holding Size</label>
|
|
<select name="attr_holding_size">
|
|
<option value="Tiny">Tiny</option>
|
|
<option value="Small">Small</option>
|
|
<option value="Medium">Medium</option>
|
|
<option value="Large">Large</option>
|
|
<option value="Massive">Massive</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Upgrade Slots</label>
|
|
<input type="number" name="attr_holding_slots">
|
|
</div>
|
|
</div>
|
|
|
|
<label>Holding Notes</label>
|
|
<textarea name="attr_holding_notes" placeholder="Base description, rooms, staff, services, income, defenses, downtime options, and upgrades."></textarea>
|
|
|
|
<button type="roll" name="roll_holding_card" value="!ff5e-card-power "@{character_name}" "@{holding_name}" "Holding / Base" "0" "0" "@{holding_size} | Slots @{holding_slots}" "@{holding_notes}"">
|
|
Holding Card
|
|
</button>
|
|
|
|
<fieldset class="repeating_holdings">
|
|
<div class="repeat-row holding">
|
|
<input type="text" name="attr_holding_upgrade_name" placeholder="Upgrade / Business">
|
|
<input type="number" name="attr_holding_rank" placeholder="Rank">
|
|
<input type="text" name="attr_holding_income" placeholder="Income Formula">
|
|
|
|
<textarea name="attr_holding_upgrade_notes" placeholder="Upgrade notes, benefits, staff, upkeep, and income details."></textarea>
|
|
|
|
<button type="roll" name="roll_holding_upgrade_card" value="!ff5e-card-power "@{character_name}" "@{holding_upgrade_name}" "Holding Upgrade" "@{holding_income}" "0" "Rank @{holding_rank}" "@{holding_upgrade_notes}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<!-- =========================
|
|
MONSTER MODE
|
|
========================== -->
|
|
|
|
<div class="mode-monster">
|
|
|
|
<div class="tab-buttons monster-tabs">
|
|
<button type="action" name="act_tab_monster_core">Core</button>
|
|
<button type="action" name="act_tab_monster_actions">Actions</button>
|
|
<button type="action" name="act_tab_monster_status">Weaknesses</button>
|
|
<button type="action" name="act_tab_monster_import">Import</button>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
MONSTER CORE TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-monster-core">
|
|
|
|
<div class="resource-bar">
|
|
|
|
<div class="resource hp">
|
|
<label>NPC HP</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_npc_hp_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_npc_hp_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_npc_hp_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_npc_hp_subtract">- HP</button>
|
|
<button type="action" name="act_npc_hp_add">+ HP</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource mp">
|
|
<label>NPC MP</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_npc_mp_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_npc_mp_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_npc_mp_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_npc_mp_subtract">- MP</button>
|
|
<button type="action" name="act_npc_mp_add">+ MP</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource limit">
|
|
<label>NPC Limit</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_npc_limit_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_npc_limit_max" value="100">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_npc_limit_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_npc_limit_subtract">- Limit</button>
|
|
<button type="action" name="act_npc_limit_add">+ Limit</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource">
|
|
<label>Boss Phase</label>
|
|
|
|
<div class="resource-main single-resource">
|
|
<input type="number" name="attr_boss_phase" value="1">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_boss_phase_adjust" value="1" placeholder="Phase">
|
|
<button type="action" name="act_boss_phase_subtract">- Phase</button>
|
|
<button type="action" name="act_boss_phase_add">+ Phase</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource">
|
|
<label>HP Percent</label>
|
|
|
|
<div class="resource-main single-resource">
|
|
<input type="number" name="attr_npc_hp_percent" readonly>
|
|
<span>%</span>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="overview-grid">
|
|
|
|
<div class="ff7-card">
|
|
<h2>Enemy Profile</h2>
|
|
|
|
<div class="monster-profile-grid">
|
|
<div>
|
|
<label>Name</label>
|
|
<input type="text" name="attr_npc_name" placeholder="Monster Name">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Enemy Type</label>
|
|
<select name="attr_npc_type">
|
|
<option value="Fiend">Fiend</option>
|
|
<option value="Machina">Machina</option>
|
|
<option value="Humanoid">Humanoid</option>
|
|
<option value="Beast">Beast</option>
|
|
<option value="Dragon">Dragon</option>
|
|
<option value="Undead">Undead</option>
|
|
<option value="Eidolon">Eidolon</option>
|
|
<option value="Primal">Primal</option>
|
|
<option value="Weapon">Weapon</option>
|
|
<option value="Construct">Construct</option>
|
|
<option value="Other">Other</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Level / CR</label>
|
|
<input type="number" name="attr_npc_level" value="1">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Proficiency</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_npc_proficiency_bonus" readonly>
|
|
<span name="attr_npc_proficiency_bonus"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Scale</label>
|
|
<select name="attr_npc_scale">
|
|
<option value="personal">Personal</option>
|
|
<option value="armor">Armor</option>
|
|
<option value="ship">Ship</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Armor Class</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_npc_ac" value="10">
|
|
<span name="attr_npc_ac"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Initiative</label>
|
|
<div class="initiative-row">
|
|
<input type="number" name="attr_npc_initiative" value="0">
|
|
|
|
<button type="roll" name="roll_npc_initiative" value="!ff5e-card-init "@{character_id}" "@{npc_name}" "Monster" @{npc_initiative}">
|
|
Initiative
|
|
</button>
|
|
</div>
|
|
|
|
<div class="monster-profile-grid">
|
|
<div>
|
|
<label>Speed</label>
|
|
<input type="text" name="attr_npc_speed" placeholder="30 ft., fly 60 ft., etc.">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Senses</label>
|
|
<input type="text" name="attr_npc_senses" placeholder="Darkvision, tremorsense, etc.">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Monster Quick Rolls</h2>
|
|
|
|
<p class="sheet-help">
|
|
These use the same themed card as player checks and saves.
|
|
</p>
|
|
|
|
<div class="quick-roll-grid">
|
|
<div>
|
|
<label>STR Bonus</label>
|
|
<input type="number" name="attr_npc_str_bonus" value="0">
|
|
<button type="roll" name="roll_npc_str_check" value="!ff5e-card-d20 "@{npc_name}" "Strength Roll" "Monster Check / Save" @{npc_str_bonus} "Monster Strength check or saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>DEX Bonus</label>
|
|
<input type="number" name="attr_npc_dex_bonus" value="0">
|
|
<button type="roll" name="roll_npc_dex_check" value="!ff5e-card-d20 "@{npc_name}" "Dexterity Roll" "Monster Check / Save" @{npc_dex_bonus} "Monster Dexterity check or saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>CON Bonus</label>
|
|
<input type="number" name="attr_npc_con_bonus" value="0">
|
|
<button type="roll" name="roll_npc_con_check" value="!ff5e-card-d20 "@{npc_name}" "Constitution Roll" "Monster Check / Save" @{npc_con_bonus} "Monster Constitution check or saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>INT Bonus</label>
|
|
<input type="number" name="attr_npc_int_bonus" value="0">
|
|
<button type="roll" name="roll_npc_int_check" value="!ff5e-card-d20 "@{npc_name}" "Intelligence Roll" "Monster Check / Save" @{npc_int_bonus} "Monster Intelligence check or saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>WIS Bonus</label>
|
|
<input type="number" name="attr_npc_wis_bonus" value="0">
|
|
<button type="roll" name="roll_npc_wis_check" value="!ff5e-card-d20 "@{npc_name}" "Wisdom Roll" "Monster Check / Save" @{npc_wis_bonus} "Monster Wisdom check or saving throw."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>CHA Bonus</label>
|
|
<input type="number" name="attr_npc_cha_bonus" value="0">
|
|
<button type="roll" name="roll_npc_cha_check" value="!ff5e-card-d20 "@{npc_name}" "Charisma Roll" "Monster Check / Save" @{npc_cha_bonus} "Monster Charisma check or saving throw."">Roll</button>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Custom Roll Name</label>
|
|
<input type="text" name="attr_npc_custom_roll_name" placeholder="Example: Perception">
|
|
|
|
<label>Custom Roll Bonus</label>
|
|
<input type="number" name="attr_npc_custom_roll_bonus" value="0">
|
|
|
|
<button type="roll" name="roll_npc_custom_check" value="!ff5e-card-d20 "@{npc_name}" "@{npc_custom_roll_name}" "Monster Custom Roll" @{npc_custom_roll_bonus} "Custom monster roll."">
|
|
Custom Roll
|
|
</button>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Boss Phase Engine</h2>
|
|
|
|
<div class="boss-grid">
|
|
<div>
|
|
<label>Suggested Phase</label>
|
|
<input type="number" name="attr_boss_phase_suggested" readonly>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Current AI State</label>
|
|
<select name="attr_npc_ai_state">
|
|
<option value="Normal">Normal</option>
|
|
<option value="Aggressive">Aggressive</option>
|
|
<option value="Defensive">Defensive</option>
|
|
<option value="Charging">Charging</option>
|
|
<option value="Enraged">Enraged</option>
|
|
<option value="Staggered">Staggered</option>
|
|
<option value="Scripted">Scripted</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Phase 2 Trigger</label>
|
|
<input type="text" name="attr_phase_2_trigger" value="50% HP">
|
|
|
|
<label>Phase 3 Trigger</label>
|
|
<input type="text" name="attr_phase_3_trigger" value="25% HP">
|
|
|
|
<label>Phase 4 / Enrage Trigger</label>
|
|
<input type="text" name="attr_enrage_trigger" value="10% HP">
|
|
|
|
<label>Boss Notes</label>
|
|
<textarea name="attr_boss_notes" placeholder="Boss behavior, phase scripts, legendary actions, reactions, lair effects, and encounter notes."></textarea>
|
|
|
|
<button type="roll" name="roll_boss_phase_card" value="!ff5e-card-power "@{npc_name}" "Boss Phase" "Boss State" "0" "0" "Current Phase @{boss_phase} | Suggested @{boss_phase_suggested} | HP @{npc_hp_percent}%" "@{boss_notes}"">
|
|
Phase Card
|
|
</button>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Defenses</h2>
|
|
|
|
<label>Saving Throws</label>
|
|
<textarea name="attr_npc_saves" placeholder="Example: STR +6, CON +5, WIS +3"></textarea>
|
|
|
|
<label>Skills</label>
|
|
<textarea name="attr_npc_skills" placeholder="Example: Perception +6, Athletics +8"></textarea>
|
|
|
|
<label>Resistances</label>
|
|
<textarea name="attr_npc_resistances" placeholder="Damage resistances and conditional resistance notes."></textarea>
|
|
|
|
<label>Immunities</label>
|
|
<textarea name="attr_npc_immunities" placeholder="Damage immunities."></textarea>
|
|
|
|
<label>Condition Immunities</label>
|
|
<textarea name="attr_npc_condition_immunities" placeholder="Poisoned, charmed, frightened, etc."></textarea>
|
|
|
|
<button type="roll" name="roll_npc_defense_card" value="!ff5e-card-power "@{npc_name}" "Defenses" "Monster Defense Profile" "0" "0" "AC @{npc_ac} | Saves @{npc_saves} | Skills @{npc_skills}" "Resistances: @{npc_resistances} | Immunities: @{npc_immunities} | Condition Immunities: @{npc_condition_immunities}"">
|
|
Defense Card
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
MONSTER ACTIONS TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-monster-actions">
|
|
<div class="ff7-card">
|
|
<h2>Enemy Actions</h2>
|
|
|
|
<fieldset class="repeating_npcactions">
|
|
<div class="repeat-row npc-action">
|
|
<input type="text" name="attr_npc_action_name" placeholder="Action Name">
|
|
|
|
<select name="attr_npc_action_category">
|
|
<option>Action</option>
|
|
<option>Bonus Action</option>
|
|
<option>Reaction</option>
|
|
<option>Legendary Action</option>
|
|
<option>Lair Action</option>
|
|
<option>Phase Action</option>
|
|
<option>Enrage Action</option>
|
|
<option>Counter</option>
|
|
</select>
|
|
|
|
<input type="text" name="attr_npc_action_type" placeholder="Attack Type / Save Type">
|
|
<input type="text" name="attr_npc_action_recharge" placeholder="Recharge, e.g. 5-6">
|
|
<input type="number" name="attr_npc_action_mp_cost" placeholder="MP Cost" value="0">
|
|
|
|
<input type="text" name="attr_npc_action_attack" placeholder="Attack Roll, e.g. 1d20+6">
|
|
<input type="text" name="attr_npc_action_roll" placeholder="Damage / Effect Roll">
|
|
<input type="text" name="attr_npc_action_damage_type" placeholder="Damage Type / Notes">
|
|
<input type="text" name="attr_npc_action_element" placeholder="Element / Detail">
|
|
<input type="text" name="attr_npc_action_range" placeholder="Range / Area">
|
|
<input type="text" name="attr_npc_action_save" placeholder="Save / DC">
|
|
|
|
<select name="attr_npc_action_scale">
|
|
<option value="personal">Personal</option>
|
|
<option value="armor">Armor</option>
|
|
<option value="ship">Ship</option>
|
|
</select>
|
|
|
|
<input type="text" name="attr_npc_action_status" placeholder="Status Inflicted">
|
|
<input type="number" name="attr_npc_action_status_rounds" placeholder="Status Rounds" value="1">
|
|
|
|
<textarea name="attr_npc_action_desc" placeholder="Action description, targeting, recharge rules, rider effects, status effects, and phase notes."></textarea>
|
|
|
|
<div class="button-strip">
|
|
<button type="roll" name="roll_npc_action_attack" value="!ff5e-card-attack-formula "@{npc_name}" "@{npc_action_name}" "@{npc_action_category}: @{npc_action_type}" "@{npc_action_attack}" "@{npc_action_roll}" @{npc_action_mp_cost} "@{npc_action_desc}"">
|
|
Attack
|
|
</button>
|
|
|
|
<button type="roll" name="roll_npc_power" value="!ff5e-card-power "@{npc_name}" "@{npc_action_name}" "@{npc_action_category}: @{npc_action_type}" "@{npc_action_roll}" "@{npc_action_mp_cost}" "@{npc_action_element} | @{npc_action_save} | @{npc_action_range} | Recharge @{npc_action_recharge}" "@{npc_action_desc}"">
|
|
Power
|
|
</button>
|
|
|
|
<button type="roll" name="roll_npc_status_api" value="!ff5e-status add @{target|Status Target|token_id} @{npc_action_status} @{npc_action_status_rounds}">
|
|
Status
|
|
</button>
|
|
|
|
<button type="roll" name="roll_npc_recharge_api" value="!ff5e-recharge @{npc_action_recharge}">
|
|
Recharge
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Legendary / Lair Actions</h2>
|
|
|
|
<fieldset class="repeating_legendaryactions">
|
|
<div class="repeat-row npc-action">
|
|
<input type="text" name="attr_legendary_name" placeholder="Legendary Action">
|
|
<input type="number" name="attr_legendary_cost" placeholder="Cost">
|
|
<input type="text" name="attr_legendary_roll" placeholder="Roll Formula">
|
|
<input type="text" name="attr_legendary_element" placeholder="Element / Detail">
|
|
<input type="text" name="attr_legendary_range" placeholder="Range / Area">
|
|
<input type="text" name="attr_legendary_save" placeholder="Save / DC">
|
|
|
|
<textarea name="attr_legendary_desc" placeholder="Legendary action description, timing, triggers, and effects."></textarea>
|
|
|
|
<button type="roll" name="roll_legendary_action" value="!ff5e-card-power "@{npc_name}" "@{legendary_name}" "Legendary / Lair Action" "@{legendary_roll}" "@{legendary_cost} Action Cost" "@{legendary_element} | @{legendary_save} | @{legendary_range}" "@{legendary_desc}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>AI Pattern</h2>
|
|
|
|
<fieldset class="repeating_aipattern">
|
|
<div class="repeat-row npc-action">
|
|
<input type="number" name="attr_ai_round" placeholder="Round">
|
|
<input type="text" name="attr_ai_phase" placeholder="Phase">
|
|
<input type="text" name="attr_ai_action" placeholder="Preferred Action">
|
|
|
|
<textarea name="attr_ai_notes" placeholder="AI behavior, priorities, conditions, reactions, and tactical notes."></textarea>
|
|
|
|
<button type="roll" name="roll_ai_pattern_card" value="!ff5e-card-power "@{npc_name}" "AI Round @{ai_round}" "AI Pattern" "0" "0" "Phase @{ai_phase} | Action @{ai_action}" "@{ai_notes}"">
|
|
AI Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
MONSTER WEAKNESSES TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-monster-status">
|
|
<div class="ff7-card">
|
|
<h2>Elemental Profile</h2>
|
|
|
|
<div class="element-grid">
|
|
<div class="element-row header">
|
|
<span>Element</span>
|
|
<span>Affinity</span>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Fire</label>
|
|
<select name="attr_npc_affinity_fire">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Ice</label>
|
|
<select name="attr_npc_affinity_ice">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Lightning</label>
|
|
<select name="attr_npc_affinity_lightning">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Water</label>
|
|
<select name="attr_npc_affinity_water">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Wind</label>
|
|
<select name="attr_npc_affinity_wind">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Earth</label>
|
|
<select name="attr_npc_affinity_earth">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Holy</label>
|
|
<select name="attr_npc_affinity_holy">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Dark</label>
|
|
<select name="attr_npc_affinity_dark">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="element-row">
|
|
<label>Poison</label>
|
|
<select name="attr_npc_affinity_poison">
|
|
<option>Normal</option>
|
|
<option>Weak</option>
|
|
<option>Resist</option>
|
|
<option>Null</option>
|
|
<option>Absorb</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Weakness / Resistance Notes</label>
|
|
<textarea name="attr_npc_affinity_notes" placeholder="Conditional weaknesses, phase changes, stagger rules, exposed cores, shield effects, and special damage rules."></textarea>
|
|
|
|
<h3>Damage Calculator Helper</h3>
|
|
|
|
<div class="damage-helper-grid">
|
|
<div>
|
|
<label>Incoming Damage</label>
|
|
<input type="number" name="attr_npc_incoming_damage" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Incoming Element</label>
|
|
<select name="attr_npc_incoming_element">
|
|
<option value="fire">Fire</option>
|
|
<option value="ice">Ice</option>
|
|
<option value="lightning">Lightning</option>
|
|
<option value="water">Water</option>
|
|
<option value="wind">Wind</option>
|
|
<option value="earth">Earth</option>
|
|
<option value="holy">Holy</option>
|
|
<option value="dark">Dark</option>
|
|
<option value="poison">Poison</option>
|
|
<option value="none">None</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Adjusted Damage</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_npc_adjusted_damage" readonly>
|
|
<span name="attr_npc_adjusted_damage"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Affinity Result</label>
|
|
<input type="text" name="attr_npc_damage_affinity_result" readonly>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="roll" name="roll_npc_affinity_card" value="!ff5e-card-power "@{npc_name}" "Affinity Damage" "Damage Helper" "@{npc_adjusted_damage}" "0" "Incoming @{npc_incoming_damage} | @{npc_incoming_element}" "@{npc_damage_affinity_result}"">
|
|
Affinity Card
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
MONSTER IMPORT TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-monster-import">
|
|
<div class="ff7-card">
|
|
<h2>Monster Database Import</h2>
|
|
|
|
<p class="sheet-help">
|
|
Use this with the monster database API script. Enter a monster key such as guard_scorpion,
|
|
bomb, behemoth, ifrit, or tonberry.
|
|
</p>
|
|
|
|
<label>Monster Import Key</label>
|
|
<input type="text" name="attr_npc_import_key" placeholder="Example: guard_scorpion">
|
|
|
|
<button type="roll" name="roll_import_monster" value="!ff5e-import-monster @{selected|token_id} @{npc_import_key}">
|
|
Import Selected
|
|
</button>
|
|
|
|
<label>Manual JSON Import</label>
|
|
<textarea name="attr_npc_import_json" placeholder='Paste monster JSON here for API/manual reference.'></textarea>
|
|
|
|
<button type="roll" name="roll_import_monster_json" value="!ff5e-import-json @{selected|token_id}">
|
|
Import JSON
|
|
</button>
|
|
</div>
|
|
|
|
<div class="ff7-card compendium-drop-target" accept="Monster,NPC">
|
|
<h2>Compendium / Drop Target</h2>
|
|
|
|
<p class="sheet-help">
|
|
This panel is prepared as a compendium drop target. Full private compendium support depends on your Roll20 compendium setup.
|
|
</p>
|
|
|
|
<div class="monster-profile-grid">
|
|
<div>
|
|
<label>Dropped Name</label>
|
|
<input type="text" name="attr_drop_name" accept="Name">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Dropped Type</label>
|
|
<input type="text" name="attr_drop_type" accept="Type">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Dropped HP</label>
|
|
<input type="text" name="attr_drop_hp" accept="Hit Points">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Dropped AC</label>
|
|
<input type="text" name="attr_drop_ac" accept="Armor Class">
|
|
</div>
|
|
</div>
|
|
|
|
<label>Dropped Notes</label>
|
|
<textarea name="attr_drop_notes" placeholder="Dropped compendium notes or manual import notes."></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- =========================
|
|
VEHICLE MODE
|
|
========================== -->
|
|
|
|
<div class="mode-vehicle">
|
|
|
|
<div class="tab-buttons vehicle-tabs">
|
|
<button type="action" name="act_tab_vehicle_core">Core</button>
|
|
<button type="action" name="act_tab_vehicle_weapons">Weapons</button>
|
|
<button type="action" name="act_tab_vehicle_systems">Systems</button>
|
|
<button type="action" name="act_tab_vehicle_scale">Scale</button>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
VEHICLE CORE TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-vehicle-core">
|
|
|
|
<div class="resource-bar">
|
|
|
|
<div class="resource hp">
|
|
<label>Hull HP</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_vehicle_hp_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_vehicle_hp_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_vehicle_hp_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_vehicle_hp_subtract">- HP</button>
|
|
<button type="action" name="act_vehicle_hp_add">+ HP</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource mp">
|
|
<label>Vehicle MP / Energy</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_vehicle_mp_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_vehicle_mp_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_vehicle_mp_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_vehicle_mp_subtract">- MP</button>
|
|
<button type="action" name="act_vehicle_mp_add">+ MP</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource limit">
|
|
<label>Vehicle Limit</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_vehicle_limit_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_vehicle_limit_max" value="100">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_vehicle_limit_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_vehicle_limit_subtract">- Limit</button>
|
|
<button type="action" name="act_vehicle_limit_add">+ Limit</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource mp">
|
|
<label>Shield</label>
|
|
|
|
<div class="resource-main">
|
|
<input type="number" name="attr_vehicle_shield_current" value="0">
|
|
<span>/</span>
|
|
<input type="number" name="attr_vehicle_shield_max" value="0">
|
|
</div>
|
|
|
|
<div class="resource-adjust">
|
|
<input type="number" name="attr_vehicle_shield_adjust" value="0" placeholder="Amount">
|
|
<button type="action" name="act_vehicle_shield_subtract">- Shield</button>
|
|
<button type="action" name="act_vehicle_shield_add">+ Shield</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="resource">
|
|
<label>Condition</label>
|
|
|
|
<div class="resource-main single-resource">
|
|
<input type="text" name="attr_vehicle_condition" readonly>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="overview-grid">
|
|
|
|
<div class="ff7-card">
|
|
<h2>Vehicle Profile</h2>
|
|
|
|
<div class="vehicle-profile-grid">
|
|
<div>
|
|
<label>Name</label>
|
|
<input type="text" name="attr_vehicle_name" placeholder="Vehicle Name">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Vehicle Type</label>
|
|
<select name="attr_vehicle_type">
|
|
<option value="mount">Mount</option>
|
|
<option value="warmachina">Warmachina</option>
|
|
<option value="land_vehicle">Land Vehicle</option>
|
|
<option value="airship">Airship</option>
|
|
<option value="dreadnought">Dreadnought</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Scale</label>
|
|
<select name="attr_vehicle_scale">
|
|
<option value="personal">Personal</option>
|
|
<option value="armor">Armor</option>
|
|
<option value="ship">Ship</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Armor Class</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_vehicle_ac" value="10">
|
|
<span name="attr_vehicle_ac"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Initiative</label>
|
|
<div class="initiative-row">
|
|
<input type="number" name="attr_vehicle_initiative" value="0">
|
|
|
|
<button type="roll" name="roll_vehicle_initiative" value="!ff5e-card-init "@{character_id}" "@{vehicle_name}" "Vehicle" @{vehicle_initiative}">
|
|
Initiative
|
|
</button>
|
|
</div>
|
|
|
|
<div class="vehicle-profile-grid">
|
|
<div>
|
|
<label>Speed</label>
|
|
<input type="text" name="attr_vehicle_speed" placeholder="Speed / travel pace">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Capacity</label>
|
|
<input type="number" name="attr_vehicle_capacity" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Crew Required</label>
|
|
<input type="number" name="attr_vehicle_crew_required" value="0">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Crew Stations</h2>
|
|
|
|
<div class="crew-grid">
|
|
<div>
|
|
<label>Captain</label>
|
|
<input type="text" name="attr_crew_captain">
|
|
<label>Captain Bonus</label>
|
|
<input type="number" name="attr_captain_bonus" value="0">
|
|
<button type="roll" name="roll_captain_action" value="!ff5e-card-d20 "@{vehicle_name}" "Captain Command" "Vehicle Station Check" @{captain_bonus} "Captain: @{crew_captain}. Grant advantage or command a station."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Pilot</label>
|
|
<input type="text" name="attr_crew_pilot">
|
|
<label>Pilot Bonus</label>
|
|
<input type="number" name="attr_pilot_bonus" value="0">
|
|
<button type="roll" name="roll_pilot_action" value="!ff5e-card-d20 "@{vehicle_name}" "Evasive Maneuver" "Vehicle Station Check" @{pilot_bonus} "Pilot: @{crew_pilot}. Reposition or increase defense."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Gunner</label>
|
|
<input type="text" name="attr_crew_gunner">
|
|
<label>Gunner Bonus</label>
|
|
<input type="number" name="attr_gunner_bonus" value="0">
|
|
<button type="roll" name="roll_gunner_action" value="!ff5e-card-d20 "@{vehicle_name}" "Fire Weapon Systems" "Vehicle Station Check" @{gunner_bonus} "Gunner: @{crew_gunner}. Fire one vehicle weapon."">Roll</button>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Engineer</label>
|
|
<input type="text" name="attr_crew_engineer">
|
|
<label>Engineer Bonus</label>
|
|
<input type="number" name="attr_engineer_bonus" value="0">
|
|
<button type="roll" name="roll_engineer_action" value="!ff5e-card-d20 "@{vehicle_name}" "Emergency Repairs" "Vehicle Station Check" @{engineer_bonus} "Engineer: @{crew_engineer}. Repair hull or stabilize systems."">Roll</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ff7-card">
|
|
<h2>Vehicle Notes</h2>
|
|
|
|
<label>Features</label>
|
|
<textarea name="attr_vehicle_features" placeholder="Vehicle traits, systems, movement rules, special actions, and upgrades."></textarea>
|
|
|
|
<label>Damage Notes</label>
|
|
<textarea name="attr_vehicle_damage_notes" placeholder="Critical damage, disabled systems, hull breaches, repairs, and shield rules."></textarea>
|
|
|
|
<label>Cargo</label>
|
|
<textarea name="attr_vehicle_cargo" placeholder="Cargo, passengers, supplies, fuel, trade goods, and stored gear."></textarea>
|
|
|
|
<button type="roll" name="roll_vehicle_profile_card" value="!ff5e-card-power "@{vehicle_name}" "Vehicle Profile" "Vehicle Info" "0" "0" "@{vehicle_type} | @{vehicle_scale} | AC @{vehicle_ac} | Speed @{vehicle_speed}" "@{vehicle_features}"">
|
|
Info Card
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
VEHICLE WEAPONS TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-vehicle-weapons">
|
|
<div class="ff7-card">
|
|
<h2>Vehicle Weapons</h2>
|
|
|
|
<fieldset class="repeating_vehicleweapons">
|
|
<div class="repeat-row vehicle-weapon">
|
|
<input type="text" name="attr_vehicle_weapon_name" placeholder="Weapon Name">
|
|
<input type="text" name="attr_vehicle_weapon_range" placeholder="Range / Area">
|
|
<input type="text" name="attr_vehicle_weapon_damage" placeholder="Damage Dice">
|
|
<input type="text" name="attr_vehicle_weapon_type" placeholder="Damage Type / Notes">
|
|
<input type="text" name="attr_vehicle_weapon_element" placeholder="Element / Detail">
|
|
<input type="number" name="attr_vehicle_weapon_bonus" placeholder="Attack Bonus" value="0">
|
|
<input type="number" name="attr_vehicle_weapon_mp_cost" placeholder="MP / Energy Cost" value="0">
|
|
|
|
<select name="attr_vehicle_weapon_scale">
|
|
<option value="personal">Personal</option>
|
|
<option value="armor">Armor</option>
|
|
<option value="ship">Ship</option>
|
|
</select>
|
|
|
|
<textarea name="attr_vehicle_weapon_notes" placeholder="Weapon notes, firing arc, reload rules, ammo, charges, misfire, and special effects."></textarea>
|
|
|
|
<button type="roll" name="roll_vehicle_weapon" value="!ff5e-card-attack "@{vehicle_name}" "@{vehicle_weapon_name}" "Vehicle Weapon" @{vehicle_weapon_bonus} "@{vehicle_weapon_damage}" @{vehicle_weapon_mp_cost} "@{vehicle_weapon_notes}"">
|
|
Fire
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
VEHICLE SYSTEMS TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-vehicle-systems">
|
|
<div class="ff7-card">
|
|
<h2>Systems & Cargo</h2>
|
|
|
|
<fieldset class="repeating_vehiclesystems">
|
|
<div class="repeat-row vehicle-system">
|
|
<input type="text" name="attr_vehicle_system_name" placeholder="System / Upgrade">
|
|
<input type="text" name="attr_vehicle_system_status" placeholder="Status">
|
|
|
|
<textarea name="attr_vehicle_system_notes" placeholder="System notes, upgrade effects, broken state, repair DC, power cost, and crew actions."></textarea>
|
|
|
|
<button type="roll" name="roll_vehicle_system_card" value="!ff5e-card-power "@{vehicle_name}" "@{vehicle_system_name}" "Vehicle System" "0" "0" "Status: @{vehicle_system_status}" "@{vehicle_system_notes}"">
|
|
Card
|
|
</button>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
VEHICLE SCALE COMBAT TAB
|
|
========================== -->
|
|
|
|
<div class="tab-panel tab-vehicle-scale">
|
|
<div class="ff7-card">
|
|
<h2>Scale Damage Calculator</h2>
|
|
|
|
<div class="scale-grid">
|
|
<div>
|
|
<label>Base Damage</label>
|
|
<input type="number" name="attr_scale_base_damage" value="0">
|
|
</div>
|
|
|
|
<div>
|
|
<label>Attacker Scale</label>
|
|
<select name="attr_scale_attacker">
|
|
<option value="personal">Personal</option>
|
|
<option value="armor">Armor</option>
|
|
<option value="ship">Ship</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Target Scale</label>
|
|
<select name="attr_scale_target">
|
|
<option value="personal">Personal</option>
|
|
<option value="armor">Armor</option>
|
|
<option value="ship">Ship</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Final Scaled Damage</label>
|
|
<div class="display-stat-pair">
|
|
<input type="number" name="attr_scale_final_damage" readonly>
|
|
<span name="attr_scale_final_damage"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Scale Result</label>
|
|
<input type="text" name="attr_scale_result_text" readonly>
|
|
|
|
<div class="button-strip">
|
|
<button type="roll" name="roll_scale_damage_card" value="!ff5e-card-power "@{vehicle_name}" "Scale Damage" "Scale Combat" "@{scale_final_damage}" "0" "Base @{scale_base_damage} | @{scale_attacker} to @{scale_target}" "@{scale_result_text}"">
|
|
Card
|
|
</button>
|
|
|
|
<button type="roll" name="roll_scale_damage_api" value="!ff5e-scale-damage @{scale_base_damage} @{scale_attacker} @{scale_target}">
|
|
API
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =========================
|
|
THEMED ROLL TEMPLATES
|
|
API-BACKED CARD SYSTEM
|
|
Roll20-compliant custom templates
|
|
========================== -->
|
|
|
|
<rolltemplate class="sheet-rolltemplate-ff5e_card_d20">
|
|
<div class="sheet-ff5e-chat-card sheet-ff5e-chat-d20">
|
|
|
|
<div class="sheet-ff5e-card-title sheet-ff5e-title-d20">
|
|
<div class="sheet-ff5e-card-name">{{name}}</div>
|
|
<div class="sheet-ff5e-card-subtitle">{{actor}} • {{type}}</div>
|
|
</div>
|
|
|
|
{{#description}}
|
|
<div class="sheet-ff5e-card-description">
|
|
{{description}}
|
|
</div>
|
|
{{/description}}
|
|
|
|
<div class="sheet-ff5e-card-body">
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>D20 Roll</span>
|
|
|
|
{{#crit}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat20">{{d20}}</strong>
|
|
{{/crit}}
|
|
|
|
{{#fail}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat1">{{d20}}</strong>
|
|
{{/fail}}
|
|
|
|
{{#normal}}
|
|
<strong class="sheet-ff5e-roll-box">{{d20}}</strong>
|
|
{{/normal}}
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>Modifier</span>
|
|
<strong>{{modifier}}</strong>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row sheet-ff5e-total-row">
|
|
<span>Total Result</span>
|
|
|
|
{{#crit}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat20">{{total}}</strong>
|
|
{{/crit}}
|
|
|
|
{{#fail}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat1">{{total}}</strong>
|
|
{{/fail}}
|
|
|
|
{{#normal}}
|
|
<strong class="sheet-ff5e-roll-box">{{total}}</strong>
|
|
{{/normal}}
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>Rolled</span>
|
|
<strong>{{formula}}</strong>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</rolltemplate>
|
|
|
|
<rolltemplate class="sheet-rolltemplate-ff5e_card_attack">
|
|
<div class="sheet-ff5e-chat-card sheet-ff5e-chat-attack">
|
|
|
|
<div class="sheet-ff5e-card-title sheet-ff5e-title-attack">
|
|
<div class="sheet-ff5e-card-name">{{name}}</div>
|
|
<div class="sheet-ff5e-card-subtitle">{{actor}} • {{type}}</div>
|
|
</div>
|
|
|
|
{{#description}}
|
|
<div class="sheet-ff5e-card-description">
|
|
{{description}}
|
|
</div>
|
|
{{/description}}
|
|
|
|
<div class="sheet-ff5e-card-body">
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>MP Cost</span>
|
|
<strong>{{mpcost}}</strong>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row sheet-ff5e-total-row">
|
|
<span>Attack Roll</span>
|
|
|
|
{{#crit}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat20">{{attacktotal}}</strong>
|
|
{{/crit}}
|
|
|
|
{{#fail}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat1">{{attacktotal}}</strong>
|
|
{{/fail}}
|
|
|
|
{{#normal}}
|
|
<strong class="sheet-ff5e-roll-box">{{attacktotal}}</strong>
|
|
{{/normal}}
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>D20 Roll</span>
|
|
|
|
{{#crit}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat20">{{attackd20}}</strong>
|
|
{{/crit}}
|
|
|
|
{{#fail}}
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-nat1">{{attackd20}}</strong>
|
|
{{/fail}}
|
|
|
|
{{#normal}}
|
|
<strong class="sheet-ff5e-roll-box">{{attackd20}}</strong>
|
|
{{/normal}}
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>Modifier</span>
|
|
<strong>{{attackmodifier}}</strong>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>Rolled</span>
|
|
<strong>{{attackformula}}</strong>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row sheet-ff5e-total-row">
|
|
<span>Damage</span>
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-damage-box">{{damage}}</strong>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>Damage Roll</span>
|
|
<strong>{{damageformula}}</strong>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</rolltemplate>
|
|
|
|
<rolltemplate class="sheet-rolltemplate-ff5e_card_power">
|
|
<div class="sheet-ff5e-chat-card sheet-ff5e-chat-power">
|
|
|
|
<div class="sheet-ff5e-card-title sheet-ff5e-title-power">
|
|
<div class="sheet-ff5e-card-name">{{name}}</div>
|
|
<div class="sheet-ff5e-card-subtitle">{{actor}} • {{type}}</div>
|
|
</div>
|
|
|
|
{{#description}}
|
|
<div class="sheet-ff5e-card-description">
|
|
{{description}}
|
|
</div>
|
|
{{/description}}
|
|
|
|
<div class="sheet-ff5e-card-body">
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>MP / Cost</span>
|
|
<strong>{{mpcost}}</strong>
|
|
</div>
|
|
|
|
{{#detail}}
|
|
<div class="sheet-ff5e-card-row sheet-ff5e-detail-row">
|
|
<span>Details</span>
|
|
<strong>{{detail}}</strong>
|
|
</div>
|
|
{{/detail}}
|
|
|
|
<div class="sheet-ff5e-card-row sheet-ff5e-total-row">
|
|
<span>Result</span>
|
|
<strong class="sheet-ff5e-roll-box sheet-ff5e-power-box">{{result}}</strong>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-row">
|
|
<span>Rolled</span>
|
|
<strong>{{formula}}</strong>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</rolltemplate>
|
|
|
|
<rolltemplate class="sheet-rolltemplate-ff5e_card_resource">
|
|
<div class="sheet-ff5e-chat-card sheet-ff5e-chat-resource">
|
|
|
|
<div class="sheet-ff5e-card-title sheet-ff5e-title-resource">
|
|
<div class="sheet-ff5e-card-name">{{name}}</div>
|
|
<div class="sheet-ff5e-card-subtitle">{{actor}} • {{type}}</div>
|
|
</div>
|
|
|
|
<div class="sheet-ff5e-card-body">
|
|
<div class="sheet-ff5e-resource-change">
|
|
<span>{{before}}</span>
|
|
<strong>→</strong>
|
|
<span>{{after}}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{{#description}}
|
|
<div class="sheet-ff5e-card-description">
|
|
{{description}}
|
|
</div>
|
|
{{/description}}
|
|
|
|
</div>
|
|
</rolltemplate>
|
|
|
|
<!-- =========================
|
|
SHEET WORKERS
|
|
========================== -->
|
|
|
|
<script type="text/worker">
|
|
|
|
/* =========================
|
|
CORE HELPERS
|
|
========================= */
|
|
|
|
var FF5E = {
|
|
mod: function(score) {
|
|
return Math.floor((parseInt(score || 10, 10) - 10) / 2);
|
|
},
|
|
|
|
prof: function(level) {
|
|
level = parseInt(level || 1, 10);
|
|
|
|
if (level >= 17) return 6;
|
|
if (level >= 13) return 5;
|
|
if (level >= 9) return 4;
|
|
if (level >= 5) return 3;
|
|
|
|
return 2;
|
|
},
|
|
|
|
baselineCP: function(level) {
|
|
level = parseInt(level || 1, 10);
|
|
return 10 + ((level - 1) * 2);
|
|
},
|
|
|
|
bool: function(value) {
|
|
value = String(value || "0").toLowerCase();
|
|
return value === "1" || value === "on" || value === "true" || value === "yes";
|
|
},
|
|
|
|
number: function(value, fallback) {
|
|
var parsed = parseInt(value, 10);
|
|
return isNaN(parsed) ? (fallback || 0) : parsed;
|
|
},
|
|
|
|
blankBonuses: function() {
|
|
return {
|
|
strength: 0,
|
|
dexterity: 0,
|
|
constitution: 0,
|
|
intelligence: 0,
|
|
wisdom: 0,
|
|
charisma: 0
|
|
};
|
|
},
|
|
|
|
addBonus: function(bonuses, ability, amount) {
|
|
if (ability && Object.prototype.hasOwnProperty.call(bonuses, ability)) {
|
|
bonuses[ability] += parseInt(amount || 0, 10);
|
|
}
|
|
},
|
|
|
|
clampResource: function(current, max, amount, mode) {
|
|
current = FF5E.number(current, 0);
|
|
max = FF5E.number(max, 0);
|
|
amount = FF5E.number(amount, 0);
|
|
|
|
var next = current;
|
|
|
|
if (mode === "add") {
|
|
next = current + amount;
|
|
}
|
|
|
|
if (mode === "subtract") {
|
|
next = current - amount;
|
|
}
|
|
|
|
if (max > 0) {
|
|
next = Math.min(next, max);
|
|
}
|
|
|
|
return Math.max(0, next);
|
|
},
|
|
|
|
proficiencyPart: function(profBonus, proficient, expert) {
|
|
profBonus = FF5E.number(profBonus, 2);
|
|
|
|
if (FF5E.bool(expert)) {
|
|
return profBonus * 2;
|
|
}
|
|
|
|
if (FF5E.bool(proficient)) {
|
|
return profBonus;
|
|
}
|
|
|
|
return 0;
|
|
},
|
|
|
|
saveTotal: function(abilityMod, profBonus, proficient, miscBonus) {
|
|
abilityMod = FF5E.number(abilityMod, 0);
|
|
profBonus = FF5E.number(profBonus, 2);
|
|
miscBonus = FF5E.number(miscBonus, 0);
|
|
|
|
return abilityMod + miscBonus + (FF5E.bool(proficient) ? profBonus : 0);
|
|
},
|
|
|
|
skillTotal: function(abilityMod, profBonus, proficient, expert, miscBonus) {
|
|
abilityMod = FF5E.number(abilityMod, 0);
|
|
profBonus = FF5E.number(profBonus, 2);
|
|
miscBonus = FF5E.number(miscBonus, 0);
|
|
|
|
return abilityMod + miscBonus + FF5E.proficiencyPart(profBonus, proficient, expert);
|
|
},
|
|
|
|
expNextByLevel: function(level) {
|
|
level = FF5E.number(level, 1);
|
|
|
|
var table = {
|
|
1: 300,
|
|
2: 900,
|
|
3: 2700,
|
|
4: 6500,
|
|
5: 14000,
|
|
6: 23000,
|
|
7: 34000,
|
|
8: 48000,
|
|
9: 64000,
|
|
10: 85000,
|
|
11: 100000,
|
|
12: 120000,
|
|
13: 140000,
|
|
14: 165000,
|
|
15: 195000,
|
|
16: 225000,
|
|
17: 265000,
|
|
18: 305000,
|
|
19: 355000,
|
|
20: 0
|
|
};
|
|
|
|
return table[level] || 0;
|
|
},
|
|
|
|
scaleRank: {
|
|
personal: 1,
|
|
armor: 2,
|
|
ship: 3
|
|
},
|
|
|
|
scaleDamage: function(baseDamage, attackerScale, targetScale) {
|
|
var attacker = FF5E.scaleRank[attackerScale] || 1;
|
|
var target = FF5E.scaleRank[targetScale] || 1;
|
|
var multiplier = 1;
|
|
|
|
if (attacker < target) multiplier = 0.1;
|
|
if (attacker > target) multiplier = 10;
|
|
|
|
return Math.max(0, Math.floor(FF5E.number(baseDamage, 0) * multiplier));
|
|
},
|
|
|
|
affinityDamage: function(baseDamage, affinity) {
|
|
var dmg = FF5E.number(baseDamage, 0);
|
|
var result = "Normal";
|
|
|
|
if (affinity === "Weak") {
|
|
dmg = Math.floor(dmg * 1.5);
|
|
result = "Weak: x1.5 damage";
|
|
}
|
|
|
|
if (affinity === "Resist") {
|
|
dmg = Math.floor(dmg / 2);
|
|
result = "Resist: half damage";
|
|
}
|
|
|
|
if (affinity === "Null") {
|
|
dmg = 0;
|
|
result = "Null: no damage";
|
|
}
|
|
|
|
if (affinity === "Absorb") {
|
|
dmg = dmg * -1;
|
|
result = "Absorb: healing instead of damage";
|
|
}
|
|
|
|
return {
|
|
damage: dmg,
|
|
result: result
|
|
};
|
|
}
|
|
};
|
|
|
|
/* =========================
|
|
FULL RACE DATA
|
|
========================= */
|
|
|
|
var FF5E_FULL_RACES = {
|
|
"Hume": {
|
|
speed: 30,
|
|
cp_bonus: 2,
|
|
features: "Ability Score Increase: use Bonus Choice 1 and Bonus Choice 2. Endless Potential: +2 starting CP. Skill Proficiency: choice of any one skill."
|
|
},
|
|
|
|
"Miqo'te": {
|
|
speed: 35,
|
|
bonuses: { dexterity: 2 },
|
|
variants: {
|
|
"Seeker": { charisma: 1 },
|
|
"Keeper": { wisdom: 1 }
|
|
},
|
|
features: "Heightened Senses: Hearing and Smell. Skill Proficiency: Acrobatics. Feline Grace: no damage from falls of 30 feet or less."
|
|
},
|
|
|
|
"Elezen": {
|
|
speed: 30,
|
|
bonuses: { intelligence: 2 },
|
|
variants: {
|
|
"Wildwood": { dexterity: 1 },
|
|
"Duskwight": { constitution: 1 }
|
|
},
|
|
features: "Long-Limbed: melee reach increased by 5 feet. Skill Proficiency: History. Keen Mind: recall anything seen or heard within the past month."
|
|
},
|
|
|
|
"Lalafell": {
|
|
speed: 25,
|
|
bonuses: { charisma: 2, intelligence: 1 },
|
|
features: "Resilient: advantage on INT/WIS/CHA saves against magic. Skill Proficiency: Deception. Nimble Escape: move through spaces of larger creatures."
|
|
},
|
|
|
|
"Roegadyn": {
|
|
speed: 30,
|
|
bonuses: { constitution: 2, strength: 1 },
|
|
hp_per_level_bonus: 1,
|
|
features: "Toughness: maximum HP increases by +1 per character level. Skill Proficiency: Intimidation. Immovable: advantage against prone/forced movement."
|
|
},
|
|
|
|
"Viera": {
|
|
speed: 35,
|
|
bonuses: { dexterity: 2 },
|
|
variants: {
|
|
"Rava": { wisdom: 1 },
|
|
"Veena": { intelligence: 1 }
|
|
},
|
|
features: "Heightened Senses: Hearing. Jumping: jump distance doubled and ignore falling damage under 30 feet. Spellcasting: Druidcraft cantrip."
|
|
},
|
|
|
|
"Au Ra": {
|
|
speed: 30,
|
|
bonuses: { constitution: 2 },
|
|
variants: {
|
|
"Raen": { wisdom: 1 },
|
|
"Xaela": { strength: 1 }
|
|
},
|
|
natural_ac_base: 12,
|
|
features: "Raen: resistance to Radiant damage. Xaela: resistance to Cold damage. Ancestral Scales: unarmored AC is 12 + DEX modifier. Skill Proficiency: Insight."
|
|
},
|
|
|
|
"Hrothgar": {
|
|
speed: 30,
|
|
bonuses: { strength: 2, constitution: 1 },
|
|
features: "Natural Weapons: claws/fangs deal 1d6 + STR. Lancet: once per short rest gain temporary HP after hitting with melee attack. Skill Proficiency: Survival."
|
|
},
|
|
|
|
"Moogle": {
|
|
speed: 25,
|
|
bonuses: { intelligence: 2, charisma: 1 },
|
|
fly_speed: 30,
|
|
features: "Flight: 30 ft fly speed, cannot wear medium or heavy armor. Tool Proficiency: Tinker's Tools and Vehicles Airships. Inconspicuous."
|
|
},
|
|
|
|
"Bangaa": {
|
|
speed: 30,
|
|
bonuses: { strength: 2, constitution: 1 },
|
|
natural_ac_base: 13,
|
|
features: "Reptilian Hide: unarmored AC is 13 + DEX modifier. Edge: advantage on STR Athletics checks for grappling or shoving."
|
|
},
|
|
|
|
"Al Bhed": {
|
|
speed: 30,
|
|
bonuses: { intelligence: 2, dexterity: 1 },
|
|
features: "Salvager: advantage on Investigation checks to understand or repair machinery. Tool Proficiency: Thieves' Tools and Tinker's Tools. Cipher Tongue."
|
|
},
|
|
|
|
"Cetra": {
|
|
speed: 30,
|
|
bonuses: { wisdom: 2, charisma: 1 },
|
|
mp_bonus: 10,
|
|
features: "Energy Bonus: +10 maximum MP. Planet's Pulse: cast Detect Magic at will without MP. Skill Proficiency: Nature."
|
|
},
|
|
|
|
"Burmecian": {
|
|
speed: 35,
|
|
bonuses: { dexterity: 2, constitution: 1 },
|
|
features: "Jumping: jump distance tripled and ignore first 50 feet of falling damage. Weapon Proficiency: Polearms/Spears. Rain Dancer."
|
|
},
|
|
|
|
"Guado": {
|
|
speed: 30,
|
|
bonuses: { charisma: 2, wisdom: 1 },
|
|
features: "Spellcasting: Minor Illusion cantrip. Macalania's Step: ignore difficult terrain from roots, vines, and natural forest growth. Skill Proficiency: Religion."
|
|
},
|
|
|
|
"Nu Mou": {
|
|
speed: 25,
|
|
bonuses: { wisdom: 2, intelligence: 1 },
|
|
mp_bonus: 5,
|
|
features: "Beast Speaker: communicate simple ideas to beasts and monstrosities. Skill Proficiency: Animal Handling. Energy Bonus: +5 maximum MP."
|
|
},
|
|
|
|
"Dwarf": {
|
|
speed: 25,
|
|
bonuses: { constitution: 2 },
|
|
variants: {
|
|
"Tholl": { intelligence: 1 },
|
|
"Gogg": { strength: 1 }
|
|
},
|
|
features: "Resistance: Poison damage and advantage against poison. Tool Proficiency: Smith's Tools. Darkvision: 60 feet."
|
|
},
|
|
|
|
"Garlean": {
|
|
speed: 30,
|
|
bonuses: { strength: 2, intelligence: 2 },
|
|
mp_override: 0,
|
|
chassis_cp_bonus: 3,
|
|
features: "Aetherial Ineptitude: 0 MP, cannot purchase Spellcasting Attributes, use Materia, or cast magic natively. Magitek Mastery: +3 CP for Combat Techniques, Armour, or Tech/Gadget Attributes. Spatial Awareness: advantage on Initiative."
|
|
},
|
|
|
|
"Hybrid": {
|
|
speed: 30,
|
|
features: "Custom Lineage: use Bonus Choice 1 and Bonus Choice 2, then manually add remaining lineage traits as needed."
|
|
}
|
|
};
|
|
|
|
/* =========================
|
|
FULL JOB DATA
|
|
========================= */
|
|
|
|
var FF5E_FULL_JOBS = {
|
|
"Freelancer": { chassis: "Custom", hit_die: 8, role: "Flexible / Custom", spellcasting: "Optional" },
|
|
"Custom": { chassis: "Custom", hit_die: 8, role: "Custom Class / Job", spellcasting: "Optional" },
|
|
|
|
"Warrior": { chassis: "Warrior", hit_die: 10, role: "Vanguard Frontliner", spellcasting: "No" },
|
|
"Fighter": { chassis: "Warrior", hit_die: 10, role: "Weapon Specialist", spellcasting: "No" },
|
|
"Barbarian": { chassis: "Warrior", hit_die: 12, role: "Rage / Heavy Frontliner", spellcasting: "No" },
|
|
"Paladin": { chassis: "Warrior", hit_die: 10, role: "Tank / Holy Defender", spellcasting: "Optional" },
|
|
"Dark Knight": { chassis: "Warrior", hit_die: 10, role: "Drain Tank / Dark Striker", spellcasting: "Optional" },
|
|
"Gunbreaker": { chassis: "Warrior", hit_die: 10, role: "Tank / Magitek Weapon Specialist", spellcasting: "No" },
|
|
"Samurai": { chassis: "Warrior", hit_die: 10, role: "Burst Melee Striker", spellcasting: "No" },
|
|
"Dragoon": { chassis: "Warrior", hit_die: 10, role: "Jumping Vanguard / Anti-Flying Striker", spellcasting: "No" },
|
|
"Reaper": { chassis: "Warrior", hit_die: 10, role: "Dark Melee Striker / Avatar", spellcasting: "Optional" },
|
|
"Viper": { chassis: "Adept", hit_die: 8, role: "Dual-Blade Skirmisher", spellcasting: "No" },
|
|
"Monk": { chassis: "Adept", hit_die: 8, role: "Unarmed Striker", spellcasting: "No" },
|
|
"Mystic Knight": { chassis: "Adept", hit_die: 8, role: "Spellblade / Enchanted Weapon", spellcasting: "Intelligence" },
|
|
"Rune Knight": { chassis: "Adept", hit_die: 8, role: "Runic Defender / Spellblade", spellcasting: "Wisdom" },
|
|
"Berserker": { chassis: "Warrior", hit_die: 12, role: "High-Risk Melee Damage", spellcasting: "No" },
|
|
"Onion Knight": { chassis: "Custom", hit_die: 8, role: "Scaling Generalist", spellcasting: "Optional" },
|
|
|
|
"Rogue": { chassis: "Expert", hit_die: 8, role: "Precision / Skills", spellcasting: "No" },
|
|
"Thief": { chassis: "Expert", hit_die: 8, role: "Utility / Steal / Scout", spellcasting: "No" },
|
|
"Ninja": { chassis: "Expert", hit_die: 8, role: "Skirmisher / Stealth Striker", spellcasting: "Optional" },
|
|
"Ranger": { chassis: "Expert", hit_die: 8, role: "Ranged Scout", spellcasting: "Optional" },
|
|
"Archer": { chassis: "Expert", hit_die: 8, role: "Ranged Attacker", spellcasting: "No" },
|
|
"Sniper": { chassis: "Expert", hit_die: 8, role: "Precision Ranged Striker", spellcasting: "No" },
|
|
"Machinist": { chassis: "Expert", hit_die: 8, role: "Firearms / Gadgets / Magitek", spellcasting: "No" },
|
|
"Engineer": { chassis: "Expert", hit_die: 8, role: "Machines / Gadgets / Repair", spellcasting: "No" },
|
|
"Artificer": { chassis: "Expert", hit_die: 8, role: "Infusions / Crafting / Tech Magic", spellcasting: "Intelligence" },
|
|
"Bard": { chassis: "Expert", hit_die: 8, role: "Support / Songs", spellcasting: "Charisma" },
|
|
"Dancer": { chassis: "Expert", hit_die: 8, role: "Support / Mobility / Charm", spellcasting: "Charisma" },
|
|
"Alchemist": { chassis: "Expert", hit_die: 8, role: "Items / Crafting / Potion Support", spellcasting: "Optional" },
|
|
"Chemist": { chassis: "Expert", hit_die: 8, role: "Items / Mix / Recovery", spellcasting: "No" },
|
|
"Beastmaster": { chassis: "Expert", hit_die: 8, role: "Creature Control / Monster Tactics", spellcasting: "Optional" },
|
|
"Puppetmaster": { chassis: "Expert", hit_die: 8, role: "Automaton Controller", spellcasting: "No" },
|
|
"Corsair": { chassis: "Expert", hit_die: 8, role: "Guns / Luck / Party Support", spellcasting: "Optional" },
|
|
"Gambler": { chassis: "Expert", hit_die: 8, role: "Luck / Risk Effects", spellcasting: "Optional" },
|
|
"Mime": { chassis: "Expert", hit_die: 8, role: "Copycat / Reactive Utility", spellcasting: "Optional" },
|
|
|
|
"Black Mage": { chassis: "Mage", hit_die: 6, role: "Elemental Damage Caster", spellcasting: "Intelligence" },
|
|
"White Mage": { chassis: "Mage", hit_die: 6, role: "Healing / Holy Support", spellcasting: "Wisdom" },
|
|
"Red Mage": { chassis: "Adept", hit_die: 8, role: "Hybrid Spellblade", spellcasting: "Charisma" },
|
|
"Blue Mage": { chassis: "Adept", hit_die: 8, role: "Monster Magic / Adaptive Caster", spellcasting: "Charisma" },
|
|
"Time Mage": { chassis: "Mage", hit_die: 6, role: "Haste / Slow / Time Control", spellcasting: "Intelligence" },
|
|
"Green Mage": { chassis: "Mage", hit_die: 6, role: "Buffs / Debuffs / Status Magic", spellcasting: "Wisdom" },
|
|
"Geomancer": { chassis: "Mage", hit_die: 8, role: "Terrain / Nature Magic", spellcasting: "Wisdom" },
|
|
"Summoner": { chassis: "Mage", hit_die: 6, role: "Eidolons / Primal Magic", spellcasting: "Charisma" },
|
|
"Scholar": { chassis: "Mage", hit_die: 6, role: "Tactical Healing / Barrier Support", spellcasting: "Intelligence" },
|
|
"Sage": { chassis: "Mage", hit_die: 6, role: "Barrier Healing / Arcane Medicine", spellcasting: "Intelligence" },
|
|
"Astrologian": { chassis: "Mage", hit_die: 6, role: "Divination / Cards / Healing", spellcasting: "Wisdom" },
|
|
"Wizard": { chassis: "Mage", hit_die: 6, role: "Prepared Arcane Caster", spellcasting: "Intelligence" },
|
|
"Sorcerer": { chassis: "Mage", hit_die: 6, role: "Innate Arcane Caster", spellcasting: "Charisma" },
|
|
"Warlock": { chassis: "Mage", hit_die: 8, role: "Pact Magic / Dark Patron", spellcasting: "Charisma" },
|
|
"Cleric": { chassis: "Mage", hit_die: 8, role: "Divine Caster / Support", spellcasting: "Wisdom" },
|
|
"Druid": { chassis: "Mage", hit_die: 8, role: "Nature Magic / Forms", spellcasting: "Wisdom" },
|
|
"Oracle": { chassis: "Mage", hit_die: 6, role: "Prophecy / Curse / Support", spellcasting: "Wisdom" },
|
|
"Necromancer": { chassis: "Mage", hit_die: 6, role: "Undead / Dark Magic", spellcasting: "Intelligence" },
|
|
"Pictomancer": { chassis: "Mage", hit_die: 6, role: "Painted Constructs / Arcane Art", spellcasting: "Intelligence" }
|
|
};
|
|
|
|
/* =========================
|
|
VEHICLE DATA
|
|
========================= */
|
|
|
|
var FF5E_VEHICLE = {
|
|
scaleHPBase: function(type) {
|
|
var table = {
|
|
mount: 20,
|
|
warmachina: 100,
|
|
land_vehicle: 50,
|
|
airship: 150,
|
|
dreadnought: 300
|
|
};
|
|
|
|
return table[type] || 50;
|
|
},
|
|
|
|
defaultScale: function(type) {
|
|
var table = {
|
|
mount: "personal",
|
|
warmachina: "armor",
|
|
land_vehicle: "armor",
|
|
airship: "ship",
|
|
dreadnought: "ship"
|
|
};
|
|
|
|
return table[type] || "armor";
|
|
}
|
|
};
|
|
|
|
/* =========================
|
|
RESOURCE BUTTON HELPERS
|
|
========================= */
|
|
|
|
function adjustResource(currentAttr, maxAttr, adjustAttr, mode) {
|
|
getAttrs([currentAttr, maxAttr, adjustAttr], function(values) {
|
|
var current = FF5E.number(values[currentAttr], 0);
|
|
var max = FF5E.number(values[maxAttr], 0);
|
|
var amount = FF5E.number(values[adjustAttr], 0);
|
|
var next = FF5E.clampResource(current, max, amount, mode);
|
|
|
|
var update = {};
|
|
update[currentAttr] = next;
|
|
|
|
setAttrs(update);
|
|
});
|
|
}
|
|
|
|
function adjustUnboundedNumber(currentAttr, adjustAttr, mode, minimum) {
|
|
getAttrs([currentAttr, adjustAttr], function(values) {
|
|
var current = FF5E.number(values[currentAttr], 0);
|
|
var amount = FF5E.number(values[adjustAttr], 0);
|
|
var next = mode === "add" ? current + amount : current - amount;
|
|
|
|
if (minimum !== undefined) {
|
|
next = Math.max(minimum, next);
|
|
}
|
|
|
|
var update = {};
|
|
update[currentAttr] = next;
|
|
|
|
setAttrs(update);
|
|
});
|
|
}
|
|
|
|
/* Character resource buttons */
|
|
on("clicked:hp_add", function() {
|
|
adjustResource("hp_current", "hp_max", "hp_adjust", "add");
|
|
});
|
|
|
|
on("clicked:hp_subtract", function() {
|
|
adjustResource("hp_current", "hp_max", "hp_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:mp_add", function() {
|
|
adjustResource("mp_current", "mp_max", "mp_adjust", "add");
|
|
});
|
|
|
|
on("clicked:mp_subtract", function() {
|
|
adjustResource("mp_current", "mp_max", "mp_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:limit_add", function() {
|
|
adjustResource("limit_current", "limit_max", "limit_adjust", "add");
|
|
});
|
|
|
|
on("clicked:limit_subtract", function() {
|
|
adjustResource("limit_current", "limit_max", "limit_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:exp_add", function() {
|
|
adjustUnboundedNumber("exp_current", "exp_adjust", "add", 0);
|
|
});
|
|
|
|
on("clicked:exp_subtract", function() {
|
|
adjustUnboundedNumber("exp_current", "exp_adjust", "subtract", 0);
|
|
});
|
|
|
|
/* Monster resource buttons */
|
|
on("clicked:npc_hp_add", function() {
|
|
adjustResource("npc_hp_current", "npc_hp_max", "npc_hp_adjust", "add");
|
|
});
|
|
|
|
on("clicked:npc_hp_subtract", function() {
|
|
adjustResource("npc_hp_current", "npc_hp_max", "npc_hp_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:npc_mp_add", function() {
|
|
adjustResource("npc_mp_current", "npc_mp_max", "npc_mp_adjust", "add");
|
|
});
|
|
|
|
on("clicked:npc_mp_subtract", function() {
|
|
adjustResource("npc_mp_current", "npc_mp_max", "npc_mp_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:npc_limit_add", function() {
|
|
adjustResource("npc_limit_current", "npc_limit_max", "npc_limit_adjust", "add");
|
|
});
|
|
|
|
on("clicked:npc_limit_subtract", function() {
|
|
adjustResource("npc_limit_current", "npc_limit_max", "npc_limit_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:boss_phase_add", function() {
|
|
adjustUnboundedNumber("boss_phase", "boss_phase_adjust", "add", 1);
|
|
});
|
|
|
|
on("clicked:boss_phase_subtract", function() {
|
|
adjustUnboundedNumber("boss_phase", "boss_phase_adjust", "subtract", 1);
|
|
});
|
|
|
|
/* Vehicle resource buttons */
|
|
on("clicked:vehicle_hp_add", function() {
|
|
adjustResource("vehicle_hp_current", "vehicle_hp_max", "vehicle_hp_adjust", "add");
|
|
});
|
|
|
|
on("clicked:vehicle_hp_subtract", function() {
|
|
adjustResource("vehicle_hp_current", "vehicle_hp_max", "vehicle_hp_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:vehicle_mp_add", function() {
|
|
adjustResource("vehicle_mp_current", "vehicle_mp_max", "vehicle_mp_adjust", "add");
|
|
});
|
|
|
|
on("clicked:vehicle_mp_subtract", function() {
|
|
adjustResource("vehicle_mp_current", "vehicle_mp_max", "vehicle_mp_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:vehicle_limit_add", function() {
|
|
adjustResource("vehicle_limit_current", "vehicle_limit_max", "vehicle_limit_adjust", "add");
|
|
});
|
|
|
|
on("clicked:vehicle_limit_subtract", function() {
|
|
adjustResource("vehicle_limit_current", "vehicle_limit_max", "vehicle_limit_adjust", "subtract");
|
|
});
|
|
|
|
on("clicked:vehicle_shield_add", function() {
|
|
adjustResource("vehicle_shield_current", "vehicle_shield_max", "vehicle_shield_adjust", "add");
|
|
});
|
|
|
|
on("clicked:vehicle_shield_subtract", function() {
|
|
adjustResource("vehicle_shield_current", "vehicle_shield_max", "vehicle_shield_adjust", "subtract");
|
|
});
|
|
|
|
/* =========================
|
|
MODE / TAB BUTTONS
|
|
========================= */
|
|
|
|
on("clicked:mode_character", function() {
|
|
setAttrs({ sheet_mode: "character", sheet_tab: "overview" });
|
|
});
|
|
|
|
on("clicked:mode_monster", function() {
|
|
setAttrs({ sheet_mode: "monster", sheet_tab: "monster-core" });
|
|
});
|
|
|
|
on("clicked:mode_vehicle", function() {
|
|
setAttrs({ sheet_mode: "vehicle", sheet_tab: "vehicle-core" });
|
|
});
|
|
|
|
on("clicked:tab_overview", function() { setAttrs({ sheet_tab: "overview" }); });
|
|
on("clicked:tab_cp", function() { setAttrs({ sheet_tab: "cp" }); });
|
|
on("clicked:tab_combat", function() { setAttrs({ sheet_tab: "combat" }); });
|
|
on("clicked:tab_magic", function() { setAttrs({ sheet_tab: "magic" }); });
|
|
on("clicked:tab_equipment", function() { setAttrs({ sheet_tab: "equipment" }); });
|
|
on("clicked:tab_status", function() { setAttrs({ sheet_tab: "status" }); });
|
|
on("clicked:tab_bio", function() { setAttrs({ sheet_tab: "bio" }); });
|
|
|
|
on("clicked:tab_monster_core", function() { setAttrs({ sheet_tab: "monster-core" }); });
|
|
on("clicked:tab_monster_actions", function() { setAttrs({ sheet_tab: "monster-actions" }); });
|
|
on("clicked:tab_monster_status", function() { setAttrs({ sheet_tab: "monster-status" }); });
|
|
on("clicked:tab_monster_import", function() { setAttrs({ sheet_tab: "monster-import" }); });
|
|
|
|
on("clicked:tab_vehicle_core", function() { setAttrs({ sheet_tab: "vehicle-core" }); });
|
|
on("clicked:tab_vehicle_weapons", function() { setAttrs({ sheet_tab: "vehicle-weapons" }); });
|
|
on("clicked:tab_vehicle_systems", function() { setAttrs({ sheet_tab: "vehicle-systems" }); });
|
|
on("clicked:tab_vehicle_scale", function() { setAttrs({ sheet_tab: "vehicle-scale" }); });
|
|
|
|
/* =========================
|
|
JOB LEVELS / TOTAL LEVEL / EXP
|
|
Proficiency is now editable/manual.
|
|
========================= */
|
|
|
|
function updateTotalLevel() {
|
|
getAttrs(["primary_job_level", "secondary_job_level", "exp_next", "level"], function(values) {
|
|
var primary = Math.max(0, FF5E.number(values.primary_job_level, 1));
|
|
var secondary = Math.max(0, FF5E.number(values.secondary_job_level, 0));
|
|
var total = Math.max(1, primary + secondary);
|
|
|
|
var updates = {
|
|
level: total,
|
|
cp_baseline: FF5E.baselineCP(total)
|
|
};
|
|
|
|
if (!values.exp_next || FF5E.number(values.exp_next, 0) === 0) {
|
|
updates.exp_next = FF5E.expNextByLevel(total);
|
|
}
|
|
|
|
setAttrs(updates);
|
|
});
|
|
}
|
|
|
|
function updateExpTracker() {
|
|
getAttrs(["exp_current", "exp_next", "level"], function(values) {
|
|
var current = Math.max(0, FF5E.number(values.exp_current, 0));
|
|
var next = Math.max(0, FF5E.number(values.exp_next, FF5E.expNextByLevel(values.level)));
|
|
var remaining = Math.max(0, next - current);
|
|
var status = "Tracking";
|
|
|
|
if (next <= 0) {
|
|
status = "Max Level / Manual";
|
|
remaining = 0;
|
|
} else if (current >= next) {
|
|
status = "Ready to Level";
|
|
remaining = 0;
|
|
} else {
|
|
status = remaining + " EXP needed";
|
|
}
|
|
|
|
setAttrs({
|
|
exp_current: current,
|
|
exp_remaining: remaining,
|
|
exp_status: status
|
|
});
|
|
});
|
|
}
|
|
|
|
on("change:primary_job_level change:secondary_job_level sheet:opened", updateTotalLevel);
|
|
on("change:exp_current change:exp_next change:level sheet:opened", updateExpTracker);
|
|
|
|
/* =========================
|
|
RACE + EFFECTIVE STATS
|
|
Race features stay editable.
|
|
========================= */
|
|
|
|
function recalculateEffectiveStats() {
|
|
getAttrs([
|
|
"strength",
|
|
"dexterity",
|
|
"constitution",
|
|
"intelligence",
|
|
"wisdom",
|
|
"charisma",
|
|
"race",
|
|
"race_variant",
|
|
"race_choice_1",
|
|
"race_choice_2",
|
|
"race_features"
|
|
], function(values) {
|
|
var race = FF5E_FULL_RACES[values.race] || FF5E_FULL_RACES.Hume;
|
|
var bonuses = FF5E.blankBonuses();
|
|
|
|
if (race.bonuses) {
|
|
Object.keys(race.bonuses).forEach(function(ability) {
|
|
FF5E.addBonus(bonuses, ability, race.bonuses[ability]);
|
|
});
|
|
}
|
|
|
|
if (race.variants && values.race_variant && race.variants[values.race_variant]) {
|
|
var variant = race.variants[values.race_variant];
|
|
|
|
Object.keys(variant).forEach(function(ability) {
|
|
FF5E.addBonus(bonuses, ability, variant[ability]);
|
|
});
|
|
}
|
|
|
|
FF5E.addBonus(bonuses, values.race_choice_1, 1);
|
|
FF5E.addBonus(bonuses, values.race_choice_2, 1);
|
|
|
|
var totals = {};
|
|
var mods = {};
|
|
|
|
["strength", "dexterity", "constitution", "intelligence", "wisdom", "charisma"].forEach(function(ability) {
|
|
totals[ability] = FF5E.number(values[ability], 10) + bonuses[ability];
|
|
mods[ability] = FF5E.mod(totals[ability]);
|
|
});
|
|
|
|
var updates = {
|
|
strength_total: totals.strength,
|
|
dexterity_total: totals.dexterity,
|
|
constitution_total: totals.constitution,
|
|
intelligence_total: totals.intelligence,
|
|
wisdom_total: totals.wisdom,
|
|
charisma_total: totals.charisma,
|
|
|
|
strength_mod: mods.strength,
|
|
dexterity_mod: mods.dexterity,
|
|
constitution_mod: mods.constitution,
|
|
intelligence_mod: mods.intelligence,
|
|
wisdom_mod: mods.wisdom,
|
|
charisma_mod: mods.charisma,
|
|
|
|
initiative: mods.dexterity,
|
|
speed: race.speed || 30,
|
|
racial_cp_bonus: race.cp_bonus || 0,
|
|
fly_speed: race.fly_speed || 0,
|
|
racial_mp_bonus: race.mp_bonus || 0,
|
|
natural_ac_base: race.natural_ac_base || 0,
|
|
hp_per_level_bonus: race.hp_per_level_bonus || 0
|
|
};
|
|
|
|
if (!values.race_features) {
|
|
updates.race_features = race.features || "";
|
|
}
|
|
|
|
if (race.chassis_cp_bonus) {
|
|
updates.chassis_cp_bonus = race.chassis_cp_bonus;
|
|
}
|
|
|
|
if (race.mp_override === 0) {
|
|
updates.mp_max = 0;
|
|
updates.mp_current = 0;
|
|
updates.aetherial_ineptitude = "Yes";
|
|
} else {
|
|
updates.aetherial_ineptitude = "No";
|
|
}
|
|
|
|
setAttrs(updates);
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:race change:race_variant change:race_choice_1 change:race_choice_2 change:strength change:dexterity change:constitution change:intelligence change:wisdom change:charisma sheet:opened",
|
|
recalculateEffectiveStats
|
|
);
|
|
|
|
/* =========================
|
|
JOB PRESETS
|
|
========================= */
|
|
|
|
function applyJobPreset(jobName, prefix) {
|
|
var job = FF5E_FULL_JOBS[jobName] || FF5E_FULL_JOBS.Custom;
|
|
var updates = {};
|
|
|
|
if (prefix === "primary") {
|
|
updates.chassis = job.chassis;
|
|
updates.hit_die = job.hit_die;
|
|
updates.primary_role = job.role;
|
|
updates.job_spellcasting = job.spellcasting;
|
|
|
|
if (job.spellcasting === "Intelligence") {
|
|
updates.spellcasting_ability = "intelligence_mod";
|
|
}
|
|
|
|
if (job.spellcasting === "Wisdom") {
|
|
updates.spellcasting_ability = "wisdom_mod";
|
|
}
|
|
|
|
if (job.spellcasting === "Charisma") {
|
|
updates.spellcasting_ability = "charisma_mod";
|
|
}
|
|
}
|
|
|
|
if (prefix === "secondary") {
|
|
updates.secondary_role = jobName ? job.role : "";
|
|
updates.secondary_spellcasting = jobName ? job.spellcasting : "";
|
|
}
|
|
|
|
setAttrs(updates);
|
|
}
|
|
|
|
on("change:primary_job sheet:opened", function() {
|
|
getAttrs(["primary_job"], function(values) {
|
|
applyJobPreset(values.primary_job || "Freelancer", "primary");
|
|
});
|
|
});
|
|
|
|
on("change:secondary_job sheet:opened", function() {
|
|
getAttrs(["secondary_job"], function(values) {
|
|
applyJobPreset(values.secondary_job || "", "secondary");
|
|
});
|
|
});
|
|
|
|
/* =========================
|
|
CP ENGINE
|
|
========================= */
|
|
|
|
function updateCPTotalFromRepeating() {
|
|
getSectionIDs("attributes", function(ids) {
|
|
var fields = [];
|
|
|
|
ids.forEach(function(id) {
|
|
fields.push("repeating_attributes_" + id + "_attribute_cost");
|
|
});
|
|
|
|
fields.push("cp_baseline", "racial_cp_bonus", "defect_cp_bonus", "chassis_cp_bonus");
|
|
|
|
getAttrs(fields, function(values) {
|
|
var spent = 0;
|
|
|
|
ids.forEach(function(id) {
|
|
spent += FF5E.number(values["repeating_attributes_" + id + "_attribute_cost"], 0);
|
|
});
|
|
|
|
var baseline = FF5E.number(values.cp_baseline, 10);
|
|
var racial = FF5E.number(values.racial_cp_bonus, 0);
|
|
var defect = FF5E.number(values.defect_cp_bonus, 0);
|
|
var chassis = FF5E.number(values.chassis_cp_bonus, 0);
|
|
var total = baseline + racial + defect + chassis;
|
|
|
|
setAttrs({
|
|
cp_total: total,
|
|
cp_spent: spent,
|
|
cp_remaining: total - spent,
|
|
cp_warning: spent > total ? "Overspent" : "OK"
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:repeating_attributes:attribute_cost remove:repeating_attributes change:cp_baseline change:racial_cp_bonus change:defect_cp_bonus change:chassis_cp_bonus sheet:opened",
|
|
updateCPTotalFromRepeating
|
|
);
|
|
|
|
/* =========================
|
|
ABILITY CHECK AUTOMATION
|
|
========================= */
|
|
|
|
function updateAbilityChecks() {
|
|
getAttrs([
|
|
"strength_mod",
|
|
"dexterity_mod",
|
|
"constitution_mod",
|
|
"intelligence_mod",
|
|
"wisdom_mod",
|
|
"charisma_mod",
|
|
"proficiency_bonus",
|
|
|
|
"check_strength_prof",
|
|
"check_strength_expert",
|
|
"check_strength_bonus",
|
|
|
|
"check_dexterity_prof",
|
|
"check_dexterity_expert",
|
|
"check_dexterity_bonus",
|
|
|
|
"check_constitution_prof",
|
|
"check_constitution_expert",
|
|
"check_constitution_bonus",
|
|
|
|
"check_intelligence_prof",
|
|
"check_intelligence_expert",
|
|
"check_intelligence_bonus",
|
|
|
|
"check_wisdom_prof",
|
|
"check_wisdom_expert",
|
|
"check_wisdom_bonus",
|
|
|
|
"check_charisma_prof",
|
|
"check_charisma_expert",
|
|
"check_charisma_bonus"
|
|
], function(values) {
|
|
var prof = FF5E.number(values.proficiency_bonus, 2);
|
|
|
|
setAttrs({
|
|
check_strength_total: FF5E.skillTotal(values.strength_mod, prof, values.check_strength_prof, values.check_strength_expert, values.check_strength_bonus),
|
|
check_dexterity_total: FF5E.skillTotal(values.dexterity_mod, prof, values.check_dexterity_prof, values.check_dexterity_expert, values.check_dexterity_bonus),
|
|
check_constitution_total: FF5E.skillTotal(values.constitution_mod, prof, values.check_constitution_prof, values.check_constitution_expert, values.check_constitution_bonus),
|
|
check_intelligence_total: FF5E.skillTotal(values.intelligence_mod, prof, values.check_intelligence_prof, values.check_intelligence_expert, values.check_intelligence_bonus),
|
|
check_wisdom_total: FF5E.skillTotal(values.wisdom_mod, prof, values.check_wisdom_prof, values.check_wisdom_expert, values.check_wisdom_bonus),
|
|
check_charisma_total: FF5E.skillTotal(values.charisma_mod, prof, values.check_charisma_prof, values.check_charisma_expert, values.check_charisma_bonus)
|
|
});
|
|
});
|
|
}
|
|
|
|
on("change:strength_mod change:dexterity_mod change:constitution_mod change:intelligence_mod change:wisdom_mod change:charisma_mod change:proficiency_bonus sheet:opened", updateAbilityChecks);
|
|
on("change:check_strength_prof change:check_strength_expert change:check_strength_bonus", updateAbilityChecks);
|
|
on("change:check_dexterity_prof change:check_dexterity_expert change:check_dexterity_bonus", updateAbilityChecks);
|
|
on("change:check_constitution_prof change:check_constitution_expert change:check_constitution_bonus", updateAbilityChecks);
|
|
on("change:check_intelligence_prof change:check_intelligence_expert change:check_intelligence_bonus", updateAbilityChecks);
|
|
on("change:check_wisdom_prof change:check_wisdom_expert change:check_wisdom_bonus", updateAbilityChecks);
|
|
on("change:check_charisma_prof change:check_charisma_expert change:check_charisma_bonus", updateAbilityChecks);
|
|
|
|
/* =========================
|
|
SAVING THROW AUTOMATION
|
|
========================= */
|
|
|
|
function updateSavingThrows() {
|
|
getAttrs([
|
|
"strength_mod",
|
|
"dexterity_mod",
|
|
"constitution_mod",
|
|
"intelligence_mod",
|
|
"wisdom_mod",
|
|
"charisma_mod",
|
|
"proficiency_bonus",
|
|
|
|
"save_strength_prof",
|
|
"save_dexterity_prof",
|
|
"save_constitution_prof",
|
|
"save_intelligence_prof",
|
|
"save_wisdom_prof",
|
|
"save_charisma_prof",
|
|
|
|
"save_strength_bonus",
|
|
"save_dexterity_bonus",
|
|
"save_constitution_bonus",
|
|
"save_intelligence_bonus",
|
|
"save_wisdom_bonus",
|
|
"save_charisma_bonus"
|
|
], function(values) {
|
|
var prof = FF5E.number(values.proficiency_bonus, 2);
|
|
|
|
setAttrs({
|
|
save_strength_total: FF5E.saveTotal(values.strength_mod, prof, values.save_strength_prof, values.save_strength_bonus),
|
|
save_dexterity_total: FF5E.saveTotal(values.dexterity_mod, prof, values.save_dexterity_prof, values.save_dexterity_bonus),
|
|
save_constitution_total: FF5E.saveTotal(values.constitution_mod, prof, values.save_constitution_prof, values.save_constitution_bonus),
|
|
save_intelligence_total: FF5E.saveTotal(values.intelligence_mod, prof, values.save_intelligence_prof, values.save_intelligence_bonus),
|
|
save_wisdom_total: FF5E.saveTotal(values.wisdom_mod, prof, values.save_wisdom_prof, values.save_wisdom_bonus),
|
|
save_charisma_total: FF5E.saveTotal(values.charisma_mod, prof, values.save_charisma_prof, values.save_charisma_bonus)
|
|
});
|
|
});
|
|
}
|
|
|
|
on("change:strength_mod change:dexterity_mod change:constitution_mod change:intelligence_mod change:wisdom_mod change:charisma_mod change:proficiency_bonus sheet:opened", updateSavingThrows);
|
|
on("change:save_strength_prof change:save_dexterity_prof change:save_constitution_prof change:save_intelligence_prof change:save_wisdom_prof change:save_charisma_prof", updateSavingThrows);
|
|
on("change:save_strength_bonus change:save_dexterity_bonus change:save_constitution_bonus change:save_intelligence_bonus change:save_wisdom_bonus change:save_charisma_bonus", updateSavingThrows);
|
|
|
|
/* =========================
|
|
SKILL AUTOMATION
|
|
========================= */
|
|
|
|
function updateSkills() {
|
|
getAttrs([
|
|
"strength_mod",
|
|
"dexterity_mod",
|
|
"constitution_mod",
|
|
"intelligence_mod",
|
|
"wisdom_mod",
|
|
"charisma_mod",
|
|
"proficiency_bonus",
|
|
|
|
"skill_acrobatics_prof", "skill_acrobatics_expert", "skill_acrobatics_bonus",
|
|
"skill_animal_handling_prof", "skill_animal_handling_expert", "skill_animal_handling_bonus",
|
|
"skill_arcana_prof", "skill_arcana_expert", "skill_arcana_bonus",
|
|
"skill_athletics_prof", "skill_athletics_expert", "skill_athletics_bonus",
|
|
"skill_deception_prof", "skill_deception_expert", "skill_deception_bonus",
|
|
"skill_history_prof", "skill_history_expert", "skill_history_bonus",
|
|
"skill_insight_prof", "skill_insight_expert", "skill_insight_bonus",
|
|
"skill_intimidation_prof", "skill_intimidation_expert", "skill_intimidation_bonus",
|
|
"skill_investigation_prof", "skill_investigation_expert", "skill_investigation_bonus",
|
|
"skill_medicine_prof", "skill_medicine_expert", "skill_medicine_bonus",
|
|
"skill_nature_prof", "skill_nature_expert", "skill_nature_bonus",
|
|
"skill_perception_prof", "skill_perception_expert", "skill_perception_bonus",
|
|
"skill_performance_prof", "skill_performance_expert", "skill_performance_bonus",
|
|
"skill_persuasion_prof", "skill_persuasion_expert", "skill_persuasion_bonus",
|
|
"skill_religion_prof", "skill_religion_expert", "skill_religion_bonus",
|
|
"skill_sleight_of_hand_prof", "skill_sleight_of_hand_expert", "skill_sleight_of_hand_bonus",
|
|
"skill_stealth_prof", "skill_stealth_expert", "skill_stealth_bonus",
|
|
"skill_survival_prof", "skill_survival_expert", "skill_survival_bonus"
|
|
], function(values) {
|
|
var prof = FF5E.number(values.proficiency_bonus, 2);
|
|
|
|
setAttrs({
|
|
skill_acrobatics: FF5E.skillTotal(values.dexterity_mod, prof, values.skill_acrobatics_prof, values.skill_acrobatics_expert, values.skill_acrobatics_bonus),
|
|
skill_animal_handling: FF5E.skillTotal(values.wisdom_mod, prof, values.skill_animal_handling_prof, values.skill_animal_handling_expert, values.skill_animal_handling_bonus),
|
|
skill_arcana: FF5E.skillTotal(values.intelligence_mod, prof, values.skill_arcana_prof, values.skill_arcana_expert, values.skill_arcana_bonus),
|
|
skill_athletics: FF5E.skillTotal(values.strength_mod, prof, values.skill_athletics_prof, values.skill_athletics_expert, values.skill_athletics_bonus),
|
|
skill_deception: FF5E.skillTotal(values.charisma_mod, prof, values.skill_deception_prof, values.skill_deception_expert, values.skill_deception_bonus),
|
|
skill_history: FF5E.skillTotal(values.intelligence_mod, prof, values.skill_history_prof, values.skill_history_expert, values.skill_history_bonus),
|
|
skill_insight: FF5E.skillTotal(values.wisdom_mod, prof, values.skill_insight_prof, values.skill_insight_expert, values.skill_insight_bonus),
|
|
skill_intimidation: FF5E.skillTotal(values.charisma_mod, prof, values.skill_intimidation_prof, values.skill_intimidation_expert, values.skill_intimidation_bonus),
|
|
skill_investigation: FF5E.skillTotal(values.intelligence_mod, prof, values.skill_investigation_prof, values.skill_investigation_expert, values.skill_investigation_bonus),
|
|
skill_medicine: FF5E.skillTotal(values.wisdom_mod, prof, values.skill_medicine_prof, values.skill_medicine_expert, values.skill_medicine_bonus),
|
|
skill_nature: FF5E.skillTotal(values.intelligence_mod, prof, values.skill_nature_prof, values.skill_nature_expert, values.skill_nature_bonus),
|
|
skill_perception: FF5E.skillTotal(values.wisdom_mod, prof, values.skill_perception_prof, values.skill_perception_expert, values.skill_perception_bonus),
|
|
skill_performance: FF5E.skillTotal(values.charisma_mod, prof, values.skill_performance_prof, values.skill_performance_expert, values.skill_performance_bonus),
|
|
skill_persuasion: FF5E.skillTotal(values.charisma_mod, prof, values.skill_persuasion_prof, values.skill_persuasion_expert, values.skill_persuasion_bonus),
|
|
skill_religion: FF5E.skillTotal(values.intelligence_mod, prof, values.skill_religion_prof, values.skill_religion_expert, values.skill_religion_bonus),
|
|
skill_sleight_of_hand: FF5E.skillTotal(values.dexterity_mod, prof, values.skill_sleight_of_hand_prof, values.skill_sleight_of_hand_expert, values.skill_sleight_of_hand_bonus),
|
|
skill_stealth: FF5E.skillTotal(values.dexterity_mod, prof, values.skill_stealth_prof, values.skill_stealth_expert, values.skill_stealth_bonus),
|
|
skill_survival: FF5E.skillTotal(values.wisdom_mod, prof, values.skill_survival_prof, values.skill_survival_expert, values.skill_survival_bonus)
|
|
});
|
|
});
|
|
}
|
|
|
|
on("change:strength_mod change:dexterity_mod change:constitution_mod change:intelligence_mod change:wisdom_mod change:charisma_mod change:proficiency_bonus sheet:opened", updateSkills);
|
|
|
|
on("change:skill_acrobatics_prof change:skill_acrobatics_expert change:skill_acrobatics_bonus", updateSkills);
|
|
on("change:skill_animal_handling_prof change:skill_animal_handling_expert change:skill_animal_handling_bonus", updateSkills);
|
|
on("change:skill_arcana_prof change:skill_arcana_expert change:skill_arcana_bonus", updateSkills);
|
|
on("change:skill_athletics_prof change:skill_athletics_expert change:skill_athletics_bonus", updateSkills);
|
|
on("change:skill_deception_prof change:skill_deception_expert change:skill_deception_bonus", updateSkills);
|
|
on("change:skill_history_prof change:skill_history_expert change:skill_history_bonus", updateSkills);
|
|
on("change:skill_insight_prof change:skill_insight_expert change:skill_insight_bonus", updateSkills);
|
|
on("change:skill_intimidation_prof change:skill_intimidation_expert change:skill_intimidation_bonus", updateSkills);
|
|
on("change:skill_investigation_prof change:skill_investigation_expert change:skill_investigation_bonus", updateSkills);
|
|
on("change:skill_medicine_prof change:skill_medicine_expert change:skill_medicine_bonus", updateSkills);
|
|
on("change:skill_nature_prof change:skill_nature_expert change:skill_nature_bonus", updateSkills);
|
|
on("change:skill_perception_prof change:skill_perception_expert change:skill_perception_bonus", updateSkills);
|
|
on("change:skill_performance_prof change:skill_performance_expert change:skill_performance_bonus", updateSkills);
|
|
on("change:skill_persuasion_prof change:skill_persuasion_expert change:skill_persuasion_bonus", updateSkills);
|
|
on("change:skill_religion_prof change:skill_religion_expert change:skill_religion_bonus", updateSkills);
|
|
on("change:skill_sleight_of_hand_prof change:skill_sleight_of_hand_expert change:skill_sleight_of_hand_bonus", updateSkills);
|
|
on("change:skill_stealth_prof change:skill_stealth_expert change:skill_stealth_bonus", updateSkills);
|
|
on("change:skill_survival_prof change:skill_survival_expert change:skill_survival_bonus", updateSkills);
|
|
|
|
/* =========================
|
|
ATTACK BONUSES
|
|
========================= */
|
|
|
|
function updateRepeatingAttackBonuses() {
|
|
getSectionIDs("attacks", function(ids) {
|
|
var baseFields = [
|
|
"strength_mod",
|
|
"dexterity_mod",
|
|
"intelligence_mod",
|
|
"wisdom_mod",
|
|
"charisma_mod",
|
|
"proficiency_bonus"
|
|
];
|
|
|
|
var rowFields = [];
|
|
|
|
ids.forEach(function(id) {
|
|
rowFields.push("repeating_attacks_" + id + "_attack_stat");
|
|
rowFields.push("repeating_attacks_" + id + "_attack_proficient");
|
|
rowFields.push("repeating_attacks_" + id + "_attack_weapon_bonus");
|
|
});
|
|
|
|
getAttrs(baseFields.concat(rowFields), function(values) {
|
|
var updates = {};
|
|
var prof = FF5E.number(values.proficiency_bonus, 2);
|
|
|
|
ids.forEach(function(id) {
|
|
var statKey = values["repeating_attacks_" + id + "_attack_stat"] || "strength_mod";
|
|
var statMod = FF5E.number(values[statKey], 0);
|
|
var proficient = FF5E.bool(values["repeating_attacks_" + id + "_attack_proficient"]);
|
|
var weaponBonus = FF5E.number(values["repeating_attacks_" + id + "_attack_weapon_bonus"], 0);
|
|
|
|
updates["repeating_attacks_" + id + "_attack_total_bonus"] =
|
|
statMod + weaponBonus + (proficient ? prof : 0);
|
|
});
|
|
|
|
setAttrs(updates);
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:strength_mod change:dexterity_mod change:intelligence_mod change:wisdom_mod change:charisma_mod change:proficiency_bonus change:repeating_attacks:attack_stat change:repeating_attacks:attack_proficient change:repeating_attacks:attack_weapon_bonus remove:repeating_attacks sheet:opened",
|
|
updateRepeatingAttackBonuses
|
|
);
|
|
|
|
/* =========================
|
|
MATERIA BONUSES + SPELL LINKS
|
|
========================= */
|
|
|
|
function updateMateriaBonuses() {
|
|
getSectionIDs("materia", function(ids) {
|
|
var fields = [];
|
|
|
|
ids.forEach(function(id) {
|
|
fields.push("repeating_materia_" + id + "_materia_equipped");
|
|
fields.push("repeating_materia_" + id + "_materia_grants_spell");
|
|
fields.push("repeating_materia_" + id + "_materia_mp_bonus");
|
|
fields.push("repeating_materia_" + id + "_materia_str_bonus");
|
|
fields.push("repeating_materia_" + id + "_materia_dex_bonus");
|
|
fields.push("repeating_materia_" + id + "_materia_con_bonus");
|
|
fields.push("repeating_materia_" + id + "_materia_int_bonus");
|
|
fields.push("repeating_materia_" + id + "_materia_wis_bonus");
|
|
fields.push("repeating_materia_" + id + "_materia_cha_bonus");
|
|
});
|
|
|
|
getAttrs(fields, function(values) {
|
|
var mpBonus = 0;
|
|
var strBonus = 0;
|
|
var dexBonus = 0;
|
|
var conBonus = 0;
|
|
var intBonus = 0;
|
|
var wisBonus = 0;
|
|
var chaBonus = 0;
|
|
var grantedSpells = [];
|
|
|
|
ids.forEach(function(id) {
|
|
var equipped = values["repeating_materia_" + id + "_materia_equipped"] || "0";
|
|
|
|
if (equipped === "1") {
|
|
mpBonus += FF5E.number(values["repeating_materia_" + id + "_materia_mp_bonus"], 0);
|
|
strBonus += FF5E.number(values["repeating_materia_" + id + "_materia_str_bonus"], 0);
|
|
dexBonus += FF5E.number(values["repeating_materia_" + id + "_materia_dex_bonus"], 0);
|
|
conBonus += FF5E.number(values["repeating_materia_" + id + "_materia_con_bonus"], 0);
|
|
intBonus += FF5E.number(values["repeating_materia_" + id + "_materia_int_bonus"], 0);
|
|
wisBonus += FF5E.number(values["repeating_materia_" + id + "_materia_wis_bonus"], 0);
|
|
chaBonus += FF5E.number(values["repeating_materia_" + id + "_materia_cha_bonus"], 0);
|
|
|
|
var spell = values["repeating_materia_" + id + "_materia_grants_spell"];
|
|
|
|
if (spell) {
|
|
grantedSpells.push(String(spell).toLowerCase());
|
|
}
|
|
}
|
|
});
|
|
|
|
setAttrs({
|
|
materia_mp_bonus: mpBonus,
|
|
materia_str_bonus: strBonus,
|
|
materia_dex_bonus: dexBonus,
|
|
materia_con_bonus: conBonus,
|
|
materia_int_bonus: intBonus,
|
|
materia_wis_bonus: wisBonus,
|
|
materia_cha_bonus: chaBonus,
|
|
materia_granted_spells: grantedSpells.join(", ")
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:repeating_materia:materia_equipped change:repeating_materia:materia_mp_bonus change:repeating_materia:materia_str_bonus change:repeating_materia:materia_dex_bonus change:repeating_materia:materia_con_bonus change:repeating_materia:materia_int_bonus change:repeating_materia:materia_wis_bonus change:repeating_materia:materia_cha_bonus change:repeating_materia:materia_grants_spell remove:repeating_materia sheet:opened",
|
|
updateMateriaBonuses
|
|
);
|
|
|
|
function updateSpellUnlocksFromMateria() {
|
|
getSectionIDs("spells", function(spellIds) {
|
|
getAttrs(["materia_granted_spells"], function(baseValues) {
|
|
var granted = String(baseValues.materia_granted_spells || "").toLowerCase();
|
|
var fields = [];
|
|
|
|
spellIds.forEach(function(id) {
|
|
fields.push("repeating_spells_" + id + "_spell_name");
|
|
fields.push("repeating_spells_" + id + "_spell_source");
|
|
});
|
|
|
|
getAttrs(fields, function(values) {
|
|
var updates = {};
|
|
|
|
spellIds.forEach(function(id) {
|
|
var name = String(values["repeating_spells_" + id + "_spell_name"] || "").toLowerCase();
|
|
var source = values["repeating_spells_" + id + "_spell_source"] || "";
|
|
|
|
if (source === "Materia") {
|
|
updates["repeating_spells_" + id + "_spell_unlocked"] =
|
|
name && granted.indexOf(name) !== -1 ? "Yes" : "No";
|
|
} else {
|
|
updates["repeating_spells_" + id + "_spell_unlocked"] = "Yes";
|
|
}
|
|
});
|
|
|
|
setAttrs(updates);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:materia_granted_spells change:repeating_spells:spell_name change:repeating_spells:spell_source remove:repeating_spells sheet:opened",
|
|
updateSpellUnlocksFromMateria
|
|
);
|
|
|
|
/* =========================
|
|
SPELLCASTING / MP
|
|
========================= */
|
|
|
|
function updateSpellcastingStats() {
|
|
getAttrs([
|
|
"spellcasting_ability",
|
|
"intelligence_mod",
|
|
"wisdom_mod",
|
|
"charisma_mod",
|
|
"level",
|
|
"proficiency_bonus",
|
|
"racial_mp_bonus",
|
|
"materia_mp_bonus",
|
|
"aetherial_ineptitude"
|
|
], function(values) {
|
|
if (values.aetherial_ineptitude === "Yes") {
|
|
setAttrs({
|
|
spellcasting_mod: 0,
|
|
spell_attack_bonus: 0,
|
|
spell_save_dc: 0,
|
|
total_mp_bonus: 0,
|
|
mp_max: 0,
|
|
mp_current: 0
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
var level = FF5E.number(values.level, 1);
|
|
var prof = FF5E.number(values.proficiency_bonus, FF5E.prof(level));
|
|
var spellMod = FF5E.number(values.intelligence_mod, 0);
|
|
|
|
if (values.spellcasting_ability === "wisdom_mod") {
|
|
spellMod = FF5E.number(values.wisdom_mod, 0);
|
|
}
|
|
|
|
if (values.spellcasting_ability === "charisma_mod") {
|
|
spellMod = FF5E.number(values.charisma_mod, 0);
|
|
}
|
|
|
|
var racialMP = FF5E.number(values.racial_mp_bonus, 0);
|
|
var materiaMP = FF5E.number(values.materia_mp_bonus, 0);
|
|
var totalBonus = racialMP + materiaMP;
|
|
|
|
setAttrs({
|
|
spellcasting_mod: spellMod,
|
|
spell_attack_bonus: spellMod + prof,
|
|
spell_save_dc: 8 + prof + spellMod,
|
|
total_mp_bonus: totalBonus,
|
|
mp_max: Math.max(0, (spellMod * 2) + level + totalBonus)
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:spellcasting_ability change:intelligence_mod change:wisdom_mod change:charisma_mod change:level change:proficiency_bonus change:racial_mp_bonus change:materia_mp_bonus change:aetherial_ineptitude sheet:opened",
|
|
updateSpellcastingStats
|
|
);
|
|
|
|
/* =========================
|
|
ARMOR CLASS
|
|
========================= */
|
|
|
|
function updateArmorClass() {
|
|
getAttrs([
|
|
"armor_type",
|
|
"armor_base_ac",
|
|
"natural_ac_base",
|
|
"armor_bonus",
|
|
"shield_bonus",
|
|
"gear_ac_bonus",
|
|
"dexterity_mod"
|
|
], function(values) {
|
|
var dexMod = FF5E.number(values.dexterity_mod, 0);
|
|
var armorType = values.armor_type || "unarmored";
|
|
var base = FF5E.number(values.armor_base_ac, 10);
|
|
var naturalBase = FF5E.number(values.natural_ac_base, 0);
|
|
var armorBonus = FF5E.number(values.armor_bonus, 0);
|
|
var shield = FF5E.number(values.shield_bonus, 0);
|
|
var gear = FF5E.number(values.gear_ac_bonus, 0);
|
|
|
|
if (armorType === "natural" && naturalBase > 0) {
|
|
base = naturalBase;
|
|
}
|
|
|
|
var dexToAC = dexMod;
|
|
|
|
if (armorType === "medium") dexToAC = Math.min(dexMod, 2);
|
|
if (armorType === "heavy") dexToAC = 0;
|
|
|
|
setAttrs({
|
|
ac: base + dexToAC + armorBonus + shield + gear
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:armor_type change:armor_base_ac change:natural_ac_base change:armor_bonus change:shield_bonus change:gear_ac_bonus change:dexterity_mod sheet:opened",
|
|
updateArmorClass
|
|
);
|
|
|
|
/* =========================
|
|
LIMIT READY
|
|
========================= */
|
|
|
|
on("change:limit_current change:limit_max sheet:opened", function() {
|
|
getAttrs(["limit_current", "limit_max"], function(values) {
|
|
var current = FF5E.number(values.limit_current, 0);
|
|
var max = FF5E.number(values.limit_max, 100);
|
|
|
|
setAttrs({
|
|
limit_ready: current >= max ? "Yes" : "No"
|
|
});
|
|
});
|
|
});
|
|
|
|
/* =========================
|
|
NPC / BOSS AUTOMATION
|
|
========================= */
|
|
|
|
on("change:npc_level sheet:opened", function() {
|
|
getAttrs(["npc_level"], function(values) {
|
|
var level = FF5E.number(values.npc_level, 1);
|
|
|
|
setAttrs({
|
|
npc_proficiency_bonus: FF5E.prof(level)
|
|
});
|
|
});
|
|
});
|
|
|
|
on("change:npc_hp_current change:npc_hp_max sheet:opened", function() {
|
|
getAttrs(["npc_hp_current", "npc_hp_max"], function(values) {
|
|
var current = FF5E.number(values.npc_hp_current, 0);
|
|
var max = Math.max(1, FF5E.number(values.npc_hp_max, 1));
|
|
var pct = Math.floor((current / max) * 100);
|
|
|
|
var phaseSuggestion = 1;
|
|
|
|
if (pct <= 50) phaseSuggestion = 2;
|
|
if (pct <= 25) phaseSuggestion = 3;
|
|
if (pct <= 10) phaseSuggestion = 4;
|
|
|
|
setAttrs({
|
|
npc_hp_percent: pct,
|
|
boss_phase_suggested: phaseSuggestion
|
|
});
|
|
});
|
|
});
|
|
|
|
/* =========================
|
|
NPC AFFINITY DAMAGE HELPER
|
|
========================= */
|
|
|
|
function updateNpcAdjustedDamage() {
|
|
getAttrs([
|
|
"npc_incoming_damage",
|
|
"npc_incoming_element",
|
|
"npc_affinity_fire",
|
|
"npc_affinity_ice",
|
|
"npc_affinity_lightning",
|
|
"npc_affinity_water",
|
|
"npc_affinity_wind",
|
|
"npc_affinity_earth",
|
|
"npc_affinity_holy",
|
|
"npc_affinity_dark",
|
|
"npc_affinity_poison"
|
|
], function(values) {
|
|
var element = values.npc_incoming_element || "none";
|
|
var affinity = "Normal";
|
|
|
|
if (element !== "none") {
|
|
affinity = values["npc_affinity_" + element] || "Normal";
|
|
}
|
|
|
|
var result = FF5E.affinityDamage(values.npc_incoming_damage, affinity);
|
|
|
|
setAttrs({
|
|
npc_adjusted_damage: result.damage,
|
|
npc_damage_affinity_result: result.result
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:npc_incoming_damage change:npc_incoming_element change:npc_affinity_fire change:npc_affinity_ice change:npc_affinity_lightning change:npc_affinity_water change:npc_affinity_wind change:npc_affinity_earth change:npc_affinity_holy change:npc_affinity_dark change:npc_affinity_poison sheet:opened",
|
|
updateNpcAdjustedDamage
|
|
);
|
|
|
|
/* =========================
|
|
VEHICLE AUTOMATION
|
|
========================= */
|
|
|
|
on("change:vehicle_type sheet:opened", function() {
|
|
getAttrs(["vehicle_type", "vehicle_hp_max"], function(values) {
|
|
var type = values.vehicle_type || "land_vehicle";
|
|
var updates = {
|
|
vehicle_scale: FF5E_VEHICLE.defaultScale(type)
|
|
};
|
|
|
|
if (!values.vehicle_hp_max || FF5E.number(values.vehicle_hp_max, 0) === 0) {
|
|
updates.vehicle_hp_max = FF5E_VEHICLE.scaleHPBase(type);
|
|
}
|
|
|
|
setAttrs(updates);
|
|
});
|
|
});
|
|
|
|
on("change:vehicle_hp_current change:vehicle_hp_max sheet:opened", function() {
|
|
getAttrs(["vehicle_hp_current", "vehicle_hp_max"], function(values) {
|
|
var current = FF5E.number(values.vehicle_hp_current, 0);
|
|
var max = Math.max(1, FF5E.number(values.vehicle_hp_max, 1));
|
|
var pct = Math.max(0, Math.min(100, Math.floor((current / max) * 100)));
|
|
|
|
var condition = "Operational";
|
|
|
|
if (pct <= 50) condition = "Damaged";
|
|
if (pct <= 25) condition = "Critical";
|
|
if (pct <= 0) condition = "Disabled";
|
|
|
|
setAttrs({
|
|
vehicle_hp_percent: pct,
|
|
vehicle_condition: condition
|
|
});
|
|
});
|
|
});
|
|
|
|
/* =========================
|
|
SCALE DAMAGE HELPER
|
|
========================= */
|
|
|
|
function updateScaleDamageHelper() {
|
|
getAttrs(["scale_base_damage", "scale_attacker", "scale_target"], function(values) {
|
|
var baseDamage = FF5E.number(values.scale_base_damage, 0);
|
|
var attacker = values.scale_attacker || "personal";
|
|
var target = values.scale_target || "personal";
|
|
var finalDamage = FF5E.scaleDamage(baseDamage, attacker, target);
|
|
|
|
var text = "Same scale: normal damage.";
|
|
|
|
if ((FF5E.scaleRank[attacker] || 1) < (FF5E.scaleRank[target] || 1)) {
|
|
text = "Smaller attacker vs larger target: damage divided by 10.";
|
|
}
|
|
|
|
if ((FF5E.scaleRank[attacker] || 1) > (FF5E.scaleRank[target] || 1)) {
|
|
text = "Larger attacker vs smaller target: damage multiplied by 10.";
|
|
}
|
|
|
|
setAttrs({
|
|
scale_final_damage: finalDamage,
|
|
scale_result_text: text
|
|
});
|
|
});
|
|
}
|
|
|
|
on(
|
|
"change:scale_base_damage change:scale_attacker change:scale_target sheet:opened",
|
|
updateScaleDamageHelper
|
|
);
|
|
|
|
</script> |