Merge remote-tracking branch 'refs/remotes/Roll20/master'

This commit is contained in:
timdenee
2016-08-15 09:22:39 +12:00
199 changed files with 39742 additions and 22309 deletions
+72
View File
@@ -0,0 +1,72 @@
.charsheet {
background-color: #c0c0c0;
}
.charsheet table{
border-collapse:separate;
border-spacing:10px;
}
.charsheet textarea{
resize:vertical;
}
.charsheet .sheet-section{
border-top: 5px solid #505050;
padding-top:10px;
padding-bottom:10px;
}
.charsheet input[type=number].sheet-smallnumber{
width:40px;
}
.charsheet input[type=text].sheet-smalltext{
width:60px;
height: 18px;
margin:0px;
}
.charsheet input[type=text].sheet-shorttext{
padding-top:2px;
padding-bottom:2px;
}
.charsheet input[type=text].sheet-skilltext{
width:100px;
padding:2px;
margin-left:3px;
}
.charsheet .sheet-right{
float:right;
}
.charsheet .sheet-bold{
font-size: 12pt;
margin-bottom: 10px;
}
.charsheet .sheet-border{
border: 2px solid white;
vertical-align:top;
width:100%;
padding: 2px;
margin: 2px;
}
.charsheet input[type=number].sheet-smallshortnumber{
width:40px;
padding-top:2px;
padding-bottom:2px;
display: inline-block;
float:right;
}
.charsheet input[type=number].sheet-shortnumber{
padding-top:2px;
padding-bottom:2px;
}
.charsheet label.sheet-areaLabel{
margin:5px;
}
+110
View File
@@ -0,0 +1,110 @@
<div class="sheet-section-main" style=" position:relative;">
<div name="header" style="text-align: Center;">
<img src="http://www.ilhadotabuleiro.com.br/upload/jogo/imagem/mini/23420.jpg"/>
</div>
<div name="characterinfo" class="sheet-section">
<div class='sheet-2colrow'>
<div class='sheet-col' style="display:inline-block;">
<label>Nome:<input class="sheet-right sheet-shorttext" type="text" name="attr_charactername" style="width:65%;"/></label>
<label>Pontos:<input class="sheet-right sheet-shorttext" type="number" name="attr_playername" style="width:70%;"/></label>
</div>
</div>
</div>
<div name="attributes" class="sheet-section">
<div class="sheet-3colrow">
<div name="Atributos" class="sheet-col">
<div name="Força" class="sheet-bold sheet-border">
<button type='roll' value='/roll d6 - @{forca}' >Força</button>
<div style="float:right;">
<input type="number" name="attr_forca" class="sheet-smallnumber sheet-shortnumber" min="0" value="0"/>
</div>
</div>
<div name="Habilidade" class="sheet-bold sheet-border">
<button type='roll' class="astext" value='/roll d6 - @{habilidade}' >Habilidade</button>
<div style="float:right">
<input type="number" name="attr_habilidade" class="sheet-smallnumber sheet-shortnumber" min="0" value="0"/>
</div>
</div>
<div name="Resistencia" class="sheet-bold sheet-border">
<button type='roll' class="astext" value='/roll d6 - @{resistencia}' >Resistência</button>
<div style="float:right;">
<input type="number" name="attr_resistencia" class="sheet-smallnumber sheet-shortnumber" min="0" value="0"/>
</div>
</div>
<div name="Armadura" class="sheet-bold sheet-border">
<button type='roll' class="astext" value='/roll d6 - @{armadura}'>Armadura</button>
<div style="float:right;">
<input type="number" name="attr_armadura" class="sheet-smallnumber sheet-shortnumber" min="0" value="0"/>
</div>
</div>
<div name="Poder-de-Fogo" class="sheet-bold sheet-border">
<button type='roll' value='/roll d6 - @{poderdefogo}' >Poder de Fogo</button>
<div style="float:right;">
<input type="number" name="attr_poderdefogo" class="sheet-smallnumber sheet-shortnumber" min="0" value="0"/>
</div>
</div>
</div>
</div>
</div>
<div name="characterpoints" class="sheet-section">
<div class="sheet-3colrow">
<div name="VidaMagia" class="sheet-col">
<div name="vida" class="sheet-bold">
<div style="float:right;">
<label>Pontos de Vida
<input type="number" name="attr_vida" class="sheet-smallnumber sheet-shortnumber" value="@{resistencia} * 5"/>
</label>
</div>
</div>
<div name="magia" class="sheet-bold">
<div style="float:right;">
<label>Pontos de Magia
<input type="number" name="attr_magia" class="sheet-smallnumber sheet-shortnumber" value="@{resistencia} * 5"/>
</label>
</div>
</div>
<div name="experiencia" class="sheet-bold">
<div style="float:right;">
<label>Pontos de Experiência
<input type="number" name="attr_experiencia" class="sheet-smallnumber sheet-shortnumber" value="0"/>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div name="characterbasics" class="sheet-section">
<div class='sheet-2colrow'>
<div name="Basic-Info" class='sheet-col'>
<label style="padding-top: 4px; padding-bottom: 2px;">Dinheiro<input type="number" name="attr_dinheiro" min="0" class="sheet-smallshortnumber" style="width: 35%; float: right; padding-bottom: 2px;"/></label>
</div>
</div>
<div name="characterfeatures" class="sheet-section">
<div class="sheet-3colrow">
<div name="Vantagens" class="sheet-col">
<label class="sheet-areaLabel">Vantagens:</label>
<textarea name="attr_vantagens" style="height:100px; width:250px;"></textarea>
</div>
<div name="Desvantagens" class="sheet-col">
<label class="sheet-areaLabel">Desvantagens:</label>
<textarea name="attr_desvantagens" style="height:100px; width:250px;"></textarea>
</div>
<div name="Dano" class="sheet-col">
<label class="sheet-areaLabel">Tipos de Dano:</label>
<textarea name="attr_dano" style="height:100px; width:250px;"></textarea>
</div>
<div name="Magias" class="sheet-col">
<label class="sheet-areaLabel">Magias Conhecidas:</label>
<textarea name="attr_magias" style="height:100px; width:250px;"></textarea>
</div>
<div name="Itens" class="sheet-col">
<label class="sheet-areaLabel">Itens:</label>
<textarea name="attr_itens" style="height:100px; width:250px;"></textarea>
</div>
<div name="Hitoria" class="sheet-col">
<label class="sheet-areaLabel">História:</label>
<textarea name="attr_historia" style="height:100px; width:250px;"></textarea>
</div>
</div>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

+8
View File
@@ -0,0 +1,8 @@
{
"html": "3DeT_ALPHA.html",
"css": "3DeT_ALPHA.css",
"authors": "Julio Melanda",
"roll20userid": "1413302",
"preview": "3DeT_ALPHA.png",
"instructions": "This is a character sheet for 3D&T Defensores de Tóquio 3ª Edição Alpha"
}
File diff suppressed because one or more lines are too long
+78 -13
View File
File diff suppressed because one or more lines are too long
+5 -3
View File
@@ -29,8 +29,8 @@ Please report any bugs in the [issues tab](https://github.com/mlenser/roll20-cha
* Roll settings to choose to always roll with advantage, disadvantage, or query for both
* Optional bonuses to all skills, abilities, saving throws, etc.
![PC sheet](http://i.imgur.com/T2hbvnA.jpg "PC sheet")
![NPC sheet](http://i.imgur.com/li1ETpJ.jpg "NPC sheet")
![NPC sheet](http://i.imgur.com/CTSxo4a.png "NPC sheet")
![PC sheet](http://i.imgur.com/ufXveK2.png "PC sheet")
## How to Update the sheet yourself (as Pro):
@@ -40,7 +40,9 @@ Please report any bugs in the [issues tab](https://github.com/mlenser/roll20-cha
4. In the HTML tab paste the HTML code
5. Copy the [css](https://raw.githubusercontent.com/mlenser/roll20-character-sheets/master/5eShaped/5eShaped.css) from github
6. On Roll20 in the CSS tab paste the CSS code.
7. Hit save.
7. Copy the [translation](https://github.com/mlenser/roll20-character-sheets/tree/master/5eShaped/translations) from the appropriate file on github (en is English, fr is French, de is German, it is Italian, etc)
8. On Roll20 in the Translation tab paste the JSON from the appropriate file.
9. Hit save.
## Contribute
Since many have asked for it: If you appreciate what I do and want to compensate me for the countless hours that I have spent building this character sheet feel free to support me on [Patreon](https://www.patreon.com/mlenser) or Paypal (mlenser@gmail.com).
+16
View File
@@ -0,0 +1,16 @@
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true
},
"extends": "airbnb/base",
"rules": {
"arrow-body-style": 0,
"max-len": 0,
"no-cond-assign": 0,
"no-console": 0,
"no-param-reassign": 0,
"no-restricted-syntax": 0
}
}
+48 -21
View File
@@ -458,6 +458,13 @@ $pad-mar: (
}
.sheet-slide-input-pc {
&:checked ~ div {
.sheet-trait {
span {
line-height: 1.15;
}
}
}
&:checked ~ div .sheet-pc,
&:checked ~ .sheet-pc,
&:not(:checked) ~ div .sheet-npc,
@@ -465,6 +472,8 @@ $pad-mar: (
display: none;
}
}
.sheet-slide-input-pc {
}
.sheet-small-note {
font-size: 10px;
@@ -608,15 +617,18 @@ $pad-mar: (
}
.sheet-ability-wrapper {
height: 69px;
margin-bottom: 12px;
height: 62px;
margin-bottom: 15px;
padding-left: 1px;
padding-right: 1px;
padding-top: 1px;
position: relative;
& .sheet-ability-score-wrapper {
background-color: $white;
border: 1px solid $black;
border-radius: 50%;
bottom: -10px;
bottom: -11px;
height: 24px;
left: 0;
margin-left: auto;
@@ -640,12 +652,9 @@ $pad-mar: (
.sheet-ability-modifier {
font-size: 24px;
font-weight: bold;
padding-bottom: 8px !important;
padding-top: 8px !important;
padding-top: 6px !important;
input.sheet-toggle-edit-mode:checked ~ div & {
padding-bottom: 0 !important;
padding-top: 0 !important;
}
}
@@ -735,6 +744,7 @@ $pad-mar: (
select {
padding: 0;
}
padding-right: 1px;
}
.sheet-skills-ability-selector {
@@ -762,6 +772,10 @@ $pad-mar: (
}
}
input.sheet-toggle-use-custom-saving-throws:not([value='1']) ~ div .sheet-resistances-immunities {
margin-left: -75px;
}
.sheet-shield {
height: 55px;
margin-left: auto;
@@ -791,7 +805,7 @@ $pad-mar: (
}
.sheet-wrap-box-title {
margin-top: 1px;
margin-top: 2px;
}
}
@@ -819,13 +833,15 @@ $pad-mar: (
}
.sheet-big-text {
font-size: 16px;
font-size: 18px;
}
.sheet-initiative,
.sheet-speed {
.sheet-big-text {
padding: .4em;
display: block;
min-height: 1.6em;
padding: .2em;
}
}
@@ -841,9 +857,8 @@ $pad-mar: (
.sheet-wrap-box-title,
.sheet-ability-name {
font-size: 10px;
font-size: 9px;
font-weight: bold;
letter-spacing: -.2px;
}
.sheet-wrap-box-title {
@@ -976,7 +991,7 @@ $pad-mar: (
.sheet-exhaustion-wrapper {
border: 1px solid $black;
border-radius: 50%;
height: 30px;
height: 29px;
left: -6px;
position: absolute;
top: -3px;
@@ -1042,6 +1057,10 @@ $pad-mar: (
}
}
.sheet-hit-dice-container {
min-height: 2.7em;
}
.sheet-death-success,
.sheet-death-fail {
.sheet-checkbox-label {
@@ -1545,7 +1564,6 @@ input.sheet-attack-toggle:not(:checked) ~ div.sheet-attack-toggle,
input.sheet-show-uses:not(:checked) ~ .sheet-show-uses,
input.sheet-toggle-use-custom-saving-throws[value='1'] ~ div .sheet-default-saving-throw,
input.sheet-toggle-use-custom-saving-throws:not([value='1']) ~ div .sheet-custom-saving-throw,
input.sheet-toggle-hide-ac[value='1'] ~ div .sheet-ac,
input.sheet-has-sorcerer-levels:not([value='1']) ~ div .sheet-has-sorcerer-levels {
display: none;
}
@@ -1816,12 +1834,21 @@ textarea {
resize: both;
}
.sheet-background-text {
.sheet-background-text,
.sheet-trait {
display: block;
.sheet-toggle-edit-mode:not(:checked) ~ div & {
max-height: 4em;
overflow-x: hidden;
overflow-y: scroll;
overflow-x: hidden;
overflow-y: auto;
}
.sheet-background-text {
line-height: 1.1;
max-height: 4.2em;
min-height: 1.1em;
}
.sheet-trait {
max-height: 5.5em;
span {
line-height: 1.1;
}
}
@@ -1918,7 +1945,7 @@ textarea {
}
@include faded-border-bottom;
border-bottom: 0;
border-top: 1px solid black;
border-top: 1px solid $black;
padding-bottom: 5px;
padding-top: 5px;
width: 50%;
@@ -1926,7 +1953,7 @@ textarea {
&:first-child,
&:nth-child(2) {
border-image: none;
border-top: none;
border-top: 0;
padding-top: 0;
}
@@ -1,23 +1,21 @@
<input type="hidden" name="attr_attack_formula">
<div class="shaped-row vert-top mar-t-sm">
<input type="checkbox" name="attr_roll_toggle" value="{{vs_ac=1}} {{vs_saving_throw=@{attacks_vs_a_saving_throw}}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}" class="attack-toggle" checked>
<input type="checkbox" name="attr_roll_toggle" value="{{vs_ac=1}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}" class="attack-toggle" checked>
<div class="bold italic mar-r-sm"><span data-i18n="ATTACK"></span>.</div>
<div class="attack-toggle col-08 center pad-r-sm">
<input type="checkbox" name="attr_proficiency" checked>
<div class="small-label" data-i18n="PROF"></div>
</div>
<div class="attack-toggle col-16 center pad-r-sm">
<div class="attack-toggle col-10 center pad-r-sm">
<select name="attr_attack_ability">
<option value="">&#8212;</option>
<option value="finesse" data-i18n="FINESSE">Finesse</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="finesse" data-i18n="FINESSE"></option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
@@ -1,22 +1,21 @@
<input type="hidden" name="attr_attack_formula">
<div class="shaped-row vert-top mar-t-sm">
<input type="checkbox" name="attr_roll_toggle" value="{{vs_ac=1}} {{vs_saving_throw=@{attacks_vs_a_saving_throw}}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}" class="attack-toggle">
<input type="checkbox" name="attr_roll_toggle" value="{{vs_ac=1}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}" class="attack-toggle">
<div class="bold italic mar-r-sm"><span data-i18n="ATTACK"></span>.</div>
<div class="attack-toggle col-08 center pad-r-sm">
<input type="checkbox" name="attr_proficiency" checked>
<div class="small-label" data-i18n="PROF"></div>
</div>
<div class="attack-toggle col-16 center pad-r-sm">
<div class="attack-toggle col-10 center pad-r-sm">
<select name="attr_attack_ability">
<option value="">&#8212;</option>
<option value="finesse" data-i18n="FINESSE">Finesse</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="finesse" data-i18n="FINESSE"></option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
@@ -9,16 +9,16 @@
<input type="text" name="attr_damage" class="center" accept="Damage" placeholder="1d6">
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
<div class="attack-toggle col-14 center">
<div class="attack-toggle col-10 center">
<select name="attr_damage_ability">
<option value="">&#8212;</option>
<option value="finesse" data-i18n="FINESSE">Finesse</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="finesse" data-i18n="FINESSE"></option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
@@ -28,7 +28,7 @@
<div class="attack-toggle col-18 center pad-r-sm">
<input type="text" name="attr_damage_type" class="center" data-i18n-placeholder="SLASHING" accept="Damage Type">
</div>
<div class="attack-toggle col-18 center pad-l-sm">
<div class="attack-toggle col-16 center pad-l-sm">
<input type="text" name="attr_damage_crit" class="center">
<div class="small-label relative">
<span data-i18n="CRIT"></span>
@@ -40,4 +40,4 @@
</div>
</div>
</div>
</div>
</div>
@@ -9,16 +9,16 @@
<input type="text" name="attr_second_damage" class="center" accept="Secondary Damage" placeholder="1d6">
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
<div class="attack-toggle col-14 center">
<div class="attack-toggle col-10 center">
<select name="attr_second_damage_ability">
<option value="" selected>&#8212;</option>
<option value="finesse" data-i18n="FINESSE">Finesse</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="finesse" data-i18n="FINESSE"></option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
@@ -28,7 +28,7 @@
<div class="attack-toggle col-18 center pad-r-sm">
<input type="text" name="attr_second_damage_type" class="center" data-i18n-placeholder="FIRE" accept="Secondary Damage Type">
</div>
<div class="attack-toggle col-18 center pad-l-sm">
<div class="attack-toggle col-16 center pad-l-sm">
<input type="text" name="attr_second_damage_crit" class="center">
<div class="small-label relative">
<span data-i18n="CRIT"></span>
@@ -9,16 +9,16 @@
<input type="text" name="attr_damage" class="center" accept="Damage" placeholder="1d6">
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
<div class="attack-toggle col-14 center">
<div class="attack-toggle col-10 center">
<select name="attr_damage_ability">
<option value="">&#8212;</option>
<option value="finesse" data-i18n="FINESSE">Finesse</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="finesse" data-i18n="FINESSE"></option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
<div class="attack-toggle center pad-l-sm pad-r-sm">+</div>
@@ -28,7 +28,7 @@
<div class="attack-toggle col-18 center pad-r-sm">
<input type="text" name="attr_damage_type" class="center" data-i18n-placeholder="FIRE" accept="Damage Type">
</div>
<div class="attack-toggle col-18 center pad-l-sm">
<div class="attack-toggle col-16 center pad-l-sm">
<input type="text" name="attr_damage_crit" class="center">
<div class="small-label relative">
<span data-i18n="CRIT"></span>
@@ -6,15 +6,15 @@
<input type="text" name="attr_heal" class="center" accept="Healing" placeholder="1d6">
</div>
<div class="attack-toggle pad-l-sm pad-r-sm">+</div>
<div class="attack-toggle col-16">
<div class="attack-toggle col-10">
<select name="attr_heal_ability">
<option value="" selected>&#8212;</option>
<option value="strength" data-i18n="STR" selected>Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
<div class="attack-toggle pad-l-sm pad-r-sm">+</div>
@@ -5,9 +5,9 @@
<textarea class="one-line-textarea" name="attr_saving_throw_condition" data-i18n-placeholder="IF_THE_TARGET_IS"></textarea>
</div>
<div class="attack-toggle col-100"></div>
<div class="attack-toggle col-16 center">
<div class="attack-toggle col-10 center">
<select name="attr_saving_throw_ability">
<option value="">&#8212;</option>
<option value="0">&#8212;</option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
@@ -1,21 +1,21 @@
<div class="shaped-row vert-top mar-t-sm relative">
<input type="checkbox" name="attr_special_effects_toggle" value="{{fx=@{type}-@{color} @{points_of_origin}}}" class="attack-toggle">
<input type="checkbox" name="attr_special_effects_toggle" value="{{fx=@{special_effects_type}-@{special_effects_color} @{special_effects_points_of_origin}}}" class="attack-toggle">
<div class="bold italic mar-r-sm"><span data-i18n="SPECIAL_EFFECTS"></span>.</div>
<div class="attack-toggle col-15 center mar-b-sm">
<input type="text" name="attr_type" class="center" placeholder="explode">
<input type="text" name="attr_special_effects_type" class="center" placeholder="explode">
<div class="small-label" data-i18n="TYPE"></div>
</div>
<div class="attack-toggle col-15 center pad-l-sm mar-b-sm">
<input type="text" name="attr_color" class="center" data-i18n-placeholder="FIRE">
<input type="text" name="attr_special_effects_color" class="center" data-i18n-placeholder="FIRE">
<div class="small-label" data-i18n="COLOR"></div>
</div>
<div class="attack-toggle col-30 center pad-l-sm mar-b-sm">
<select name="attr_points_of_origin">
<option value="sourceToTarget @{target|token_id}"><span data-i18n="SOURCE">Source</span> &rarr; <span data-i18n="TARGET">Target</span></option>
<option value="target @{target|token_id}" data-i18n="TARGET">target</option>
<option value="source" data-i18n="SOURCE">source</option>
<option value="targetToSource @{target|token_id}"><span data-i18n="TARGET">Target</span> &rarr; <span data-i18n="SOURCE">Source</span></option>
<select name="attr_special_effects_points_of_origin">
<option value="sourceToTarget @{target|token_id}" data-i18n="SOURCE_TO_TARGET"></option>
<option value="target @{target|token_id}" data-i18n="TARGET"></option>
<option value="source" data-i18n="SOURCE"></option>
<option value="targetToSource @{target|token_id}" data-i18n="TARGET_TO_SOURCE"></option>
</select>
<div class="small-label" data-i18n="POINTS_OF_ORIGIN"></div>
</div>
@@ -1,8 +1,8 @@
<div class="col-17 center pad-l-sm pad-r-sm">
<select name="attr_type">
<option value="Other" data-i18n="OTHER">Other</option>
<option value="Melee Weapon" data-i18n="MELEE">Melee</option>
<option value="Ranged Weapon" data-i18n="RANGED">Ranged</option>
<option value="Other" data-i18n="OTHER_TYPE"></option>
<option value="Melee Weapon" data-i18n="MELEE_WEAPON"></option>
<option value="Ranged Weapon" data-i18n="RANGED_WEAPON"></option>
</select>
<div class="small-label" data-i18n="TYPE"></div>
</div>
@@ -6,14 +6,14 @@
</div>
</div>
<select name="attr_default_ability">
<option value="">&#8212;</option>
<option value="finesse" data-i18n="FINESSE">Finesse</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="finesse" data-i18n="FINESSE"></option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
<div class="wrap-box-title center" data-i18n="DEFAULT_ABILITY"></div>
</div>
@@ -2,7 +2,7 @@
<div class="ac col-33 center">
<button type="roll" name="roll_shaped_ac" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=^{AC}}} {{text_big=[[@{ac}]]}}">
<div class="shield">
<span name="attr_AC" class="big-text bold block center"></span>
<span name="attr_AC" class="big-text block center"></span>
<div class="wrap-box-title center" data-i18n="ARMOR_CLASS"></div>
</div>
</button>
@@ -14,10 +14,10 @@
<div>+</div>
<input type="text" name="attr_initiative_bonus" class="center no-border" value="0">
<div>=</div>
<span name="attr_initiative" class="big-text bold block center"></span>
<span name="attr_initiative" class="big-text block center"></span>
</div>
<button type="roll" name="roll_shaped_initiative" value="@{initiative_output_option} &{template:5e-shaped} {{ability=1}} {{character_name=@{character_name}}} @{show_character_name} {{title=^{INITIATIVE}}} {{roll1=[[@{initiative_roll} + @{initiative_to_tracker} + @{initiative_tie_breaker}]]}} @{attacher_initiative}">
<span name="attr_initiative" class="presentation big-text bold block center initiative-total"></span>
<span name="attr_initiative" class="presentation big-text block center initiative-total"></span>
<div class="wrap-box-title center" data-i18n="INITIATIVE"></div>
</button>
</div>
@@ -25,10 +25,10 @@
<div class="col-29 center pad-l-md">
<div class="wrap-box center speed">
<div class="edit">
<input type="number" name="attr_speed" class="big-text bold center no-spin no-border" step="1">
<input type="number" name="attr_speed" class="big-text center no-spin no-border" step="1">
</div>
<button type="roll" name="roll_shaped_speed" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=^{SPEED}}} {{text_big=[[@{speed}]]}}">
<span name="attr_speed" class="presentation big-text bold block center"></span>
<span name="attr_speed" class="presentation big-text block center"></span>
<div class="wrap-box-title" data-i18n="SPEED"></div>
</button>
</div>
@@ -33,9 +33,9 @@
</div>
<div class="col-17 center pad-l-sm pad-r-sm">
<select name="attr_type" accept="Item Type">
<option value="Other" data-i18n="OTHER">Other</option>
<option value="Melee Weapon" data-i18n="MELEE">Melee</option>
<option value="Ranged Weapon" data-i18n="RANGED">Ranged</option>
<option value="Other" data-i18n="OTHER"></option>
<option value="Melee Weapon" data-i18n="MELEE"></option>
<option value="Ranged Weapon" data-i18n="RANGED"></option>
</select>
<div class="small-label" data-i18n="TYPE"></div>
</div>
@@ -1,22 +1,26 @@
<div class="section-core pc">
<div class="shaped-row">
<div class="col-32 pad-r-sm">
<div class="col-30 pad-r-sm">
<div class="shaped-row mar-b-smd">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
//= include abilities.html
</div>
<div class="col-70 pad-l-sm">
<div class="col-71 pad-l-sm">
//= include inspiration.html
//= include proficiency.html
//= include savingThrows.html
//= include skills.html
<div class="resistances-immunities wrap-box">
//= include resistancesVulnerabilities.html
<div class="wrap-box-title center" data-i18n="RESISTANCES_AND_IMMUNITIES"></div>
</div>
</div>
</div>
<div>
//= include languagesProficiencies.html
</div>
</div>
<div class="col-39 pad-l-sm pad-r-sm">
<div class="col-38 pad-l-sm pad-r-sm">
<div class="shaped-row">
<div class="col-58 pad-r-sm">
//= include armorInit.html
@@ -32,10 +36,6 @@
</div>
<div class="col-42 pad-l-sm">
//= include ../spells/spellSlots.html
<div class="resistances-immunities wrap-box mar-b-smd">
//= include resistancesVulnerabilities.html
<div class="wrap-box-title center" data-i18n="RESISTANCES_AND_IMMUNITIES"></div>
</div>
//= include exhaustion.html
//= include rests.html
</div>
@@ -47,7 +47,7 @@
//= include equipment.html
</div>
</div>
<div class="col-29 pad-l-sm">
<div class="col-32 pad-l-sm">
//= include background.html
//= include traits.html
</div>
@@ -1,7 +1,7 @@
<div class="exhaustion wrap-box relative mar-b-smd">
<div class="shaped-row vert-center">
<div class="exhaustion-wrapper">
<input type="number" name="attr_exhaustion_level" class="no-spin bold big-font no-border" min="0" value="0" max="6">
<input type="number" name="attr_exhaustion_level" class="no-spin big-font no-border" min="0" value="0" max="6">
</div>
<button type="roll" name="roll_shaped_exhaustion" class="wrapper-button" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=^{EXHAUSTION_LEVEL}}} {{text_big=[[@{exhaustion_level}]]}}">
<div class="wrap-box-title white-space-no-wrap" data-i18n="EXHAUSTION_LEVEL"></div>
@@ -1,4 +1,6 @@
<div class="hit-dice wrap-box center mar-b-smd">
//= include ../hitDice/hitDice.html
<div class="hit-dice-container">
//= include ../hitDice/hitDice.html
</div>
<div class="wrap-box-title" data-i18n="HIT_DICE"></div>
</div>
@@ -3,11 +3,11 @@
<div class="heart mar-b-smd">
<div class="shaped-row center flex-end no-wrap pad-t-seven">
<div class="col-40">
<input type="number" name="attr_HP" class="big-text bold no-spin no-border" step="1">
<input type="number" name="attr_HP" class="big-text no-spin no-border" step="1">
</div>
<div class="heart-divider pad-l-sm pad-r-sm">&#47;</div>
<div class="col-40">
<input type="number" name="attr_HP_max" class="big-text bold no-spin no-border" min="1" step="1">
<input type="number" name="attr_HP_max" class="big-text no-spin no-border" min="1" step="1">
</div>
</div>
<button type="roll" name="roll_shaped_hp" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=^{HIT_POINTS}}} {{text_big=[[@{HP}]]&#47;[[@{HP|max}]]}}">
@@ -2,7 +2,7 @@
<button type="roll" name="roll_shaped_pb" class="wrapper-button" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=^{PROFICIENCY_BONUS}}} {{text_big=[[@{pb}]]}}" tabindex="-1">
<div class="shaped-row vert-center">
<div class="proficiency-bonus-wrapper center">
<input type="number" name="attr_PB" class="bold big-font no-border" readonly tabindex="-1">
<input type="number" name="attr_PB" class="big-font no-border" readonly tabindex="-1">
<input type="hidden" name="attr_exp">
<input type="hidden" name="attr_h_PB" value="[[floor(@{PB}/2)]]">
</div>
@@ -1,19 +1,19 @@
<div class="skills wrap-box">
<div class="skills wrap-box mar-b-smd">
<input type="checkbox" name="attr_show_passive_skills" class="item-shown hidden">
<fieldset class="repeating_skill">
<div class="shaped-row no-wrap flex-end">
<div class="col-10 no-shrink edit">
<div class="col-10 no-shrink edit pad-r-sm">
<select name="attr_skill_d20">
<option value="@{shaped_d20}" data-i18n="NORMAL">Normal</option>
<option value="2d20@{d20_mod}kh1" data-i18n="ADVANTAGE">Advantage</option>
<option value="2d20@{d20_mod}kl1" data-i18n="DISADVANTAGE">Disadvantage</option>
<option value="@{shaped_d20}" data-i18n="NORMAL"></option>
<option value="2d20@{d20_mod}kh1" data-i18n="ADVANTAGE"></option>
<option value="2d20@{d20_mod}kl1" data-i18n="DISADVANTAGE"></option>
</select>
</div>
<div class="col-10 skill-select-wrapper no-shrink">
<div class="col-08 skill-select-wrapper no-shrink">
<select name="attr_proficiency" class="no-border">
<option value="unproficient">&#8212; &#160;&#160;<span data-i18n="UNPROFICIENT">Unproficient</span></option>
<option value="proficient">&check; &#160;&#160; <span data-i18n="PROFICIENT">Proficient</span></option>
<option value="expertise">&cross; &#160;&#160; <span data-i18n="EXPERTISE">Expertise</span></option>
<option value="unproficient" data-i18n="SKILL_SELECT_UNPROFICIENT"></option>
<option value="proficient" data-i18n="SKILL_SELECT_PROFICIENT"></option>
<option value="expertise" data-i18n="SKILL_SELECT_EXPERTISE"></option>
</select>
</div>
<div class="col-09 edit no-shrink">
@@ -35,13 +35,13 @@
<div class="shaped-row no-wrap vert-center">
<span>(</span>
<select name="attr_ability" class="skills-ability-selector">
<option value="">&#8212;</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
<span>)</span>
</div>
@@ -52,7 +52,7 @@
<input type="hidden" name="attr_passive">
<button type="roll" name="roll_passive" class="item-to-show" value="@{output_option} &{template:5e-shaped} {{ability=1}} {{character_name=@{character_name}}} @{show_character_name} {{title=^{PASSIVE} @{name} (<span data-i18n=@{ability_key}>@{ability_key}<span>)}} @{roll_info} {{roll1=[[@{passive}]]}} @{hide_gm_info} @{attacher_skill}" tabindex="-1">
<div class="shaped-row no-wrap flex-end">
<span name="attr_passive" class="col-1-3-em input-like center border-bottom"></span>
<span name="attr_passive" class="col-1-3-em input-like small-label center border-bottom"></span>
</div>
</button>
</div>
@@ -25,13 +25,13 @@
</div>
<div class="col-17 center pad-r-sm">
<select name="attr_type" accept="Item Type">
<option value="Light Armor" data-i18n="LIGHT_ARMOR">Light Armor</option>
<option value="Medium Armor" data-i18n="MEDIUM_ARMOR">Medium Armor</option>
<option value="Heavy Armor" data-i18n="HEAVY_ARMOR">Heavy Armor</option>
<option value="Armored" data-i18n="OTHER_ARMOR">Other Armor</option>
<option value="Shield" data-i18n="SHIELD">Shield</option>
<option value="AC" data-i18n="ARMORED_AND_UNARMORED">Armored and Unarmored</option>
<option value="Unarmored" data-i18n="UNARMORED">Unarmored</option>
<option value="Light Armor" data-i18n="LIGHT_ARMOR"></option>
<option value="Medium Armor" data-i18n="MEDIUM_ARMOR"></option>
<option value="Heavy Armor" data-i18n="HEAVY_ARMOR"></option>
<option value="Armored" data-i18n="OTHER_ARMOR"></option>
<option value="Shield" data-i18n="SHIELD"></option>
<option value="AC" data-i18n="ARMORED_AND_UNARMORED"></option>
<option value="Unarmored" data-i18n="UNARMORED"></option>
</select>
</div>
<div class="edit col-05 center">
@@ -48,8 +48,8 @@
<div class="col-11 pad-l-md">
<select name="attr_strength_requirements">
<option value="no">&#8212;</option>
<option value="Str 13"><span data-i18n="STR">Str</span> 13</option>
<option value="Str 15"><span data-i18n="STR">Str</span> 15</option>
<option value="Str 13" data-i18n="STR_13"></option>
<option value="Str 15" data-i18n="STR_15"></option>
</select>
</div>
<div class="col-09 center pad-l-md">
@@ -79,12 +79,12 @@
<div class="col-12 center pad-r-md">
<select name="attr_ac_unarmored_ability">
<option value="" selected>&#8212;</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
<div class="small-label" data-i18n="AC_UNARMORED_ABILITY"></div>
</div>
@@ -92,10 +92,10 @@
<span name="attr_ac_unarmored_calc" class="pseudo-input center border-bottom"></span>
<div class="small-label" data-i18n="AC_UNARMORED"></div>
</div>
<div class="col-15 center bold">
<div class="col-15 center">
<button type="roll" name="roll_shaped_ac" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=^{AC}}} {{text_big=[[@{ac}]]}}">
<div class="shield">
<span name="attr_AC" class="pseudo-input center big-text bold"></span>
<span name="attr_AC" class="pseudo-input center big-text"></span>
<div class="wrap-box-title center" data-i18n="ARMOR_CLASS"></div>
</div>
</button>
@@ -16,5 +16,4 @@
<input type="hidden" name="attr_shaped_d20" value="d20">
<input type="hidden" name="attr_d20_mod">
<input type="hidden" name="attr_use_custom_saving_throws" class="toggle-use-custom-saving-throws hidden">
<input type="hidden" name="attr_hide_ac" class="toggle-hide-ac hidden">
<input type="hidden" name="attr_use_custom_saving_throws" class="toggle-use-custom-saving-throws hidden">
@@ -7,105 +7,105 @@
<input type="checkbox" name="attr_hd_d20_toggle" value="1" class="toggle-hd-d20 hidden">
<div class="shaped-row center flex-end toggle-hd-d2">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d2" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d2_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d2_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d2" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d2_query}d2 ^{HIT_DICE}}} {{uses=@{hd_d2}}} {{uses_max=@{hd_d2|max}}} @{roll_info} {{roll1=[[{((@{hd_d2_query})d2[d2 * hd] + ((@{hd_d2_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d2
</button>
</div>
</div>
<div class="shaped-row center flex-end toggle-hd-d4">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d4" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d4_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d4_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d4" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d4_query}d4 ^{HIT_DICE}}} {{uses=@{hd_d4}}} {{uses_max=@{hd_d4|max}}} @{roll_info} {{roll1=[[{((@{hd_d4_query})d4[d4 * hd] + ((@{hd_d4_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d4
</button>
</div>
</div>
<div class="shaped-row center flex-end toggle-hd-d6">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d6" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d6_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d6_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d6" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d6_query}d6 ^{HIT_DICE}}} {{uses=@{hd_d6}}} {{uses_max=@{hd_d6|max}}} @{roll_info} {{roll1=[[{((@{hd_d6_query})d6[d6 * hd] + ((@{hd_d6_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d6
</button>
</div>
</div>
<div class="shaped-row center flex-end toggle-hd-d8">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d8" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d8_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d8_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d8" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d8_query}d8 ^{HIT_DICE}}} {{uses=@{hd_d8}}} {{uses_max=@{hd_d8|max}}} @{roll_info} {{roll1=[[{((@{hd_d8_query})d8[d8 * hd] + ((@{hd_d8_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d8
</button>
</div>
</div>
<div class="shaped-row center flex-end toggle-hd-d10">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d10" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d10_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d10_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d10" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d10_query}d10 ^{HIT_DICE}}} {{uses=@{hd_d10}}} {{uses_max=@{hd_d10|max}}} @{roll_info} {{roll1=[[{((@{hd_d10_query})d10[d10 * hd] + ((@{hd_d10_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d10
</button>
</div>
</div>
<div class="shaped-row center flex-end toggle-hd-d12">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d12" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d12_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d12_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d12" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d12_query}d12 ^{HIT_DICE}}} {{uses=@{hd_d12}}} {{uses_max=@{hd_d12|max}}} @{roll_info} {{roll1=[[{((@{hd_d12_query})d12[d12 * hd] + ((@{hd_d12_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d12
</button>
</div>
</div>
<div class="shaped-row center flex-end toggle-hd-d20">
<div class="col-30 pad-r-sm">
<div class="col-29 pad-r-sm">
<input type="number" name="attr_hd_d20" class="no-spin no-border" min="0" step="1">
</div>
<div class="col-05">&#47;</div>
<div class="col-30">
<div class="col-29">
<span name="attr_hd_d20_max" class="center"></span>
</div>
<input type="hidden" name="attr_hd_d20_query">
<div class="col-33 center">
<div class="col-37 center">
<button type="roll" name="roll_shaped_hd_d20" class="bold" value="@{hit_dice_output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{hd_d20_query}d20 ^{HIT_DICE}}} {{uses=@{hd_d20}}} {{uses_max=@{hd_d20|max}}} @{roll_info} {{roll1=[[{((@{hd_d20_query})d20[d20 * hd] + ((@{hd_d20_query}) * @{constitution_mod})[con mod * hd]), 0d0+1}kh1[minimum of 1]]]}} @{attacher_hit_dice}">
d20
</button>
@@ -1,8 +1,8 @@
<div class="shaped-row center">
<div class="col-40">
<select name="attr_ability_checks_text_size">
<option value="text" data-i18n="NORMAL">Normal</option>
<option value="text_big" selected data-i18n="BIG">Big</option>
<option value="text" data-i18n="NORMAL"></option>
<option value="text_big" data-i18n="BIG" selected></option>
</select>
<div class="small-label" data-i18n="TEXT_SIZE"></div>
</div>
@@ -2,8 +2,8 @@
<div class="shaped-row center">
<div class="col-40">
<select name="attr_saving_throws_text_size">
<option value="text" data-i18n="NORMAL">Normal</option>
<option value="text_big" selected data-i18n="BIG">Big</option>
<option value="text" data-i18n="NORMAL"></option>
<option value="text_big" data-i18n="BIG" selected></option>
</select>
<div class="small-label" data-i18n="TEXT_SIZE"></div>
</div>
@@ -15,8 +15,8 @@
<div class="shaped-row center">
<div class="col-40">
<select name="attr_spells_text_size">
<option value="" data-i18n="NORMAL">Normal</option>
<option value="big" data-i18n="BIG">Big</option>
<option value="" data-i18n="NORMAL"></option>
<option value="big" data-i18n="BIG"></option>
</select>
<div class="small-label" data-i18n="TEXT_SIZE"></div>
</div>
@@ -9,9 +9,9 @@
//= include ../actionComponents/range.html
//= include ../actionComponents/recharge.html
</div>
<input type="checkbox" name="attr_toggle_details" class="toggle-icon-settings edit" checked><span class="toggle-icon-settings pictos edit">y</span>
<input type="checkbox" name="attr_toggle_details" class="toggle-icon-settings edit"><span class="toggle-icon-settings pictos edit">y</span>
<div class="details edit">
//= include ../actionComponents/attack.html
//= include ../actionComponents/attackSpell.html
//= include ../actionComponents/savingThrow.html
//= include ../actionComponents/damage.html
//= include ../actionComponents/damageSecondary.html
@@ -86,7 +86,7 @@
<input type="number" name="attr_fortitude_save_bonus" class="no-spin small-label" value="0" step="1">
</div>
<button type="roll" name="roll_shaped_fortitude_saving_throw" class="inline" value="@{output_option} &{template:5e-shaped} {{saving_throw=1}} {{character_name=@{character_name}}} @{show_character_name} {{title=^{FORTITUDE} ^{SAVE}}} @{roll_info} {{roll1=[[@{shaped_d20} + @{fortitude_saving_throw_mod}]]}} @{roll_setting} + @{fortitude_saving_throw_mod}]]}} @{hide_gm_info} @{attacher_fortitude_saving_throw}" tabindex="-1">
<span data-i18n="FORT"></span>
<span data-i18n="FORTITUDE"></span>
<span name="attr_fortitude_saving_throw_mod_with_sign" class="inline-block center"></span>
</button>
</div>
@@ -99,7 +99,7 @@
<input type="number" name="attr_reflex_save_bonus" class="no-spin small-label" value="0" step="1">
</div>
<button type="roll" name="roll_shaped_reflex_saving_throw" class="inline" value="@{output_option} &{template:5e-shaped} {{saving_throw=1}} {{character_name=@{character_name}}} @{show_character_name} {{title=^{REFLEX} ^{SAVE}}} @{roll_info} {{roll1=[[@{shaped_d20} + @{reflex_saving_throw_mod}]]}} @{roll_setting} + @{reflex_saving_throw_mod}]]}} @{hide_gm_info} @{attacher_reflex_saving_throw}" tabindex="-1">
<span data-i18n="REF"></span>
<span data-i18n="REFLEX"></span>
<span name="attr_reflex_saving_throw_mod_with_sign" class="inline-block center"></span>
</button>
</div>
@@ -1,12 +1,12 @@
<div class="shaped-row edit">
<div class="col-20 pad-r-sm">
<select name="attr_size" class="italic no-border" accept="Size">
<option value="Tiny" data-i18n="TINY">Tiny</option>
<option value="Small" data-i18n="SMALL">Small</option>
<option value="Medium" data-i18n="MEDIUM">Medium</option>
<option value="Large" data-i18n="LARGE" selected>Large</option>
<option value="Huge" data-i18n="HUGE">Huge</option>
<option value="Gargantuan" data-i18n="GARGANTUAN">Gargantuan</option>
<option value="Tiny" data-i18n="TINY"></option>
<option value="Small" data-i18n="SMALL"></option>
<option value="Medium" data-i18n="MEDIUM"></option>
<option value="Large" data-i18n="LARGE" selected></option>
<option value="Huge" data-i18n="HUGE"></option>
<option value="Gargantuan" data-i18n="GARGANTUAN"></option>
</select>
</div>
<div class="col-30 pad-l-sm pad-r-sm">
+12 -12
View File
@@ -8,16 +8,16 @@
<div class="shaped-row no-wrap vert-center">
<div class="col-1-3-em no-shrink edit">
<select name="attr_skill_d20">
<option value="@{shaped_d20}" data-i18n="NORMAL">Normal</option>
<option value="2d20@{d20_mod}kh1" data-i18n="ADVANTAGE">Advantage</option>
<option value="2d20@{d20_mod}kl1" data-i18n="DISADVANTAGE">Disadvantage</option>
<option value="@{shaped_d20}" data-i18n="NORMAL"></option>
<option value="2d20@{d20_mod}kh1" data-i18n="ADVANTAGE"></option>
<option value="2d20@{d20_mod}kl1" data-i18n="DISADVANTAGE"></option>
</select>
</div>
<div class="col-1-3-em skill-select-wrapper edit">
<select name="attr_proficiency" class="no-border">
<option value="unproficient">&#8212; &#160;&#160;<span data-i18n="UNPROFICIENT">Unproficient</span></option>
<option value="proficient">&check; &#160;&#160; <span data-i18n="PROFICIENT">Proficient</span></option>
<option value="expertise">&cross; &#160;&#160; <span data-i18n="EXPERTISE">Expertise</span></option>
<option value="unproficient" data-i18n="SKILL_SELECT_UNPROFICIENT"></option>
<option value="proficient" data-i18n="SKILL_SELECT_PROFICIENT"></option>
<option value="expertise" data-i18n="SKILL_SELECT_EXPERTISE"></option>
</select>
</div>
<div class="col-1-3-em edit">
@@ -40,12 +40,12 @@
<span>(</span>
<select name="attr_ability" class="skills-ability-selector">
<option value="0">&#8212;</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX">Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX"></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
<span>)</span>
</div>
@@ -100,15 +100,10 @@
{{#targetName}}
<span>{{targetName}}</span>
{{/targetName}}
{{^vs_saving_throw}}
<span data-i18n="AC">AC</span>
{{#targetAC}}
<span>{{targetAC}}</span>
{{/targetAC}}
{{/vs_saving_throw}}
{{#vs_saving_throw}}
<span>[<span data-i18n="{{vs_saving_throw}}">{{vs_saving_throw}}</span>](~target|shaped_{{vs_saving_throw}}_saving_throw)</span>
{{/vs_saving_throw}}
<span data-i18n="AC">AC</span>
{{#targetAC}}
<span>{{targetAC}}</span>
{{/targetAC}}
</div>
{{/vs_ac}}
</div>
@@ -298,12 +293,12 @@
{{#text_big}}
<div class="output-small">{{text_big}}</div>
{{/text_big}}
{{#allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac vs_saving_throw ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type crit_name crit_text damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell spell_list saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure spell_level school ritual content cast_as_level heal casting_time duration components materials hide_ability_checks hide_saving_throws hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge fx trait armor equipment cantrips spells_level_1 spells_level_1_uses spells_level_1_show spells_level_2 spells_level_2_uses spells_level_2_show spells_level_3 spells_level_3_uses spells_level_3_show spells_level_4 spells_level_4_uses spells_level_4_show spells_level_5 spells_level_5_uses spells_level_5_show spells_level_6 spells_level_6_uses spells_level_6_show spells_level_7 spells_level_7_uses spells_level_7_show spells_level_8 spells_level_8_uses spells_level_8_show spells_level_9 spells_level_9_uses spells_level_9_show spells_text_size}}
{{#allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type crit_name crit_text damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell spell_list saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure spell_level school ritual content cast_as_level heal casting_time duration components materials hide_ability_checks hide_saving_throws hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge fx trait armor equipment cantrips spells_level_1 spells_level_1_uses spells_level_1_show spells_level_2 spells_level_2_uses spells_level_2_show spells_level_3 spells_level_3_uses spells_level_3_show spells_level_4 spells_level_4_uses spells_level_4_show spells_level_5 spells_level_5_uses spells_level_5_show spells_level_6 spells_level_6_uses spells_level_6_show spells_level_7 spells_level_7_uses spells_level_7_show spells_level_8 spells_level_8_uses spells_level_8_show spells_level_9 spells_level_9_uses spells_level_9_show spells_text_size}}
<div>
<span class="bold italic">{{key}}.</span>
{{value}}
</div>
{{/allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac vs_saving_throw ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type crit_name crit_text damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell spell_list saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure spell_level school ritual content cast_as_level heal casting_time duration components materials hide_ability_checks hide_saving_throws hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge fx trait armor equipment cantrips spells_level_1 spells_level_1_uses spells_level_1_show spells_level_2 spells_level_2_uses spells_level_2_show spells_level_3 spells_level_3_uses spells_level_3_show spells_level_4 spells_level_4_uses spells_level_4_show spells_level_5 spells_level_5_uses spells_level_5_show spells_level_6 spells_level_6_uses spells_level_6_show spells_level_7 spells_level_7_uses spells_level_7_show spells_level_8 spells_level_8_uses spells_level_8_show spells_level_9 spells_level_9_uses spells_level_9_show spells_text_size}}
{{/allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type crit_name crit_text damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell spell_list saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure spell_level school ritual content cast_as_level heal casting_time duration components materials hide_ability_checks hide_saving_throws hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge fx trait armor equipment cantrips spells_level_1 spells_level_1_uses spells_level_1_show spells_level_2 spells_level_2_uses spells_level_2_show spells_level_3 spells_level_3_uses spells_level_3_show spells_level_4 spells_level_4_uses spells_level_4_show spells_level_5 spells_level_5_uses spells_level_5_show spells_level_6 spells_level_6_uses spells_level_6_show spells_level_7 spells_level_7_uses spells_level_7_show spells_level_8 spells_level_8_uses spells_level_8_show spells_level_9 spells_level_9_uses spells_level_9_show spells_text_size}}
{{#freetext}}
<div class="{{#hide_freetext}} gm-info-block{{/hide_freetext}}">{{freetext}}</div>
@@ -1,15 +1,19 @@
<div class="wrap-box relative">
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="AMMO_AUTO_USE"></span>
<input type="checkbox" name="attr_ammo_auto_use" class="mar-l-md" value="1">
<input type="checkbox" name="attr_ammo_auto_use" class="mar-l-md no-shrink" value="1">
</div>
<div class="shaped-row space-between vert-center">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="AUTO_REVERT_ADV"></span>
<input type="checkbox" name="attr_auto_revert_advantage" class="mar-l-md">
<input type="checkbox" name="attr_auto_revert_advantage" class="mar-l-md no-shrink">
</div>
<div class="shaped-row space-between vert-center">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="SHOW_RESTS"></span>
<input type="checkbox" name="attr_show_rests" class="mar-l-md">
<input type="checkbox" name="attr_show_rests" class="mar-l-md no-shrink">
</div>
<div class="shaped-row space-between vert-center no-wrap">
<span class="small-label" data-i18n="EXPERTISE_AS_ADVANTAGE"></span>
<input type="checkbox" name="attr_expertise_as_advantage" class="mar-l-md no-shrink" value="1">
</div>
<div class="tooltip-position-wrapper">
<div class="tooltip">
@@ -1,23 +1,23 @@
<div class="wrap-box">
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="COIN_CONVERSION_GP_PER_CP"></span>
<div class="col-25">
<input type="number" name="attr_copper_per_gold" value="100">
</div>
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="COIN_CONVERSION_GP_PER_SP"></span>
<div class="col-25">
<input type="number" name="attr_silver_per_gold" value="10">
</div>
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="COIN_CONVERSION_GP_PER_EP"></span>
<div class="col-25">
<input type="number" name="attr_electrum_per_gold" value="2">
</div>
</div>
<div class="shaped-row space-between vert-center">
<div class="shaped-row space-between vert-center no-wrap">
<span class="small-label" data-i18n="COIN_CONVERSION_GP_PER_PP"></span>
<div class="col-25">
<input type="number" name="attr_platinum_per_gold" value="10">
@@ -1,13 +1,15 @@
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="USE_CUSTOM_SAVING_THROWS"></span><input type="checkbox" name="attr_use_custom_saving_throws" value="1">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="USE_CUSTOM_SAVING_THROWS"></span>
<input type="checkbox" name="attr_use_custom_saving_throws" class="mar-l-md no-shrink" value="1">
</div>
<div class="custom-saving-throw shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="AVERAGE_OF_ABILITIES"></span><input type="checkbox" name="attr_average_of_abilities" value="1">
<div class="custom-saving-throw shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="AVERAGE_OF_ABILITIES"></span>
<input type="checkbox" name="attr_average_of_abilities" class="mar-l-md no-shrink" value="1">
</div>
<div class="custom-saving-throw shaped-row space-between vert-center mar-b-sm">
<div class="custom-saving-throw shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="FORTITUDE">Fortitude</span>
<div>
<div class="shaped-row vert-center">
<div class="shaped-row vert-center justify-flex-end no-wrap">
<div>
<span class="small-label" data-i18n="STR">Str</span><input type="checkbox" name="attr_fortitude_strength" value="1">
</div>
@@ -18,7 +20,7 @@
<span class="small-label" data-i18n="CON">Con</span><input type="checkbox" name="attr_fortitude_constitution" value="1">
</div>
</div>
<div class="shaped-row vert-center justify-flex-end">
<div class="shaped-row vert-center justify-flex-end no-wrap">
<div>
<span class="small-label" data-i18n="INT">Int</span><input type="checkbox" name="attr_fortitude_intelligence" value="1">
</div>
@@ -32,10 +34,10 @@
</div>
</div>
<hr class="custom-saving-throw">
<div class="custom-saving-throw shaped-row space-between vert-center mar-b-sm">
<div class="custom-saving-throw shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="REFLEX">Reflex</span>
<div>
<div class="shaped-row vert-center">
<div class="shaped-row vert-center justify-flex-end no-wrap">
<div>
<span class="small-label" data-i18n="STR">Str</span><input type="checkbox" name="attr_reflex_strength" value="1">
</div>
@@ -46,7 +48,7 @@
<span class="small-label" data-i18n="CON">Con</span><input type="checkbox" name="attr_reflex_constitution" value="1">
</div>
</div>
<div class="shaped-row vert-center justify-flex-end">
<div class="shaped-row vert-center justify-flex-end no-wrap">
<div>
<span class="small-label" data-i18n="INT">Int</span><input type="checkbox" name="attr_reflex_intelligence" value="1">
</div>
@@ -60,10 +62,10 @@
</div>
</div>
<hr class="custom-saving-throw">
<div class="custom-saving-throw shaped-row space-between vert-center mar-b-sm">
<div class="custom-saving-throw shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="WILL">Will</span>
<div>
<div class="shaped-row vert-center">
<div class="shaped-row vert-center justify-flex-end no-wrap">
<div>
<span class="small-label" data-i18n="STR">Str</span><input type="checkbox" name="attr_will_strength" value="1">
</div>
@@ -74,7 +76,7 @@
<span class="small-label" data-i18n="CON">Con</span><input type="checkbox" name="attr_will_constitution" value="1">
</div>
</div>
<div class="shaped-row vert-center justify-flex-end">
<div class="shaped-row vert-center justify-flex-end no-wrap">
<div>
<span class="small-label" data-i18n="INT">Int</span><input type="checkbox" name="attr_will_intelligence" value="1">
</div>
@@ -1,44 +1,46 @@
<div class="wrap-box relative">
<input type="hidden" name="attr_hide_gm_info" value="@{hide_attack} @{hide_damage} @{hide_ability_checks} @{hide_saving_throws} @{hide_saving_throw_dc} @{hide_spell_content} @{hide_action_freetext} @{hide_saving_throw_failure} @{hide_saving_throw_success} @{hide_recharge}">
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_ATTACK"></span>
<input type="checkbox" name="attr_hide_attack" class="mar-l-md" value="{{hide_attack=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_DAMAGE"></span>
<input type="checkbox" name="attr_hide_damage" class="mar-l-md" value="{{hide_damage=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<input type="hidden" name="attr_hide_gm_info" value="@{hide_attack} @{hide_damage} @{hide_ability_checks} @{hide_saving_throws} @{hide_saving_throw_dc} @{hide_spell_content} @{hide_freetext} @{hide_saving_throw_failure} @{hide_saving_throw_success} @{hide_recharge}">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_ABILITY_CHECKS"></span>
<input type="checkbox" name="attr_hide_ability_checks" class="mar-l-md" value="{{hide_ability_checks=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_SAVING_THROWS"></span>
<input type="checkbox" name="attr_hide_saving_throws" class="mar-l-md" value="{{hide_saving_throws=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<hr>
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_ATTACK"></span>
<input type="checkbox" name="attr_hide_attack" class="mar-l-md" value="{{hide_attack=1}}">
</div>
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_DAMAGE"></span>
<input type="checkbox" name="attr_hide_damage" class="mar-l-md" value="{{hide_damage=1}}">
</div>
<hr>
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_FREETEXT"></span>
<input type="checkbox" name="attr_hide_freetext" class="mar-l-md" value="{{hide_freetext=1}}">
</div>
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_RECHARGE"></span>
<input type="checkbox" name="attr_hide_recharge" class="mar-l-md" value="{{hide_recharge=1}}">
</div>
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_SAVING_THROW_DC"></span>
<input type="checkbox" name="attr_hide_saving_throw_dc" class="mar-l-md" value="{{hide_saving_throw_dc=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_SPELL_CONTENT"></span>
<input type="checkbox" name="attr_hide_spell_content" class="mar-l-md" value="{{hide_spell_content=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_ACTION_FREETEXT"></span>
<input type="checkbox" name="attr_hide_action_freetext" class="mar-l-md" value="{{hide_freetext=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_SAVING_THROW_FAILURE"></span>
<input type="checkbox" name="attr_hide_saving_throw_failure" class="mar-l-md" value="{{hide_saving_throw_failure=1}}">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="HIDE_INFO_SAVING_THROW_SUCCESS"></span>
<input type="checkbox" name="attr_hide_saving_throw_success" class="mar-l-md" value="{{hide_saving_throw_success=1}}">
</div>
<div class="shaped-row space-between vert-center">
<span class="small-label" data-i18n="HIDE_INFO_RECHARGE"></span>
<input type="checkbox" name="attr_hide_recharge" class="mar-l-md" value="{{hide_recharge=1}}">
<div class="shaped-row space-between vert-center no-wrap">
<span class="small-label" data-i18n="HIDE_INFO_SPELL_CONTENT"></span>
<input type="checkbox" name="attr_hide_spell_content" class="mar-l-md" value="{{hide_spell_content=1}}">
</div>
<div class="tooltip-position-wrapper">
<div class="tooltip">
@@ -1,36 +1,16 @@
<div class="wrap-box">
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="wrap-box mar-b-smd">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label center" data-i18n="BASE_DC"></span>
<div class="col-15">
<input type="number" name="attr_base_dc" value="8">
</div>
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label center" data-i18n="MEDIUM_ARMOR_MAX_DEX"></span>
<div class="col-15">
<input type="number" name="attr_medium_armor_max_dex" value="2">
</div>
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="HIDE_AC"></span><input type="checkbox" name="attr_hide_ac" value="1">
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<span class="small-label" data-i18n="ATTACKS_VS_A_SAVING_THROW"></span>
<div class="col-15">
<select name="attr_attacks_vs_a_saving_throw">
<option value="">&#8212;</option>
<option value="STRENGTH" data-i18n="STR" class="default-saving-throw">Str</option>
<option value="DEXTERITY" data-i18n="DEX" class="default-saving-throw">Dex</option>
<option value="CONSTITUTION" data-i18n="CON" class="default-saving-throw">Con</option>
<option value="INTELLIGENCE" data-i18n="INT" class="default-saving-throw">Int</option>
<option value="WISDOM" data-i18n="WIS" class="default-saving-throw">Wis</option>
<option value="CHARISMA" data-i18n="CHA" class="default-saving-throw">Cha</option>
<option value="FORTITUDE" data-i18n="FORT" class="custom-saving-throw">Fort</option>
<option value="REFLEX" data-i18n="REF" class="custom-saving-throw">Ref</option>
<option value="WILL" data-i18n="WILL" class="custom-saving-throw">Will</option>
</select>
</div>
</div>
<div class="wrap-box-title center" data-i18n="HOUSERULES"></div>
</div>
@@ -3,9 +3,9 @@
<span class="small-label" data-i18n="OUTPUT"></span>
<div class="col-60">
<select name="attr_initiative_output_option">
<option value="@{output_option}" data-i18n="SHEET_OUTPUT" selected>Sheet output</option>
<option value="" data-i18n="PUBLIC_FOR_ALL">Public for all to see</option>
<option value="/w GM" data-i18n="WHISPERED_TO_GM">Whispered to the GM</option>
<option value="@{output_option}" data-i18n="SHEET_OUTPUT" selected></option>
<option value="" data-i18n="PUBLIC_FOR_ALL"></option>
<option value="/w GM" data-i18n="WHISPERED_TO_GM"></option>
</select>
</div>
</div>
@@ -13,9 +13,9 @@
<span class="small-label" data-i18n="ROLL_OPTIONS"></span>
<div class="col-60">
<select name="attr_initiative_roll">
<option value="@{shaped_d20}" data-i18n="NORMAL">Normal</option>
<option value="2d20@{d20_mod}kh1" data-i18n="ADVANTAGE">Advantage</option>
<option value="2d20@{d20_mod}kl1" data-i18n="DISADVANTAGE">Disadvantage</option>
<option value="@{shaped_d20}" data-i18n="NORMAL"></option>
<option value="2d20@{d20_mod}kh1" data-i18n="ADVANTAGE"></option>
<option value="2d20@{d20_mod}kl1" data-i18n="DISADVANTAGE"></option>
</select>
</div>
</div>
@@ -23,8 +23,8 @@
<span class="small-label" data-i18n="TRACKER"></span>
<div class="col-60">
<select name="attr_initiative_to_tracker">
<option value="@{selected|initiative_formula} &{tracker}" data-i18n="TO_TRACKER" selected>Send to Tracker</option>
<option value="@{initiative_formula}" data-i18n="DONT">Don't</option>
<option value="@{selected|initiative_formula} &{tracker}" data-i18n="TO_TRACKER" selected></option>
<option value="@{initiative_formula}" data-i18n="DONT"></option>
</select>
</div>
</div>
@@ -36,13 +36,13 @@
<span class="small-label" data-i18n="INITIATIVE_ABILITY"></span>
<div class="col-20">
<select name="attr_initiative_ability">
<option value="">&#8212;</option>
<option value="strength" data-i18n="STR">Str</option>
<option value="dexterity" data-i18n="DEX" selected>Dex</option>
<option value="constitution" data-i18n="CON">Con</option>
<option value="intelligence" data-i18n="INT">Int</option>
<option value="wisdom" data-i18n="WIS">Wis</option>
<option value="charisma" data-i18n="CHA">Cha</option>
<option value="0">&#8212;</option>
<option value="strength" data-i18n="STR"></option>
<option value="dexterity" data-i18n="DEX" selected></option>
<option value="constitution" data-i18n="CON"></option>
<option value="intelligence" data-i18n="INT"></option>
<option value="wisdom" data-i18n="WIS"></option>
<option value="charisma" data-i18n="CHA"></option>
</select>
</div>
</div>
@@ -1,5 +1,5 @@
<div class="wrap-box">
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="CHARACTER_NAME_ON_ROLL_TEMPLATES"></span>
<div class="col-15">
<select name="attr_show_character_name">
@@ -8,7 +8,7 @@
</select>
</div>
</div>
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="SHOW_TARGET_AC_ON_ATTACKS"></span>
<div class="col-15">
<select name="attr_attacks_vs_target_ac">
@@ -17,7 +17,7 @@
</select>
</div>
</div>
<div class="shaped-row space-between vert-center">
<div class="shaped-row space-between vert-center no-wrap">
<span class="small-label" data-i18n="SHOW_TARGET_NAME_ON_ATTACKS"></span>
<div class="col-15">
<select name="attr_attacks_vs_target_name">
@@ -1,7 +1,7 @@
<div class="wrap-box">
<div class="shaped-row space-between vert-center mar-b-sm">
<div class="shaped-row space-between vert-center no-wrap mar-b-sm">
<span class="small-label" data-i18n="ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS"></span>
<input type="checkbox" name="attr_saving_throws_half_proficiency" class="mar-l-md">
<input type="checkbox" name="attr_saving_throws_half_proficiency" class="mar-l-md no-shrink">
</div>
//= include customSavingThrows.html
<div class="wrap-box-title center" data-i18n="SAVING_THROWS">Saving throws</div>
@@ -9,7 +9,7 @@
<div class="col-28 pad-l-sm pad-r-sm">
//= include rollTemplate.html
</div>
<div class="pad-l-sm">
<div class="col-22 pad-l-sm">
//= include api.html
</div>
<div class="pad-l-sm pad-r-sm">
@@ -23,11 +23,9 @@
</div>
<div class="col-22 pad-l-sm pad-r-sm">
//= include houserules.html
</div>
<div class="col-22 pad-l-sm pad-r-sm">
//= include savingThrows.html
</div>
<div class="pad-l-sm pad-r-sm">
<div class="col-20 pad-l-sm pad-r-sm">
//= include hideInfo.html
</div>
<div class="col-22 pad-r-sm">
File diff suppressed because it is too large Load Diff
@@ -70,28 +70,28 @@
<div class="shaped-row vert-center">
<div class="col-18">
<select name="attr_spell_level" class="italic no-border" accept="Level">
<option value="CANTRIP" data-i18n="CANTRIP">Cantrip</option>
<option value="1ST_LEVEL" data-i18n="1ST_LEVEL">1st-level</option>
<option value="2ND_LEVEL" data-i18n="2ND_LEVEL">2nd-level</option>
<option value="3RD_LEVEL" data-i18n="3RD_LEVEL">3rd-level</option>
<option value="4TH_LEVEL" data-i18n="4TH_LEVEL">4th-level</option>
<option value="5TH_LEVEL" data-i18n="5TH_LEVEL">5th-level</option>
<option value="6TH_LEVEL" data-i18n="6TH_LEVEL">6th-level</option>
<option value="7TH_LEVEL" data-i18n="7TH_LEVEL">7th-level</option>
<option value="8TH_LEVEL" data-i18n="8TH_LEVEL">8th-level</option>
<option value="9TH_LEVEL" data-i18n="9TH_LEVEL">9th-level</option>
<option value="CANTRIP" data-i18n="CANTRIP"></option>
<option value="1ST_LEVEL" data-i18n="1ST_LEVEL"></option>
<option value="2ND_LEVEL" data-i18n="2ND_LEVEL"></option>
<option value="3RD_LEVEL" data-i18n="3RD_LEVEL"></option>
<option value="4TH_LEVEL" data-i18n="4TH_LEVEL"></option>
<option value="5TH_LEVEL" data-i18n="5TH_LEVEL"></option>
<option value="6TH_LEVEL" data-i18n="6TH_LEVEL"></option>
<option value="7TH_LEVEL" data-i18n="7TH_LEVEL"></option>
<option value="8TH_LEVEL" data-i18n="8TH_LEVEL"></option>
<option value="9TH_LEVEL" data-i18n="9TH_LEVEL"></option>
</select>
</div>
<div class="col-26 center">
<select name="attr_school" class="italic no-border">
<option value="ABJURATION" data-i18n="ABJURATION">Abjuration</option>
<option value="CONJURATION" data-i18n="CONJURATION">Conjuration</option>
<option value="DIVINATION" data-i18n="DIVINATION">Divination</option>
<option value="ENCHANTMENT" data-i18n="ENCHANTMENT">Enchantment</option>
<option value="EVOCATION" data-i18n="EVOCATION">Evocation</option>
<option value="ILLUSION" data-i18n="ILLUSION">Illusion</option>
<option value="NECROMANCY" data-i18n="NECROMANCY">Necromancy</option>
<option value="TRANSMUTATION" data-i18n="TRANSMUTATION">Transmutation</option>
<option value="ABJURATION" data-i18n="ABJURATION"></option>
<option value="CONJURATION" data-i18n="CONJURATION"></option>
<option value="DIVINATION" data-i18n="DIVINATION"></option>
<option value="ENCHANTMENT" data-i18n="ENCHANTMENT"></option>
<option value="EVOCATION" data-i18n="EVOCATION"></option>
<option value="ILLUSION" data-i18n="ILLUSION"></option>
<option value="NECROMANCY" data-i18n="NECROMANCY"></option>
<option value="TRANSMUTATION" data-i18n="TRANSMUTATION"></option>
</select>
</div>
<div class="mar-l-lg">
@@ -125,13 +125,13 @@
<span class="bold mar-r-sm"><span data-i18n="COMPONENTS"></span>:</span>
<div class="col-14 center pad-l-sm">
<select name="attr_components" class="no-border">
<option value="COMPONENTS_V_S_M" data-i18n="COMPONENTS_V_S_M">V, S, M</option>
<option value="COMPONENTS_V_S" data-i18n="COMPONENTS_V_S">V, S</option>
<option value="COMPONENTS_V_M" data-i18n="COMPONENTS_V_M">V, M</option>
<option value="COMPONENTS_V" data-i18n="COMPONENTS_V">V</option>
<option value="COMPONENTS_S_M" data-i18n="COMPONENTS_S_M">S, M</option>
<option value="COMPONENTS_S" data-i18n="COMPONENTS_S">S</option>
<option value="COMPONENTS_M" data-i18n="COMPONENTS_M">M</option>
<option value="COMPONENTS_V_S_M" data-i18n="COMPONENTS_V_S_M"></option>
<option value="COMPONENTS_V_S" data-i18n="COMPONENTS_V_S"></option>
<option value="COMPONENTS_V_M" data-i18n="COMPONENTS_V_M"></option>
<option value="COMPONENTS_V" data-i18n="COMPONENTS_V"></option>
<option value="COMPONENTS_S_M" data-i18n="COMPONENTS_S_M"></option>
<option value="COMPONENTS_S" data-i18n="COMPONENTS_S"></option>
<option value="COMPONENTS_M" data-i18n="COMPONENTS_M"></option>
</select>
</div>
<div class="flex-grow pad-l-sm">
@@ -18,7 +18,7 @@
<div class="edit small-label center" data-i18n="USES"></div>
</div>
</div>
<button type="roll" name="roll_trait" class="presentation trait wrapper-button traits-presentation-wrapper" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{name}}} {{trait=1}} {{recharge=@{recharge}}} @{saving_throw_toggle} @{damage_toggle} @{second_damage_toggle} {{uses=@{uses}}} {{uses_max=@{uses|max}}} @{heal_toggle} @{hide_gm_info} @{extras_toggle}">
<button type="roll" name="roll_trait" class="presentation trait wrapper-button" value="@{output_option} &{template:5e-shaped} {{character_name=@{character_name}}} @{show_character_name} {{title=@{name}}} {{trait=1}} {{recharge=@{recharge}}} @{saving_throw_toggle} @{damage_toggle} @{second_damage_toggle} {{uses=@{uses}}} {{uses_max=@{uses|max}}} @{heal_toggle} @{hide_gm_info} @{extras_toggle}">
<span class="heading"></span>
<span name="attr_name" class="bold italic"></span><span name="attr_recharge_display" class="bold italic"></span><span class="bold italic">.</span>
<span name="attr_display_text" class="pre-line"></span>
+23 -29
View File
@@ -21,12 +21,17 @@ const request = require('request');
const gutil = require('gulp-util');
const sortJSON = require('gulp-json-sort').default;
String.prototype.capitalize = function () {
return this.replace(/\w\S*/g, function (txt) {
const browserify = require('browserify');
const babelify = require('babelify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
String.prototype.capitalize = () => {
return this.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.substr(1)
});
};
String.prototype.lowercase = function () {
String.prototype.lowercase = () => {
return this.toLowerCase();
};
@@ -69,22 +74,24 @@ const compileSheetHTML = () => {
}));
};
const compileSheetWorkers = () => {
return gulp.src(['components/sheetWorkers.js'])
.pipe(babel({
return browserify('./scripts/sheetWorkers.js')
.transform(babelify, {
presets: ['es2015'],
comments: false,
compact: true
}))
}).bundle()
.pipe(source('sheetWorkers.js'))
.pipe(buffer())
.pipe(wrapper({
header: '<script type="text/worker">',
footer: '</script>'
}));
}))
};
const compileRollTemplate = () => {
return gulp.src(['./components/rollTemplate.html']);
};
gulp.task('compile', ['sass', 'translationDist'], function () {
gulp.task('compile', ['sass', 'translationDist'], () => {
return streamqueue({objectMode: true},
compileSheetHTML(),
compileSheetWorkers(),
@@ -94,22 +101,9 @@ gulp.task('compile', ['sass', 'translationDist'], function () {
.pipe(gulp.dest('../'))
});
const esLintConfig = {
parser: 'babel-eslint',
extends: 'airbnb/base',
rules: {
'arrow-body-style': 0,
'indent': 0,
'max-len': 0,
'no-cond-assign': 0,
'no-console': 0,
'no-param-reassign': 0,
'no-undef': 0
}
};
gulp.task('lint', function () {
return gulp.src(['components/sheetWorkers.js'])
.pipe(eslint(esLintConfig))
gulp.task('lint', () => {
return gulp.src(['./scripts/*.js'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
@@ -126,23 +120,23 @@ const sassConfig = {
include: 0
}
};
gulp.task('sass', function () {
gulp.task('sass', () => {
return gulp.src('./5eShaped.scss')
.pipe(sass().on('error', sass.logError))
.pipe(autoprefixer())
.pipe(minifyCss())
.pipe(gulp.dest('../'));
});
gulp.task('sass-lint', function() {
gulp.task('sass-lint', () => {
return gulp.src('./5eShaped.scss')
.pipe(sassLint(sassConfig))
.pipe(sassLint.format())
.pipe(sassLint.failOnError())
});
gulp.task('sort-translations', function() {
gulp.task('sort-translations', () => {
return gulp.src('../translations/*.json')
.pipe(sortJSON({ space: 1 }))
.pipe(sortJSON({ space: 2 }))
.pipe(replaceTask({
patterns: [
{
@@ -192,7 +186,7 @@ gulp.task('submit', ['compile'], (done) => {
);
});
gulp.task('translationDist', function () {
gulp.task('translationDist', () => {
return gulp.src('../translations/en.json')
.pipe(rename('translation.json'))
.pipe(gulp.dest('../'));
+18 -10
View File
@@ -1,33 +1,41 @@
{
"name": "5eShaped",
"version": "5.0.6",
"version": "6.0.4",
"bin": "./",
"description": "5e Shaped character sheet for Roll20.net",
"main": "gulpfile.js",
"devDependencies": {
"babel-eslint": "^6.0.0",
"babel-preset-es2015": "6.6.0",
"eslint-config-airbnb": "3.1.0",
"babel-eslint": "^6.1.2",
"babel-preset-es2015": "^6.9.0",
"babelify": "^7.3.0",
"browserify": "^13.0.1",
"eslint": "^3.1.1",
"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-import": "^1.11.1",
"eslint-plugin-jsx-a11y": "^2.0.1",
"eslint-plugin-react": "^5.2.2",
"gulp": "^3.9.0",
"gulp-autoprefixer": "^3.1.0",
"gulp-babel": "6.1.2",
"gulp-change": "^1.0.0",
"gulp-concat": "^2.6.0",
"gulp-eslint": "1.1.1",
"gulp-include": "^2.1.0",
"gulp-inject": "^3.0.0",
"gulp-eslint": "^3.0.1",
"gulp-htmlmin": "latest",
"gulp-include": "^2.3.0",
"gulp-inject": "^4.1.0",
"gulp-json-sort": "^1.0.0",
"gulp-minify-css": "^1.2.2",
"gulp-minify-html": "^1.0.4",
"gulp-rename": "^1.2.2",
"gulp-replace-task": "^0.11.0",
"gulp-sass": "^2.2.0",
"gulp-sass-lint": "^1.1.1",
"gulp-sass": "^2.3.2",
"gulp-sass-lint": "^1.2.0",
"gulp-util": "latest",
"gulp-wrapper": "1.0.0",
"request": "latest",
"streamqueue": "^1.1.1",
"gulp-htmlmin": "latest"
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
},
"repository": {
"type": "git",
+128
View File
@@ -0,0 +1,128 @@
/* global on:false */
import { AbilityChecks } from './AbilityChecks';
const abilityChecks = new AbilityChecks();
import { Actions } from './Actions';
const actions = new Actions();
import { Attacks } from './Attacks';
const attacks = new Attacks();
import { Spells } from './Spells';
const spells = new Spells();
import { getSetItems, getIntValue, getFloatValue, getAbilityMod, addArithmeticOperator, showSign, firstThree } from './utilities';
export class Abilities {
updateModifier(ability) {
const collectionArray = [ability, `${ability}_bonus`, `${ability}_mod`, `${ability}_mod_with_sign`, `${ability}_check_mod`, `${ability}_check_mod_formula`, `${ability}_check_bonus`, 'global_ability_bonus', 'strength_mod', 'dexterity_mod', 'jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'global_check_bonus'];
if (ability === 'strength' || ability === 'dexterity') {
collectionArray.push('finesse_mod');
}
if (ability === 'strength') {
collectionArray.push('weight_multiplier');
collectionArray.push('carrying_capacity');
collectionArray.push('max_push_drag_lift');
collectionArray.push('encumbered');
collectionArray.push('heavily_encumbered');
}
getSetItems('abilities.updateModifier', {
collectionArray,
callback: (v, finalSetAttrs) => {
const abilityScore = getIntValue(v[ability]);
const abilityBonus = getIntValue(v[`${ability}_bonus`]);
const globalAbilityBonus = v.global_ability_bonus;
let abilityScoreCalc = abilityScore + abilityBonus;
if (!isNaN(globalAbilityBonus)) {
abilityScoreCalc += getIntValue(globalAbilityBonus);
}
const abilityCheckBonus = getIntValue(v[`${ability}_check_bonus`]);
const abilityMod = getAbilityMod(abilityScoreCalc);
let abilityCheck = abilityMod;
let abilityCheckFormula = '';
if (abilityMod !== 0) {
abilityCheckFormula = `${abilityMod}[${firstThree(ability)} mod with bonus]`;
}
if ((ability === 'strength' || ability === 'dexterity' || ability === 'constitution') && v.remarkable_athlete_toggle === '@{remarkable_athlete}') {
const remarkableAthlete = getIntValue(v.remarkable_athlete);
abilityCheck += remarkableAthlete;
abilityCheckFormula += `${addArithmeticOperator(abilityCheckFormula, remarkableAthlete)}[remarkable athlete]`;
} else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') {
const jackOfAllTrades = getIntValue(v.jack_of_all_trades);
abilityCheck += jackOfAllTrades;
abilityCheckFormula += `${addArithmeticOperator(abilityCheckFormula, jackOfAllTrades)}[jack of all trades]`;
}
if (abilityCheckBonus) {
abilityCheck += abilityCheckBonus;
abilityCheckFormula += `${addArithmeticOperator(abilityCheckFormula, abilityCheckBonus)}[${ability} check bonus]`;
}
if (v.global_check_bonus) {
if (!isNaN(v.global_check_bonus)) {
abilityCheck += getIntValue(v.global_check_bonus);
}
if (abilityCheckFormula) {
abilityCheckFormula += ' + ';
}
abilityCheckFormula += '(@{global_check_bonus})[global check bonus]';
}
finalSetAttrs[`${ability}_calculated`] = abilityScoreCalc;
finalSetAttrs[`${ability}_mod`] = abilityMod;
finalSetAttrs[`${ability}_mod_with_sign`] = showSign(abilityMod);
finalSetAttrs[`${ability}_check_mod`] = abilityCheck;
finalSetAttrs[`${ability}_check_mod_with_sign`] = showSign(abilityCheck);
finalSetAttrs[`${ability}_check_mod_formula`] = abilityCheckFormula;
if (ability === 'strength') {
finalSetAttrs.finesse_mod = Math.max(abilityMod, getIntValue(v.dexterity_mod));
const weightMultiplier = getFloatValue(v.weight_multiplier, 1);
finalSetAttrs.carrying_capacity = abilityScore * 15 * weightMultiplier;
finalSetAttrs.max_push_drag_lift = abilityScore * 30 * weightMultiplier;
finalSetAttrs.encumbered = abilityScore * 5 * weightMultiplier;
finalSetAttrs.heavily_encumbered = abilityScore * 10 * weightMultiplier;
} else if (ability === 'dexterity') {
finalSetAttrs.finesse_mod = Math.max(abilityMod, getIntValue(v.strength_mod));
}
},
});
}
updateModifiers() {
this.updateModifier('strength');
this.updateModifier('dexterity');
this.updateModifier('constitution');
this.updateModifier('intelligence');
this.updateModifier('wisdom');
this.updateModifier('charisma');
}
setup() {
on('change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus change:global_check_bonus', () => {
this.updateModifiers();
});
on('change:strength change:strength_bonus change:strength_check_mod change:strength_check_bonus change:remarkable_athlete_toggle change:remarkable_athlete change:weight_multiplier', () => {
this.updateModifier('strength');
});
on('change:dexterity change:dexterity_bonus change:dexterity_check_mod change:dexterity_check_bonus change:remarkable_athlete_toggle change:remarkable_athlete', () => {
this.updateModifier('dexterity');
});
on('change:constitution change:constitution_bonus change:constitution_check_mod change:constitution_check_bonus change:remarkable_athlete_toggle change:remarkable_athlete', () => {
this.updateModifier('constitution');
});
on('change:intelligence change:intelligence_bonus change:intelligence_check_mod change:intelligence_check_bonus', () => {
this.updateModifier('intelligence');
});
on('change:wisdom change:wisdom_bonus change:wisdom_check_mod change:wisdom_check_bonus', () => {
this.updateModifier('wisdom');
});
on('change:charisma change:charisma_bonus change:charisma_check_mod change:charisma_check_bonus', () => {
this.updateModifier('charisma');
});
on('change:strength_mod change:dexterity_mod change:constitution_mod change:intelligence_mod change:wisdom_mod change:charisma_mod', () => {
abilityChecks.updateSkill();
attacks.update();
spells.update();
actions.updateAll();
});
}
}
@@ -0,0 +1,305 @@
/* global on:false, generateRowID:false, getTranslationByKey:false */
import { getSetItems, getSetRepeatingItems, isUndefinedOrEmpty, getAbilityValue, getAbilityShortName, getIntValue, addArithmeticOperator, showSign, capitalize, exists, getRepeatingInfo, isUndefined } from './utilities';
import { ABILITIES } from './constants';
import { ProficiencyBonus } from './ProficiencyBonus';
const proficiencyBonus = new ProficiencyBonus();
export class AbilityChecks {
updateMacro() {
const collectionArray = ['ability_checks_query_var', 'ability_checks_macro_var', 'ability_checks_show_totals'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_check_mod`);
collectionArray.push(`${ability}_check_mod_with_sign`);
}
getSetRepeatingItems('abilityChecks.updateMacro', {
repeatingItems: ['repeating_skill'],
collectionArray,
collectionArrayAddItems: ['name', 'ability', 'total_with_sign'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
finalSetAttrs.ability_checks_query_var = '?{Ability Check';
finalSetAttrs.ability_checks_macro_var = '';
finalSetAttrs.skills_macro_var = '';
for (const ability of ABILITIES) {
finalSetAttrs.ability_checks_query_var += `|${capitalize(ability)},{{title=${capitalize(ability)}&#125;&#125; {{roll1=[[@{shaped_d20} + ${v[`${ability}_check_mod`]}]]&#125;&#125; @{roll_setting} + ${v[`${ability}_check_mod`]}]]&#125;&#125;`;
if (v.ability_checks_show_totals === 'on') {
finalSetAttrs.ability_checks_macro_var += `[${capitalize(ability)} ${v[`${ability}_check_mod_with_sign`]}](~shaped_${ability}_check)`;
} else {
finalSetAttrs.ability_checks_macro_var += `[${capitalize(ability)}](~shaped_${ability}_check)`;
}
finalSetAttrs.ability_checks_macro_var += ', ';
}
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
finalSetAttrs.ability_checks_query_var += `|${v[`${repeatingString}name`]}, {{title=${v[`${repeatingString}name`]} (${capitalize(getAbilityShortName(v[`${repeatingString}ability`]))})&#125;&#125; {{roll1=[[@{shaped_d20} + @{${repeatingString}formula}]]&#125;&#125; @{roll_setting} + @{${repeatingString}formula}]]&#125;&#125;`;
if (id !== ids[0]) {
finalSetAttrs.ability_checks_macro_var += ', ';
finalSetAttrs.skills_macro_var += ', ';
}
let skillButton;
if (v.ability_checks_show_totals === 'on') {
skillButton = `[${v[`${repeatingString}name`]} ${v[`${repeatingString}total_with_sign`]}](~repeating_skill_${id}_skill)`;
} else {
skillButton = `[${v[`${repeatingString}name`]}](~repeating_skill_${id}_skill)`;
}
finalSetAttrs.ability_checks_macro_var += skillButton;
finalSetAttrs.skills_macro_var += skillButton;
}
finalSetAttrs.ability_checks_query_var += '}';
},
});
}
updateSkill(rowId) {
const collectionArray = ['jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'pb', 'exp', 'global_check_bonus'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
collectionArray.push(`${ability}_check_bonus`);
}
getSetRepeatingItems('abilityChecks.updateSkill', {
repeatingItems: ['repeating_skill'],
collectionArray,
collectionArrayAddItems: ['skill_d20', 'skill_info', 'proficiency', 'name', 'storage_name', 'ability', 'bonus', 'ability_key', 'formula', 'total', 'total_with_sign', 'passive_bonus', 'passive_total'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
const skillName = v[`${repeatingString}name`];
if (isUndefinedOrEmpty(skillName)) {
return;
}
finalSetAttrs[`${repeatingString}ability_key`] = getAbilityShortName(v[`${repeatingString}ability`]).toUpperCase();
let total = 0;
let totalFormula = '';
const proficiency = v[`${repeatingString}proficiency`];
if (!proficiency || proficiency === 'unproficient') {
if ((v[`${repeatingString}ability`] === 'strength' || v[`${repeatingString}ability`] === 'dexterity' || v[`${repeatingString}ability`] === 'constitution') && v.remarkable_athlete_toggle === '@{remarkable_athlete}') {
const remarkableAthlete = getIntValue(v.remarkable_athlete);
total += remarkableAthlete;
totalFormula += `${remarkableAthlete}[remarkable athlete]`;
} else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') {
const jackOfAllTrades = getIntValue(v.jack_of_all_trades);
total += jackOfAllTrades;
totalFormula += `${jackOfAllTrades}[jack of all trades]`;
}
} else if (proficiency === 'proficient') {
const pb = getIntValue(v.pb);
total += pb;
totalFormula += `${pb}[proficient]`;
} else if (proficiency === 'expertise') {
const exp = getIntValue(v.exp);
total += exp;
totalFormula += `${exp}[expertise]`;
}
const abilityValue = getAbilityValue(v, v[`${repeatingString}ability`], 'strength');
if (exists(abilityValue)) {
total += abilityValue;
totalFormula += `${addArithmeticOperator(totalFormula, abilityValue)}[${getAbilityShortName(v[`${repeatingString}ability`])}]`;
}
const skillBonus = getIntValue(v[`${repeatingString}bonus`]);
if (exists(skillBonus)) {
total += skillBonus;
totalFormula += `${addArithmeticOperator(totalFormula, skillBonus)}[bonus]`;
}
if (exists(v[`${repeatingString}ability`])) {
let checkBonus = v[`${v[`${repeatingString}ability`]}_check_bonus`];
if (exists(checkBonus)) {
checkBonus = getIntValue(checkBonus);
total += checkBonus;
totalFormula += `${addArithmeticOperator(totalFormula, checkBonus)}[${getAbilityShortName(v[`${repeatingString}ability`])} check bonus]`;
}
}
const globalCheckBonus = v.global_check_bonus;
if (exists(globalCheckBonus)) {
if (!isNaN(globalCheckBonus)) {
total += getIntValue(globalCheckBonus);
}
if (totalFormula) {
totalFormula += ' + ';
}
totalFormula += '(@{global_check_bonus})[global check bonus]';
}
const passiveBonus = getIntValue(v[`${repeatingString}passive_bonus`]);
let advantageOrDisadvantage = 0;
finalSetAttrs[`${repeatingString}skill_info`] = '';
if (v[`${repeatingString}skill_d20`] && v[`${repeatingString}skill_d20`].indexOf('kh1') !== -1) {
finalSetAttrs[`${repeatingString}skill_info`] = '{{advantage=1}}';
advantageOrDisadvantage = 5;
} else if (v[`${repeatingString}skill_d20`] && v[`${repeatingString}skill_d20`].indexOf('kl1') !== -1) {
finalSetAttrs[`${repeatingString}skill_info`] = '{{disadvantage=1}}';
advantageOrDisadvantage = -5;
} else {
finalSetAttrs[`${repeatingString}skill_info`] = '';
}
const passiveTotal = 10 + total + passiveBonus + advantageOrDisadvantage;
finalSetAttrs[`${repeatingString}total`] = total;
finalSetAttrs[`${repeatingString}passive`] = passiveTotal;
finalSetAttrs[`${repeatingString}total_with_sign`] = showSign(total);
finalSetAttrs[`${repeatingString}formula`] = totalFormula;
}
},
setFinalAttrsCallback: () => {
this.updateMacro();
},
});
}
updateSkillsFromSRD() {
getSetRepeatingItems('abilityChecks.updateSkillsFromSRD', {
repeatingItems: ['repeating_skill'],
collectionArray: ['skills_srd', 'level', 'challenge', 'strength_mod', 'dexterity_mod', 'constitution_mod', 'intelligence_mod', 'wisdom_mod', 'charisma_mod', 'expertise_as_advantage'],
collectionArrayAddItems: ['name', 'ability'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
const skillsFromSRD = v.skills_srd;
const skillsObj = {};
const pb = proficiencyBonus.get(v.level, v.challenge);
const expertise = pb * 2;
let skillName;
let repeatingString;
if (!isUndefinedOrEmpty(skillsFromSRD)) {
for (const id of ids) {
repeatingString = `${repeatingItem}_${id}_`;
skillName = v[`${repeatingString}name`];
skillsObj[skillName] = id;
}
const re = /(\w+)\s?((?:\+|\-)\d+)/gi;
let match;
while ((match = re.exec(skillsFromSRD)) !== null) {
if (match && match[1] && match[2]) {
skillName = match[1];
if (skillsObj[skillName]) {
const skillId = skillsObj[skillName];
repeatingString = `${repeatingItem}_${skillId}_`;
const skillAbility = v[`${repeatingString}ability`];
const abilityValue = getAbilityValue(v, skillAbility);
const skillBonus = getIntValue(match[2]) - abilityValue;
if (skillBonus >= expertise) {
if (v.expertise_as_advantage === '1') {
finalSetAttrs[`${repeatingString}skill_d20`] = '2d20@{d20_mod}kh1';
finalSetAttrs[`${repeatingString}proficiency`] = 'proficient';
} else {
finalSetAttrs[`${repeatingString}proficiency`] = 'expertise';
}
if (skillBonus > expertise) {
finalSetAttrs[`${repeatingString}bonus`] = skillBonus - expertise;
}
} else if (skillBonus >= pb) {
finalSetAttrs[`${repeatingString}proficiency`] = 'proficient';
if (skillBonus > pb) {
finalSetAttrs[`${repeatingString}bonus`] = skillBonus - pb;
}
}
} else {
console.warn(`${skillName} does not exist in the list of skills`);
}
}
}
}
},
});
}
updateInitiative() {
const collectionArray = ['initiative', 'initiative_ability', 'initiative_formula', 'initiative_bonus', 'jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'global_check_bonus'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
collectionArray.push(`${ability}_check_bonus`);
}
getSetItems('abilityChecks.updateInitiative', {
collectionArray,
callback: (v, finalSetAttrs) => {
finalSetAttrs.initiative = 0;
let initiativeAbility = v.initiative_ability;
if (isUndefined(initiativeAbility)) {
initiativeAbility = 'dexterity';
}
const abilityMod = getAbilityValue(v, initiativeAbility);
if (exists(abilityMod)) {
finalSetAttrs.initiative += abilityMod;
}
finalSetAttrs.initiative_formula = `${abilityMod}[${getAbilityShortName(initiativeAbility)}]`;
const abilityCheckBonus = getIntValue(v[`${initiativeAbility}_check_bonus`]);
if (exists(abilityCheckBonus)) {
finalSetAttrs.initiative += abilityCheckBonus;
finalSetAttrs.initiative_formula += `${addArithmeticOperator(finalSetAttrs.initiative_formula, abilityCheckBonus)}[${getAbilityShortName(initiativeAbility)} check bonus]`;
}
const initiativeBonus = v.initiative_bonus;
if (exists(initiativeBonus)) {
if (!isNaN(initiativeBonus)) {
finalSetAttrs.initiative += getIntValue(initiativeBonus);
}
finalSetAttrs.initiative_formula += `${addArithmeticOperator(finalSetAttrs.initiative_formula, initiativeBonus)}[initiative bonus]`;
}
if (v.remarkable_athlete_toggle === '@{remarkable_athlete}') {
const remarkableAthlete = getIntValue(v.remarkable_athlete);
if (exists(remarkableAthlete)) {
finalSetAttrs.initiative += remarkableAthlete;
finalSetAttrs.initiative_formula += `${addArithmeticOperator(finalSetAttrs.initiative_formula, remarkableAthlete)}[remarkable athlete]`;
}
} else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') {
const jackOfAllTrades = getIntValue(v.jack_of_all_trades);
if (exists(jackOfAllTrades)) {
finalSetAttrs.initiative += jackOfAllTrades;
finalSetAttrs.initiative_formula += `${addArithmeticOperator(finalSetAttrs.initiative_formula, jackOfAllTrades)}[jack of all trades]`;
}
}
const globalCheckBonus = v.global_check_bonus;
if (exists(globalCheckBonus)) {
if (finalSetAttrs.initiative_formula) {
finalSetAttrs.initiative_formula += ' + ';
}
finalSetAttrs.initiative_formula += '(@{global_check_bonus})[global check bonus]';
}
},
});
}
setup() {
on('change:repeating_skill', (eventInfo) => {
const repeatingInfo = getRepeatingInfo('repeating_skill', eventInfo);
if (repeatingInfo && repeatingInfo.field !== 'ability_key' && repeatingInfo.field !== 'total' && repeatingInfo.field !== 'total_with_sign' && repeatingInfo.field !== 'passive_total' && repeatingInfo.field !== 'passive_total_with_sign' && repeatingInfo.field !== 'formula') {
this.updateSkill(repeatingInfo.rowId);
}
});
on('change:pb change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_check_bonus change:strength_check_bonus change:dexterity_check_bonus change:constitution_check_bonus change:intelligence_check_bonus change:wisdom_check_bonus change:charisma_check_bonus', () => {
this.updateSkill();
});
on('change:skills_srd', () => {
this.updateSkillsFromSRD();
});
on('remove:repeating_skill change:ability_checks_show_totals', () => {
this.updateMacro();
});
const initiativeWatch = ['change:initiative_ability', 'change:initiative_bonus', 'change:jack_of_all_trades_toggle', 'change:jack_of_all_trades', 'change:remarkable_athlete_toggle', 'change:remarkable_athlete', 'change:global_check_bonus'];
for (const ability of ABILITIES) {
initiativeWatch.push(`change:${ability}_mod`);
initiativeWatch.push(`change:${ability}_check_bonus`);
}
on(initiativeWatch.join(' '), () => {
this.updateInitiative();
});
}
}
+495
View File
@@ -0,0 +1,495 @@
/* global on:false */
import { ABILITIES, TOGGLE_VARS } from './constants';
import { ProficiencyBonus } from './ProficiencyBonus';
const proficiencyBonus = new ProficiencyBonus();
import { getSetRepeatingItems, isUndefined, isUndefinedOrEmpty, fromVOrFinalSetAttrs, setCritDamage, getIntValue, getRepeatingInfo, lowercaseDamageTypes, exists } from './utilities';
import { updateAttackToggle, updateSavingThrowToggle, updateDamageToggle, updateHealToggle } from './updateToggles';
export class Actions {
updateAll() {
this.update('trait');
this.update('action');
this.update('reaction');
this.update('legendaryaction');
this.update('lairaction');
this.update('regionaleffect');
}
update(type, rowId) {
const rechargeRegex = /\s*?\((?:Recharge\s*?(\d+\-\d+|\d+)|Recharges\safter\sa\s(.*))\)/gi;
const rechargeDayRegex = /\s*?\((\d+\/Day)\)/gi;
const collectionArray = ['pb', 'strength_mod', 'finesse_mod', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability', 'base_dc'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
}
getSetRepeatingItems('actions.update', {
repeatingItems: [`repeating_${type}`],
collectionArray,
collectionArrayAddItems: ['name', 'type', 'uses', 'uses_max', 'has_uses', 'roll_toggle', 'to_hit', 'attack_formula', 'proficiency', 'attack_ability', 'attack_bonus', 'saving_throw_toggle', 'saving_throw_ability', 'saving_throw_bonus', 'saving_throw_dc', 'damage_toggle', 'damage_formula', 'damage', 'damage_ability', 'damage_bonus', 'damage_type', 'damage_crit', 'second_damage_toggle', 'second_damage_formula', 'second_damage', 'second_damage_ability', 'second_damage_bonus', 'second_damage_type', 'second_damage_crit', 'damage_string', 'heal_toggle', 'heal', 'heal_ability', 'heal_bonus', 'heal_query_toggle', 'parsed', 'recharge', 'recharge_display', 'extras_toggle', 'emote', 'freetext', 'freeform'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
const actionName = v[`${repeatingString}name`];
if (!isUndefinedOrEmpty(actionName)) {
const rechargeResult = rechargeRegex.exec(actionName);
if (rechargeResult) {
finalSetAttrs[`${repeatingString}recharge`] = rechargeResult[1] || rechargeResult[2];
finalSetAttrs[`${repeatingString}name`] = actionName.replace(rechargeRegex, '');
}
const rechargeDayResult = rechargeDayRegex.exec(actionName);
if (rechargeDayResult) {
finalSetAttrs[`${repeatingString}recharge`] = rechargeDayResult[1] || rechargeDayResult[2];
finalSetAttrs[`${repeatingString}name`] = actionName.replace(rechargeDayRegex, '');
}
}
if (v[`${repeatingString}uses`] || v[`${repeatingString}uses_max`]) {
finalSetAttrs[`${repeatingString}has_uses`] = 1;
} else if (!isUndefinedOrEmpty(v[`${repeatingString}has_uses`])) {
finalSetAttrs[`${repeatingString}has_uses`] = 0;
}
const recharge = fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}recharge`);
if (exists(recharge)) {
if (isNaN(recharge)) {
finalSetAttrs[`${repeatingString}recharge_display`] = ` (${recharge})`;
} else {
finalSetAttrs[`${repeatingString}recharge_display`] = ` (Recharge ${recharge})`;
}
} else if (exists(v[`${repeatingString}recharge_display`])) {
finalSetAttrs[`${repeatingString}recharge_display`] = '';
}
let attackOptions = {};
if (type !== 'trait') {
attackOptions = {
globalAttackBonus: v.global_attack_bonus,
globalAttackBonusLabel: 'global attack bonus',
globalMeleeAttackBonus: v.global_melee_attack_bonus,
globalRangedAttackBonus: v.global_ranged_attack_bonus,
type: 'attack',
};
}
updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions);
updateSavingThrowToggle(v, finalSetAttrs, repeatingString);
let damageOptions = {};
if (type !== 'trait') {
damageOptions = {
globalDamageBonus: v.global_damage_bonus,
globalMeleeDamageBonus: v.global_melee_damage_bonus,
globalRangedDamageBonus: v.global_ranged_damage_bonus,
type: 'attack',
};
}
updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions);
if (v.damage_type) {
finalSetAttrs.damage_type = lowercaseDamageTypes(v.damage_type);
}
if (v.second_damage_type) {
finalSetAttrs.second_damage_type = lowercaseDamageTypes(v.second_damage_type);
}
setCritDamage(v, finalSetAttrs, repeatingString);
updateHealToggle(v, finalSetAttrs, repeatingString);
if (isUndefined(v[`${repeatingString}extras_toggle`]) && (v[`${repeatingString}emote`] || v[`${repeatingString}freetext`] || v[`${repeatingString}freeform`])) {
finalSetAttrs[`${repeatingString}extras_toggle`] = TOGGLE_VARS.extras;
}
}
},
});
}
updateIfTriggered(type, eventInfo) {
const repeatingInfo = getRepeatingInfo(`repeating_${type}`, eventInfo);
if (repeatingInfo && repeatingInfo.field !== 'name' && repeatingInfo.field !== 'freetext' && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'damage_crit' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'second_damage_crit' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'parsed' && repeatingInfo.field !== 'recharge_display') {
this.update(type, repeatingInfo.rowId);
}
}
updateChatMacro(type) {
getSetRepeatingItems('actions.updateChatMacro', {
repeatingItems: [`repeating_${type}`],
collectionArray: [`${type}s_macro_var`, `${type}s_chat_var`, `${type}s_exist`],
collectionArrayAddItems: ['name', 'freetext'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
finalSetAttrs[`${type}s_macro_var`] = '';
finalSetAttrs[`${type}s_chat_var`] = '';
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
let actionName = v[`${repeatingString}name`];
const freeText = v[`${repeatingString}freetext`];
if (id !== ids[0]) {
finalSetAttrs[`${type}s_macro_var`] += ', ';
}
let actionType = 'action';
let title;
if (type === 'trait') {
title = 'Traits';
actionType = 'trait';
} else if (type === 'action') {
title = 'Actions';
} else if (type === 'reaction') {
title = 'Reactions';
} else if (type === 'legendaryaction') {
title = 'Legendary Actions';
} else if (type === 'lairaction') {
title = 'Lair Actions';
actionName = freeText;
} else if (type === 'regionaleffect') {
title = 'Regional Effects';
actionName = freeText;
}
if (actionName && actionName.length > 50) {
actionName = `${actionName.substring(0, 50)}...`;
}
finalSetAttrs[`${type}s_macro_var`] += `[${actionName}](~repeating_${type}_${id}_${actionType})`;
finalSetAttrs[`${type}s_chat_var`] += `{{${title}=${finalSetAttrs[`${type}s_macro_var`]}}}`;
}
},
});
}
findClosest(array, goal) {
return array.reduce((prev, curr) => {
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
});
}
getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, fieldName, bonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod) {
let closest;
if (bonus) {
if (spellAttack) {
closest = this.findClosest(spellMods, bonus);
bonus -= closest;
if (closest === spellMods[0]) {
finalSetAttrs[repeatingString + fieldName] = 'intelligence';
} else if (closest === spellMods[1]) {
finalSetAttrs[repeatingString + fieldName] = 'wisdom';
} else if (closest === spellMods[2]) {
finalSetAttrs[repeatingString + fieldName] = 'charisma';
}
} else {
if (rangedAttack) {
finalSetAttrs[`${repeatingString}attack_ability`] = 'dexterity';
bonus -= dexMod;
} else {
closest = this.findClosest(meleeMods, bonus);
bonus -= closest;
if (closest === meleeMods[0]) {
finalSetAttrs[repeatingString + fieldName] = 'strength';
} else if (closest === meleeMods[1]) {
finalSetAttrs[repeatingString + fieldName] = 'dexterity';
}
}
}
} else {
finalSetAttrs[repeatingString + fieldName] = 0;
}
return bonus;
}
getAnyCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, fieldName, bonus, abilityMods) {
const closest = this.findClosest(abilityMods, bonus);
if (bonus) {
bonus -= closest;
if (closest === abilityMods[0]) {
finalSetAttrs[repeatingString + fieldName] = 'strength';
} else if (closest === abilityMods[1]) {
finalSetAttrs[repeatingString + fieldName] = 'dexterity';
} else if (closest === abilityMods[2]) {
finalSetAttrs[repeatingString + fieldName] = 'constitution';
} else if (closest === abilityMods[3]) {
finalSetAttrs[repeatingString + fieldName] = 'intelligence';
} else if (closest === abilityMods[4]) {
finalSetAttrs[repeatingString + fieldName] = 'wisdom';
} else if (closest === abilityMods[5]) {
finalSetAttrs[repeatingString + fieldName] = 'charisma';
}
} else {
finalSetAttrs[repeatingString + fieldName] = 0;
}
return bonus;
}
parseDamage(finalSetAttrs, repeatingString, freetext, regex, name, spellMods, meleeMods, spellAttack, rangedAttack, dexMod) {
const damageParseRegex = /(\d+d?\d+)(?:\s?(?:\+|\-)\s?(\d+))?/gi;
const damage = regex.exec(freetext);
let damageBonus;
if (damage) {
/*
1 is damage with dice. Example '2d6+4'
2 is damage type. Example 'slashing' or 'lightning or thunder'
*/
if (damage[1]) {
const damageParsed = damageParseRegex.exec(damage[1]);
if (damageParsed) {
if (damageParsed[1]) {
finalSetAttrs[repeatingString + name] = damageParsed[1];
}
if (damageParsed[2]) {
damageBonus = damageParsed[2];
}
}
}
damageBonus = this.getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, `${name}_ability`, damageBonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod);
if (damage[2]) {
finalSetAttrs[`${repeatingString}${name}_type`] = damage[2];
}
if (damageBonus) {
finalSetAttrs[`${repeatingString}${name}_bonus`] = damageBonus;
}
freetext = freetext.replace(regex, '');
finalSetAttrs[`${repeatingString}${name}_toggle`] = TOGGLE_VARS[name];
}
return freetext;
}
parse(type, rowId) {
const collectionArray = ['level', 'challenge', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
}
const damageSyntax = /(?:(\d+d?\d+(?:\s\+\s\d+)?)(?:\))?)\s*?/;
const damageType = /((?:[a-zA-Z]+|[a-zA-Z]+\s(?:or|and)\s[a-zA-Z]+)(?:\s*?\([a-zA-Z\s]+\))?)\s*damage\s?(\([a-zA-Z'\s]+\))?/;
const altDamageSyntax = /(?:,\s*?or\s*?)/;
const plus = /\s*?plus\s*?/;
const savingThrowRe = /(?:DC)\s*?(\d+)\s*?([a-zA-Z]*)\s*?(?:saving throw)/;
const saveSuccess = /or\s(.*)?\son a successful one./;
const damageRegex = new RegExp(damageSyntax.source + damageType.source, 'i');
const damagePlusRegex = new RegExp(plus.source + damageSyntax.source + damageType.source, 'i');
const altDamageRegex = new RegExp(altDamageSyntax.source + damageSyntax.source + damageType.source, 'i');
const savingThrowRegex = new RegExp(savingThrowRe.source, 'i');
const saveSuccessRegex = new RegExp(saveSuccess.source, 'i');
const typeRegex = /(melee|ranged|melee or ranged)\s*(spell|weapon)\s*attack/gi;
const toHitRegex = /:\s?\+\s?(\d+)\s*(?:to hit)/gi;
const reachRegex = /(?:reach)\s?(\d+)\s?(?:ft)/gi;
const rangeRegex = /(?:range)\s?(\d+)\/(\d+)\s?(ft)/gi;
const spellcastingRegex = /(\d+)\w+\slevel\s\((\d+)\s?slot(?:s)?\)/gi;
const spellcastingLevelRegex = /(\d+)(?:st|dn|rd|th)-level spellcaster/i;
const spellcastingAbilityRegex = /spellcasting ability is (\w+)/i;
getSetRepeatingItems('actions.parse', {
repeatingItems: [`repeating_${type}`],
collectionArray,
collectionArrayAddItems: ['name', 'freetext', 'type'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
const pb = proficiencyBonus.get(v.level, v.challenge);
const strMod = getIntValue(v.strength_mod);
const dexMod = getIntValue(v.dexterity_mod);
const conMod = getIntValue(v.constitution_mod);
const intMod = getIntValue(v.intelligence_mod);
const wisMod = getIntValue(v.wisdom_mod);
const chaMod = getIntValue(v.charisma_mod);
const meleeMods = [strMod, dexMod];
const spellMods = [intMod, wisMod, chaMod];
const abilityMods = [strMod, dexMod, conMod, intMod, wisMod, chaMod];
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
let rangedAttack = false;
let spellAttack = false;
const name = v[`${repeatingString}name`];
let freetext = v[`${repeatingString}freetext`];
if (name && name.indexOf('Spellcasting') !== -1) {
const spellcastingSearch = spellcastingAbilityRegex.exec(freetext);
if (spellcastingSearch && spellcastingSearch[1]) {
const spellcastingAbility = spellcastingSearch[1].toLowerCase();
finalSetAttrs.default_ability = `@{${spellcastingAbility}_mod}`;
}
const spellcastingLevelSearch = spellcastingLevelRegex.exec(freetext);
if (spellcastingLevelSearch && spellcastingLevelSearch[1]) {
finalSetAttrs.caster_level = spellcastingLevelSearch[1];
}
let match;
while ((match = spellcastingRegex.exec(freetext)) !== null) {
if (match && match[1] && match[2]) {
finalSetAttrs[`spell_slots_l${match[1]}_bonus`] = match[2];
}
}
}
const actionType = typeRegex.exec(freetext);
if (actionType) {
if (actionType[1]) {
actionType[1] = actionType[1].toLowerCase();
if (isUndefined(v[`${repeatingString}type`]) && actionType[1] === 'melee') {
finalSetAttrs[`${repeatingString}type`] = 'Melee Weapon';
} else if (isUndefined(v[`${repeatingString}type`]) && actionType[1] === 'ranged') {
finalSetAttrs[`${repeatingString}type`] = 'Ranged Weapon';
rangedAttack = true;
} else {
finalSetAttrs[`${repeatingString}type`] = 'Other';
}
}
if (actionType[2]) {
actionType[2] = actionType[2].toLowerCase();
if (actionType[2] === 'spell') {
spellAttack = true;
}
}
freetext = freetext.replace(typeRegex, '');
}
const reach = reachRegex.exec(freetext);
if (reach && reach[1]) {
finalSetAttrs[`${repeatingString}reach`] = `${reach[1]}ft.`;
freetext = freetext.replace(reachRegex, '');
}
const range = rangeRegex.exec(freetext);
if (range && range[1] && range[2]) {
finalSetAttrs[`${repeatingString}range`] = `${range[1]}ft.`;
freetext = freetext.replace(rangeRegex, '');
}
const toHit = toHitRegex.exec(freetext);
if (toHit && toHit[1]) {
let hitBonus = toHit[1];
hitBonus -= pb;
hitBonus = this.getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, 'attack_ability', hitBonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod);
if (hitBonus) {
finalSetAttrs[`${repeatingString}attack_bonus`] = hitBonus;
}
freetext = freetext.replace(toHitRegex, '');
finalSetAttrs[`${repeatingString}roll_toggle`] = TOGGLE_VARS.roll;
} else {
finalSetAttrs[`${repeatingString}roll_toggle`] = '0';
}
const savingThrow = savingThrowRegex.exec(freetext);
if (savingThrow) {
if (savingThrow[1]) {
let savingThrowTotal = savingThrow[1];
savingThrowTotal -= 8;
savingThrowTotal -= pb;
savingThrowTotal = this.getAnyCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, 'saving_throw_ability', savingThrowTotal, abilityMods);
if (savingThrowTotal) {
finalSetAttrs[`${repeatingString}saving_throw_bonus`] = savingThrowTotal;
}
freetext = freetext.replace(savingThrowRegex, '');
finalSetAttrs[`${repeatingString}saving_throw_toggle`] = TOGGLE_VARS.saving_throw;
}
if (savingThrow[2]) {
finalSetAttrs[`${repeatingString}saving_throw_vs_ability`] = savingThrow[2].toUpperCase();
}
const halfDamage = saveSuccessRegex.exec(freetext);
if (halfDamage && halfDamage[1]) {
finalSetAttrs[`${repeatingString}saving_throw_success`] = halfDamage[1];
freetext = freetext.replace(saveSuccessRegex, '');
}
} else {
finalSetAttrs[`${repeatingString}saving_throw_toggle`] = '0';
}
freetext = this.parseDamage(finalSetAttrs, repeatingString, freetext, damageRegex, 'damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod);
freetext = this.parseDamage(finalSetAttrs, repeatingString, freetext, altDamageRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod);
freetext = this.parseDamage(finalSetAttrs, repeatingString, freetext, damagePlusRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod);
if (!exists(finalSetAttrs[`${repeatingString}second_damage`])) {
freetext = this.parseDamage(finalSetAttrs, repeatingString, freetext, damageRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod);
}
finalSetAttrs[`${repeatingString}extras_toggle`] = TOGGLE_VARS.extras;
finalSetAttrs[`${repeatingString}toggle_details`] = 0;
}
},
setFinalAttrsCallback: () => {
this.update(type, rowId);
},
});
}
count(type) {
getSetRepeatingItems('actions.count', {
repeatingItems: [`repeating_${type}`],
collectionArray: [`${type}s_exist`],
callback: (v, finalSetAttrs, ids) => {
if (ids.length > 0) {
finalSetAttrs[`${type}s_exist`] = 1;
} else if (exists(v[`${type}s_exist`])) {
finalSetAttrs[`${type}s_exist`] = 0;
}
},
});
}
setup() {
on('change:pb', () => {
this.update();
});
on('change:repeating_trait', (eventInfo) => {
this.updateIfTriggered('trait', eventInfo);
});
on('change:repeating_action', (eventInfo) => {
this.updateIfTriggered('action', eventInfo);
});
on('change:repeating_reaction', (eventInfo) => {
this.updateIfTriggered('reaction', eventInfo);
});
on('change:repeating_legendaryaction', (eventInfo) => {
this.updateIfTriggered('legendaryaction', eventInfo);
});
on('change:repeating_lairaction', (eventInfo) => {
this.updateIfTriggered('lairaction', eventInfo);
});
on('change:repeating_regionaleffect', (eventInfo) => {
this.updateIfTriggered('regionaleffect', eventInfo);
});
on('change:repeating_trait remove:repeating_trait', () => {
this.count('trait');
this.updateChatMacro('trait');
});
on('change:repeating_action remove:repeating_action', () => {
this.count('action');
this.updateChatMacro('action');
});
on('change:repeating_reaction remove:repeating_reaction', () => {
this.count('reaction');
this.updateChatMacro('reaction');
});
on('change:repeating_legendaryaction remove:repeating_legendaryaction', () => {
this.count('legendaryaction');
this.updateChatMacro('legendaryaction');
});
on('change:repeating_lairaction remove:repeating_lairaction', () => {
this.count('lairaction');
this.updateChatMacro('lairaction');
});
on('change:repeating_regionaleffect remove:repeating_regionaleffect', () => {
this.count('regionaleffect');
this.updateChatMacro('regionaleffect');
});
on('change:repeating_trait:freetext', (eventInfo) => {
this.parse('trait', getRepeatingInfo('repeating_trait', eventInfo).rowId);
});
on('change:repeating_action:freetext', (eventInfo) => {
this.parse('action', getRepeatingInfo('repeating_action', eventInfo).rowId);
});
on('change:repeating_reaction:freetext', (eventInfo) => {
this.parse('reaction', getRepeatingInfo('repeating_reaction', eventInfo).rowId);
});
on('change:repeating_legendaryaction:freetext', (eventInfo) => {
this.parse('legendaryaction', getRepeatingInfo('repeating_legendaryaction', eventInfo).rowId);
});
on('change:repeating_lairaction:freetext', (eventInfo) => {
this.parse('lairaction', getRepeatingInfo('repeating_lairaction', eventInfo).rowId);
});
on('change:global_attack_bonus change:global_melee_attack_bonus change:global_ranged_attack_bonus change:global_damage_bonus change:global_melee_damage_bonus change:global_ranged_damage_bonus change:ammo_auto_use', () => {
this.update('action');
this.update('reaction');
this.update('legendaryaction');
this.update('lairaction');
});
}
}
+60
View File
@@ -0,0 +1,60 @@
/* global on:false */
import { ABILITIES } from './constants';
import { getSetRepeatingItems, exists } from './utilities';
export class Attachers {
update() {
const collectionArray = ['attacher_initiative', 'attacher_death_saving_throw', 'attacher_hit_dice', 'attacher_attack', 'attacher_spell', 'attacher_skill', 'attacher_crit'];
const itemsToPush = ['initiative', 'death_saving_throw', 'hit_dice', 'attack', 'spell', 'skill'];
for (const ability of ABILITIES) {
collectionArray.push(`attacher_${ability}_check`);
collectionArray.push(`attacher_${ability}_saving_throw`);
itemsToPush.push(`${ability}_check`);
itemsToPush.push(`${ability}_saving_throw`);
}
getSetRepeatingItems('attachers.update', {
repeatingItems: ['repeating_attacher'],
collectionArray,
collectionArrayAddItems: ['name', 'freetext', 'freeform', 'crit_attacher'],
itemsToPush,
itemToPushSuffix: 'attacher',
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const itemToPush of itemsToPush) {
finalSetAttrs[`attacher_${itemToPush}`] = '';
}
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
for (const itemToPush of itemsToPush) {
const attacher = v[`${repeatingString}${itemToPush}_attacher`];
if (exists(attacher) && attacher === 'on') {
const attacherName = v[`${repeatingString}name`] || '';
const freeText = v[`${repeatingString}freetext`];
if (exists(attacherName) && exists(freeText)) {
const critAttacher = v[`${repeatingString}crit_attacher`];
if (critAttacher === 'on') {
finalSetAttrs[`attacher_${itemToPush}`] += `{{crit_name=${attacherName}}} `;
finalSetAttrs[`attacher_${itemToPush}`] += `{{crit_text=${freeText}}} `;
} else {
finalSetAttrs[`attacher_${itemToPush}`] += `{{${attacherName}=${freeText}}} `;
}
}
const freeForm = v[`${repeatingString}freeform`];
if (exists(freeForm)) {
finalSetAttrs[`attacher_${itemToPush}`] += `${freeForm} `;
}
}
}
}
},
});
}
setup() {
on('change:repeating_attacher remove:repeating_attacher', () => {
this.update();
});
}
}
+183
View File
@@ -0,0 +1,183 @@
/* global on:false, generateRowID:false */
import { ABILITIES } from './constants';
import { updateAttackToggle, updateSavingThrowToggle, updateDamageToggle } from './updateToggles';
import { getSetRepeatingItems, isUndefinedOrEmpty, setFinalAttrs, setCritDamage, sumRepeating, lowercaseDamageTypes, exists, getIntValue, getRepeatingInfo } from './utilities';
export class Attacks {
findAmmo(name, callback) {
let repeatingString;
getSetRepeatingItems('attacks.findAmmo', {
repeatingItems: ['repeating_ammo'],
collectionArrayAddItems: ['name', 'qty'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
repeatingString = `${repeatingItem}_${id}_`;
if (v[`${repeatingString}name`] === name) {
callback(`@{${repeatingString}qty}`);
return;
}
}
console.warn(`cannot find ammo field by the name ${name}, adding it`);
repeatingString = `${repeatingItem}_${generateRowID()}_`;
finalSetAttrs[`${repeatingString}name`] = name;
finalSetAttrs[`${repeatingString}qty`] = 20;
callback(`@{${repeatingString}qty}`);
},
});
}
update(rowId) {
const collectionArray = ['pb', 'strength_mod', 'finesse_mod', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability', 'ammo_auto_use', 'base_dc'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
}
getSetRepeatingItems('attacks.update', {
repeatingItems: ['repeating_attack'],
collectionArray,
collectionArrayAddItems: ['name', 'type', 'roll_toggle', 'to_hit', 'attack_formula', 'proficiency', 'attack_ability', 'attack_bonus', 'ammo_toggle_var', 'ammo_field_name', 'ammo_used', 'saving_throw_toggle', 'saving_throw_ability', 'saving_throw_bonus', 'saving_throw_dc', 'damage_toggle', 'damage_formula', 'damage', 'damage_ability', 'damage_bonus', 'damage_type', 'damage_crit', 'second_damage_toggle', 'second_damage_formula', 'second_damage', 'second_damage_ability', 'second_damage_bonus', 'second_damage_type', 'second_damage_crit', 'damage_string', 'modifiers', 'properties', 'weight', 'parsed'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
const attackName = v[`${repeatingString}name`];
if (isUndefinedOrEmpty(attackName)) {
return;
}
if (isUndefinedOrEmpty(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('modifiers') === -1) {
const attackModifiers = v[`${repeatingString}modifiers`];
if (exists(attackModifiers)) {
const attackBonus = attackModifiers.replace(/.*(?:Melee|Ranged) Attacks \+(\d+).*/gi, '$1');
const damageBonus = attackModifiers.replace(/.*(?:Melee|Ranged) Damage \+(\d+).*/gi, '$1');
finalSetAttrs[`${repeatingString}attack_bonus`] = attackBonus;
finalSetAttrs[`${repeatingString}damage_bonus`] = damageBonus;
if (!finalSetAttrs[`${repeatingString}parsed`]) {
finalSetAttrs[`${repeatingString}parsed`] = '';
}
finalSetAttrs[`${repeatingString}parsed`] += ' modifiers';
}
}
if (isUndefinedOrEmpty(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('attackProperties') === -1) {
const attackProperties = v[`${repeatingString}properties`];
if (exists(attackProperties)) {
if (attackProperties.indexOf('Reach') !== -1) {
finalSetAttrs[`${repeatingString}reach`] = '10 ft';
} else if (v[`${repeatingString}type`] === 'Melee Weapon') {
finalSetAttrs[`${repeatingString}reach`] = '5 ft';
}
if (attackProperties.indexOf('Finesse') !== -1) {
finalSetAttrs[`${repeatingString}attack_ability`] = 'finesse';
finalSetAttrs[`${repeatingString}damage_ability`] = 'finesse';
}
if (!finalSetAttrs[`${repeatingString}parsed`]) {
finalSetAttrs[`${repeatingString}parsed`] = '';
}
finalSetAttrs[`${repeatingString}parsed`] += ' attackProperties';
}
}
const attackOptions = {
globalAttackBonus: v.global_attack_bonus,
globalAttackBonusLabel: 'global attack bonus',
globalMeleeAttackBonus: v.global_melee_attack_bonus,
globalRangedAttackBonus: v.global_ranged_attack_bonus,
type: 'attack',
};
updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions);
const ammoName = v[`${repeatingString}ammo_field_name`];
const ammoUsed = getIntValue(v[`${repeatingString}ammo_used`], 1);
if (!isUndefinedOrEmpty(ammoName)) {
let ammoAutoUse;
if (v.ammo_auto_use === '1') {
ammoAutoUse = 1;
} else {
ammoAutoUse = 0;
}
this.findAmmo(ammoName, (ammoQtyName) => {
const setAmmo = {};
setAmmo[`${repeatingString}ammo_toggle_var`] = `{{ammo=[[${ammoQtyName}-${ammoAutoUse * ammoUsed}]]}} {{ammo_name=${ammoName}}}`;
setFinalAttrs(v, setAmmo, 'findAmmo');
});
}
updateSavingThrowToggle(v, finalSetAttrs, repeatingString);
const damageOptions = {
globalDamageBonus: v.global_damage_bonus,
globalMeleeDamageBonus: v.global_melee_damage_bonus,
globalRangedDamageBonus: v.global_ranged_damage_bonus,
type: 'attack',
};
updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions);
if (v.damage_type) {
finalSetAttrs.damage_type = lowercaseDamageTypes(v.damage_type);
}
if (v.second_damage_type) {
finalSetAttrs.second_damage_type = lowercaseDamageTypes(v.second_damage_type);
}
setCritDamage(v, finalSetAttrs, repeatingString);
}
},
});
}
weigh() {
const options = {
collection: 'attack',
toggle: 'carried',
qty: 'qty',
};
const sumItems = [
{
fieldToAdd: 'weight',
itemTotal: 'weight_total',
totalField: 'weight_attacks',
},
];
sumRepeating(options, sumItems);
}
updateChatMacro() {
getSetRepeatingItems('attacks.updateChatMacro', {
repeatingItems: ['repeating_attack'],
collectionArray: ['attacks_macro_var'],
collectionArrayAddItems: ['name'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
finalSetAttrs.attacks_macro_var = '';
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
let actionName = v[`${repeatingString}name`];
if (actionName && actionName.length > 50) {
actionName = `${actionName.substring(0, 50)}...`;
}
if (id !== ids[0]) {
finalSetAttrs.attacks_macro_var += ', ';
}
finalSetAttrs.attacks_macro_var += `[${actionName}](~repeating_attack_${id}_attack)`;
}
},
});
}
setup() {
on('change:repeating_attack', (eventInfo) => {
const repeatingInfo = getRepeatingInfo('repeating_attack', eventInfo);
if (repeatingInfo && repeatingInfo.field !== 'roll_toggle' && repeatingInfo.field !== 'toggle_details' && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'damage_crit' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'second_damage_crit' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'qty' && repeatingInfo.field !== 'weight' && repeatingInfo.field !== 'parsed') {
this.update(repeatingInfo.row);
}
});
on('change:pb, change:global_attack_bonus change:global_melee_attack_bonus change:global_ranged_attack_bonus change:global_damage_bonus change:global_melee_damage_bonus change:global_ranged_damage_bonus change:ammo_auto_use', () => {
this.update();
});
on('change:repeating_attack:carried change:repeating_attack:qty change:repeating_attack:weight remove:repeating_attack', () => {
this.weigh();
});
on('change:repeating_attack remove:repeating_attack', () => {
this.updateChatMacro();
});
}
}
+314
View File
@@ -0,0 +1,314 @@
/* global on:false */
import { ABILITIES, CLASSES } from './constants';
import { ClassFeatures } from './ClassFeatures';
const classFeatures = new ClassFeatures();
import { Spells } from './Spells';
const spells = new Spells();
import { getSetItems, getSetRepeatingItems, isUndefinedOrEmpty, getIntValue, exists, capitalize, getRepeatingInfo, updateHD } from './utilities';
export class Character {
updateLevels(repeatingInfo) {
const defaultClassDetails = {
barbarian: {
hd: 'd12',
},
bard: {
hd: 'd8',
spellcasting: 'full',
},
cleric: {
hd: 'd8',
spellcasting: 'full',
},
druid: {
hd: 'd8',
spellcasting: 'full',
},
fighter: {
hd: 'd10',
},
monk: {
hd: 'd8',
},
paladin: {
hd: 'd10',
spellcasting: 'half',
},
ranger: {
hd: 'd10',
spellcasting: 'half',
},
rogue: {
hd: 'd8',
},
sorcerer: {
hd: 'd6',
spellcasting: 'full',
},
warlock: {
hd: 'd8',
spellcasting: 'warlock',
},
wizard: {
hd: 'd6',
spellcasting: 'full',
},
};
const hd = {
d20: 0,
d12: 0,
d10: 0,
d8: 0,
d6: 0,
d4: 0,
d2: 0,
d0: 0,
};
const spellcasting = {
full: 0,
half: 0,
third: 0,
warlock: 0,
};
let totalLevel = 0;
const classLevels = {};
let classesWithSpellcasting = 0;
const xpTable = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000, 305000, 355000, 385000, 405000, 435000, 465000, 495000, 525000, 555000, 585000, 605000, 635000, 665000];
const collectionArray = ['is_npc', 'caster_level', 'caster_type', 'class_and_level', 'level', 'xp_next_level'];
for (const className of CLASSES) {
collectionArray.push(`${className}_level`);
collectionArray.push(`has_${className}_levels`);
}
for (const key in hd) {
if (hd.hasOwnProperty(key)) {
collectionArray.push(`hd_${key}_max`);
collectionArray.push(`hd_${key}_query`);
collectionArray.push(`hd_${key}_toggle`);
}
}
getSetRepeatingItems('character.updateLevels', {
repeatingItems: ['repeating_class'],
collectionArray,
collectionArrayAddItems: ['level', 'name', 'custom_name', 'hd', 'spellcasting', 'custom_class_toggle'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const className of CLASSES) {
finalSetAttrs[`${className}_level`] = 0;
}
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
let className = v[`${repeatingString}name`];
let classLevel = v[`${repeatingString}level`];
if (isUndefinedOrEmpty(className) && isUndefinedOrEmpty(classLevel)) {
continue;
}
if (isUndefinedOrEmpty(className)) {
className = 'barbarian';
}
if (className === 'custom') {
finalSetAttrs[`${repeatingString}custom_class_toggle`] = 'on';
const customName = v[`${repeatingString}custom_name`];
if (exists(customName)) {
className = customName;
} else {
className = 'custom';
}
} else if (v[`${repeatingString}custom_class_toggle`]) {
finalSetAttrs[`${repeatingString}custom_class_toggle`] = 0;
}
if (isUndefinedOrEmpty(classLevel)) {
classLevel = 1;
finalSetAttrs[`${repeatingString}level`] = classLevel;
finalSetAttrs[`${className}_level`] = classLevel;
} else {
classLevel = getIntValue(classLevel);
totalLevel += classLevel;
if (classLevels[className]) {
classLevels[className] += classLevel;
} else {
classLevels[className] = classLevel;
}
}
let classHd = v[`${repeatingString}hd`];
if (isUndefinedOrEmpty(classHd) || (repeatingInfo && repeatingInfo.field === 'name')) {
if (defaultClassDetails.hasOwnProperty(className)) {
classHd = defaultClassDetails[className].hd;
} else {
classHd = 'd12';
}
finalSetAttrs[`${repeatingString}hd`] = classHd;
}
if (classHd && classLevel) {
hd[classHd] += classLevel;
}
let classSpellcasting = v[`${repeatingString}spellcasting`];
if (isUndefinedOrEmpty(classSpellcasting)) {
if (defaultClassDetails.hasOwnProperty(className)) {
classSpellcasting = defaultClassDetails[className].spellcasting;
if (classSpellcasting) {
finalSetAttrs[`${repeatingString}spellcasting`] = classSpellcasting;
}
} else {
finalSetAttrs[`${repeatingString}spellcasting`] = 'none';
}
} else if (classSpellcasting === 'warlock') {
spellcasting[classSpellcasting] += classLevel;
} else {
classesWithSpellcasting += 1;
spellcasting[classSpellcasting] += classLevel;
}
}
finalSetAttrs.number_of_classes = 0;
finalSetAttrs.class_and_level = '';
for (const prop in classLevels) {
if (classLevels.hasOwnProperty(prop)) {
finalSetAttrs.number_of_classes = finalSetAttrs.number_of_classes + 1;
if (classLevels.hasOwnProperty(prop)) {
finalSetAttrs[`${prop}_level`] = classLevels[prop];
if (finalSetAttrs.class_and_level !== '') {
finalSetAttrs.class_and_level += ', ';
}
finalSetAttrs.class_and_level += `${capitalize(prop)} ${classLevels[prop]}`;
}
}
}
finalSetAttrs.level = totalLevel;
let xpForNextLevel = 0;
if (!totalLevel) {
totalLevel = 0;
}
if (totalLevel > 30) {
xpForNextLevel = xpTable[30];
} else {
xpForNextLevel = xpTable[totalLevel];
}
finalSetAttrs.xp_next_level = xpForNextLevel;
for (const className of CLASSES) {
if (finalSetAttrs[`${className}_level`] > 0) {
finalSetAttrs[`has_${className}_levels`] = 1;
} else if (!isUndefinedOrEmpty(v[`has_${className}_levels`])) {
finalSetAttrs[`has_${className}_levels`] = 0;
}
}
updateHD(v, finalSetAttrs, hd);
let casterLevel = 0;
if (!v.is_npc || v.is_npc === '0' || v.is_npc === 0) {
if (classesWithSpellcasting > 1) {
casterLevel += spellcasting.full;
casterLevel += Math.floor(spellcasting.half / 2);
casterLevel += Math.floor(spellcasting.third / 3);
} else {
casterLevel = spellcasting.full + spellcasting.half + spellcasting.third;
}
finalSetAttrs.caster_level = casterLevel;
}
if (classesWithSpellcasting > 1 || spellcasting.full) {
finalSetAttrs.caster_type = 'full';
} else if (spellcasting.half) {
finalSetAttrs.caster_type = 'half';
} else if (spellcasting.third) {
finalSetAttrs.caster_type = 'third';
}
},
setFinalAttrsCallback: () => {
classFeatures.set();
spells.updateSlots();
},
});
}
watchForClassLevelChanges() {
const classFeatureWatch = [];
for (const ability of ABILITIES) {
classFeatureWatch.push(`change:${ability}_mod`);
}
classFeatureWatch.push('change:careful_spell_toggle');
classFeatureWatch.push('change:distant_spell_toggle');
classFeatureWatch.push('change:empowered_spell_toggle');
classFeatureWatch.push('change:extended_spell_toggle');
classFeatureWatch.push('change:heightened_spell_toggle');
classFeatureWatch.push('change:quickened_spell_toggle');
classFeatureWatch.push('change:subtle_spell_toggle');
classFeatureWatch.push('change:twinned_spell_toggle');
on(classFeatureWatch.join(' '), () => {
classFeatures.set();
});
}
updateJackOfAllTrades() {
getSetItems('character.updateJackOfAllTrades', {
collectionArray: ['pb', 'jack_of_all_trades'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.jack_of_all_trades = Math.floor(getIntValue(v.pb) / 2);
},
});
}
updateRemarkableAthlete() {
getSetItems('character.updateRemarkableAthlete', {
collectionArray: ['pb', 'remarkable_athlete'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.remarkable_athlete = Math.ceil(getIntValue(v.pb) / 2);
},
});
}
updateD20Mod() {
getSetItems('character.updateD20Mod', {
collectionArray: ['halfling_luck'],
callback: (v, finalSetAttrs) => {
if (v.halfling_luck === 'on') {
finalSetAttrs.d20_mod = 'ro<1';
} else {
finalSetAttrs.d20_mod = '';
}
},
});
}
updateAlignment() {
getSetItems('character.updateAlignment', {
collectionArray: ['alignment', 'is_npc'],
callback: (v, finalSetAttrs) => {
if (v.alignment && v.is_npc === '1') {
finalSetAttrs.alignment = v.alignment.toLowerCase();
}
},
});
}
setup() {
on('change:repeating_class', (eventInfo) => {
const repeatingInfo = getRepeatingInfo('repeating_class', eventInfo);
if (repeatingInfo) {
this.updateLevels(repeatingInfo);
}
});
on('remove:repeating_class', () => {
this.updateLevels();
});
on('change:halfling_luck', () => {
this.updateD20Mod();
});
on('change:alignment', () => {
this.updateAlignment();
});
on('change:pb change:remarkable_athlete_toggle', () => {
this.updateRemarkableAthlete();
});
on('change:pb change:jack_of_all_trades_toggle', () => {
this.updateJackOfAllTrades();
});
this.watchForClassLevelChanges();
}
}
@@ -0,0 +1,966 @@
/* global getTranslationByKey:false */
import { getSetItems, isUndefinedOrEmpty, getIntValue } from './utilities';
import { CLASSES, ABILITIES, TOGGLE_VARS } from './constants';
import { Traits } from './Traits';
const traits = new Traits();
export class ClassFeatures {
extraAttack(v) {
if (v.fighter_level >= 5) {
let extraAttackTimes;
if (v.fighter_level >= 20) {
extraAttackTimes = getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK_FOUR');
} else if (v.fighter_level >= 11) {
extraAttackTimes = getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK_THREE');
} else {
extraAttackTimes = getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK_TWICE');
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK_TEXT').replace('NUMBER_OF_TIMES', extraAttackTimes),
name: getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK'),
storageName: 'Extra Attack',
});
} else if (v.barbarian_level >= 5 || v.monk_level >= 5 || v.paladin_level >= 5 || v.ranger_level >= 5) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK_TEXT').replace('NUMBER_OF_TIMES', getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK_TWICE')),
name: getTranslationByKey('CLASS_FEATURE_EXTRA_ATTACK'),
storageName: 'Extra Attack',
});
}
}
barbarian(v, finalSetAttrs) {
if (v.barbarian_level) {
let rageUses;
if (v.barbarian_level >= 20) {
rageUses = 999999;
} else if (v.barbarian_level >= 17) {
rageUses = 6;
} else if (v.barbarian_level >= 12) {
rageUses = 5;
} else if (v.barbarian_level >= 6) {
rageUses = 4;
} else if (v.barbarian_level >= 3) {
rageUses = 3;
} else {
rageUses = 2;
}
let rageDamage;
if (v.barbarian_level >= 16) {
rageDamage = 4;
} else if (v.barbarian_level >= 9) {
rageDamage = 3;
} else {
rageDamage = 2;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_RAGE_TEXT').replace('RAGE_DAMAGE', rageDamage),
name: getTranslationByKey('CLASS_FEATURE_RAGE'),
recharge: 'Long Rest',
storageName: 'Rage',
type: 'Other',
uses_max: rageUses,
});
if (isUndefinedOrEmpty(v.ac_unarmored_ability)) {
finalSetAttrs.ac_unarmored_ability = 'constitution';
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_UNARMORED_DEFENSE_BARBARIAN_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_UNARMORED_DEFENSE'),
storageName: 'Unarmored Defense Barbarian',
});
if (v.barbarian_level >= 2) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_RECKLESS_ATTACK_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_RECKLESS_ATTACK'),
storageName: 'Reckless Attack',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_DANGER_SENSE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DANGER_SENSE'),
storageName: 'Danger Sense',
});
}
if (v.barbarian_level >= 5) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FAST_MOVEMENT_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FAST_MOVEMENT'),
storageName: 'Fast Movement',
});
}
if (v.barbarian_level >= 7) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FERAL_INSTINCT_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FERAL_INSTINCT'),
storageName: 'Feral Instinct',
});
}
if (v.barbarian_level >= 9) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_BRUTAL_CRITICAL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_BRUTAL_CRITICAL'),
storageName: 'Brutal Critical',
});
}
if (v.barbarian_level >= 11) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_RELENTLESS_RAGE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_RELENTLESS_RAGE'),
storageName: 'Relentless Rage',
});
}
if (v.barbarian_level >= 15) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PERSISTENT_RAGE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PERSISTENT_RAGE'),
storageName: 'Persistent Rage',
});
}
if (v.barbarian_level >= 18) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_INDOMITABLE_MIGHT_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_INDOMITABLE_MIGHT'),
storageName: 'Indomitable Might',
});
}
if (v.barbarian_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PRIMAL_CHAMPION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PRIMAL_CHAMPION'),
storageName: 'Primal Champion',
});
}
}
}
bard(v, finalSetAttrs) {
if (v.bard_level) {
let die;
if (v.bard_level >= 15) {
die = 'd12';
} else if (v.bard_level >= 10) {
die = 'd10';
} else if (v.bard_level >= 5) {
die = 'd8';
} else {
die = 'd6';
}
let recharge = 'Long Rest';
if (v.bard_level >= 5) {
recharge = 'Short Rest';
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_BARDIC_INSPIRATION_TEXT').replace('d6', die),
name: getTranslationByKey('CLASS_FEATURE_BARDIC_INSPIRATION'),
recharge,
storageName: 'Bardic Inspiration',
uses_max: Math.max(getIntValue(v.charisma_mod), 1),
});
if (v.bard_level >= 2) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_JACK_OF_ALL_TRADES_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_JACK_OF_ALL_TRADES'),
storageName: 'Jack of All Trades',
});
finalSetAttrs.jack_of_all_trades_toggle = '@{jack_of_all_trades}';
let heal;
if (v.bard_level >= 17) {
heal = 'd12';
} else if (v.bard_level >= 13) {
heal = 'd10';
} else if (v.bard_level >= 9) {
heal = 'd8';
} else {
heal = 'd6';
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SONG_OF_REST_TEXT'),
heal,
name: getTranslationByKey('CLASS_FEATURE_SONG_OF_REST'),
storageName: 'Song of Rest',
});
}
if (v.bard_level >= 3) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EXPERTISE_BARD_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_EXPERTISE'),
storageName: 'Expertise Bard',
});
}
if (v.bard_level >= 6) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_COUNTERCHARM_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_COUNTERCHARM'),
storageName: 'Countercharm',
});
}
if (v.bard_level >= 10) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_MAGICAL_SECRETS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_MAGICAL_SECRETS'),
storageName: 'Magical Secrets',
});
}
if (v.bard_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SUPERIOR_INSPIRATION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SUPERIOR_INSPIRATION'),
storageName: 'Superior Inspiration',
});
}
}
}
cleric(v) {
if (v.cleric_level) {
if (v.cleric_level >= 2) {
let channelDivinityUses;
if (v.cleric_level >= 18) {
channelDivinityUses = 3;
} else if (v.cleric_level >= 6) {
channelDivinityUses = 2;
} else {
channelDivinityUses = 1;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY_CLERIC_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY'),
recharge: 'Short Rest',
storageName: 'Channel Divinity Cleric',
uses_max: channelDivinityUses,
});
let turnUndeadText = getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY_TURN_UNDEAD_TEXT');
if (v.cleric_level >= 5) {
let turnUndeadDestroyCR;
if (v.cleric_level >= 17) {
turnUndeadDestroyCR = '4';
} else if (v.cleric_level >= 14) {
turnUndeadDestroyCR = '3';
} else if (v.cleric_level >= 11) {
turnUndeadDestroyCR = '2';
} else if (v.cleric_level >= 8) {
turnUndeadDestroyCR = '1';
} else {
turnUndeadDestroyCR = '1/2';
}
turnUndeadText += `\n${getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY_TURN_UNDEAD_TEXT_PART_2').replace('CHALLENGE_RATING', turnUndeadDestroyCR)}`;
}
traits.set({
freetext: turnUndeadText,
name: getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY_TURN_UNDEAD'),
saving_throw_ability: 'wisdom',
saving_throw_vs_ability: 'WISDOM',
storageName: 'Turn Undead',
});
if (v.cleric_level >= 10) {
traits.set({
freeform: '{{text_top=[[d100]] > [[@{cleric_level}]]}}',
freetext: getTranslationByKey('CLASS_FEATURE_DIVINE_INTERVENTION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DIVINE_INTERVENTION'),
storageName: 'Divine Intervention',
uses_max: 1,
});
}
}
}
}
druid(v) {
if (v.druid_level) {
if (v.druid_level >= 2) {
const wildShapeHours = Math.floor(v.druid_level / 2);
let wildShapeUses;
let wildShapeCR;
let wildShapeLimitations;
if (v.druid_level >= 4) {
wildShapeCR = '1/2';
wildShapeLimitations = getTranslationByKey('CLASS_FEATURE_WILD_SHAPE_NO_FLYING');
} else if (v.druid_level >= 8) {
wildShapeCR = 1;
wildShapeLimitations = '';
} else {
wildShapeCR = '1/4';
wildShapeLimitations = getTranslationByKey('CLASS_FEATURE_WILD_SHAPE_NO_FLYING_OR_SWIMMING');
}
if (v.druid_level >= 20) {
wildShapeUses = 999999;
} else {
wildShapeUses = 2;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_WILD_SHAPE_TEXT')
.replace('WILD_SHAPE_HOURS', wildShapeHours)
.replace('CHALLENGE_RATING', wildShapeCR)
.replace('LIMITATIONS', ` ${wildShapeLimitations}`),
name: getTranslationByKey('CLASS_FEATURE_WILD_SHAPE'),
recharge: 'Short Rest',
storageName: 'Wild Shape',
uses_max: wildShapeUses,
});
}
if (v.druid_level >= 18) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_TIMELESS_BODY_DRUID_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_TIMELESS_BODY'),
storageName: 'Timeless Body',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_BEAST_SPELLS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_BEAST_SPELLS'),
storageName: 'Beast Spells',
});
}
if (v.druid_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_ARCHDRUID_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_ARCHDRUID'),
storageName: 'Archdruid',
});
}
}
}
fighter(v) {
if (v.fighter_level) {
traits.set({
freetext: `${getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE_TEXT')} ${getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE_FIGHTER_OPTIONS')}`,
name: getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE'),
storageName: 'Fighting Style',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SECOND_WIND_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SECOND_WIND'),
heal: 'd10 + @{fighter_level}',
recharge: 'Short Rest',
storageName: 'Second Wind',
uses_max: 1,
});
if (v.fighter_level >= 2) {
let actionSurgeUses;
if (v.fighter_level >= 17) {
actionSurgeUses = 2;
} else {
actionSurgeUses = 1;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_ACTION_SURGE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_ACTION_SURGE'),
recharge: 'Short Rest',
storageName: 'Action Surge',
uses_max: actionSurgeUses,
});
}
if (v.fighter_level >= 9) {
let indomitableUses;
if (v.fighter_level >= 17) {
indomitableUses = 3;
} else if (v.fighter_level >= 13) {
indomitableUses = 2;
} else {
indomitableUses = 1;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_INDOMITABLE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_INDOMITABLE'),
recharge: 'Long Rest',
storageName: 'Indomitable',
uses_max: indomitableUses,
});
}
}
}
monk(v, finalSetAttrs) {
if (v.monk_level) {
if (isUndefinedOrEmpty(v.ac_unarmored_ability)) {
finalSetAttrs.ac_unarmored_ability = 'wisdom';
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_UNARMORED_DEFENSE_MONK_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_UNARMORED_DEFENSE'),
storageName: 'Unarmored Defense Monk',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_MARTIAL_ARTS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_MARTIAL_ARTS'),
storageName: 'Martial Arts',
});
if (v.monk_level >= 2) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_KI_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_KI'),
recharge: 'Short Rest',
storageName: 'Ki',
uses_max: v.monk_level,
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FLURRY_OF_BLOWS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FLURRY_OF_BLOWS'),
storageName: 'Flurry of Blows',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PATIENT_DEFENSE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PATIENT_DEFENSE'),
storageName: 'Patient Defense',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_STEP_OF_THE_WIND_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_STEP_OF_THE_WIND'),
storageName: 'Step of the Wind',
});
let unarmoredMovementFeet;
if (v.monk_level >= 18) {
unarmoredMovementFeet = 30;
} else if (v.monk_level >= 14) {
unarmoredMovementFeet = 25;
} else if (v.monk_level >= 10) {
unarmoredMovementFeet = 20;
} else if (v.monk_level >= 6) {
unarmoredMovementFeet = 15;
} else {
unarmoredMovementFeet = 10;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_UNARMORED_MOVEMENT_TEXT').replace('UNARMORED_MOVEMENT_FEET', unarmoredMovementFeet),
name: getTranslationByKey('CLASS_FEATURE_UNARMORED_MOVEMENT'),
storageName: 'Unarmored Movement',
});
}
if (v.monk_level >= 3) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_DEFLECT_MISSILES_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DEFLECT_MISSILES'),
storageName: 'Deflect Missiles',
});
}
if (v.monk_level >= 4) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SLOW_FALL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SLOW_FALL'),
storageName: 'Slow Fall',
});
}
if (v.monk_level >= 5) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_STUNNING_STRIKE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_STUNNING_STRIKE'),
saving_throw_ability: 'wisdom',
saving_throw_failure: getTranslationByKey('CLASS_FEATURE_STUNNING_STRIKE_SAVING_THROW_FAILURE'),
saving_throw_vs_ability: 'CONSTITUTION',
storageName: 'Stunning Strike',
});
}
if (v.monk_level >= 6) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_KI_EMPOWERED_STRIKES_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_KI_EMPOWERED_STRIKES'),
storageName: 'Ki-Empowered Strikes',
});
}
if (v.monk_level >= 7) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EVASION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_EVASION'),
storageName: 'Evasion',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_STILLNESS_OF_MIND_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_STILLNESS_OF_MIND'),
storageName: 'Stillness of Mind',
});
}
if (v.monk_level >= 10) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PURITY_OF_BODY_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PURITY_OF_BODY'),
storageName: 'Purity of Body',
});
}
if (v.monk_level >= 13) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_TONGUE_OF_THE_SUN_AND_MOON_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_TONGUE_OF_THE_SUN_AND_MOON'),
storageName: 'Tongue of the Sun and Moon',
});
}
if (v.monk_level >= 14) {
finalSetAttrs.death_saving_throw_prof = '@{pb}';
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_DIAMOND_SOUL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DIAMOND_SOUL'),
storageName: 'Diamond Soul',
});
}
if (v.monk_level >= 15) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_TIMELESS_BODY_MONK_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_TIMELESS_BODY'),
storageName: 'Timeless Body',
});
}
if (v.monk_level >= 15) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EMPTY_BODY_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_EMPTY_BODY'),
storageName: 'Empty Body',
});
}
if (v.monk_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PERFECT_SELF_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PERFECT_SELF'),
storageName: 'Perfect Self',
});
}
}
}
paladin(v) {
if (v.paladin_level) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_DIVINE_SENSE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DIVINE_SENSE'),
recharge: 'Long Rest',
storageName: 'Divine Sense',
uses_max: Math.max(1 + v.charisma_mod, 1),
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_LAY_ON_HANDS_TEXT'),
heal_query_toggle: TOGGLE_VARS.heal_query,
name: getTranslationByKey('CLASS_FEATURE_LAY_ON_HANDS'),
recharge: 'Long Rest',
storageName: 'Lay on Hands',
uses_max: 5 * v.paladin_level,
});
if (v.paladin_level >= 2) {
traits.set({
freetext: `${getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE_TEXT')} ${getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE_PALADIN_OPTIONS')}`,
name: getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE'),
storageName: 'Fighting Style',
});
traits.set({
damage: '(?{Spell Level|1|2|3|4+, 4} + 1)d8',
damage_type: getTranslationByKey('RADIANT'),
freeform: '{{subheader=(as ?{Spell Level|1|2|3|4+})}}',
freetext: getTranslationByKey('CLASS_FEATURE_DIVINE_SMITE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DIVINE_SMITE'),
second_damage: 'd8',
second_damage_type: getTranslationByKey('VS_FIEND_OR_UNDEAD'),
storageName: 'Divine Smite',
type: 'Other',
});
}
if (v.paladin_level >= 3) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_DIVINE_HEALTH_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_DIVINE_HEALTH'),
storageName: 'Divine Health',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY_PALADIN_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_CHANNEL_DIVINITY'),
recharge: 'Short Rest',
storageName: 'Channel Divinity Paladin',
uses_max: 1,
});
}
if (v.paladin_level >= 6) {
let auraRange;
if (v.paladin_level >= 18) {
auraRange = 30;
} else {
auraRange = 10;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_AURA_OF_PROTECTION_TEXT').replace('AURA_RANGE', auraRange),
name: getTranslationByKey('CLASS_FEATURE_AURA_OF_PROTECTION'),
storageName: 'Aura of Protection',
});
if (v.paladin_level >= 10) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_AURA_OF_COURAGE_TEXT').replace('AURA_RANGE', auraRange),
name: getTranslationByKey('CLASS_FEATURE_AURA_OF_COURAGE'),
storageName: 'Aura of Courage',
});
}
}
if (v.paladin_level >= 11) {
traits.set({
damage: '1d8',
damage_type: 'radiant',
freetext: getTranslationByKey('CLASS_FEATURE_IMPROVED_DIVINE_SMITE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_IMPROVED_DIVINE_SMITE'),
storageName: 'Improved Divine Smite',
type: 'Other',
});
}
if (v.paladin_level >= 14) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_CLEANSING_TOUCH_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_CLEANSING_TOUCH'),
recharge: 'Long Rest',
storageName: 'Cleaning Touch',
uses_max: Math.max(getIntValue(v.charisma_mod), 1),
});
}
}
}
ranger(v) {
if (v.ranger_level) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FAVORED_ENEMY_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FAVORED_ENEMY'),
storageName: 'Favored Enemy',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_NATURAL_EXPLORER_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_NATURAL_EXPLORER'),
storageName: 'Natural Explorer',
});
if (v.ranger_level >= 2) {
traits.set({
freetext: `${getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE_TEXT')} ${getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE_RANGER_OPTIONS')}`,
name: getTranslationByKey('CLASS_FEATURE_FIGHTING_STYLE'),
storageName: 'Fighting Style',
});
}
if (v.ranger_level >= 3) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PRIMEVAL_AWARENESS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PRIMEVAL_AWARENESS'),
storageName: 'Primeval Awareness',
});
}
if (v.ranger_level >= 8) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_LANDS_STRIDE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_LANDS_STRIDE'),
storageName: 'Land\'s Stride',
});
}
if (v.ranger_level >= 10) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_HIDE_IN_PLAIN_SIGHT_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_HIDE_IN_PLAIN_SIGHT'),
storageName: 'Hide in Plain Sight',
});
}
if (v.ranger_level >= 14) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_VANISH_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_VANISH'),
storageName: 'Vanish',
});
}
if (v.ranger_level >= 18) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FERAL_SENSES_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FERAL_SENSES'),
storageName: 'Feral Senses',
});
}
if (v.ranger_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FOE_SLAYER_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FOE_SLAYER'),
storageName: 'Foe Slayer',
});
}
}
}
rogue(v) {
if (v.rogue_level) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EXPERTISE_ROGUE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_EXPERTISE'),
storageName: 'Expertise Rogue',
});
traits.set({
damage: `${Math.ceil(getIntValue(v.rogue_level) / 2)}d6`,
freetext: getTranslationByKey('CLASS_FEATURE_SNEAK_ATTACK_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SNEAK_ATTACK'),
storageName: 'Sneak Attack',
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_THIEVES_CANT_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_THIEVES_CANT'),
storageName: 'Thieves\' Cant',
});
if (v.rogue_level >= 2) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_CUNNING_ACTION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_CUNNING_ACTION'),
storageName: 'Cunning Action',
});
}
if (v.rogue_level >= 5) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_UNCANNY_DODGE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_UNCANNY_DODGE'),
storageName: 'Uncanny Dodge',
});
}
if (v.rogue_level >= 7) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_EVASION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_EVASION'),
storageName: 'Evasion',
});
}
if (v.rogue_level >= 11) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_RELIABLE_TALENT_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_RELIABLE_TALENT'),
storageName: 'Reliable Talent',
});
}
if (v.rogue_level >= 14) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_BLINDSENSE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_BLINDSENSE'),
storageName: 'Blindsense',
});
}
if (v.rogue_level >= 15) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SLIPPERY_MIND_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SLIPPERY_MIND'),
storageName: 'Slippery Mind',
});
}
if (v.rogue_level >= 18) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_ELUSIVE_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_ELUSIVE'),
storageName: 'Elusive',
});
}
if (v.rogue_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_STROKE_OF_LUCK_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_STROKE_OF_LUCK'),
recharge: 'Short Rest',
storageName: 'Stroke of Luck',
uses_max: 1,
});
}
}
}
sorcerer(v) {
if (v.sorcerer_level) {
if (v.sorcerer_level >= 2) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SORCERY_POINTS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SORCERY_POINTS'),
recharge: 'Long Rest',
storageName: 'Sorcery Points',
uses_max: v.sorcerer_level,
});
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_FLEXIBLE_CASTING_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_FLEXIBLE_CASTING'),
storageName: 'Flexible Casting',
});
if (v.sorcerer_level >= 3) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC'),
storageName: 'Metamagic',
});
}
if (v.sorcerer_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SORCEROUS_RESTORATION_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SORCEROUS_RESTORATION'),
storageName: 'Sorcerous Restoration',
});
}
}
}
}
warlock(v) {
if (v.warlock_level) {
let warlockSpellSlots;
if (v.warlock_level >= 17) {
warlockSpellSlots = 4;
} else if (v.warlock_level >= 11) {
warlockSpellSlots = 3;
} else if (v.warlock_level >= 2) {
warlockSpellSlots = 2;
} else {
warlockSpellSlots = 1;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_WARLOCK_SPELL_SLOTS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_WARLOCK_SPELL_SLOTS'),
recharge: 'Short Rest',
storageName: 'Warlock Spell Slots',
uses_max: warlockSpellSlots,
});
if (v.warlock_level >= 2) {
let eldritchInvocations;
if (v.warlock_level >= 17) {
eldritchInvocations = 8;
} else if (v.warlock_level >= 15) {
eldritchInvocations = 7;
} else if (v.warlock_level >= 12) {
eldritchInvocations = 6;
} else if (v.warlock_level >= 9) {
eldritchInvocations = 5;
} else if (v.warlock_level >= 7) {
eldritchInvocations = 4;
} else if (v.warlock_level >= 5) {
eldritchInvocations = 3;
} else {
eldritchInvocations = 2;
}
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_ELDRITCH_INVOCATIONS_TEXT').replace('NUMBER_OF_INVOCATIONS_KNOWN', eldritchInvocations),
name: getTranslationByKey('CLASS_FEATURE_ELDRITCH_INVOCATIONS'),
storageName: 'Eldritch Invocations',
});
}
if (v.warlock_level >= 3) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_PACT_BOON_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_PACT_BOON'),
storageName: 'Pact Boon',
});
}
if (v.warlock_level >= 11) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_MYSTIC_ARCANUM_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_MYSTIC_ARCANUM'),
storageName: 'Mystic Arcanum',
});
}
if (v.warlock_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_ELDRITCH_MASTER_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_ELDRITCH_MASTER'),
recharge: 'Long Rest',
storageName: 'Eldritch Master',
});
}
}
}
wizard(v) {
if (v.wizard_level) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_ARCANE_RECOVERY_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_ARCANE_RECOVERY'),
recharge: 'Long Rest',
storageName: 'Arcane Recovery',
uses_max: 1,
});
if (v.wizard_level >= 18) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SPELL_MASTERY_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SPELL_MASTERY'),
storageName: 'Spell Mastery',
});
}
if (v.wizard_level >= 20) {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_SIGNATURE_SPELLS_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_SIGNATURE_SPELLS'),
storageName: 'Signature Spells',
});
}
}
}
metamagic(v) {
if (v.careful_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_CAREFUL_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_CAREFUL_SPELL'),
storageName: 'Careful Spell',
});
}
if (v.distant_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_DISTANT_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_DISTANT_SPELL'),
storageName: 'Distant Spell',
});
}
if (v.empowered_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_EMPOWERED_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_EMPOWERED_SPELL'),
storageName: 'Empowered Spell',
});
}
if (v.extended_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_EXTENDED_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_EXTENDED_SPELL'),
storageName: 'Extended Spell',
});
}
if (v.heightened_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_HEIGHTENED_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_HEIGHTENED_SPELL'),
storageName: 'Heightened Spell',
});
}
if (v.quickened_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_QUICKENED_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_QUICKENED_SPELL'),
storageName: 'Quickened Spell',
});
}
if (v.subtle_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_SUBTLE_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_SUBTLE_SPELL'),
storageName: 'Subtle Spell',
});
}
if (v.twinned_spell_toggle === '1') {
traits.set({
freetext: getTranslationByKey('CLASS_FEATURE_METAMAGIC_TWINNED_SPELL_TEXT'),
name: getTranslationByKey('CLASS_FEATURE_METAMAGIC_TWINNED_SPELL'),
storageName: 'Twinned Spell',
});
}
}
set() {
const collectionArray = ['ac_unarmored_ability', 'jack_of_all_trades_toggle', 'careful_spell_toggle', 'distant_spell_toggle', 'empowered_spell_toggle', 'extended_spell_toggle', 'heightened_spell_toggle', 'quickened_spell_toggle', 'subtle_spell_toggle', 'twinned_spell_toggle'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
}
for (const className of CLASSES) {
collectionArray.push(`${className}_level`);
}
getSetItems('classFeatures.set', {
collectionArray,
callback: (v, finalSetAttrs) => {
this.extraAttack(v);
this.barbarian(v, finalSetAttrs);
this.bard(v, finalSetAttrs);
this.cleric(v);
this.druid(v);
this.fighter(v);
this.monk(v, finalSetAttrs);
this.paladin(v);
this.ranger(v);
this.rogue(v);
this.sorcerer(v);
this.warlock(v);
this.wizard(v);
this.metamagic(v);
},
});
}
}
+195
View File
@@ -0,0 +1,195 @@
/* global on:false */
import { ABILITIES, SKILLS } from './constants';
import { getSetItems, getSetRepeatingItems, getSkillIdByStorageName, getFloatValue, sumRepeating, isUndefinedOrEmpty, getRepeatingInfo, exists, round } from './utilities';
export class Equipment {
setAdvantageOnStealth(mode) {
getSetRepeatingItems('equipment.setAdvantageOnStealth', {
repeatingItems: ['repeating_skill'],
collectionArrayAddItems: ['storage_name', 'skill_d20'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const prop in SKILLS) {
if (SKILLS.hasOwnProperty(prop)) {
const skillId = getSkillIdByStorageName(v, repeatingItem, ids, prop);
const repeatingString = `${repeatingItem}_${skillId}_`;
if (v[`${repeatingString}storage_name`] === 'STEALTH') {
if (mode === 'dis') {
finalSetAttrs[`${repeatingString}skill_d20`] = '2d20@{d20_mod}kl1';
} else if (mode === 'normal') {
finalSetAttrs[`${repeatingString}skill_d20`] = '@{shaped_d20}';
}
}
}
}
},
});
}
updateArmor(rowId) {
let stealthPenalty;
getSetRepeatingItems('equipment.updateArmor', {
repeatingItems: ['repeating_armor'],
collectionArrayAddItems: ['parsed', 'modifiers', 'stealth'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (isUndefinedOrEmpty(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('acBonus') === -1) {
const armorModifiers = v[`${repeatingString}modifiers`];
if (exists(armorModifiers)) {
finalSetAttrs[`${repeatingString}ac_bonus`] = armorModifiers.replace(/^\D+/g, '');
}
if (isUndefinedOrEmpty(finalSetAttrs[`${repeatingString}parsed`])) {
finalSetAttrs[`${repeatingString}parsed`] = '';
}
finalSetAttrs[`${repeatingString}parsed`] += ' acBonus';
}
if (v[`${repeatingString}stealth`] === 'Disadvantage') {
stealthPenalty = true;
}
}
if (stealthPenalty) {
this.setAdvantageOnStealth('dis');
} else {
this.setAdvantageOnStealth('normal');
}
},
});
const options = {
collection: 'armor',
getExtraFields: ['medium_armor_max_dex', 'dexterity_mod', 'ac_unarmored_ability', 'is_npc'],
toggle: 'worn',
};
for (const ability of ABILITIES) {
options.getExtraFields.push(`${ability}_mod`);
}
const sumItems = [
{
fieldToAdd: 'weight',
totalField: 'weight_armor',
},
{
fieldToAdd: 'ac_base',
bonus: 'ac_bonus',
armorType: 'type',
itemTotal: 'ac_total',
totalField: 'ac_armored_calc',
totalFieldSecondary: 'ac_unarmored_calc',
},
];
sumRepeating(options, sumItems);
}
update(rowId) {
getSetRepeatingItems('equipment.update', {
repeatingItems: ['repeating_equipment'],
collectionArrayAddItems: ['content'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (isUndefinedOrEmpty(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('content') === -1) {
let content = v[`${repeatingString}content`];
if (exists(content)) {
content = content.replace(/\s(\d+d\d+\s(?:\+|\-)\s\d+)\s/g, ' [[$1]] ')
.replace(/\s(\d+d\d+)\s/g, ' [[$1]] ')
.replace(/\s(\d+)\s/g, ' [[$1]] ');
finalSetAttrs[`${repeatingString}content`] = content;
if (isUndefinedOrEmpty(finalSetAttrs[`${repeatingString}parsed`])) {
finalSetAttrs[`${repeatingString}parsed`] = '';
}
finalSetAttrs[`${repeatingString}parsed`] += ' content';
}
}
}
},
});
}
weigh() {
const options = {
collection: 'equipment',
toggle: 'carried',
qty: 'qty',
};
const sumItems = [
{
fieldToAdd: 'weight',
itemTotal: 'weight_total',
totalField: 'weight_equipment',
},
];
sumRepeating(options, sumItems);
}
updateWeight() {
getSetItems('equipment.updateWeight', {
collectionArray: ['weight_attacks', 'weight_ammo', 'weight_armor', 'weight_equipment', 'weight_coinage'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.weight_total = round((getFloatValue(v.weight_attacks) + getFloatValue(v.weight_ammo) + getFloatValue(v.weight_armor) + getFloatValue(v.weight_equipment) + getFloatValue(v.weight_coinage)), 2);
},
});
}
weighAmmo() {
const options = {
collection: 'ammo',
qty: 'qty',
};
const sumItems = [
{
fieldToAdd: 'weight',
totalField: 'weight_ammo',
},
];
sumRepeating(options, sumItems);
}
calculateGold() {
getSetItems('equipment.calculateGold', {
collectionArray: ['cp', 'copper_per_gold', 'sp', 'silver_per_gold', 'ep', 'electrum_per_gold', 'gp', 'pp', 'platinum_per_gold'],
callback: (v, finalSetAttrs) => {
const copperPieces = getFloatValue(v.cp);
const silverPieces = getFloatValue(v.sp);
const electrumPieces = getFloatValue(v.ep);
const goldPieces = getFloatValue(v.gp);
const platinumPieces = getFloatValue(v.pp);
const copperPerGold = getFloatValue(v.copper_per_gold, 100);
const silverPerGold = getFloatValue(v.silver_per_gold, 10);
const electrumPerGold = getFloatValue(v.electrum_per_gold, 2);
const platinumPerGold = getFloatValue(v.platinum_per_gold, 10);
finalSetAttrs.total_gp = ((copperPieces / copperPerGold) + (silverPieces / silverPerGold) + (electrumPieces / electrumPerGold) + goldPieces + (platinumPieces * platinumPerGold)).toFixed(2);
finalSetAttrs.weight_coinage = (copperPieces + silverPieces + electrumPieces + goldPieces + platinumPieces) / 50;
},
});
}
setup() {
on('change:repeating_armor', (eventInfo) => {
const repeatingInfo = getRepeatingInfo('repeating_armor', eventInfo);
if (repeatingInfo && repeatingInfo.field !== 'ac_total') {
this.updateArmor(repeatingInfo.rowId);
}
});
on('change:dexterity_mod change:medium_armor_max_dex change:ac_unarmored_ability remove:repeating_armor', () => {
this.updateArmor();
});
on('change:repeating_equipment', (eventInfo) => {
this.update(getRepeatingInfo('repeating_equipment', eventInfo).rowId);
});
on('change:repeating_equipment:carried change:repeating_equipment:qty change:repeating_equipment:weight remove:repeating_equipment', () => {
this.weigh();
});
on('change:repeating_ammo:weight change:repeating_ammo:qty', () => {
this.weighAmmo();
});
on('change:weight_attacks change:weight_ammo change:weight_armor change:weight_equipment change:weight_coinage', () => {
this.updateWeight();
});
on('change:cp change:copper_per_gold change:sp change:silver_per_gold change:ep change:electrum_per_gold change:gp change:pp change:platinum_per_gold', () => {
this.calculateGold();
});
}
}
@@ -0,0 +1,62 @@
/* global on:false, generateRowID:false */
import { Initialize } from './Initialize';
const initialize = new Initialize();
import { getSetItems } from './utilities';
export class ImportData {
import() {
getSetItems('importData.import', {
collectionArray: ['import_data', 'version'],
callback: (v, finalSetAttrs) => {
if (v.import_data) {
const importObject = JSON.parse(v.import_data);
if (importObject.npc) {
if (!v.version) {
initialize.sheetOpened();
}
for (const prop in importObject.npc) {
if (importObject.npc.hasOwnProperty(prop)) {
finalSetAttrs[prop] = importObject.npc[prop];
}
}
}
if (importObject.spells) {
importObject.spells.forEach(spell => {
const repeatingString = `repeating_spell_${generateRowID()}_`;
for (const prop in spell) {
if (spell.hasOwnProperty(prop)) {
finalSetAttrs[`${repeatingString}${prop}`] = spell[prop];
}
}
});
}
finalSetAttrs.import_data = '';
finalSetAttrs.import_data_present = 'off';
}
},
});
}
delete() {
getSetItems('importData.delete', {
collectionArray: ['import_data', 'version'],
callback: (v, finalSetAttrs) => {
const importObject = JSON.parse(v.import_data);
if (importObject.npc && !v.version) {
initialize.sheetOpened(); // NPC import will have wiped all the existing attributes
}
finalSetAttrs.import_data = '';
finalSetAttrs.import_data_present = 'off';
},
});
}
setup() {
on('change:accept_import', () => {
this.import();
});
on('change:reject_import', () => {
this.delete();
});
}
}
+121
View File
@@ -0,0 +1,121 @@
/* global on:false, generateRowID:false, getTranslationByKey:false */
import { Abilities } from './Abilities';
const abilities = new Abilities();
import { AbilityChecks } from './AbilityChecks';
const abilityChecks = new AbilityChecks();
import { Character } from './Character';
const character = new Character();
import { SKILLS } from './constants';
import { Equipment } from './Equipment';
const equipment = new Equipment();
import { ProficiencyBonus } from './ProficiencyBonus';
const proficiencyBonus = new ProficiencyBonus();
import { SavingThrows } from './SavingThrows';
const savingThrows = new SavingThrows();
import { Spells } from './Spells';
const spells = new Spells();
import { Upgrade } from './Upgrade';
const upgrade = new Upgrade();
import { getSetItems, getSetRepeatingItems, isUndefinedOrEmpty, setFinalAttrs, getSkillIdByStorageName } from './utilities';
import { currentVersion } from './version';
export class Initialize {
generateSkills() {
getSetRepeatingItems('initialize.generateSkills', {
repeatingItems: ['repeating_skill'],
collectionArrayAddItems: ['storage_name', 'name', 'ability'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const prop in SKILLS) {
if (SKILLS.hasOwnProperty(prop)) {
let skillId = getSkillIdByStorageName(v, repeatingItem, ids, prop);
if (!skillId) {
skillId = generateRowID();
}
const repeatingString = `${repeatingItem}_${skillId}_`;
finalSetAttrs[`${repeatingString}storage_name`] = prop;
finalSetAttrs[`${repeatingString}name`] = getTranslationByKey(prop);
finalSetAttrs[`${repeatingString}ability`] = SKILLS[prop];
abilityChecks.updateSkill(skillId);
}
}
},
setFinalAttrsCallback: () => {
abilityChecks.updateMacro();
},
});
}
checkVersionFormat(version, finalSetAttrs) {
const versionRegex = /\d+\.\d+\.\d+/gi;
const versionIsProperFormat = versionRegex.exec(version);
if (version && !versionIsProperFormat) {
finalSetAttrs.version = version = currentVersion;
}
return version;
}
sheetOpened() {
console.log('initialize.sheetOpened');
getSetItems('initialize.sheetOpened', {
collectionArray: ['version', 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma', 'import_data', 'roll_setting'],
callback: (v, finalSetAttrs) => {
const version = this.checkVersionFormat(v.version, finalSetAttrs);
if (!version) {
if (!v.import_data) {
finalSetAttrs.edit_mode = 'on';
}
if (isUndefinedOrEmpty(v.roll_setting)) { // API Script import sets this when making characters
finalSetAttrs.roll_setting = '{{ignore=[[0';
}
const setAbilities = {};
if (isUndefinedOrEmpty(v.strength)) {
setAbilities.strength = 10;
}
if (isUndefinedOrEmpty(v.dexterity)) {
setAbilities.dexterity = 10;
}
if (isUndefinedOrEmpty(v.constitution)) {
setAbilities.constitution = 10;
}
if (isUndefinedOrEmpty(v.intelligence)) {
setAbilities.intelligence = 10;
}
if (isUndefinedOrEmpty(v.wisdom)) {
setAbilities.wisdom = 10;
}
if (isUndefinedOrEmpty(v.charisma)) {
setAbilities.charisma = 10;
}
setFinalAttrs(v, setAbilities, 'initialize', () => {
proficiencyBonus.update();
this.generateSkills();
savingThrows.update();
character.updateLevels();
abilityChecks.updateInitiative();
equipment.updateArmor();
spells.updateShowHide();
abilities.updateModifiers();
});
} else {
upgrade.upgrade();
}
if (isUndefinedOrEmpty(version) || !version || version !== currentVersion) {
finalSetAttrs.version = currentVersion;
}
},
});
}
setup() {
on('change:generate_skills', () => {
this.generateSkills();
});
on('sheet:opened', () => {
this.sheetOpened();
});
}
}
+434
View File
@@ -0,0 +1,434 @@
/* global on:false, generateRowID:false */
import { ABILITIES } from './constants';
import { getSetItems, getIntValue, isUndefinedOrEmpty, addArithmeticOperator, getAbilityMod, numberWithCommas, exists, updateHD } from './utilities';
export class Npc {
updateType() {
getSetItems('npc.updateType', {
collectionArray: ['type'],
callback: (v, finalSetAttrs) => {
if (v.type) {
finalSetAttrs.type = v.type.toLowerCase();
}
},
});
}
updateSize() {
getSetItems('npc.updateSize', {
collectionArray: ['size'],
callback: (v, finalSetAttrs) => {
const creatureSize = v.size || 'Large';
const sizeToHdSize = {
Tiny: 4,
Small: 6,
Medium: 8,
Large: 10,
Huge: 12,
Gargantuan: 20,
};
finalSetAttrs.hit_die = `d${sizeToHdSize[creatureSize]}`;
},
});
}
updateAC() {
getSetItems('npc.updateAC', {
collectionArray: ['ac_srd', 'ac', 'ac_note', 'dexterity_mod'],
callback: (v, finalSetAttrs) => {
if (exists(v.ac_srd)) {
const match = v.ac_srd.match(/(\d+)\s?(.*)/);
if (match && match[1]) {
finalSetAttrs.AC = match[1];
}
if (match && match[2]) {
finalSetAttrs.ac_note = match[2].replace(/\(|\)/g, '');
}
}
},
});
}
switchTo() {
getSetItems('npc.switchTo', {
collectionArray: ['is_npc', 'size'],
callback: (v, finalSetAttrs) => {
const isNPC = getIntValue(v.is_npc) === 1;
if (isNPC && isUndefinedOrEmpty(v.size)) {
finalSetAttrs.size = 'Large';
}
if (isNPC) {
finalSetAttrs.hit_dice_output_option = '/w GM';
} else {
finalSetAttrs.hit_dice_output_option = '';
}
},
});
}
updateChallenge() {
const xpPerChallenge = {
0: 0,
'1/8': 25,
'1/4': 50,
'1/2': 100,
1: 200,
2: 450,
3: 700,
4: 1100,
5: 1800,
6: 2300,
7: 2900,
8: 3900,
9: 5000,
10: 5900,
11: 7200,
12: 8400,
13: 10000,
14: 11500,
15: 13000,
16: 15000,
17: 18000,
18: 20000,
19: 22000,
20: 25000,
21: 33000,
22: 41000,
23: 50000,
24: 62000,
25: 75000,
26: 90000,
27: 105000,
28: 120000,
29: 135000,
30: 155000,
};
getSetItems('npc.updateChallenge', {
collectionArray: ['challenge', 'xp'],
callback: (v, finalSetAttrs) => {
const challenge = v.challenge;
finalSetAttrs.xp = xpPerChallenge[challenge];
finalSetAttrs.xp_readable = numberWithCommas(finalSetAttrs.xp);
finalSetAttrs.level = challenge;
if (finalSetAttrs.level < 1) {
finalSetAttrs.level = 1;
}
},
});
}
updateHPFromSRD() {
getSetItems('npc.updateHPFromSRD', {
collectionArray: ['hp_srd', 'constitution', 'constitution_mod', 'constitution_bonus', 'global_ability_bonus'],
callback: (v, finalSetAttrs) => {
if (exists(v.hp_srd)) {
const match = v.hp_srd.match(/\((\d+)d(\d+)(?:\s?(\+|\-)\s?(\d+))?\)/i);
if (!match || !match[1] || !match[2]) {
console.warn('Character doesn\'t have valid HP/HD format');
} else {
const hdNum = getIntValue(match[1]);
let conMod = getIntValue(v.constitution_mod);
if (!conMod) {
const conScore = getIntValue(v.constitution);
const conBonus = getIntValue(v.constitution_bonus);
const globalAbilityBonus = getIntValue(v.global_ability_bonus);
conMod = getAbilityMod((conScore + conBonus + globalAbilityBonus));
}
finalSetAttrs.hit_dice = hdNum;
finalSetAttrs.hit_die = `d${getIntValue(match[2])}`;
const hpExpectedBonus = hdNum * conMod;
const hpBonusSign = match[3];
const hpBonus = getIntValue(match[4]);
if (hpBonus !== hpExpectedBonus) {
if (hpBonusSign === '-') {
finalSetAttrs.hp_extra = hpBonus + hpExpectedBonus;
} else {
finalSetAttrs.hp_extra = hpBonus - hpExpectedBonus;
}
}
}
}
},
});
}
updateHP() {
getSetItems('npc.updateHP', {
collectionArray: ['HP', 'HP_max', 'hp_formula', 'hit_dice', 'hit_die', 'hp_extra', 'constitution_mod'],
callback: (v, finalSetAttrs) => {
const hdNum = getIntValue(v.hit_dice);
const hdSize = getIntValue(v.hit_die.replace('d', ''));
const hdAverage = (hdSize / 2) + 0.5;
let hpFormula = `${hdNum}d${hdSize}`;
const conMod = getIntValue(v.constitution_mod);
let totalHP = Math.floor(hdNum * hdAverage);
let amount;
if (conMod !== 0) {
const bonusHP = hdNum * conMod;
totalHP += bonusHP;
hpFormula += addArithmeticOperator(hpFormula, bonusHP);
}
if (exists(v.hp_extra)) {
const regex = (/(?:(\+|\-)\s?)?(\d+)(?:d(\d+))?/gi);
let splitFormula;
while ((splitFormula = regex.exec(v.hp_extra)) !== null) {
if (!splitFormula || !splitFormula[2]) {
console.warn('Character doesn\'t have valid hp formula');
} else {
amount = 0;
if (!splitFormula[3]) {
amount = getIntValue(splitFormula[2]);
} else {
const extraHdNum = getIntValue(splitFormula[2]);
const extraHdSize = getIntValue(splitFormula[3]);
const extraHdAverage = (extraHdSize / 2) + 0.5;
amount = Math.floor(extraHdNum * extraHdAverage);
}
if (!splitFormula[1] || splitFormula[1] === '+') {
totalHP += amount;
hpFormula += ` + ${amount}`;
} else if (splitFormula[1] === '-') {
totalHP -= amount;
hpFormula += ` - ${amount}`;
}
}
v.hp_extra.toString().replace(splitFormula[0], '');
}
}
if (totalHP) {
finalSetAttrs.HP = totalHP;
finalSetAttrs.HP_max = totalHP;
finalSetAttrs.hp_formula = hpFormula;
}
},
});
}
updateHD() {
const hd = {
d20: 0,
d12: 0,
d10: 0,
d8: 0,
d6: 0,
d4: 0,
d2: 0,
d0: 0,
};
const collectionArray = ['hit_dice', 'hit_die'];
for (const key in hd) {
if (hd.hasOwnProperty(key)) {
collectionArray.push(`hd_${key}_max`);
collectionArray.push(`hd_${key}_query`);
collectionArray.push(`hd_${key}_toggle`);
}
}
getSetItems('npc.updateHD', {
collectionArray,
callback: (v, finalSetAttrs) => {
const hdNum = getIntValue(v.hit_dice);
const hdSize = v.hit_die;
if (hdNum && hdSize) {
hd[hdSize] = hdNum;
updateHD(v, finalSetAttrs, hd);
}
},
});
}
parseSRDContentSection(content, finalSetAttrs, title, name) {
const re = /@(.*)@:\s([^@]+)/gi;
let match;
let section;
if (content.indexOf(title) !== -1) {
const contentSplit = content.split(`${title}\n`);
section = contentSplit[1];
content = contentSplit[0];
}
if (exists(section)) {
if (name === 'legendaryaction') {
const legendaryActionsMatch = section.match(/Can take (\d+) Legendary Actions/i);
if (legendaryActionsMatch && legendaryActionsMatch[1]) {
finalSetAttrs.legendary_action_amount = legendaryActionsMatch[1];
}
}
while ((match = re.exec(section.replace(/\*\*/g, '@'))) !== null) {
if (match && match[1] && match[2]) {
const repeatingString = `repeating_${name}_${generateRowID()}_`;
finalSetAttrs[`${repeatingString}name`] = match[1];
const text = match[2].trim();
if (name === 'trait') {
finalSetAttrs[`${repeatingString}display_text`] = text;
}
finalSetAttrs[`${repeatingString}freetext`] = text;
} else {
console.warn(`Character doesn\'t have a valid ${name} format`);
}
}
}
return content;
}
setDefaultAbility(v, finalSetAttrs) {
const abilityScores = [getIntValue(v.intelligence), getIntValue(v.wisdom), getIntValue(v.charisma)];
const highestAbilityScore = Math.max.apply(Math, abilityScores);
let highestAbilityName = 'intelligence';
if (highestAbilityScore === abilityScores[1]) {
highestAbilityName = 'wisdom';
} else if (highestAbilityScore === abilityScores[2]) {
highestAbilityName = 'charisma';
}
finalSetAttrs.default_ability = highestAbilityName;
}
updateContent() {
const collectionArray = ['content_srd'];
for (const ability of ABILITIES) {
collectionArray.push(ability);
}
getSetItems('npc.updateContent', {
collectionArray,
callback: (v, finalSetAttrs) => {
let content = v.content_srd;
let regionalEffects;
let lairActions;
let repeatingString;
this.setDefaultAbility(v, finalSetAttrs);
if (exists(content)) {
if (content.indexOf('Regional Effects') !== -1) {
const regionalEffectsSplit = content.split(/Regional Effects\n/);
regionalEffects = regionalEffectsSplit[1];
content = regionalEffectsSplit[0];
}
if (exists(regionalEffects)) {
const regionalEffectsList = regionalEffects.split(/\*\*/);
regionalEffectsList.slice(1, -1).forEach((regionalEffect) => {
repeatingString = `repeating_regionaleffect_${generateRowID()}_`;
finalSetAttrs[`${repeatingString}freetext`] = regionalEffect.trim();
});
finalSetAttrs.regional_effects_fade = regionalEffectsList.slice(-1)[0];
}
if (content.indexOf('Lair Actions') !== -1) {
const lairActionsSplit = content.split(/Lair Actions\n/);
lairActions = lairActionsSplit[1];
content = lairActionsSplit[0];
}
if (exists(lairActions)) {
lairActions.split(/\*\*/).slice(1).forEach((lairAction) => {
repeatingString = `repeating_lairaction_${generateRowID()}_`;
finalSetAttrs[`${repeatingString}freetext`] = lairAction.trim();
});
}
content = this.parseSRDContentSection(content, finalSetAttrs, 'Legendary Actions', 'legendaryaction');
content = this.parseSRDContentSection(content, finalSetAttrs, 'Reactions', 'reaction');
content = this.parseSRDContentSection(content, finalSetAttrs, 'Actions', 'action');
this.parseSRDContentSection(content, finalSetAttrs, 'Traits', 'trait');
}
},
});
}
updateSenses() {
getSetItems('npc.updateSenses', {
collectionArray: ['senses'],
callback: (v, finalSetAttrs) => {
if (v.senses) {
finalSetAttrs.senses_exist = 1;
finalSetAttrs.senses = v.senses.toLowerCase();
} else {
finalSetAttrs.senses_exist = 0;
}
},
});
}
updateLanguages() {
getSetItems('npc.updateLanguages', {
collectionArray: ['languages', 'languages_exist', 'languages_chat_var'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.languages_exist = 0;
finalSetAttrs.languages_chat_var = '';
if (v.languages) {
finalSetAttrs.languages_exist = 1;
finalSetAttrs.languages_chat_var = '{{Languages=@{languages}}}';
}
},
});
}
updateSpeed() {
getSetItems('npc.updateSpeed', {
collectionArray: ['npc_speed'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.npc_speed = v.npc_speed.toLowerCase();
const match = finalSetAttrs.npc_speed.match(/^\s*(\d+)\s*ft/);
if (match && match[1]) {
finalSetAttrs.speed = match[1];
}
},
});
}
updateACNote() {
getSetItems('npc.updateACNote', {
collectionArray: ['ac_note'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.ac_note = v.ac_note.toLowerCase();
},
});
}
setup() {
on('change:type', () => {
this.updateType();
});
on('change:size', () => {
this.updateSize();
});
on('change:ac_srd', () => {
this.updateAC();
});
on('change:is_npc', () => {
this.switchTo();
});
on('change:challenge', () => {
this.updateChallenge();
});
on('change:hp_srd', () => {
this.updateHPFromSRD();
});
on('change:hit_dice change:hit_die change:hp_extra change:constitution_mod', () => {
this.updateHP();
});
on('change:hit_dice change:hit_die', () => {
this.updateHD();
});
on('change:content_srd', () => {
this.updateContent();
});
on('change:senses', () => {
this.updateSenses();
});
on('change:languages', () => {
this.updateLanguages();
});
on('change:npc_speed', () => {
this.updateSpeed();
});
on('change:ac_note', () => {
this.updateACNote();
});
}
}
@@ -0,0 +1,38 @@
/* global on:false */
import { getSetItems, getIntValue, exists } from './utilities';
export class ProficiencyBonus {
get(level, challenge) {
let pb = 2;
level = getIntValue(level);
if (challenge === '1/8' || challenge === '1/4' || challenge === '1/2') {
challenge = 1;
} else {
getIntValue(challenge);
}
const levelOrChallenge = Math.max(level, challenge);
if (exists(levelOrChallenge)) {
pb += Math.floor(Math.abs((levelOrChallenge - 1) / 4));
}
return pb;
}
update() {
getSetItems('proficiencyBonus.update', {
collectionArray: ['level', 'challenge', 'pb', 'exp', 'h_PB'],
callback: (v, finalSetAttrs) => {
const pb = this.get(v.level, v.challenge);
finalSetAttrs.pb = pb;
finalSetAttrs.exp = pb * 2;
finalSetAttrs.h_PB = pb / 2;
},
});
}
setup() {
on('change:level', () => {
this.update();
});
}
}
@@ -0,0 +1,98 @@
/* global on:false */
import { getSetItems, lowercaseDamageTypes } from './utilities';
export class Resistances {
updateDamageResistancesVar() {
getSetItems('resistances.updateDamageResistancesVar', {
collectionArray: ['damage_resistances_var', 'damage_vulnerabilities_exist', 'damage_resistances_exist', 'damage_immunities_exist', 'condition_immunities_exist'],
callback: (v, finalSetAttrs) => {
const resistancesVar = [];
if (v.damage_vulnerabilities_exist) {
resistancesVar.push('{{Damage Vulnerabilities=@{damage_vulnerabilities}}}');
}
if (v.damage_resistances_exist) {
resistancesVar.push('{{Damage Resistances=@{damage_resistances}}}');
}
if (v.damage_immunities_exist) {
resistancesVar.push('{{Damage Immunities=@{damage_immunities}}}');
}
if (v.condition_immunities_exist) {
resistancesVar.push('{{Condition Immunities=@{condition_immunities}}}');
}
finalSetAttrs.damage_resistances_var = resistancesVar.join(' ');
},
});
}
updateDamageVulnerabilities() {
getSetItems('resistances.updateDamageVulnerabilities', {
collectionArray: ['damage_vulnerabilities'],
callback: (v, finalSetAttrs) => {
if (v.damage_vulnerabilities) {
finalSetAttrs.damage_vulnerabilities_exist = 1;
finalSetAttrs.damage_vulnerabilities = lowercaseDamageTypes(v.damage_vulnerabilities);
} else {
finalSetAttrs.damage_vulnerabilities_exist = 0;
}
},
});
}
updateDamageResistances() {
getSetItems('resistances.updateDamageResistances', {
collectionArray: ['damage_resistances'],
callback: (v, finalSetAttrs) => {
if (v.damage_resistances) {
finalSetAttrs.damage_resistances_exist = 1;
finalSetAttrs.damage_resistances = lowercaseDamageTypes(v.damage_resistances);
} else {
finalSetAttrs.damage_resistances_exist = 0;
}
},
});
}
updateDamageImmunities() {
getSetItems('resistances.updateDamageImmunities', {
collectionArray: ['damage_immunities'],
callback: (v, finalSetAttrs) => {
if (v.damage_immunities) {
finalSetAttrs.damage_immunities_exist = 1;
finalSetAttrs.damage_immunities = lowercaseDamageTypes(v.damage_immunities);
} else {
finalSetAttrs.damage_immunities_exist = 0;
}
},
});
}
updateConditionImmunities() {
getSetItems('resistances.updateConditionImmunities', {
collectionArray: ['condition_immunities'],
callback: (v, finalSetAttrs) => {
if (v.condition_immunities) {
finalSetAttrs.condition_immunities_exist = 1;
finalSetAttrs.condition_immunities = lowercaseDamageTypes(v.condition_immunities);
} else {
finalSetAttrs.condition_immunities_exist = 0;
}
},
});
}
setup() {
on('change:damage_vulnerabilities change:damage_resistances change:damage_immunities change:condition_immunities', () => {
this.updateDamageResistancesVar();
});
on('change:damage_vulnerabilities', () => {
this.updateDamageVulnerabilities();
});
on('change:damage_resistances', () => {
this.updateDamageResistances();
});
on('change:damage_immunities', () => {
this.updateDamageImmunities();
});
on('change:condition_immunities', () => {
this.updateConditionImmunities();
});
}
}
@@ -0,0 +1,250 @@
/* global on:false */
import { getSetItems, getIntValue, getAbilityShortName, addArithmeticOperator, isUndefinedOrEmpty, exists, showSign, getAbilityMod } from './utilities';
import { ABILITIES } from './constants';
export class SavingThrows {
getHighestOfAbilityScoresForSavingThrow(v, savingThrowName) {
let abilityName;
let highestValue = 0;
for (const ability of ABILITIES) {
const abilityMod = getIntValue(v[`${ability}_mod`]);
if (v[`${savingThrowName}_${ability}`] === '1' && (highestValue === 0 || abilityMod > highestValue)) {
highestValue = abilityMod;
abilityName = ability;
}
}
return abilityName;
}
findHighest(arr) {
const highestAbility = Math.max.apply(Math, arr.map((ability) => ability.score));
return arr.find((ability) => ability.score === highestAbility);
}
getHighestAbilityScores(v, savingThrowName) {
const abilities = [];
for (const ability of ABILITIES) {
if (v[`${savingThrowName}_${ability}`] === '1') {
abilities.push({
name: ability,
score: getIntValue(v[`${ability}_calculated`]),
});
}
}
const highestAbilities = [];
if (abilities.length > 0) {
const highestAbilityObj = this.findHighest(abilities);
highestAbilities.push(highestAbilityObj);
abilities.splice(abilities.findIndex((ability) => ability.name === highestAbilityObj.name), 1);
}
if (abilities.length > 0) {
const secondHighestAbilityObj = this.findHighest(abilities);
highestAbilities.push(secondHighestAbilityObj);
}
return highestAbilities;
}
getAverageOfHighestAbilityScoresForSavingThrow(v, savingThrowName) {
const obj = {
abilitiesUsed: [],
};
let sum = 0;
const highestAbilities = this.getHighestAbilityScores(v, savingThrowName);
for (const ability of highestAbilities) {
obj.abilitiesUsed.push(getAbilityShortName(ability.name));
sum += getAbilityMod(v[`${ability.name}_calculated`]);
}
if (obj.abilitiesUsed.length > 0) {
obj.avg = Math.floor(sum / obj.abilitiesUsed.length);
}
return obj;
}
setCustomSaveProf(v, finalSetAttrs, savingThrowName) {
const pbVar = '@{PB}';
for (const ability of ABILITIES) {
if (v[`${savingThrowName}_${ability}`] === '1' && v[`${ability}_save_prof`] === pbVar && !exists(v[`${savingThrowName}_save_prof`])) {
finalSetAttrs[`${savingThrowName}_save_prof`] = pbVar;
}
}
}
updateSavingThrow(savingThrowName) {
const collectionArray = ['pb', `${savingThrowName}_save_prof`, `${savingThrowName}_save_bonus`, 'global_saving_throw_bonus', 'saving_throws_half_proficiency', 'average_of_abilities'];
const customSaves = ['fortitude', 'reflex', 'will'];
const customSavingThrow = customSaves.indexOf(savingThrowName) !== -1;
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_calculated`);
collectionArray.push(`${ability}_mod`);
collectionArray.push(`${savingThrowName}_${ability}`);
if (customSavingThrow) {
collectionArray.push(`${ability}_save_prof`);
}
}
getSetItems('savingThrows.updateSavingThrow', {
collectionArray,
callback: (v, finalSetAttrs) => {
let total = 0;
let totalFormula = '';
let ability;
if (customSavingThrow) {
if (v.average_of_abilities === '1') {
const obj = this.getAverageOfHighestAbilityScoresForSavingThrow(v, savingThrowName);
if (obj.avg) {
total = obj.avg;
totalFormula = `${obj.avg}[${obj.abilitiesUsed.join(' ')} avg]`;
}
} else {
ability = this.getHighestOfAbilityScoresForSavingThrow(v, savingThrowName);
}
this.setCustomSaveProf(v, finalSetAttrs, savingThrowName);
} else {
ability = savingThrowName;
}
if (ability) {
const abilityMod = getIntValue(v[`${ability}_mod`]);
total = abilityMod;
totalFormula = `${abilityMod}[${getAbilityShortName(ability)}]`;
}
const pb = getIntValue(v.pb);
if (v[`${savingThrowName}_save_prof`] === '@{PB}') {
total += pb;
totalFormula += `${addArithmeticOperator(totalFormula, pb)}[proficient]`;
} else if (v.saving_throws_half_proficiency === 'on') {
const halfPB = Math.floor(pb / 2);
total += halfPB;
totalFormula += `${addArithmeticOperator(totalFormula, halfPB)}[half proficiency]`;
}
const abilitySavingThrowBonus = getIntValue(v[`${savingThrowName}_save_bonus`]);
if (abilitySavingThrowBonus) {
total += abilitySavingThrowBonus;
totalFormula += `${addArithmeticOperator(totalFormula, abilitySavingThrowBonus)}[${getAbilityShortName(ability)}saving throw bonus]`;
}
const globalSavingThrowBonus = v.global_saving_throw_bonus;
if (!isUndefinedOrEmpty(globalSavingThrowBonus)) {
if (!isNaN(globalSavingThrowBonus)) {
total += getIntValue(globalSavingThrowBonus);
}
totalFormula += `${addArithmeticOperator(totalFormula, globalSavingThrowBonus)}[global saving throw bonus]`;
}
finalSetAttrs[`${savingThrowName}_saving_throw_mod`] = totalFormula;
finalSetAttrs[`${savingThrowName}_saving_throw_mod_with_sign`] = showSign(total);
},
});
}
updateCustomSavingThrows() {
this.updateSavingThrow('fortitude');
this.updateSavingThrow('reflex');
this.updateSavingThrow('will');
}
updateCustomSavingThrowToggle() {
getSetItems('savingThrows.updateCustomSavingThrowToggle', {
collectionArray: ['use_custom_saving_throws', 'saving_throw_macro_var_to_use'],
callback: (v, finalSetAttrs) => {
if (v.use_custom_saving_throws === '1') {
finalSetAttrs.saving_throw_macro_var_to_use = '@{custom_saving_throw_macro_var}';
} else {
finalSetAttrs.saving_throw_macro_var_to_use = '@{saving_throw_macro_var}';
}
},
});
}
update() {
this.updateSavingThrow('strength');
this.updateSavingThrow('dexterity');
this.updateSavingThrow('constitution');
this.updateSavingThrow('intelligence');
this.updateSavingThrow('wisdom');
this.updateSavingThrow('charisma');
this.updateCustomSavingThrows();
}
updateFromSRD() {
getSetItems('savingThrows.updateFromSRD', {
collectionArray: ['saving_throws_srd'],
callback: (v, finalSetAttrs) => {
const savingThrowsFromSRD = v.saving_throws_srd;
const pbVar = '@{PB}';
if (savingThrowsFromSRD.indexOf('Str') !== -1) {
finalSetAttrs.strength_save_prof = pbVar;
}
if (savingThrowsFromSRD.indexOf('Dex') !== -1) {
finalSetAttrs.dexterity_save_prof = pbVar;
}
if (savingThrowsFromSRD.indexOf('Con') !== -1) {
finalSetAttrs.constitution_save_prof = pbVar;
}
if (savingThrowsFromSRD.indexOf('Int') !== -1) {
finalSetAttrs.intelligence_save_prof = pbVar;
}
if (savingThrowsFromSRD.indexOf('Wis') !== -1) {
finalSetAttrs.wisdom_save_prof = pbVar;
}
if (savingThrowsFromSRD.indexOf('Cha') !== -1) {
finalSetAttrs.charisma_save_prof = pbVar;
}
},
});
}
watchForCustomSavingThrowChanges(savingThrowName) {
const classFeatureWatch = [`change:${savingThrowName}_save_prof`, `change:${savingThrowName}_save_bonus`, 'change:average_of_abilities'];
for (const ability of ABILITIES) {
classFeatureWatch.push(`change:${savingThrowName}_${ability}`);
}
on(classFeatureWatch.join(' '), () => {
this.updateSavingThrow(savingThrowName);
});
}
watchAbilityChanges() {
const classFeatureWatch = [];
for (const ability of ABILITIES) {
classFeatureWatch.push(`change:${ability}`);
classFeatureWatch.push(`change:${ability}_mod`);
}
on(classFeatureWatch.join(' '), () => {
this.updateCustomSavingThrows();
});
}
setup() {
on('change:strength_mod change:strength_save_prof change:strength_save_bonus', () => {
this.updateSavingThrow('strength');
});
on('change:dexterity_mod change:dexterity_save_prof change:dexterity_save_bonus', () => {
this.updateSavingThrow('dexterity');
});
on('change:constitution_mod change:constitution_save_prof change:constitution_save_bonus', () => {
this.updateSavingThrow('constitution');
});
on('change:intelligence_mod change:intelligence_save_prof change:intelligence_save_bonus', () => {
this.updateSavingThrow('intelligence');
});
on('change:wisdom_mod change:wisdom_save_prof change:wisdom_save_bonus', () => {
this.updateSavingThrow('wisdom');
});
on('change:charisma_mod change:charisma_save_prof change:charisma_save_bonus', () => {
this.updateSavingThrow('charisma');
});
on('change:pb change:global_saving_throw_bonus change:saving_throws_half_proficiency', () => {
this.update();
});
on('change:use_custom_saving_throws', () => {
this.updateCustomSavingThrowToggle();
});
on('change:saving_throws_srd', () => {
this.updateFromSRD();
});
this.watchForCustomSavingThrowChanges('fortitude');
this.watchForCustomSavingThrowChanges('reflex');
this.watchForCustomSavingThrowChanges('will');
this.watchAbilityChanges();
}
}
+29
View File
@@ -0,0 +1,29 @@
/* global on:false */
import { getSetItems } from './utilities';
export class Settings {
updateShapedD20() {
getSetItems('settings.updateShapedD20', {
collectionArray: ['roll_setting', 'roll_info', 'shaped_d20'],
callback: (v, finalSetAttrs) => {
finalSetAttrs.roll_info = '';
finalSetAttrs.shaped_d20 = 'd20';
if (v.roll_setting === 'adv {{ignore=[[0') {
finalSetAttrs.roll_info = '{{advantage=1}}';
finalSetAttrs.shaped_d20 = '2d20@{d20_mod}kh1';
} else if (v.roll_setting === 'dis {{ignore=[[0') {
finalSetAttrs.roll_info = '{{disadvantage=1}}';
finalSetAttrs.shaped_d20 = '2d20@{d20_mod}kl1';
}
},
});
}
setup() {
on('change:roll_setting', () => {
this.updateShapedD20();
});
}
}
+465
View File
@@ -0,0 +1,465 @@
/* global on:false, generateRowID:false */
import { ABILITIES, TOGGLE_VARS } from './constants';
import { updateAttackToggle, updateSavingThrowToggle, updateDamageToggle, updateHealToggle, updateHigherLevelToggle } from './updateToggles';
import { getSetItems, getSetRepeatingItems, ordinalSpellLevel, getIntValue, isUndefined, isUndefinedOrEmpty, setCritDamage, fromVOrFinalSetAttrs, lowercaseDamageTypes, getRepeatingInfo, exists } from './utilities';
export class Spells {
parseSRD(v, finalSetAttrs, repeatingString) {
if (v[`${repeatingString}spell_level_from_srd`]) {
finalSetAttrs[`${repeatingString}spell_level`] = ordinalSpellLevel(v[`${repeatingString}spell_level_from_srd`]);
finalSetAttrs[`${repeatingString}spell_level_from_srd`] = '';
}
if (v[`${repeatingString}school_from_srd`]) {
finalSetAttrs[`${repeatingString}school`] = v[`${repeatingString}school_from_srd`].toUpperCase();
finalSetAttrs[`${repeatingString}school_from_srd`] = '';
}
if (v[`${repeatingString}casting_time_from_srd`]) {
finalSetAttrs[`${repeatingString}casting_time`] = v[`${repeatingString}casting_time_from_srd`].trim().toUpperCase().replace(/\s/g, '_');
finalSetAttrs[`${repeatingString}casting_time_from_srd`] = '';
}
if (v[`${repeatingString}components_from_srd`]) {
finalSetAttrs[`${repeatingString}components`] = `COMPONENTS_${v[`${repeatingString}components_from_srd`].trim().toUpperCase().replace(/\s/g, '_')}`;
finalSetAttrs[`${repeatingString}components_from_srd`] = '';
}
if (v[`${repeatingString}duration_from_srd`]) {
let duration = '';
if (v[`${repeatingString}duration_from_srd`].toLowerCase().indexOf('up to') !== -1) {
duration += 'CONCENTRATION_';
}
duration += v[`${repeatingString}duration_from_srd`].trim().toUpperCase().replace(/\s/g, '_');
finalSetAttrs[`${repeatingString}duration`] = duration;
finalSetAttrs[`${repeatingString}duration_from_srd`] = '';
}
if (v[`${repeatingString}saving_throw_vs_ability_from_srd`]) {
finalSetAttrs[`${repeatingString}saving_throw_vs_ability`] = v[`${repeatingString}saving_throw_vs_ability_from_srd`].toUpperCase();
finalSetAttrs[`${repeatingString}saving_throw_vs_ability_from_srd`] = '';
}
}
updateFromSRD() {
getSetItems('spells.updateFromSRD', {
collectionArray: ['spells_srd'],
callback: (v, finalSetAttrs) => {
const spellsFromSrd = v.spells_srd.split(', ');
for (const spell of spellsFromSrd) {
const repeatingString = `repeating_spell_${generateRowID()}_`;
finalSetAttrs[`${repeatingString}name`] = spell;
finalSetAttrs[`${repeatingString}toggle_details`] = 0;
}
},
});
}
update(rowId) {
const collectionArray = ['is_npc', 'pb', 'finesse_mod', 'global_spell_attack_bonus', 'global_spell_damage_bonus', 'global_spell_dc_bonus', 'global_spell_heal_bonus', 'default_ability', 'caster_level', 'base_dc'];
for (const ability of ABILITIES) {
collectionArray.push(`${ability}_mod`);
}
getSetRepeatingItems('spells.update', {
repeatingItems: ['repeating_spell'],
collectionArray,
collectionArrayAddItems: ['name', 'school', 'spell_level', 'spell_level_from_srd', 'school_from_srd', 'casting_time', 'casting_time_from_srd', 'components', 'components_from_srd', 'concentration', 'duration', 'duration_from_srd', 'type', 'roll_toggle', 'to_hit', 'attack_formula', 'proficiency', 'attack_ability', 'attack_bonus', 'saving_throw_toggle', 'saving_throw_ability', 'saving_throw_vs_ability', 'saving_throw_vs_ability_from_srd', 'saving_throw_bonus', 'saving_throw_dc', 'damage_toggle', 'damage_formula', 'damage', 'damage_ability', 'damage_bonus', 'damage_type', 'damage_crit', 'second_damage_toggle', 'second_damage_formula', 'second_damage', 'second_damage_ability', 'second_damage_bonus', 'second_damage_type', 'second_damage_crit', 'damage_string', 'parsed', 'heal_toggle', 'heal', 'heal_ability', 'heal_bonus', 'heal_query_toggle', 'add_casting_modifier', 'add_second_casting_modifier', 'higher_level_toggle', 'higher_level_dice', 'higher_level_die', 'second_higher_level_dice', 'second_higher_level_die', 'higher_level_heal', 'ritual', 'ritual_output', 'materials', 'materials_show', 'extras_toggle', 'emote', 'freetext', 'freeform'],
rowId,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
this.parseSRD(v, finalSetAttrs, repeatingString);
if (v[`${repeatingString}spell_level`] === 'CANTRIP') {
finalSetAttrs[`${repeatingString}is_prepared`] = 'on';
}
if (!isUndefined(fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}duration`)) && fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}duration`).indexOf('CONCENTRATION') !== -1) {
finalSetAttrs[`${repeatingString}concentration`] = 'Yes';
} else {
finalSetAttrs[`${repeatingString}concentration`] = '';
}
if (v[`${repeatingString}ritual`] === 'Yes') {
finalSetAttrs[`${repeatingString}ritual_output`] = '?{Cast as|Ritual,{{ritual=1&#125;&#125;|Spell,}';
} else {
finalSetAttrs[`${repeatingString}ritual_output`] = '';
}
if (!isUndefinedOrEmpty(v[`${repeatingString}materials`])) {
finalSetAttrs[`${repeatingString}materials_show`] = 1;
} else if (!isUndefinedOrEmpty(v[`${repeatingString}materials_show`])) {
finalSetAttrs[`${repeatingString}materials_show`] = 0;
}
const attackOptions = {
attackAbility: true,
globalAttackBonus: v.global_spell_attack_bonus,
globalAttackBonusLabel: 'global spell attack bonus',
type: 'spell',
};
updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions);
const savingThrowOptions = {
bonusDC: v.global_spell_dc_bonus,
};
updateSavingThrowToggle(v, finalSetAttrs, repeatingString, savingThrowOptions);
const damageOptions = {
globalDamageBonus: v.global_spell_damage_bonus,
globalDamageBonusLabel: 'global spell damage bonus',
type: 'spell',
};
updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions);
if (v.damage_type) {
finalSetAttrs.damage_type = lowercaseDamageTypes(v.damage_type);
}
if (v.second_damage_type) {
finalSetAttrs.second_damage_type = lowercaseDamageTypes(v.second_damage_type);
}
setCritDamage(v, finalSetAttrs, repeatingString);
if (getIntValue(v.is_npc) === 1 && v.caster_level && v[`${repeatingString}damage`] && v[`${repeatingString}damage`].indexOf('@{level}') !== -1) {
finalSetAttrs[`${repeatingString}damage`] = v[`${repeatingString}damage`].replace('@{level}', '@{caster_level}');
}
updateHealToggle(v, finalSetAttrs, repeatingString);
updateHigherLevelToggle(v, finalSetAttrs, repeatingString);
if (isUndefinedOrEmpty(v[`${repeatingString}extras_toggle`]) && (v[`${repeatingString}emote`] || v[`${repeatingString}freetext`] || v[`${repeatingString}freeform`])) {
finalSetAttrs[`${repeatingString}extras_toggle`] = TOGGLE_VARS.extras;
}
}
},
});
}
updateSlots() {
const collectionArray = ['caster_level', 'caster_type'];
const spellSlots = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
6: 0,
7: 0,
8: 0,
9: 0,
};
for (const level in spellSlots) {
if (spellSlots.hasOwnProperty(level)) {
const repeatingString = `spell_slots_l${level}`;
collectionArray.push(`${repeatingString}_calc`);
collectionArray.push(`${repeatingString}_bonus`);
collectionArray.push(`${repeatingString}_max`);
collectionArray.push(`${repeatingString}_toggle`);
}
}
getSetItems('spells.updateSlots', {
collectionArray,
callback: (v, finalSetAttrs) => {
const casterLevel = getIntValue(v.caster_level);
const casterType = v.caster_type;
if (casterType === 'full') {
if (casterLevel >= 3) {
spellSlots[1] = 4;
} else if (casterLevel === 2) {
spellSlots[1] = 3;
} else if (casterLevel === 1) {
spellSlots[1] = 2;
}
if (casterLevel >= 4) {
spellSlots[2] = 3;
} else if (casterLevel === 3) {
spellSlots[2] = 2;
}
if (casterLevel >= 6) {
spellSlots[3] = 3;
} else if (casterLevel === 5) {
spellSlots[3] = 2;
}
if (casterLevel >= 9) {
spellSlots[4] = 3;
} else if (casterLevel === 8) {
spellSlots[4] = 2;
} else if (casterLevel === 7) {
spellSlots[4] = 1;
}
if (casterLevel >= 18) {
spellSlots[5] = 3;
} else if (casterLevel >= 10) {
spellSlots[5] = 2;
} else if (casterLevel === 9) {
spellSlots[5] = 1;
}
if (casterLevel >= 19) {
spellSlots[6] = 2;
} else if (casterLevel >= 11) {
spellSlots[6] = 1;
}
if (casterLevel >= 20) {
spellSlots[7] = 2;
} else if (casterLevel >= 13) {
spellSlots[7] = 1;
}
if (casterLevel >= 15) {
spellSlots[8] = 1;
}
if (casterLevel >= 17) {
spellSlots[9] = 1;
}
}
if (casterType === 'half') {
if (casterLevel >= 5) {
spellSlots[1] = 4;
} else if (casterLevel >= 3) {
spellSlots[1] = 3;
} else if (casterLevel === 2) {
spellSlots[1] = 2;
}
if (casterLevel >= 7) {
spellSlots[2] = 3;
} else if (casterLevel >= 5) {
spellSlots[2] = 2;
}
if (casterLevel >= 11) {
spellSlots[3] = 3;
} else if (casterLevel >= 9) {
spellSlots[3] = 2;
}
if (casterLevel >= 17) {
spellSlots[4] = 3;
} else if (casterLevel >= 15) {
spellSlots[4] = 2;
} else if (casterLevel >= 13) {
spellSlots[4] = 1;
}
if (casterLevel >= 19) {
spellSlots[5] = 2;
} else if (casterLevel >= 17) {
spellSlots[5] = 1;
}
}
if (casterType === 'third') {
if (casterLevel >= 7) {
spellSlots[1] = 4;
} else if (casterLevel >= 4) {
spellSlots[1] = 3;
} else if (casterLevel === 3) {
spellSlots[1] = 2;
}
if (casterLevel >= 10) {
spellSlots[2] = 3;
} else if (casterLevel >= 7) {
spellSlots[2] = 2;
}
if (casterLevel >= 16) {
spellSlots[3] = 3;
} else if (casterLevel >= 13) {
spellSlots[3] = 2;
}
if (casterLevel >= 19) {
spellSlots[4] = 1;
}
}
for (const level in spellSlots) {
if (spellSlots.hasOwnProperty(level)) {
const repeatingString = `spell_slots_l${level}`;
finalSetAttrs[repeatingString] = 0;
if (spellSlots[level] !== 0 || exists(v[`${repeatingString}_calc`])) {
finalSetAttrs[`spell_slots_l${level}_calc`] = spellSlots[level];
}
const slots = v[`${repeatingString}`];
const slotBonus = getIntValue(v[`${repeatingString}_bonus`]);
const spellSlotMax = spellSlots[level] + slotBonus;
if (spellSlotMax > 0) {
finalSetAttrs[`${repeatingString}_max`] = spellSlotMax;
if (isUndefinedOrEmpty(slots)) {
finalSetAttrs[repeatingString] = spellSlotMax;
}
} else {
if (exists(v[`${repeatingString}_max`])) {
finalSetAttrs[`${repeatingString}_max`] = 0;
}
}
}
}
},
});
}
updateShowHide() {
const collectionArray = ['spells_show_spell_level_if_all_slots_are_used'];
for (let i = 0; i <= 9; i++) {
collectionArray.push(`spell_slots_l${i}`);
collectionArray.push(`spell_slots_l${i}_max`);
collectionArray.push(`spell_slots_l${i}_toggle`);
collectionArray.push(`spells_level_${i}_macro_var`);
collectionArray.push(`spells_level_${i}_show`);
}
getSetItems('spells.updateShowHide', {
collectionArray,
callback: (v, finalSetAttrs) => {
const showLevelIfAllSlotsAreUsed = isUndefinedOrEmpty(v.spells_show_spell_level_if_all_slots_are_used) || v.spells_show_spell_level_if_all_slots_are_used === 'on';
for (let level = 0; level <= 9; level++) {
if (v[`spells_level_${level}_macro_var`] || getIntValue(v[`spell_slots_l${level}`]) || getIntValue(v[`spell_slots_l${level}_max`])) {
finalSetAttrs[`spell_slots_l${level}_toggle`] = 'on';
} else {
finalSetAttrs[`spell_slots_l${level}_toggle`] = 0;
}
const hasSlots = getIntValue(v[`spell_slots_l${level}`]);
const hasSpells = v[`spells_level_${level}_macro_var`];
if ((hasSlots || showLevelIfAllSlotsAreUsed) && (hasSlots || hasSpells)) {
finalSetAttrs[`spells_level_${level}_show`] = true;
} else {
finalSetAttrs[`spells_level_${level}_show`] = '';
}
}
},
});
}
updateChatMacro() {
const spellSlots = {
0: [],
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
7: [],
8: [],
9: [],
};
const collectionArray = ['spells_show_unprepared'];
for (let i = 0; i <= 9; i++) {
collectionArray.push(`spells_level_${0}_macro_var`);
}
getSetRepeatingItems('spells.updateChatMacro', {
repeatingItems: ['repeating_spell'],
collectionArray,
collectionArrayAddItems: ['name', 'spell_level', 'is_prepared'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
const showUnprepared = v.spells_show_unprepared === 'on' || isUndefinedOrEmpty(v.spells_show_unprepared);
const spellName = v[`${repeatingString}name`];
const spellLevel = getIntValue(v[`${repeatingString}spell_level`], 0);
const spellPrepared = v[`${repeatingString}is_prepared`] === 'on';
if (spellName && spellPrepared) {
spellSlots[spellLevel].push(`[${spellName}](~repeating_spell_${id}_spell)`);
} else if (spellName && showUnprepared) {
spellSlots[spellLevel].push(`<span class="sheet-unprepared">[${spellName}](~repeating_spell_${id}_spell)</span>`);
}
}
for (let i = 0; i <= 9; i++) {
if (spellSlots[i].length > 0) {
finalSetAttrs[`spells_level_${i}_macro_var`] = spellSlots[i].join(', ');
} else {
finalSetAttrs[`spells_level_${i}_macro_var`] = '';
}
}
},
});
}
generateHigherLevelQueries() {
const collectionArray = ['warlock_level', 'number_of_classes'];
for (let i = 1; i <= 8; i++) {
collectionArray.push(`cast_as_level_${i}`);
collectionArray.push(`higher_level_query_${i}`);
}
for (let i = 1; i <= 9; i++) {
collectionArray.push(`spell_slots_l${i}`);
}
getSetItems('spells.generateHigherLevelQueries', {
collectionArray,
callback: (v, finalSetAttrs) => {
for (let i = 1; i <= 8; i++) {
let higherLevelQuery = '';
if (i < 6 && v.number_of_classes === 1 && v.warlock_level > 0 && Math.ceil(getIntValue(v.warlock_level) / 2) >= i) {
let spellLevel = 1;
if (v.warlock_level >= 9) {
spellLevel = 5;
} else if (v.warlock_level >= 7) {
spellLevel = 4;
} else if (v.warlock_level >= 5) {
spellLevel = 3;
} else if (v.warlock_level >= 3) {
spellLevel = 2;
}
higherLevelQuery = spellLevel;
} else {
let levelQuery = '';
for (let j = i; j <= 9; j++) {
if (getIntValue(v[`spell_slots_l${j}`])) {
levelQuery += `|${j}`;
}
}
higherLevelQuery = `?{Spell Level${levelQuery}}`;
}
if (higherLevelQuery !== '') {
finalSetAttrs[`higher_level_query_${i}`] = higherLevelQuery;
} else {
finalSetAttrs[`higher_level_query_${i}`] = i;
}
if (v[`spell_slots_l${i}`] === '0' && higherLevelQuery !== i) {
finalSetAttrs[`cast_as_level_${i}`] = higherLevelQuery;
} else {
finalSetAttrs[`cast_as_level_${i}`] = '';
}
}
},
});
}
watchForChanges() {
const spellsWatch = ['change:spells_show_spell_level_if_all_slots_are_used'];
for (let i = 0; i <= 9; i++) {
spellsWatch.push(`change:spells_level_${i}_macro_var`);
spellsWatch.push(`change:spell_slots_l${i}`);
spellsWatch.push(`change:spell_slots_l${i}_max`);
}
on(spellsWatch.join(' '), () => {
this.updateShowHide();
});
}
setup() {
on('change:repeating_spell', (eventInfo) => {
const repeatingInfo = getRepeatingInfo('repeating_spell', eventInfo);
if (repeatingInfo && repeatingInfo.field !== 'roll_toggle' && repeatingInfo.field !== 'toggle_details' && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'damage_crit' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'second_damage_crit' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'heal_formula' && repeatingInfo.field !== 'higher_level_query' && repeatingInfo.field !== 'parsed') {
this.update(repeatingInfo.rowId);
}
});
on('change:pb change:global_spell_attack_bonus change:global_spell_damage_bonus change:global_spell_dc_bonus change:global_spell_heal_bonus', () => {
this.update();
});
on('change:spells_srd', () => {
this.updateFromSRD();
});
on('change:spell_slots_l1_bonus change:spell_slots_l2_bonus change:spell_slots_l3_bonus change:spell_slots_l4_bonus change:spell_slots_l5_bonus change:spell_slots_l6_bonus change:spell_slots_l7_bonus change:spell_slots_l8_bonus change:spell_slots_l9_bonus', () => {
this.updateSlots();
});
this.watchForChanges();
on('change:repeating_spell', (eventInfo) => {
const repeatingInfo = getRepeatingInfo('repeating_spell', eventInfo);
if (repeatingInfo && (repeatingInfo.field === 'name' || repeatingInfo.field === 'spell_level' || repeatingInfo.field === 'is_prepared')) {
this.updateChatMacro();
}
});
on('change:spells_show_unprepared remove:repeating_spell', () => {
this.updateChatMacro();
});
on('change:warlock_level change:spell_slots_l1 change:spell_slots_l2 change:spell_slots_l3 change:spell_slots_l4 change:spell_slots_l5 change:spell_slots_l6 change:spell_slots_l7 change:spell_slots_l8 change:spell_slots_l9', () => {
this.generateHigherLevelQueries();
});
}
}
+94
View File
@@ -0,0 +1,94 @@
/* global generateRowID:falsee */
import { TOGGLE_VARS } from './constants';
import { getSetRepeatingItems, isUndefinedOrEmpty } from './utilities';
export class Traits {
calculatePercentDifference(oldValue, newValue) {
return Math.abs(((oldValue - newValue) / oldValue) * 100);
}
set(obj) {
if (!obj.name) {
obj.name = obj.storageName;
}
const collectionArrayAddItems = ['storage_name', 'name', 'uses', 'freetext', 'saving_throw_toggle', 'damage_toggle', 'heal_toggle', 'extras_toggle', 'display_text'];
for (const prop in obj) {
if (obj.hasOwnProperty(prop)) {
collectionArrayAddItems.push(prop);
}
}
let itemId;
let repeatingString;
getSetRepeatingItems('traits.set', {
repeatingItems: ['repeating_trait'],
collectionArrayAddItems,
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
repeatingString = `${repeatingItem}_${id}_`;
if (v[`${repeatingString}storage_name`] === obj.storageName) {
itemId = id;
}
}
if (!itemId) {
itemId = generateRowID();
}
repeatingString = `${repeatingItem}_${itemId}_`;
if (!obj.clear && isUndefinedOrEmpty(v[`${repeatingString}storage_name`])) {
finalSetAttrs[`${repeatingString}storage_name`] = obj.storageName;
}
if (!obj.clear && v[`${repeatingString}name`] !== obj.name) {
finalSetAttrs[`${repeatingString}name`] = obj.name;
}
delete obj.storageName;
if (obj.clear) {
delete obj.clear;
for (const prop in obj) {
if (obj.hasOwnProperty(prop) && !isUndefinedOrEmpty(v[`${repeatingString}${prop}`])) {
finalSetAttrs[`${repeatingString}${prop}`] = obj[prop];
}
}
} else {
for (const prop in obj) {
if (obj.hasOwnProperty(prop)) {
if ((prop === 'name' || prop === 'freetext') && (isUndefinedOrEmpty(v[`${repeatingString}${prop}`]) || this.calculatePercentDifference(v[`${repeatingString}${prop}`].length, obj[prop].length) < 10)) {
finalSetAttrs[`${repeatingString}${prop}`] = obj[prop];
} else if (v[`${repeatingString}${prop}`] !== obj[prop]) {
finalSetAttrs[`${repeatingString}${prop}`] = obj[prop];
}
}
}
if (obj.type && isUndefinedOrEmpty(v[`${repeatingString}type`])) {
finalSetAttrs[`${repeatingString}type`] = obj.type;
}
if (obj.saving_throw_ability || obj.saving_throw_bonus || obj.saving_throw_vs_ability) {
finalSetAttrs[`${repeatingString}saving_throw_toggle`] = TOGGLE_VARS.saving_throw;
}
if (obj.damage || obj.damage_ability || obj.damage_bonus) {
finalSetAttrs[`${repeatingString}damage_toggle`] = TOGGLE_VARS.damage;
}
if (obj.heal || obj.heal_ability || obj.heal_bonus || obj.heal_query_toggle) {
finalSetAttrs[`${repeatingString}heal_toggle`] = TOGGLE_VARS.heal;
}
if (obj.freetext && isUndefinedOrEmpty(v[`${repeatingString}extras_toggle`])) {
finalSetAttrs[`${repeatingString}extras_toggle`] = TOGGLE_VARS.extras;
}
if (obj.uses_max && !obj.uses && isUndefinedOrEmpty(v[`${repeatingString}uses`])) {
finalSetAttrs[`${repeatingString}uses`] = obj.uses_max;
}
if (obj.freetext && repeatingItem === 'repeating_trait' && (isUndefinedOrEmpty(v[`${repeatingString}display_text`]) ||
this.calculatePercentDifference(v[`${repeatingString}display_text`].length, obj.freetext.length) < 10)) {
finalSetAttrs[`${repeatingString}display_text`] = obj.freetext;
}
finalSetAttrs[`${repeatingString}toggle_details`] = 0;
}
},
returnCallback: () => {
return itemId;
},
});
}
}
+599
View File
@@ -0,0 +1,599 @@
/* global on:false, generateRowID:false */
import { Abilities } from './Abilities';
const abilities = new Abilities();
import { AbilityChecks } from './AbilityChecks';
const abilityChecks = new AbilityChecks();
import { Actions } from './Actions';
const actions = new Actions();
import { Attachers } from './Attachers';
const attachers = new Attachers();
import { Attacks } from './Attacks';
const attacks = new Attacks();
import { Character } from './Character';
const character = new Character();
import { ClassFeatures } from './ClassFeatures';
const classFeatures = new ClassFeatures();
import { TOGGLE_VARS } from './constants';
import { Equipment } from './Equipment';
const equipment = new Equipment();
import { Npc } from './Npc';
const npc = new Npc();
import { Resistances } from './Resistances';
const resistances = new Resistances();
import { SavingThrows } from './SavingThrows';
const savingThrows = new SavingThrows();
import { Settings } from './Settings';
const settings = new Settings();
import { Spells } from './Spells';
const spells = new Spells();
import { isUndefined, isUndefinedOrEmpty, getAbilityName, ordinalSpellLevel, getSetItems, getSetRepeatingItems } from './utilities';
import { currentVersion } from './version';
export class Upgrade {
extasToExtrasFix(repeatingSection) {
getSetRepeatingItems('upgrade.extasToExtrasFix', {
repeatingItems: [repeatingSection],
collectionArrayAddItems: ['extas_toggle'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (!isUndefinedOrEmpty(v[`${repeatingString}extas_toggle`])) {
finalSetAttrs[`${repeatingString}extras_toggle`] = v[`${repeatingString}extas_toggle`];
}
}
},
});
}
armorPlusDexRemoval() {
getSetRepeatingItems('upgrade.armorPlusDexRemoval', {
repeatingItems: ['repeating_armor'],
collectionArrayAddItems: ['type'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
const armorType = v[`${repeatingString}type`];
if (armorType === 'Armor + Dex') {
finalSetAttrs[`${repeatingString}type`] = 'Light Armor';
}
}
},
});
}
fixRollTwo() {
getSetItems('upgrade.fixRollTwo', {
collectionArray: ['roll_setting'],
callback: (v, finalSetAttrs) => {
if (v.roll_setting === '@{attr_roll_2}') {
finalSetAttrs.roll_setting = '{{roll2=[[d20@{d20_mod}';
}
},
});
}
defaultAbility() {
getSetItems('upgrade.defaultAbility', {
collectionArray: ['default_ability'],
callback: (v, finalSetAttrs) => {
if (!isUndefinedOrEmpty(v.default_ability)) {
finalSetAttrs.default_ability = getAbilityName(v.default_ability);
}
},
});
}
hideFreetext() {
getSetItems('upgrade.hideFreetext', {
collectionArray: ['hide_freetext', 'hide_action_freetext'],
callback: (v, finalSetAttrs) => {
if (!isUndefinedOrEmpty(v.hide_action_freetext)) {
finalSetAttrs.hide_freetext = v.hide_action_freetext;
}
},
});
}
atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, field) {
if (v[`${repeatingString}${field}`]) {
finalSetAttrs[`${repeatingString}${field}`] = getAbilityName(v[`${repeatingString}${field}`]);
}
}
skillAbility() {
getSetRepeatingItems('upgrade.skillAbility', {
repeatingItems: ['repeating_skill'],
collectionArrayAddItems: ['ability'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
this.atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, 'ability');
}
},
});
}
armorAbility() {
getSetItems('upgrade.armorAbility', {
collectionArray: ['ac_unarmored_ability'],
callback: (v, finalSetAttrs) => {
if (!isUndefinedOrEmpty(v.ac_unarmored_ability)) {
finalSetAttrs.ac_unarmored_ability = getAbilityName(v.ac_unarmored_ability);
}
},
});
}
actionComponents() {
getSetRepeatingItems('upgrade.actionComponents', {
repeatingItems: ['repeating_attack', 'repeating_spell', 'repeating_trait', 'repeating_action', 'repeating_reaction', 'repeating_legendaryaction', 'repeating_lairaction', 'repeating_regionaleffect'],
collectionArrayAddItems: ['attack_ability', 'damage_ability', 'second_damage_ability', 'heal_ability', 'saving_throw_ability', 'saving_throw_vs_ability'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
this.atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, 'attack_ability');
this.atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, 'damage_ability');
this.atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, 'second_damage_ability');
this.atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, 'heal_ability');
this.atSyntaxToAbilityName(v, finalSetAttrs, repeatingString, 'saving_throw_ability');
if (v[`${repeatingString}saving_throw_vs_ability`]) {
finalSetAttrs[`${repeatingString}saving_throw_vs_ability`] = v[`${repeatingString}saving_throw_vs_ability`].toUpperCase();
}
}
},
});
}
newAttackToggle() {
getSetRepeatingItems('upgrade.newAttackToggle', {
repeatingItems: ['repeating_attack', 'repeating_spell', 'repeating_action', 'repeating_reaction', 'repeating_legendaryaction', 'repeating_lairaction', 'repeating_regionaleffect'],
collectionArrayAddItems: ['roll_toggle'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (v[`${repeatingString}roll_toggle`] === '{{vs_ac=1}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}') {
finalSetAttrs[`${repeatingString}roll_toggle`] = TOGGLE_VARS.roll;
}
}
},
});
}
newAttackToggleTwo() {
getSetRepeatingItems('upgrade.newAttackToggleTwo', {
repeatingItems: ['repeating_attack', 'repeating_spell', 'repeating_action', 'repeating_reaction', 'repeating_legendaryaction', 'repeating_lairaction', 'repeating_regionaleffect'],
collectionArrayAddItems: ['roll_toggle'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (v[`${repeatingString}roll_toggle`].indexOf('vs_saving_throw') !== -1) {
finalSetAttrs[`${repeatingString}roll_toggle`] = TOGGLE_VARS.roll;
}
}
},
});
}
newAbilityDefaults() {
getSetRepeatingItems('upgrade.newAbilityDefaults', {
repeatingItems: ['repeating_attack', 'repeating_action', 'repeating_reaction', 'repeating_legendaryaction', 'repeating_lairaction', 'repeating_regionaleffect'],
collectionArrayAddItems: ['roll_toggle', 'roll_ability', 'damage_toggle', 'damage_ability'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (!isUndefinedOrEmpty(v[`${repeatingString}roll_toggle`]) && isUndefined(v[`${repeatingString}roll_ability`])) {
finalSetAttrs[`${repeatingString}roll_ability`] = 'strength';
}
if (!isUndefinedOrEmpty(v[`${repeatingString}damage_toggle`]) && isUndefined(v[`${repeatingString}damage_ability`])) {
finalSetAttrs[`${repeatingString}damage_ability`] = 'strength';
}
}
},
});
}
changeOldToggleToNew(v, finalSetAttrs, field, oldValue, newValue) {
if (v[field] === `@{${oldValue}}`) {
finalSetAttrs[field] = newValue;
}
}
removeToggleVar() {
getSetItems('upgrade.removeToggleVar', {
collectionArray: ['careful_spell_toggle', 'distant_spell_toggle', 'empowered_spell_toggle', 'extended_spell_toggle', 'heightened_spell_toggle', 'quickened_spell_toggle', 'subtle_spell_toggle', 'twinned_spell_toggle', 'initiative_tie_breaker', 'ammo_auto_use', 'hide_attack', 'hide_damage', 'hide_saving_throw_dc', 'hide_spell_content', 'hide_action_freetext', 'hide_saving_throw_failure', 'hide_saving_throw_success', 'hide_recharge', 'initiative_output_option', 'output_option', 'death_save_output_option', 'hit_dice_output_option', 'roll_setting', 'show_character_name', 'attacks_vs_target_ac', 'attacks_vs_target_name', 'initiative_roll', 'initiative_to_tracker'],
callback: (v, finalSetAttrs) => {
this.changeOldToggleToNew(v, finalSetAttrs, 'careful_spell_toggle', 'careful_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'distant_spell_toggle', 'distant_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'empowered_spell_toggle', 'empowered_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'extended_spell_toggle', 'extended_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'heightened_spell_toggle', 'heightened_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'quickened_spell_toggle', 'quickened_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'subtle_spell_toggle', 'subtle_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'twinned_spell_toggle', 'twinned_spell_toggle_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_tie_breaker', 'initiative_tie_breaker_var', '[[@{initiative} / 100]][tie breaker]');
this.changeOldToggleToNew(v, finalSetAttrs, 'ammo_auto_use', 'ammo_auto_use_var', '1');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_attack', 'hide_attack_var', '{{hide_attack=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_damage', 'hide_damage_var', '{{hide_damage=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_saving_throw_dc', 'hide_saving_throw_dc_var', '{{hide_saving_throw_dc=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_spell_content', 'hide_spell_content_var', '{{hide_spell_content=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_action_freetext', 'hide_action_freetext_var', '{{hide_freetext=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_saving_throw_failure', 'hide_saving_throw_failure_var', '{{hide_saving_throw_failure=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_saving_throw_success', 'hide_saving_throw_success_var', '{{hide_saving_throw_success=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'hide_recharge', 'hide_recharge_var', '{{hide_recharge=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_output_option', 'output_to_all', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_output_option', 'output_to_gm', '/w GM');
this.changeOldToggleToNew(v, finalSetAttrs, 'output_option', 'output_to_all', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'output_option', 'output_to_gm', '/w GM');
this.changeOldToggleToNew(v, finalSetAttrs, 'death_save_output_option', 'output_to_all', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'death_save_output_option', 'output_to_gm', '/w GM');
this.changeOldToggleToNew(v, finalSetAttrs, 'hit_dice_output_option', 'output_to_all', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'hit_dice_output_option', 'output_to_gm', '/w GM');
this.changeOldToggleToNew(v, finalSetAttrs, 'roll_setting', 'roll_advantage', 'adv {{ignore=[[0');
this.changeOldToggleToNew(v, finalSetAttrs, 'roll_setting', 'roll_disadvantage', 'dis {{ignore=[[0');
this.changeOldToggleToNew(v, finalSetAttrs, 'roll_setting', 'roll_1', '{{ignore=[[0');
this.changeOldToggleToNew(v, finalSetAttrs, 'roll_setting', 'roll_2', '{{roll2=[[d20@{d20_mod}');
this.changeOldToggleToNew(v, finalSetAttrs, 'show_character_name', 'show_character_name_no', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'show_character_name', 'show_character_name_yes', '{{show_character_name=1}}');
this.changeOldToggleToNew(v, finalSetAttrs, 'attacks_vs_target_ac', 'attacks_vs_target_ac_no', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'attacks_vs_target_ac', 'attacks_vs_target_ac_yes', '[[@{target|AC}]]');
this.changeOldToggleToNew(v, finalSetAttrs, 'attacks_vs_target_name', 'attacks_vs_target_name_no', '');
this.changeOldToggleToNew(v, finalSetAttrs, 'attacks_vs_target_name', 'attacks_vs_target_name_yes', '@{target|token_name}');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_roll', 'normal_initiative', '@{shaped_d20}');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_roll', 'advantage_on_initiative', '2d20@{d20_mod}kh1');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_roll', 'disadvantage_on_initiative', '2d20@{d20_mod}kl1');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_to_tracker', 'initiative_to_tracker_yes', '@{selected|initiative_formula} &{tracker}');
this.changeOldToggleToNew(v, finalSetAttrs, 'initiative_to_tracker', 'initiative_to_tracker_no', '@{initiative_formula}');
},
});
}
changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, field, oldValue, newValue) {
if (v[`${repeatingString}${field}`] === `@{${oldValue}}`) {
finalSetAttrs[`${repeatingString}${field}`] = newValue;
}
}
actionComponentsToRemoveExtraFields() {
getSetRepeatingItems('upgrade.actionComponentsToRemoveExtraFields', {
repeatingItems: ['repeating_attack', 'repeating_spell', 'repeating_trait', 'repeating_action', 'repeating_reaction', 'repeating_legendaryaction', 'repeating_lairaction', 'repeating_regionaleffect'],
collectionArrayAddItems: ['roll_toggle', 'content_toggle', 'saving_throw_toggle', 'damage_toggle', 'second_damage_toggle', 'extras_toggle', 'heal_toggle', 'heal_query_toggle', 'higher_level_toggle', 'special_effects_toggle'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'roll_toggle', 'roll_toggle_var', '{{vs_ac=1}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'content_toggle', 'content_toggle_var', '{{content=@{content}}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'saving_throw_toggle', 'saving_throw_toggle_var', '{{saving_throw_condition=@{saving_throw_condition}}} {{saving_throw_dc=@{saving_throw_dc}}} {{saving_throw_vs_ability=@{saving_throw_vs_ability}}} {{saving_throw_failure=@{saving_throw_failure}}} {{saving_throw_success=@{saving_throw_success}}} {{targetName=@{attacks_vs_target_name}}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'damage_toggle', 'damage_toggle_var', '{{damage=[[@{damage_formula}]]}} {{damage_type=@{damage_type}}} {{crit_damage=[[0d0 + @{damage_crit}[crit damage] @{damage_crit_formula}]]}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'second_damage_toggle', 'second_damage_toggle_var', '{{second_damage=[[@{second_damage_formula}]]}} {{second_damage_type=@{second_damage_type}}} {{second_crit_damage=[[0d0 + @{second_damage_crit}[crit damage] @{second_damage_crit_formula}]]}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'extras_toggle', 'extras_var', '{{emote=@{emote}}} {{freetext=@{freetext}}} @{freeform}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'heal_toggle', 'heal_toggle_var', '{{heal=[[@{heal_formula}]]}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'heal_query_toggle', 'heal_query', '?{Heal Bonus Amount|}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'higher_level_toggle', 'higher_level_toggle_var', '{{cast_as_level=@{higher_level_query}}}');
this.changeOldRepeatingToggleToNew(v, finalSetAttrs, repeatingString, 'special_effects_toggle', 'special_effects_var', '{{fx=@{type}-@{color} @{points_of_origin}}}');
}
},
});
}
displayTextForTraits() {
getSetRepeatingItems('upgrade.displayTextForTraits', {
repeatingItems: ['repeating_trait'],
collectionArrayAddItems: ['display_text', 'freetext'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (isUndefinedOrEmpty(v[`${repeatingString}display_text`])) {
finalSetAttrs[`${repeatingString}display_text`] = v[`${repeatingString}freetext`];
}
}
},
});
}
spellToTranslations() {
getSetRepeatingItems('upgrade.spellToTranslations', {
repeatingItems: ['repeating_spell'],
collectionArrayAddItems: ['spell_level', 'school', 'casting_time', 'components', 'duration', 'concentration', 'saving_throw_vs_ability'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (v[`${repeatingString}spell_level`]) {
finalSetAttrs[`${repeatingString}spell_level`] = ordinalSpellLevel(v[`${repeatingString}spell_level`]);
}
if (v[`${repeatingString}school`]) {
finalSetAttrs[`${repeatingString}school`] = v[`${repeatingString}school`].toUpperCase();
}
if (v[`${repeatingString}casting_time`]) {
finalSetAttrs[`${repeatingString}casting_time`] = v[`${repeatingString}casting_time`].trim().toUpperCase().replace(/\s/g, '_');
}
if (v[`${repeatingString}components`]) {
finalSetAttrs[`${repeatingString}components`] = `COMPONENTS_${v[`${repeatingString}components`].trim().toUpperCase().replace(/\s/g, '_')}`;
}
if (v[`${repeatingString}duration`]) {
let duration = '';
if (v[`${repeatingString}concentration`] === 'Yes') {
duration += 'CONCENTRATION_';
}
duration += v[`${repeatingString}duration`].trim().toUpperCase().replace(/\s/g, '_');
finalSetAttrs[`${repeatingString}duration`] = duration;
}
if (finalSetAttrs[`${repeatingString}saving_throw_vs_ability`]) {
finalSetAttrs[`${repeatingString}saving_throw_vs_ability`] = v[`${repeatingString}saving_throw_vs_ability`].toUpperCase();
}
}
},
});
}
spellLevelForCantrips() {
getSetRepeatingItems('upgrade.spellLevelForCantrips', {
repeatingItems: ['repeating_spell'],
collectionArrayAddItems: ['spell_level'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (isUndefinedOrEmpty(v[`${repeatingString}spell_level`]) || v[`${repeatingString}spell_level`] === '0' || v[`${repeatingString}spell_level`] === 0) {
finalSetAttrs[`${repeatingString}spell_level`] = 'CANTRIP';
}
}
},
});
}
spellEffectsNaming() {
getSetRepeatingItems('upgrade.spellEffectsNaming', {
repeatingItems: ['repeating_spell'],
collectionArrayAddItems: ['special_effects_toggle', 'type', 'color', 'points_of_origin'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (!isUndefinedOrEmpty(v[`${repeatingString}special_effects_toggle`])) {
finalSetAttrs[`${repeatingString}special_effects_toggle`] = '{{fx=@{special_effects_type}-@{special_effects_color} @{special_effects_points_of_origin}}}';
if (!isUndefinedOrEmpty(v[`${repeatingString}type`]) && v[`${repeatingString}type`] !== 'Ranged' && v[`${repeatingString}type`] !== 'Melee') {
finalSetAttrs[`${repeatingString}special_effects_type`] = v[`${repeatingString}type`];
}
if (!isUndefinedOrEmpty(v[`${repeatingString}color`])) {
finalSetAttrs[`${repeatingString}special_effects_color`] = v[`${repeatingString}color`];
}
if (!isUndefinedOrEmpty(v[`${repeatingString}points_of_origin`])) {
finalSetAttrs[`${repeatingString}special_effects_points_of_origin`] = v[`${repeatingString}points_of_origin`];
}
}
}
},
});
}
critDamage() {
getSetRepeatingItems('upgrade.critDamage', {
repeatingItems: ['repeating_attack', 'repeating_spell', 'repeating_trait', 'repeating_action', 'repeating_reaction', 'repeating_legendaryaction', 'repeating_lairaction', 'repeating_regionaleffect'],
collectionArrayAddItems: ['damage', 'damage_crit', 'second_damage', 'second_damage_crit'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (!v[`${repeatingString}damage_crit`] && v[`${repeatingString}damage`]) {
finalSetAttrs[`${repeatingString}damage_crit`] = v[`${repeatingString}damage`];
} else if (v[`${repeatingString}damage`] && v[`${repeatingString}damage_crit`]) {
finalSetAttrs[`${repeatingString}damage_crit`] = `${v[`${repeatingString}damage`]} + ${v[`${repeatingString}damage_crit`]}`;
}
if (!v[`${repeatingString}second_damage_crit`] && v[`${repeatingString}second_damage`]) {
finalSetAttrs[`${repeatingString}second_damage_crit`] = v[`${repeatingString}second_damage`];
} else if (v[`${repeatingString}second_damage`] && v[`${repeatingString}second_damage_crit`]) {
finalSetAttrs[`${repeatingString}second_damage_crit`] = `${v[`${repeatingString}second_damage`]} + ${v[`${repeatingString}second_damage_crit`]}`;
}
}
},
});
}
oldValueToNew(v, finalSetAttrs, repeatingString, newRepeatingString, field) {
finalSetAttrs[`${newRepeatingString}${field}`] = v[`${repeatingString}${field}`];
}
resourcesToTraits() {
getSetRepeatingItems('upgrade.resourcesToTraits', {
repeatingItems: ['repeating_resource'],
collectionArrayAddItems: ['name', 'uses', 'uses_max', 'toggle_details', 'recharge', 'extras_toggle', 'freetext', 'freeform'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
const fieldsToSwap = ['name', 'uses', 'uses_max', 'toggle_details', 'recharge', 'extras_toggle', 'freetext', 'freeform'];
for (const id of ids) {
for (const field of fieldsToSwap) {
this.oldValueToNew(v, finalSetAttrs, `${repeatingItem}_${id}_`, `repeating_trait_${generateRowID()}_`, field);
}
}
},
});
}
classFeaturesToTraits() {
getSetRepeatingItems('upgrade.classFeaturesToTraits', {
repeatingItems: ['repeating_classfeature'],
collectionArrayAddItems: ['name', 'uses', 'uses_max', 'recharge', 'saving_throw_toggle', 'saving_throw_condition', 'saving_throw_ability', 'saving_throw_bonus', 'saving_throw_vs_ability', 'saving_throw_failure', 'saving_throw_success', 'damage_toggle', 'damage', 'damage_ability', 'damage_bonus', 'damage_type', 'second_damage_toggle', 'second_damage', 'second_damage_ability', 'second_damage_bonus', 'second_damage_type', 'heal', 'heal_ability', 'heal_bonus', 'heal_query_toggle', 'extras_toggle', 'emote', 'freetext', 'freeform'],
callback: (v, finalSetAttrs, ids, repeatingItem) => {
const fieldsToSwap = ['name', 'uses', 'uses_max', 'recharge', 'saving_throw_toggle', 'saving_throw_condition', 'saving_throw_ability', 'saving_throw_bonus', 'saving_throw_vs_ability', 'saving_throw_failure', 'saving_throw_success', 'damage_toggle', 'damage', 'damage_ability', 'damage_bonus', 'damage_type', 'second_damage_toggle', 'second_damage', 'second_damage_ability', 'second_damage_bonus', 'second_damage_type', 'heal', 'heal_ability', 'heal_bonus', 'heal_query_toggle', 'extras_toggle', 'emote', 'freetext', 'display_text', 'freeform'];
for (const id of ids) {
for (const field of fieldsToSwap) {
this.oldValueToNew(v, finalSetAttrs, `${repeatingItem}_${id}_`, `repeating_trait_${generateRowID()}_`, field);
}
}
},
});
}
versionCompare(v1, v2, options) {
const lexicographical = options && options.lexicographical;
const zeroExtend = options && options.zeroExtend;
let v1parts = v1.split('.');
let v2parts = v2.split('.');
const isValidPart = (x) => {
return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
};
if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}
if (zeroExtend) {
while (v1parts.length < v2parts.length) {
v1parts.push('0');
}
while (v2parts.length < v1parts.length) {
v2parts.push('0');
}
}
if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}
for (let i = 0; i < v1parts.length; ++i) {
if (v2parts.length === i) {
return 1;
}
if (v1parts[i] === v2parts[i]) {
continue;
} else if (v1parts[i] > v2parts[i]) {
return 1;
} else {
return -1;
}
}
if (v1parts.length !== v2parts.length) {
return -1;
}
return 0;
}
upgrade() {
if (this.versionCompare(currentVersion, '2.1.0') < 0) {
npc.updateChallenge();
resistances.updateDamageVulnerabilities();
resistances.updateDamageResistances();
resistances.updateDamageImmunities();
resistances.updateConditionImmunities();
npc.updateLanguages();
npc.updateSenses();
}
if (this.versionCompare(currentVersion, '2.1.3') < 0) {
npc.updateType();
character.updateAlignment();
}
if (this.versionCompare(currentVersion, '2.1.5') < 0) {
npc.updateAC();
}
if (this.versionCompare(currentVersion, '2.1.10') < 0) {
savingThrows.update();
}
if (this.versionCompare(currentVersion, '2.1.13') < 0) {
equipment.weigh();
}
if (this.versionCompare(currentVersion, '2.1.15') < 0) {
this.displayTextForTraits();
}
if (this.versionCompare(currentVersion, '2.2.2') < 0) {
this.resourcesToTraits();
}
if (this.versionCompare(currentVersion, '2.2.4') < 0) {
abilityChecks.updateInitiative();
}
if (this.versionCompare(currentVersion, '2.2.5') < 0) {
equipment.weighAmmo();
}
if (this.versionCompare(currentVersion, '2.2.6') < 0) {
character.updateLevels();
this.extasToExtrasFix('repeating_attack');
this.extasToExtrasFix('repeating_action');
this.extasToExtrasFix('repeating_spell');
}
if (this.versionCompare(currentVersion, '2.3.3') < 0) {
attachers.update();
}
if (this.versionCompare(currentVersion, '2.4.2') < 0) {
abilities.updateModifiers();
actions.updateChatMacro('trait');
actions.updateChatMacro('action');
actions.updateChatMacro('reaction');
actions.updateChatMacro('legendaryaction');
}
if (this.versionCompare(currentVersion, '2.4.3') < 0) {
classFeatures.set();
}
if (this.versionCompare(currentVersion, '2.4.7') < 0) {
this.classFeaturesToTraits();
}
if (this.versionCompare(currentVersion, '2.4.8') < 0) {
this.fixRollTwo();
}
if (this.versionCompare(currentVersion, '2.4.12') < 0) {
this.armorPlusDexRemoval();
equipment.updateArmor();
}
if (this.versionCompare(currentVersion, '3.1.0') < 0) {
attacks.updateChatMacro();
}
if (this.versionCompare(currentVersion, '3.2.1') < 0) {
this.critDamage();
}
if (this.versionCompare(currentVersion, '3.2.3') < 0) {
resistances.updateDamageResistancesVar();
}
if (this.versionCompare(currentVersion, '3.5.0') < 0) {
spells.updateChatMacro();
}
if (this.versionCompare(currentVersion, '3.5.1') < 0) {
spells.updateSlots();
}
if (this.versionCompare(currentVersion, '3.6.1') < 0) {
npc.updateHD();
npc.switchTo();
}
if (this.versionCompare(currentVersion, '4.1.4') < 0) {
this.armorAbility();
this.actionComponents();
this.skillAbility();
}
if (this.versionCompare(currentVersion, '4.1.5') < 0) {
abilityChecks.updateSkill();
}
if (this.versionCompare(currentVersion, '4.2.0') < 0) {
character.updateD20Mod();
settings.updateShapedD20();
}
if (this.versionCompare(currentVersion, '4.2.1') < 0) {
this.actionComponentsToRemoveExtraFields();
abilityChecks.updateMacro();
this.removeToggleVar();
}
if (this.versionCompare(currentVersion, '4.2.3') < 0) {
equipment.updateArmor();
}
if (this.versionCompare(currentVersion, '4.4.0') < 0) {
savingThrows.updateCustomSavingThrows();
this.newAttackToggle();
spells.generateHigherLevelQueries();
}
if (this.versionCompare(currentVersion, '4.4.1') < 0) {
this.newAbilityDefaults();
}
if (this.versionCompare(currentVersion, '4.4.2') < 0) {
spells.updateShowHide();
}
if (this.versionCompare(currentVersion, '5.0.0') < 0) {
this.spellToTranslations();
}
if (this.versionCompare(currentVersion, '5.0.3') < 0) {
savingThrows.updateCustomSavingThrowToggle();
}
if (this.versionCompare(currentVersion, '5.0.4') < 0) {
this.defaultAbility();
}
if (this.versionCompare(currentVersion, '5.0.6') < 0) {
this.spellLevelForCantrips();
}
if (this.versionCompare(currentVersion, '5.2.3') < 0) {
this.hideFreetext();
}
if (this.versionCompare(currentVersion, '6.0.1') < 0) {
this.newAttackToggleTwo();
spells.update();
attacks.update();
actions.updateAll();
}
if (this.versionCompare(currentVersion, '6.0.4') < 0) {
this.spellEffectsNaming();
}
}
}
+34
View File
@@ -0,0 +1,34 @@
const SKILLS = {
ACROBATICS: 'dexterity',
ANIMALHANDLING: 'wisdom',
ARCANA: 'intelligence',
ATHLETICS: 'strength',
DECEPTION: 'charisma',
HISTORY: 'intelligence',
INSIGHT: 'wisdom',
INTIMIDATION: 'charisma',
INVESTIGATION: 'intelligence',
MEDICINE: 'wisdom',
NATURE: 'intelligence',
PERCEPTION: 'wisdom',
PERFORMANCE: 'charisma',
PERSUASION: 'charisma',
RELIGION: 'intelligence',
SLEIGHTOFHAND: 'dexterity',
STEALTH: 'dexterity',
SURVIVAL: 'wisdom',
};
const CLASSES = ['barbarian', 'bard', 'cleric', 'druid', 'fighter', 'monk', 'paladin', 'ranger', 'rogue', 'sorcerer', 'warlock', 'wizard'];
const ABILITIES = ['strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma'];
const TOGGLE_VARS = {
roll: '{{vs_ac=1}} @{roll_info} {{roll1=[[@{shaped_d20}cs>@{crit_range} + @{attack_formula}]]}} @{roll_setting}cs>@{crit_range} + @{attack_formula}]]}} {{targetAC=@{attacks_vs_target_ac}}} {{targetName=@{attacks_vs_target_name}}}',
saving_throw: '{{saving_throw_condition=@{saving_throw_condition}}} {{saving_throw_dc=@{saving_throw_dc}}} {{saving_throw_vs_ability=@{saving_throw_vs_ability}}} {{saving_throw_failure=@{saving_throw_failure}}} {{saving_throw_success=@{saving_throw_success}}} {{targetName=@{attacks_vs_target_name}}}',
damage: '{{damage=[[@{damage_formula}]]}} {{damage_type=@{damage_type}}} {{crit_damage=[[0d0 + @{damage_crit}[crit damage] @{damage_crit_formula}]]}}',
second_damage: '{{second_damage=[[@{second_damage_formula}]]}} {{second_damage_type=@{second_damage_type}}} {{second_crit_damage=[[0d0 + @{second_damage_crit}[crit damage] @{second_damage_crit_formula}]]}}',
heal: '{{heal=[[@{heal_formula}]]}}',
heal_query: '?{Heal Bonus Amount|}',
extras: '{{emote=@{emote}}} {{freetext=@{freetext}}} @{freeform}',
higher_level: '{{cast_as_level=@{higher_level_query}}}',
};
export { SKILLS, CLASSES, ABILITIES, TOGGLE_VARS };
@@ -0,0 +1,47 @@
/* global setAttrs:false, getAttrs:false, on:false, getSectionIDs:false, generateRowID:false, getTranslationByKey:false */
import { Abilities } from './Abilities';
const abilities = new Abilities();
abilities.setup();
import { AbilityChecks } from './AbilityChecks';
const abilityChecks = new AbilityChecks();
abilityChecks.setup();
import { Actions } from './Actions';
const actions = new Actions();
actions.setup();
import { Attachers } from './Attachers';
const attachers = new Attachers();
attachers.setup();
import { Attacks } from './Attacks';
const attacks = new Attacks();
attacks.setup();
import { Character } from './Character';
const character = new Character();
character.setup();
import { Equipment } from './Equipment';
const equipment = new Equipment();
equipment.setup();
import { ImportData } from './ImportData';
const importData = new ImportData();
importData.setup();
import { Initialize } from './Initialize';
const initialize = new Initialize();
initialize.setup();
import { Npc } from './Npc';
const npc = new Npc();
npc.setup();
import { ProficiencyBonus } from './ProficiencyBonus';
const proficiencyBonus = new ProficiencyBonus();
proficiencyBonus.setup();
import { Resistances } from './Resistances';
const resistances = new Resistances();
resistances.setup();
import { SavingThrows } from './SavingThrows';
const savingThrows = new SavingThrows();
savingThrows.setup();
import { Settings } from './Settings';
const settings = new Settings();
settings.setup();
import { Spells } from './Spells';
const spells = new Spells();
spells.setup();
@@ -0,0 +1,380 @@
import { TOGGLE_VARS } from './constants';
import { fromVOrFinalSetAttrs, getIntValue, getAbilityValue, addArithmeticOperator, getAbilityShortName, hasUpperCase, isUndefined, isUndefinedOrEmpty, exists } from './utilities';
const parseAttackComponent = (v, repeatingString, finalSetAttrs, options) => {
let parsed = v[`${repeatingString}parsed`];
if (isUndefinedOrEmpty(parsed)) {
parsed = finalSetAttrs[`${repeatingString}parsed`];
}
if (isUndefinedOrEmpty(parsed) || parsed.indexOf(options.parseName) === -1) {
let aTriggerFieldExists = false;
if (options.triggerFields) {
for (const triggerField of options.triggerFields) {
if (!isUndefinedOrEmpty(v[`${repeatingString}${triggerField}`])) {
aTriggerFieldExists = true;
}
}
}
if (aTriggerFieldExists && isUndefinedOrEmpty(v[repeatingString + options.toggleField])) {
finalSetAttrs[repeatingString + options.toggleField] = options.toggleFieldSetTo;
if (isUndefinedOrEmpty(finalSetAttrs[`${repeatingString}parsed`])) {
finalSetAttrs[`${repeatingString}parsed`] = '';
}
finalSetAttrs[`${repeatingString}parsed`] += ` ${options.parseName}`;
}
if (options.attackAbility && isUndefined(v[`${repeatingString}attack_ability`])) {
finalSetAttrs[`${repeatingString}attack_ability`] = v.default_ability;
}
if (options.addCastingModifier) {
if (!isUndefinedOrEmpty(v[`${repeatingString}damage`]) && isUndefined(v[`${repeatingString}damage_ability`])) {
finalSetAttrs[`${repeatingString}damage_ability`] = v.default_ability;
}
if (!isUndefinedOrEmpty(v[`${repeatingString}heal`]) && isUndefined(v[`${repeatingString}heal_ability`])) {
finalSetAttrs[`${repeatingString}heal_ability`] = v.default_ability;
}
}
if (options.addSecondCastingModifier) {
if (!isUndefinedOrEmpty(v[`${repeatingString}second_damage`]) && isUndefined(v[`${repeatingString}second_damage_ability`])) {
finalSetAttrs[`${repeatingString}second_damage_ability`] = v.default_ability;
}
}
}
};
const updateAttackToggle = (v, finalSetAttrs, repeatingString, options) => {
parseAttackComponent(v, repeatingString, finalSetAttrs, {
attackAbility: options.attackAbility,
parseName: 'attack',
toggleField: 'roll_toggle',
toggleFieldSetTo: TOGGLE_VARS.roll,
triggerFields: ['type', 'attack_bonus'],
});
let attackFormula = '';
const attackToggle = v[`${repeatingString}roll_toggle`];
let toHit = 0;
if (!attackToggle || attackToggle === TOGGLE_VARS.roll) {
const proficiency = v[`${repeatingString}proficiency`];
if (!proficiency || proficiency === 'on') {
const pb = getIntValue(v.pb);
toHit += pb;
attackFormula += `${pb}[proficient]`;
}
let attackAbility = v[`${repeatingString}attack_ability`];
if (isUndefined(attackAbility) && v[`${repeatingString}type`] === 'Melee Weapon') {
attackAbility = 'strength';
finalSetAttrs[`${repeatingString}attack_ability`] = attackAbility;
} else if (isUndefined(attackAbility) && v[`${repeatingString}type`] === 'Ranged Weapon') {
attackAbility = 'dexterity';
finalSetAttrs[`${repeatingString}attack_ability`] = attackAbility;
} else if (finalSetAttrs[`${repeatingString}attack_ability`]) {
attackAbility = finalSetAttrs[`${repeatingString}attack_ability`];
}
attackAbility = getAbilityValue(v, attackAbility);
if (exists(attackAbility)) {
toHit += attackAbility;
attackFormula += `${addArithmeticOperator(attackFormula, attackAbility)}[${getAbilityShortName(v[`${repeatingString}attack_ability`])}]`;
}
const attackBonus = getIntValue(v[`${repeatingString}attack_bonus`]);
if (exists(attackBonus)) {
toHit += attackBonus;
attackFormula += `${addArithmeticOperator(attackFormula, attackBonus)}[bonus]`;
}
if (exists(options.globalAttackBonus)) {
if (!isNaN(options.globalAttackBonus)) {
toHit += getIntValue(options.globalAttackBonus);
}
attackFormula += `${addArithmeticOperator(attackFormula, options.globalAttackBonus)}[${options.globalAttackBonusLabel}]`;
}
if (v[`${repeatingString}type`] === 'Melee Weapon') {
if (exists(options.globalMeleeAttackBonus)) {
if (!isNaN(options.globalMeleeAttackBonus)) {
toHit += getIntValue(options.globalMeleeAttackBonus);
}
attackFormula += `${addArithmeticOperator(attackFormula, options.globalMeleeAttackBonus)}[global melee attack bonus]`;
}
} else if (v[`${repeatingString}type`] === 'Ranged Weapon') {
if (exists(options.globalRangedAttackBonus)) {
if (!isNaN(options.globalRangedAttackBonus)) {
toHit += getIntValue(options.globalRangedAttackBonus);
}
attackFormula += `${addArithmeticOperator(attackFormula, options.globalRangedAttackBonus)}[global ranged attack bonus]`;
}
}
finalSetAttrs[`${repeatingString}attack_formula`] = attackFormula;
}
if (options.type === 'attack') {
finalSetAttrs[`${repeatingString}to_hit`] = toHit;
}
};
const updateSavingThrowToggle = (v, finalSetAttrs, repeatingString, options) => {
parseAttackComponent(v, repeatingString, finalSetAttrs, {
parseName: 'savingThrow',
toggleField: 'saving_throw_toggle',
toggleFieldSetTo: TOGGLE_VARS.saving_throw,
triggerFields: ['saving_throw_ability', 'saving_throw_bonus', 'saving_throw_vs_ability'],
});
if (fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}saving_throw_toggle`) === TOGGLE_VARS.saving_throw) {
let savingThrowDC = getIntValue(v.base_dc) + getIntValue(v.pb);
let savingThrowAbility = v[`${repeatingString}saving_throw_ability`];
if (isUndefined(savingThrowAbility) && v.default_ability) {
savingThrowAbility = v.default_ability;
finalSetAttrs[`${repeatingString}saving_throw_ability`] = v.default_ability;
}
savingThrowDC += getAbilityValue(v, savingThrowAbility);
if (options && options.bonusDC) {
savingThrowDC += getIntValue(options.bonusDC);
}
savingThrowDC += getIntValue(v[`${repeatingString}saving_throw_bonus`]);
finalSetAttrs[`${repeatingString}saving_throw_dc`] = savingThrowDC;
}
};
const updateDamageToggle = (v, finalSetAttrs, repeatingString, options) => {
parseAttackComponent(v, repeatingString, finalSetAttrs, {
addCastingModifier: exists(v[`${repeatingString}add_casting_modifier`]),
parseName: 'damage',
toggleField: 'damage_toggle',
toggleFieldSetTo: TOGGLE_VARS.damage,
triggerFields: ['damage', 'damage_ability', 'damage_bonus', 'damage_type'],
});
let damageString = '';
let damageFormula = '';
const damageToggle = v[`${repeatingString}damage_toggle`];
let damageAbility = v[`${repeatingString}damage_ability`];
let damageType;
if (!damageToggle || damageToggle === TOGGLE_VARS.damage) {
let damageAddition = 0;
const damage = v[`${repeatingString}damage`];
if (exists(damage)) {
damageString += damage;
damageFormula += `${damage}[damage]`;
}
if (isUndefined(damageAbility) && v[`${repeatingString}type`] === 'Melee Weapon') {
damageAbility = 'strength';
finalSetAttrs[`${repeatingString}damage_ability`] = damageAbility;
} else if (isUndefined(damageAbility) && v[`${repeatingString}type`] === 'Ranged Weapon') {
damageAbility = 'dexterity';
finalSetAttrs[`${repeatingString}damage_ability`] = damageAbility;
}
if (exists(damageAbility)) {
const damageAbilityValue = getAbilityValue(v, damageAbility);
if (exists(damageAbilityValue)) {
damageAddition += damageAbilityValue;
damageFormula += `${addArithmeticOperator(damageFormula, damageAbilityValue)}[${getAbilityShortName(v[`${repeatingString}damage_ability`])}]`;
}
}
const damageBonus = getIntValue(v[`${repeatingString}damage_bonus`]);
if (exists(damageBonus)) {
damageAddition += damageBonus;
damageFormula += `${addArithmeticOperator(damageFormula, damageBonus)}[bonus]`;
}
if (exists(options.globalDamageBonus)) {
if (!isNaN(options.globalDamageBonus)) {
damageAddition += getIntValue(options.globalDamageBonus);
} else {
damageString += `${addArithmeticOperator(damageString, options.globalDamageBonus)}`;
}
damageFormula += `${addArithmeticOperator(damageFormula, options.globalDamageBonus)}[global damage bonus]`;
}
if (options && exists(options.globalMeleeDamageBonus) && (v[`${repeatingString}type`] === 'Melee Weapon')) {
if (!isNaN(options.globalMeleeDamageBonus)) {
damageAddition += getIntValue(options.globalMeleeDamageBonus);
} else {
damageString += `${addArithmeticOperator(damageString, options.globalMeleeDamageBonus)}`;
}
damageFormula += `${addArithmeticOperator(damageFormula, options.globalMeleeDamageBonus)}[global melee damage bonus]`;
} else if (options && exists(options.globalRangedDamageBonus) && v[`${repeatingString}type`] === 'Ranged Weapon') {
if (!isNaN(options.globalRangedDamageBonus)) {
damageAddition += getIntValue(options.globalRangedDamageBonus);
} else {
damageString += `${addArithmeticOperator(damageString, options.globalRangedDamageBonus)}`;
}
damageFormula += `${addArithmeticOperator(damageFormula, options.globalRangedDamageBonus)}[global ranged damage bonus]`;
}
if (exists(damageAddition)) {
damageString += addArithmeticOperator(damageString, damageAddition);
}
damageType = v[`${repeatingString}damage_type`];
if (exists(damageType)) {
if (hasUpperCase(damageType)) {
damageType = damageType.toLowerCase();
finalSetAttrs[`${repeatingString}damage_type`] = damageType;
}
damageString += ` ${damageType}`;
}
}
if (!exists(damageFormula)) {
damageFormula = 0;
}
finalSetAttrs[`${repeatingString}damage_formula`] = damageFormula;
parseAttackComponent(v, repeatingString, finalSetAttrs, {
addSecondCastingModifier: exists(v[`${repeatingString}add_second_casting_modifier`]),
parseName: 'secondDamage',
toggleField: 'second_damage_toggle',
toggleFieldSetTo: TOGGLE_VARS.second_damage,
triggerFields: ['second_damage', 'second_damage_ability', 'second_damage_bonus', 'second_damage_type'],
});
let secondDamageFormula = '';
const secondDamageToggle = fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}second_damage_toggle`);
if (secondDamageToggle === TOGGLE_VARS.second_damage) {
let secondDamageAddition = 0;
const secondDamage = v[`${repeatingString}second_damage`];
if (exists(secondDamage)) {
damageString += ` + ${secondDamage}`;
secondDamageFormula += `${secondDamage}[second damage]`;
}
let secondDamageAbility = v[`${repeatingString}second_damage_ability`];
if (exists(secondDamageAbility)) {
secondDamageAbility = getAbilityValue(v, secondDamageAbility);
if (exists(secondDamageAbility)) {
secondDamageAddition += secondDamageAbility;
secondDamageFormula += `${addArithmeticOperator(secondDamageFormula, secondDamageAbility)}[${getAbilityShortName(v[`${repeatingString}second_damage_ability`])}]`;
}
}
const secondDamageBonus = getIntValue(v[`${repeatingString}second_damage_bonus`]);
if (exists(secondDamageBonus)) {
secondDamageAddition += secondDamageBonus;
secondDamageFormula += `${addArithmeticOperator(secondDamageFormula, secondDamageBonus)}[bonus]`;
}
if (exists(secondDamageAddition)) {
damageString += addArithmeticOperator(damageString, secondDamageAddition);
}
let secondDamageType = v[`${repeatingString}second_damage_type`];
if (exists(secondDamageType)) {
if (hasUpperCase(secondDamageType)) {
secondDamageType = secondDamageType.toLowerCase();
finalSetAttrs[`${repeatingString}second_damage_type`] = secondDamageType;
}
damageString += ` ${secondDamageType}`;
}
if (isUndefinedOrEmpty(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('damageProperties') === -1) {
const damageProperties = v[`${repeatingString}properties`];
if (exists(damageProperties)) {
if (damageProperties.indexOf('Versatile') !== -1) {
if (!exists(damageAbility)) {
damageAbility = 'strength';
}
finalSetAttrs[`${repeatingString}second_damage_ability`] = damageAbility;
finalSetAttrs[`${repeatingString}second_damage_type`] = damageType;
}
if (!finalSetAttrs[`${repeatingString}parsed`]) {
finalSetAttrs[`${repeatingString}parsed`] = '';
}
finalSetAttrs[`${repeatingString}parsed`] += ' damageProperties';
}
}
}
if (!exists(secondDamageFormula)) {
secondDamageFormula = 0;
}
finalSetAttrs[`${repeatingString}second_damage_formula`] = secondDamageFormula;
if (options.type === 'attack') {
finalSetAttrs[`${repeatingString}damage_string`] = damageString;
}
};
const updateHealToggle = (v, finalSetAttrs, repeatingString) => {
parseAttackComponent(v, repeatingString, finalSetAttrs, {
addCastingModifier: exists(v[`${repeatingString}add_casting_modifier`]),
parseName: 'heal',
toggleField: 'heal_toggle',
toggleFieldSetTo: TOGGLE_VARS.heal,
triggerFields: ['heal', 'heal_query_toggle'],
});
let healFormula = '';
const healToggle = v[`${repeatingString}heal_toggle`];
if (healToggle === TOGGLE_VARS.heal) {
if (!isUndefined(v[`${repeatingString}heal`])) {
healFormula = '@{heal}[heal]';
}
if (!isUndefined(v[`${repeatingString}heal_ability`])) {
const healAbility = getAbilityValue(v, v[`${repeatingString}heal_ability`]);
healFormula += `${addArithmeticOperator(healFormula, healAbility)}[${getAbilityShortName(v[`${repeatingString}heal_ability`])}]`;
}
if (!isUndefined(v[`${repeatingString}heal_bonus`])) {
const healBonus = getIntValue(v[`${repeatingString}heal_bonus`]);
healFormula += `${addArithmeticOperator(healFormula, healBonus)}[bonus]`;
}
if (!isUndefined(v.global_spell_heal_bonus)) {
if (healFormula) {
healFormula += ' + ';
}
healFormula += '@{global_spell_heal_bonus}[global spell heal bonus]';
}
if (v[`${repeatingString}heal_query_toggle`] === TOGGLE_VARS.heal_query) {
if (healFormula) {
healFormula += ' + ';
}
healFormula += '@{heal_query_toggle}[query amount]';
}
finalSetAttrs[`${repeatingString}heal_formula`] = healFormula;
}
};
const updateHigherLevelToggle = (v, finalSetAttrs, repeatingString) => {
parseAttackComponent(v, repeatingString, finalSetAttrs, {
addCastingModifier: exists(v[`${repeatingString}add_casting_modifier`]),
parseName: 'higherLevel',
toggleField: 'higher_level_toggle',
toggleFieldSetTo: TOGGLE_VARS.higher_level,
triggerFields: ['higher_level_dice', 'higher_level_die', 'second_higher_level_dice', 'second_higher_level_die', 'higher_level_heal'],
});
const higherLevelToggle = v[`${repeatingString}higher_level_toggle`];
if (exists(higherLevelToggle) && higherLevelToggle === TOGGLE_VARS.higher_level) {
const spellLevel = getIntValue(v[`${repeatingString}spell_level`]);
finalSetAttrs[`${repeatingString}higher_level_query`] = `@{higher_level_query_${spellLevel}}`;
const damageToggle = v[`${repeatingString}damage_toggle`];
if (damageToggle && damageToggle === TOGGLE_VARS.damage) {
const higherLevelDamage = `((@{higher_level_query} - ${spellLevel}) * @{higher_level_dice})@{higher_level_die}[higher lvl]`;
finalSetAttrs[`${repeatingString}damage_formula`] += addArithmeticOperator(finalSetAttrs[`${repeatingString}damage_formula`], higherLevelDamage);
finalSetAttrs[`${repeatingString}damage_crit_formula`] = higherLevelDamage;
}
const secondDamageToggle = v[`${repeatingString}second_damage_toggle`];
if (secondDamageToggle && secondDamageToggle === TOGGLE_VARS.second_damage) {
const higherLevelSecondDamage = `((@{higher_level_query} - ${spellLevel}) * @{second_higher_level_dice})@{second_higher_level_die}[higher lvl]`;
finalSetAttrs[`${repeatingString}second_damage_formula`] += addArithmeticOperator(finalSetAttrs[`${repeatingString}second_damage_formula`], higherLevelSecondDamage);
finalSetAttrs[`${repeatingString}second_damage_crit_formula`] = higherLevelSecondDamage;
}
const healToggle = v[`${repeatingString}heal_toggle`];
if (healToggle && healToggle === TOGGLE_VARS.heal) {
if (finalSetAttrs[`${repeatingString}heal_formula`]) {
finalSetAttrs[`${repeatingString}heal_formula`] += ' + ';
}
finalSetAttrs[`${repeatingString}heal_formula`] += `((@{higher_level_query} - ${spellLevel}) * @{higher_level_dice})@{higher_level_die}[higher lvl] + (@{higher_level_heal} * (@{higher_level_query} - ${spellLevel}))[higher lvl flat amount]`;
}
}
};
export { updateAttackToggle, updateSavingThrowToggle, updateDamageToggle, updateHealToggle, updateHigherLevelToggle };
+411
View File
@@ -0,0 +1,411 @@
/* global setAttrs:false, getAttrs:false, getSectionIDs:false */
const capitalize = (string) => {
return string.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.substr(1);
});
};
const camelize = (str) => {
return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, (match, index) => {
if (+match === 0) return '';
return index === 0 ? match.toLowerCase() : match.toUpperCase();
});
};
const firstThree = (string) => {
return string.substring(0, 3);
};
const round = (value, places) => {
return +(`${Math.round(`${value}e+${places}`)}e-${places}`);
};
const isUndefined = (value) => {
if (typeof value === 'undefined') {
return true;
}
return false;
};
const isUndefinedOrEmpty = (value) => {
if (typeof value === 'undefined' || value === '') {
return true;
}
return false;
};
const isEmpty = (obj) => {
for (const prop in obj) {
if (obj.hasOwnProperty(prop)) {
return false;
}
}
return true;
};
const exists = (value) => {
if (isUndefinedOrEmpty(value) || value === '' || value === '0' || value === 0) {
return false;
}
return true;
};
const getIntValue = (value, defaultValue) => {
if (!defaultValue) {
defaultValue = 0;
}
if (value === 0 || value === '0') {
return 0;
}
return parseInt(value, 10) || defaultValue;
};
const getFloatValue = (value, defaultValue) => {
if (!defaultValue) {
defaultValue = 0;
}
return parseFloat(value) || defaultValue;
};
const getAbilityMod = (score) => {
return Math.floor((getIntValue(score) - 10) / 2);
};
const getAbilityName = (varName) => {
if (!varName) {
return 'strength';
} else if (typeof varName === 'string') {
varName = varName.replace(/\W/g, '');
}
return varName;
};
const getAbilityValue = (v, varName) => {
if (exists(varName)) {
varName = getAbilityName(varName);
return getIntValue(v[`${varName}_mod`], 0);
}
return 0;
};
const getAbilityShortName = (varName, capital) => {
if (!varName) {
return 'Str';
}
varName = varName.replace(/\W/g, '');
if (capital) {
varName = capitalize(varName);
}
return firstThree(varName);
};
const getRepeatingInfo = (leadingString, eventInfo) => {
const re = new RegExp(`${leadingString}_(-[a-zA-Z0-9\-]*)_(.*)`);
const match = eventInfo.sourceAttribute.match(re);
let result;
if (match && match[1] && match[2]) {
result = {
rowId: match[1],
field: match[2],
};
}
return result;
};
const setFinalAttrs = (v, finalSetAttrs, name, callback) => {
if (!isEmpty(finalSetAttrs)) {
for (const key in finalSetAttrs) {
if (finalSetAttrs.hasOwnProperty(key)) {
if (v[key] === finalSetAttrs[key]) {
delete finalSetAttrs[key];
}
}
}
if (!isEmpty(finalSetAttrs)) {
console.info(name, 'setFinalAttrs', finalSetAttrs);
}
if (!isEmpty(finalSetAttrs)) {
if (callback) {
setAttrs(finalSetAttrs, {}, callback);
} else {
setAttrs(finalSetAttrs);
}
}
}
};
const fromVOrFinalSetAttrs = (v, finalSetAttrs, value) => {
if (exists(finalSetAttrs[value])) {
return finalSetAttrs[value];
}
return v[value];
};
const hasUpperCase = (string) => {
return (/[A-Z]/.test(string));
};
const ordinalSpellLevel = (level) => {
let spellLevel = '';
level = getIntValue(level);
if (level === 0) {
spellLevel = 'CANTRIP';
} else {
switch (level % 10) {
case 1:
spellLevel = `${level}ST_LEVEL`;
break;
case 2:
spellLevel = `${level}ND_LEVEL`;
break;
case 3:
spellLevel = `${level}RD_LEVEL`;
break;
default:
spellLevel = `${level}TH_LEVEL`;
break;
}
}
return spellLevel;
};
const addArithmeticOperator = (string, number) => {
let value = number;
if (string) {
if (number < 0) {
value = ` - ${Math.abs(number)}`;
} else {
value = ` + ${number}`;
}
}
return value;
};
const showSign = (value) => {
if (value >= 0) {
value = `+${value}`;
}
return value;
};
const numberWithCommas = (x) => {
const parts = x.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
};
const lowercaseDamageTypes = (string) => {
if (!string) {
string = '';
}
return string
.replace('Acid', 'acid')
.replace('Cold', 'cold')
.replace('Fire', 'fire')
.replace('Force', 'force')
.replace('Lightning', 'lightning')
.replace('Necrotic', 'necrotic')
.replace('Poison', 'poison')
.replace('Psychic', 'psychic')
.replace('Radiant', 'radiant')
.replace('Thunder', 'thunder')
.replace('Bludgeoning', 'bludgeoning')
.replace('Piercing', 'piercing')
.replace('Slashing', 'slashing')
.replace('And', 'and')
.replace('From', 'from')
.replace('Nonmagical', 'nonmagical')
.replace('Weapons', 'weapons')
.replace('That', 'that')
.replace('Aren\'t', 'aren\'t')
.replace('Silvered', 'silvered')
.replace('Adamantine', 'adamantine');
};
const getSetItems = (name, obj) => {
const collectionArray = obj.collectionArray || [];
const finalSetAttrs = {};
getAttrs(collectionArray, (v) => {
if (obj.callback) {
obj.callback(v, finalSetAttrs);
}
setFinalAttrs(v, finalSetAttrs, name, () => {
if (obj.setFinalAttrsCallback) {
obj.setFinalAttrsCallback();
}
});
if (obj.returnCallback) {
obj.returnCallback();
}
});
};
const getSetRepeatingItems = (name, obj) => {
const collectionArray = obj.collectionArray || [];
const finalSetAttrs = {};
if (obj.repeatingItems) {
for (const repeatingItem of obj.repeatingItems) {
getSectionIDs(repeatingItem, (ids) => {
if (obj.rowId) {
ids = [];
ids.push(obj.rowId);
}
if (ids) {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (obj.collectionArrayAddItems) {
for (const addItem of obj.collectionArrayAddItems) {
collectionArray.push(`${repeatingString}${addItem}`);
}
}
if (obj.itemsToPush) {
for (const itemToPush of obj.itemsToPush) {
collectionArray.push(`${repeatingString}${itemToPush}_${obj.itemToPushSuffix}`);
}
}
}
}
getAttrs(collectionArray, (v) => {
if (obj.callback) {
obj.callback(v, finalSetAttrs, ids, repeatingItem);
}
setFinalAttrs(v, finalSetAttrs, name, () => {
if (obj.setFinalAttrsCallback) {
obj.setFinalAttrsCallback();
}
});
if (obj.returnCallback) {
obj.returnCallback();
}
});
});
}
}
};
const sumRepeating = (options, sumItems) => {
const repeatingItem = `repeating_${options.collection}`;
let collectionArray = [];
const finalSetAttrs = {};
getSectionIDs(repeatingItem, (ids) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
collectionArray.push(repeatingString + options.toggle);
if (options.qty) {
collectionArray.push(repeatingString + options.qty);
}
for (const sumItem of sumItems) {
finalSetAttrs[sumItem.totalField] = 0;
if (sumItem.totalFieldSecondary) {
finalSetAttrs[sumItem.totalFieldSecondary] = 0;
}
collectionArray.push(repeatingString + sumItem.fieldToAdd);
if (sumItem.bonus) {
collectionArray.push(repeatingString + sumItem.bonus);
}
if (sumItem.armorType) {
collectionArray.push(repeatingString + sumItem.armorType);
}
}
}
if (options.getExtraFields) {
collectionArray = collectionArray.concat(options.getExtraFields);
}
getAttrs(collectionArray, (v) => {
let dexMod = 0;
if (options.collection === 'armor') {
dexMod = getIntValue(v.dexterity_mod);
}
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
const qty = getIntValue(v[repeatingString + options.qty], 1);
for (const sumItem of sumItems) {
let fieldToAdd = getFloatValue(v[repeatingString + sumItem.fieldToAdd]);
if (sumItem.bonus) {
fieldToAdd += getFloatValue(v[repeatingString + sumItem.bonus]);
}
if (sumItem.armorType) {
if (!v[repeatingString + sumItem.armorType] || v[repeatingString + sumItem.armorType] === 'Light Armor') {
fieldToAdd += dexMod;
} else if (v[repeatingString + sumItem.armorType] === 'Medium Armor') {
const mediumArmorDexMod = getIntValue(v.medium_armor_max_dex, 2);
fieldToAdd += Math.min(mediumArmorDexMod, dexMod);
}
}
let itemTotal = round((qty * fieldToAdd), 2);
itemTotal = round(itemTotal, 2);
if (sumItem.itemTotal) {
finalSetAttrs[repeatingString + sumItem.itemTotal] = itemTotal;
}
const toggle = v[repeatingString + options.toggle];
if (toggle !== 0 && toggle !== '0') {
let addToPrimary = true;
let addToSecondary = false;
if (sumItem.armorType) {
if (v[repeatingString + sumItem.armorType] === 'Shield' || v[repeatingString + sumItem.armorType] === 'AC') {
addToSecondary = true;
} else if (v[repeatingString + sumItem.armorType] === 'Unarmored') {
addToPrimary = false;
addToSecondary = true;
}
}
if (addToPrimary) {
finalSetAttrs[sumItem.totalField] += itemTotal;
}
if (addToSecondary) {
finalSetAttrs[sumItem.totalFieldSecondary] += itemTotal;
}
}
}
}
for (const sumItem of sumItems) {
if (sumItem.totalField && !exists(finalSetAttrs[sumItem.totalField])) {
finalSetAttrs[sumItem.totalField] = 0;
}
if (sumItem.totalFieldSecondary && !exists(finalSetAttrs[sumItem.totalFieldSecondary])) {
finalSetAttrs[sumItem.totalFieldSecondary] = 0;
}
}
if (options.collection === 'armor' && !getIntValue(v.is_npc)) {
finalSetAttrs.ac_unarmored_calc += 10 + dexMod + getAbilityValue(v, v.ac_unarmored_ability);
finalSetAttrs.AC = Math.max(finalSetAttrs.ac_armored_calc, finalSetAttrs.ac_unarmored_calc);
}
setFinalAttrs(v, finalSetAttrs, 'sumRepeating');
});
});
};
const getSkillIdByStorageName = (v, repeatingItem, ids, prop) => {
for (const id of ids) {
const repeatingString = `${repeatingItem}_${id}_`;
if (v[`${repeatingString}storage_name`] === prop || v[`${repeatingString}storage_name`] === camelize(prop)) {
return id;
}
}
};
const setCritDamage = (v, finalSetAttrs, repeatingString) => {
if (!v[`${repeatingString}damage_crit`] && v[`${repeatingString}damage`]) {
finalSetAttrs[`${repeatingString}damage_crit`] = v[`${repeatingString}damage`];
}
if (!v[`${repeatingString}second_damage_crit`] && v[`${repeatingString}second_damage`]) {
finalSetAttrs[`${repeatingString}second_damage_crit`] = v[`${repeatingString}second_damage`];
}
};
const updateHD = (v, finalSetAttrs, hd) => {
for (const key in hd) {
if (hd.hasOwnProperty(key)) {
if (hd[key] && hd[key] !== 0) {
finalSetAttrs[`hd_${key}_max`] = hd[key];
finalSetAttrs[`hd_${key}_query`] = '?{HD';
for (let x = 1; x <= hd[key]; x++) {
finalSetAttrs[`hd_${key}_query`] += `|${x}`;
}
finalSetAttrs[`hd_${key}_query`] += '}';
finalSetAttrs[`hd_${key}_toggle`] = 1;
} else {
if (!isUndefinedOrEmpty(v[`hd_${key}_max`])) {
finalSetAttrs[`hd_${key}_max`] = 0;
}
if (!isUndefinedOrEmpty(v[`hd_${key}_query`])) {
finalSetAttrs[`hd_${key}_query`] = '';
}
if (exists(v[`hd_${key}_toggle`])) {
finalSetAttrs[`hd_${key}_toggle`] = 0;
}
}
}
}
};
export { capitalize, camelize, firstThree, round, isUndefined, isUndefinedOrEmpty, isEmpty, exists, getIntValue, getFloatValue, getAbilityMod, getAbilityName, getAbilityValue, getAbilityShortName, getRepeatingInfo, setFinalAttrs, fromVOrFinalSetAttrs, hasUpperCase, ordinalSpellLevel, addArithmeticOperator, showSign, numberWithCommas, lowercaseDamageTypes, getSetItems, getSetRepeatingItems, sumRepeating, getSkillIdByStorageName, setCritDamage, updateHD };
+3
View File
@@ -0,0 +1,3 @@
const currentVersion = '6.0.4';
export { currentVersion };
+649 -637
View File
File diff suppressed because it is too large Load Diff
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+161 -149
View File
@@ -1,83 +1,82 @@
{
"10_DAYS":"10 days",
"10_MINUTES":"10 minutes",
"12_HOURS":"12 hours",
"1ST":"1st",
"1ST_LEVEL":"1st-level",
"1_ACTION":"1 action",
"1_BONUS_ACTION":"1 bonus action",
"1_HOUR":"1 hour",
"1_MINUTE":"1 minutes",
"1_REACTION":"1 reaction",
"1_ROUND":"1 round",
"24_HOURS":"24 hours",
"2ND":"2nd",
"2ND_LEVEL":"2nd-level",
"30_DAYS":"30 days",
"3RD":"3rd",
"3RD_LEVEL":"3rd-level",
"4TH":"4th",
"4TH_LEVEL":"4th-level",
"5TH":"5th",
"5TH_LEVEL":"5th-level",
"6TH":"6th",
"6TH_LEVEL":"6th-level",
"7TH":"7th",
"7TH_LEVEL":"7th-level",
"7_DAYS":"7 days",
"8TH":"8th",
"8TH_LEVEL":"8th-level",
"8_HOURS":"8 hours",
"9TH":"9th",
"9TH_LEVEL":"9th-level",
"10_DAYS":"10 Tage",
"10_MINUTES":"10 Minuten",
"12_HOURS":"12 Stunden",
"1ST":"1.",
"1ST_LEVEL":"Stufe 1",
"1_ACTION":"1 Aktion",
"1_BONUS_ACTION":"1 Bonusaktion",
"1_HOUR":"1 Stunde",
"1_MINUTE":"1 Minute",
"1_REACTION":"1 Reaktion",
"1_ROUND":"1 Runde",
"24_HOURS":"24 Stunden",
"2ND":"2.",
"2ND_LEVEL":"Stufe 2",
"30_DAYS":"30 Tage",
"3RD":"3.",
"3RD_LEVEL":"Stufe 3",
"4TH":"4.",
"4TH_LEVEL":"Stufe 4",
"5TH":"5.",
"5TH_LEVEL":"Stufe 5",
"6TH":"6.",
"6TH_LEVEL":"Stufe 6",
"7TH":"7.",
"7TH_LEVEL":"Stufe 7",
"7_DAYS":"7 Tage",
"8TH":"8.",
"8TH_LEVEL":"Stufe 8",
"8_HOURS":"8 Stunden",
"9TH":"9.",
"9TH_LEVEL":"Stufe 9",
"ABILITY":"Fähigkeit",
"ABILITY_CHECK":"Ability check",
"ABILITY_CHECKS":"Fähigkeits-Check",
"ABILITY_CHECK":"Fähigkeits-Check",
"ABILITY_CHECKS":"Fähigkeits-Checks",
"ABILITY_CHECKS_QUERY":"Ability checks query",
"ABILITY_SCORES":"Ability scores",
"ABILITY_SCORES":"Fähigkeitswerte",
"ABJURATION":"Bannzauber",
"AC":"RK",
"ACID":"acid",
"ACID":"Säure",
"ACROBATICS":"Akrobatik",
"ACTION":"Aktion",
"ACTIONS":"Aktionen",
"AC_ARMORED":"Gepanzerte-RK",
"AC_UNARMORED":"Ungepanzerte-RK",
"AC_UNARMORED_ABILITY":"Ungepanzerte Fähigkeit",
"ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS":"Add half proficiency<br>to unproficient saving throws",
"ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS":"Halben Befähigunsbonus zu nicht befähigten Rettungswürfen addieren",
"ADVANTAGE":"Vorteil",
"AGE":"Alter",
"ALIGNMENT":"Gesinnung",
"ALL":"Alles",
"AMMO":"Munition",
"AMMO_AUTO_USE":"Automatically use ammo",
"AMMO_AUTO_USE":"Benutze Munition automatisch",
"AMMO_WEIGHT":"Munitionsgewicht",
"AMPHIBIOUS":"Amphibious",
"AMPHIBIOUS":"Amphibisch",
"ANIMALHANDLING":"Umgang mit Tieren",
"API":"API",
"APPEARANCE":"Aussehen",
"ARCANA":"Arkanes",
"ARMOR":"Rüstung",
"ARMORED_AND_UNARMORED":"Panzer und Ungepanzerten",
"ARMOR_CLASS":"Rüstungsklasse",
"ARROWS":"Arrows",
"ARMORED_AND_UNARMORED":"Gepanzert und ungepanzert",
"ARMOR_CLASS":"RK",
"ARROWS":"Pfeile",
"AS":"as",
"ATHLETICS":"Athletik",
"ATK":"ATT",
"ATTACHERS":"Attachers",
"ATTACK":"Angriff",
"ATTACKS":"Angriffe",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"AVERAGE_OF_ABILITIES":"Average of the highest 1 or 2 abilities",
"BACKGROUND":"Hintergrund",
"BARBARIAN":"Barbar",
"BARD":"Barde",
"BASE_DC":"Base DC",
"BIG":"Big",
"BITE":"Bite",
"BASE_DC":"Basis-Schwierigkeitsgrad",
"BIG":"Gross",
"BITE":"Biss",
"BLINDSIGHT":"Blindsicht",
"BLIND_BEYOND":"Blind danach",
"BLIND_BEYOND":"Blind ausserhalb",
"BLUDGEONING":"bludgeoning",
"BONDS":"Verpflichtungen",
"BONUS":"Bonus",
@@ -86,13 +85,13 @@
"BONUSES_AND_PENALTIES_TOOLTIP":"Auto add a bonus\/penalty to rolls made using the sheet macros.<br>Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter \"d4cs0cf0\" in both attack roll fields, and the saving throw one",
"BREAK_TIES":"Break ties",
"BURROW":"Graben",
"CANCEL":"Cancel",
"CANCEL":"Abbrechen",
"CANTRIP":"Zaubertrick",
"CANTRIPS":"Zaubertricks",
"CAN_HAVE":"Kann haben",
"CARRIED":"Getragen",
"CARRYING_CAPACITY":"Trage-Kapazität",
"CARRYING_PUSH_DRAG_LIFT":"Ziehen\/Schieben\/Heben",
"CARRYING_PUSH_DRAG_LIFT":"Ziehen\/Schieben\/<br>Heben",
"CASTERS_FULL":"Voll (9. ebene: Barde, Kleriker, Druide, Hexenmeister, Zauberer)",
"CASTERS_HALF":"Hälfte (5. ebene: Paladin, Waldläufer)",
"CASTERS_THIRD":"Dritte (3. ebene: Arcane Urbilder)",
@@ -107,7 +106,7 @@
"CHECK_BONUS":"Check-Bonus",
"CLASS":"Klasse",
"CLASS_AND_LEVEL":"Klasse & Stufe",
"CLASS_AND_LEVEL_PLACEHOLDER":"Generated after adding a class on the \"Character\" tab",
"CLASS_AND_LEVEL_PLACEHOLDER":"Generiert nach Hinzufügen einer Klasse im \"Charakter\"-Tab",
"CLASS_FEATURE_ACTION_SURGE":"Action Surge",
"CLASS_FEATURE_ACTION_SURGE_TEXT":"On your turn, you can take one additional action on top of your regular action and a possible bonus action.",
"CLASS_FEATURE_ARCANE_RECOVERY":"Arcane Recovery",
@@ -319,8 +318,8 @@
"COIN_CONVERSION_GP_PER_EP":"Elektrum pro Gold (2)",
"COIN_CONVERSION_GP_PER_PP":"Gold pro Platinum (10)",
"COIN_CONVERSION_GP_PER_SP":"Silber pro Gold (10)",
"COLD":"cold",
"COLOR":"Color",
"COLD":"Kälte",
"COLOR":"Farbe",
"COMPONENTS":"Komponenten",
"COMPONENTS_M":"M",
"COMPONENTS_S":"S",
@@ -332,25 +331,25 @@
"CON":"Kon",
"CONC":"Konz.",
"CONCENTRATION":"Konzentration",
"CONCENTRATION_UP_TO_10_MINUTES":"Concentration, up to 10 minute",
"CONCENTRATION_UP_TO_12_HOURS":"Concentration, up to 12 hours",
"CONCENTRATION_UP_TO_1_HOUR":"Concentration, up to 1 hour",
"CONCENTRATION_UP_TO_1_MINUTE":"Concentration, up to 1 minute",
"CONCENTRATION_UP_TO_1_ROUND":"Concentration, up to 1 round",
"CONCENTRATION_UP_TO_24_HOURS":"Concentration, up to 24 hours",
"CONCENTRATION_UP_TO_2_HOURS":"Concentration, up to 2 hours",
"CONCENTRATION_UP_TO_6_ROUNDS":"Concentration, up to 6 rounds",
"CONCENTRATION_UP_TO_8_HOURS":"Concentration, up to 8 hours",
"CONDENSE":"Condense",
"CONDITION_IMMUNITIES":"Konditionen Immunitäten",
"CONCENTRATION_UP_TO_10_MINUTES":"Konzentration, bis zu 10 Minuten",
"CONCENTRATION_UP_TO_12_HOURS":"Konzentration, bis zu 12 Stunden",
"CONCENTRATION_UP_TO_1_HOUR":"Konzentration, bis zu 1 Stunde",
"CONCENTRATION_UP_TO_1_MINUTE":"Konzentration, bis zu 1 Minute",
"CONCENTRATION_UP_TO_1_ROUND":"Konzentration, bis zu 1 Runde",
"CONCENTRATION_UP_TO_24_HOURS":"Konzentration, bis zu 24 Stunden",
"CONCENTRATION_UP_TO_2_HOURS":"Konzentration, bis zu 2 Stunden",
"CONCENTRATION_UP_TO_6_ROUNDS":"Konzentration, bis zu 6 Runden",
"CONCENTRATION_UP_TO_8_HOURS":"Konzentration, bis zu 8 Stunden",
"CONDENSE":"Komprimiert",
"CONDITION_IMMUNITIES":"Konditions-Immunitäten",
"CONJURATION":"Beschwörung",
"CONSTITUTION":"Konstitution",
"CONTENT":"Inhalt",
"COPPER_PIECES":"Copper pieces",
"COPPER_PIECES":"Kupfermünzen",
"CORE":"Kern",
"CRIT":"Krit",
"CRIT_ATTACHER_TOOLTIP":"Select one or more other categories and crit to have this message only show when a crit occurs for that category. This will not work for freeform.",
"CRIT_DAMAGE_TOOLTIP":"Determines the damage to roll for a crit. Normal weapon damage is not included.",
"CRIT_DAMAGE_TOOLTIP":"Bestimmt den Schaden, der für einen Krit zusätzlich gewürfelt wird. Standardmässig ist dies der normale Waffenschaden.",
"CRIT_RANGE":"Krit-Ab",
"CURRENT":"Aktuell",
"CUSTOM":"Benutzerdef.",
@@ -362,12 +361,12 @@
"DAMAGE_VULNERABILITIES":"Schadens-Verwundbarkeiten",
"DARKVISION":"Dunkelsicht",
"DC":"SG",
"DEATH":"Death",
"DEATH":"Tod",
"DEATH_SAVES":"Todesrettung",
"DEATH_SAVING_THROW":"Todesrettung",
"DEATH_SAVING_THROWS":"Todesrettungswürfe",
"DECEPTION":"Täuschung",
"DEFAULT_ABILITY":"Standardfähigkeit",
"DEFAULT_ABILITY":"Standard-<br>fähigkeit",
"DEFAULT_ABILITY_TOOLTIP":"This will set the ability for saving throw DCs when importing a Spell or Attack. If \"Add Casting Modifier\" is also set on the importing item it will apply to the damage ability or heal ability as well.",
"DEX":"Ges",
"DEXTERITY":"Geschick",
@@ -377,12 +376,12 @@
"DISPLAY_TEXT":"Display text",
"DIVINATION":"Erkenntniszauber",
"DMG":"DMG",
"DONT":"Nacht",
"DRAGON":"Dragon",
"DONT":"Nicht zum Tracker schicken",
"DRAGON":"Drache",
"DRUID":"Druide",
"DURATION":"Dauer",
"EFFECT":"Effekt",
"ELECTRUM_PIECES":"Electrum pieces",
"ELECTRUM_PIECES":"Elektrummünzen",
"EMOTE":"Emote",
"ENCHANTMENT":"Verzauberung",
"ENCUMBERED":"Beladen",
@@ -390,7 +389,7 @@
"EQUIPMENT":"Ausrüstung",
"EVERY":"every",
"EVOCATION":"Hervorrufung",
"EXHAUSTION_LEVEL":"Erschöpfungsstufe",
"EXHAUSTION_LEVEL":"Erschöpfung",
"EXHAUSTION_LEVEL_1":"Nachteil auf Fähigkeitschecks",
"EXHAUSTION_LEVEL_2":"Geschwindigkeit halbiert",
"EXHAUSTION_LEVEL_3":"Nachteil auf Angriffswürfe & Rettungswürfe",
@@ -399,70 +398,71 @@
"EXHAUSTION_LEVEL_6":"Tod",
"EXPERIENCE_POINTS":"Erfahrungspunkte",
"EXPERTISE":"Sachverstand",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Augen",
"FAILURES":"Fehlschläge",
"FEATURES":"Talente",
"FEATURES_AND_TRAITS":"Talente & Fertigkeiten",
"FIELD":"Field",
"FIELD":"Feld",
"FIGHTER":"Kämpfer",
"FILTERS":"Filters",
"FILTERS":"Filter",
"FINESSE":"Finesse",
"FIRE":"fire",
"FIRE":"Feuer",
"FLAT_HEAL":"Einfache Heilung",
"FLAWS":"Schwachstellen",
"FLY":"Fliegen",
"FORCE":"force",
"FORT":"Fort",
"FORTITUDE":"Fortitude",
"FORTITUDE":"Zähigkeit",
"FREEFORM":"Freiform",
"FREETEXT":"Freitext",
"GARGANTUAN":"Gargantuan",
"GENDER":"Geschlecht",
"GENERATE_SKILLS":"Fertigkeiten erzeugen",
"GOLD_PIECES":"Gold pieces",
"GOLD_PIECES":"Goldmünzen",
"HAIR":"Haar",
"HALFLING_LUCK":"Halblings Glück",
"HALF_DAMAGE":"half damage",
"HALFLING_LUCK":"Halblingsglück",
"HALF_DAMAGE":"Schaden halbiert",
"HEAL":"Heilung",
"HEAL_FOR":"Heal for",
"HEAL_FOR":"Heile um",
"HEAVY_ARMOR":"Schwere Rüstung",
"HEIGHT":"Höhe",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO":"Information verbergen",
"HIDE_INFO_ABILITY_CHECKS":"Verberge Fähigkeits-Checks",
"HIDE_INFO_ATTACK":"Verberge Angriff",
"HIDE_INFO_DAMAGE":"Verberge Schaden",
"HIDE_INFO_EFFECT":"Verberge Effekt",
"HIDE_INFO_FREETEXT":"Verberge Freitext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
"HIDE_INFO_SAVING_THROW_DC":"Hide saving throw DC",
"HIDE_INFO_SAVING_THROW_FAILURE":"Hide saving throw failure",
"HIDE_INFO_SAVING_THROW_SUCCESS":"Hide saving throw success",
"HIDE_INFO_SPELL_CONTENT":"Hide spell content",
"HIDE_INFO_RECHARGE":"Verberge Aufladung",
"HIDE_INFO_SAVING_THROWS":"Verberge Rettungswürfe",
"HIDE_INFO_SAVING_THROW_DC":"Verberge Rettungswurf-SG",
"HIDE_INFO_SAVING_THROW_FAILURE":"Verberge Rettungswurf-Erfolg",
"HIDE_INFO_SAVING_THROW_SUCCESS":"Verberge Rettungswurf-Fehlschlag",
"HIDE_INFO_SPELL_CONTENT":"Verberge Zauberinhalt",
"HIGHER_LEVEL":"Höhere Stufe",
"HISTORY":"Geschichte",
"HIT_DICE":"Trefferwürfel",
"HIT_POINTS":"Trefferpunkte",
"HIT_POINTS_ROLLED":"Hit points rolled",
"HIT_DICE":"TW",
"HIT_POINTS":"TP",
"HIT_POINTS_ROLLED":"Gewürfelte TP",
"HIT_POINTS_TEMP":"Temp TP",
"HIT_POINTS_TEMPORARY":"Temporary hit points",
"HOUSERULES":"Houserules",
"HIT_POINTS_TEMPORARY":"Temporäre Trefferpunkte",
"HOUSERULES":"Hausregeln",
"HOVER":"Schweben",
"HUGE":"Enorm",
"IDEALS":"Ideale",
"IF_THE_TARGET_IS":"If the target is",
"IF_THE_TARGET_IS":"Wenn das Ziel",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"IMPORT":"Importiere",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
"INITIATIVE_BONUS":"Initiativbonus",
"INSIGHT":"Einschätzen",
"INSPIRATION":"Inspiration",
"INSTANTANEOUS":"Instantaneous",
"INSTANTANEOUS_OR_1_HOUR":"Instantaneous or 1 hour",
"INSTANTANEOUS":"Sofort",
"INSTANTANEOUS_OR_1_HOUR":"Sofort oder 1 Stunde",
"INT":"Int",
"INTELLIGENCE":"Intelligenz",
"INTIMIDATION":"Einschüchtern",
@@ -471,18 +471,18 @@
"LAIR_ACTIONS":"Lair Actions",
"LANGUAGES":"Sprachen",
"LARGE":"Groß",
"LAWFUL_EVIL":"lawful evil",
"LBS":"lbs",
"LAWFUL_EVIL":"Rechtschaffen böse",
"LBS":"Pfund",
"LEGENDARY_ACTIONS":"Legendäre Aktionen",
"LEGENDARY_ACTIONS_TEXT_1":"The",
"LEGENDARY_ACTIONS_TEXT_2":"can take",
"LEGENDARY_ACTIONS_TEXT_3":"legendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. The",
"LEGENDARY_ACTIONS_TEXT_4":"regains spent legendary actions at the start of its turn.",
"LEVEL":"Stufe",
"LEVELS":"levels",
"LIGHTNING":"lightning",
"LEVELS":"Stufen",
"LIGHTNING":"Blitz",
"LIGHT_ARMOR":"Leichte Rüstung",
"LONG_REST":"Long Rest",
"LONG_REST":"Lange Rast",
"MACROS":"Makros",
"MAX":"Max",
"MEDICINE":"Medizin",
@@ -490,101 +490,110 @@
"MEDIUM_ARMOR":"Mittlere Rüstung",
"MEDIUM_ARMOR_MAX_DEX":"Mittlere Rüstung Max Gesch.",
"MELEE":"Nahkampf",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Sonstiges",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS":"Sonstiges",
"MISCELLANEOUS_NOTES":"Sonstige Notizen",
"MONK":"Mönch",
"MOVEMENT":"Bewegung",
"MULTIPLIER":"Multiplier",
"MULTIPLIER":"Multiplikator",
"NAME":"Name",
"NATURE":"Natur",
"NECROMANCY":"Nekromantie",
"NECROTIC":"necrotic",
"NECROTIC":"necrotischer",
"NO":"Nein",
"NORMAL":"Normalerweise",
"NPC":"NPC",
"ONE_CREATURE":"one creature",
"OR":"or",
"NPC":"NSC",
"ONE_CREATURE":"eine Kreatur",
"OR":"oder",
"OTHER":"Andere",
"OTHER_ARMOR":"Andere Rüstung",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Andere Befähigungen",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Ausgabe",
"PALADIN":"Paladin",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passiver Fähigkeitscheck",
"PC":"SC",
"PERCEPTION":"Wahrnehmung",
"PERFORMANCE":"Auftreten",
"PERSONALITY_TRAITS":"Persönlichkeitsmerkmale",
"PERSUASION":"Überzeugen",
"PIERCING":"piercing",
"PLATINUM_PIECES":"Platinum pieces",
"POINTS_OF_ORIGIN":"Points of origin",
"POISON":"poison",
"PLATINUM_PIECES":"Platinmünzen",
"POINTS_OF_ORIGIN":"Ursprungspunkte",
"POISON":"Gift",
"PREPARED":"Vorbereitet",
"PROF":"Befähigt",
"PROFICIENCIES":"Befähigungen",
"PROFICIENCY_BONUS":"Befähigungsbonus",
"PROFICIENT":"Tüchtig",
"PSYCHIC":"psychic",
"PUBLIC_FOR_ALL":"Öffentliche für alle zu sehen",
"PROFICIENT":"Befähigt",
"PSYCHIC":"psychischer",
"PUBLIC_FOR_ALL":"Öffentlich für alle",
"QTY":"Menge",
"QUERY":"Query",
"QUERY":"Abfrage",
"RACE":"Rasse",
"RADIANT":"radiant",
"RANGE":"Reichweite",
"RANGED":"Fernkampf",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Waldläufer",
"REACH":"Bereich",
"REACH":"Reichweite",
"REACTION":"Reaktion",
"REACTIONS":"Reaktionen",
"RECHARGE":"Aufladung",
"REF":"Ref",
"REFLEX":"Reflex",
"REGIONAL_EFFECTS":"Regional Effects",
"REGIONAL_EFFECTS":"Regionale Effekte",
"RELIGION":"Religion",
"REMARKABLE_ATHLETE":"Herausragender Athlet",
"REQUIRES_API":"This feature requires the API",
"REQUIRES_API":"Dieses Feature erfordert die API",
"RESISTANCES_AND_IMMUNITIES":"Resistenzen & Immunitäten",
"RESOURCES":"Ressourcen",
"RESTS":"Rests",
"RESTS":"Rast",
"RITUAL":"Ritual",
"ROGUE":"Schurke",
"ROLL_2":"Roll 2",
"ROLL_OPTIONS":"Roll options",
"ROLL_TEMPLATE":"Roll template",
"SAVE":"Save",
"SAVE_FAILURE":"Save Failure",
"SAVE_SUCCESS":"Save Success",
"SAVE":"Rettungswurf",
"SAVE_FAILURE":"RW Fehlschlag",
"SAVE_SUCCESS":"RW Erfolg",
"SAVING_DC":"Rettungs-SG",
"SAVING_THROW":"Rettungswurf",
"SAVING_THROWS":"Rettungswürfe",
"SAVING_THROWS_QUERY":"Saving throws query",
"SAVING_THROWS_QUERY":"Rettungswurfabfrage",
"SAVING_THROW_DC":"Rettungswurf-SG",
"SENSES":"Sinne",
"SHEET":"Bogen",
"SHEET_OUTPUT":"Bogen Ausgabe",
"SHIELD":"Schild",
"SHORT_REST":"Short Rest",
"SHORT_REST":"Kurze Rast",
"SHOW_ALL":"Zeige alles",
"SHOW_PASSIVE":"Show passive",
"SHOW_RESTS":"Show Rests",
"SHOW_SPELL_LEVEL_IF_ALL_SLOTS_ARE_USED":"Show levels if all slots are used",
"SHOW_PASSIVE":"Passive zeigen",
"SHOW_RESTS":"Rast anzeigen",
"SHOW_SPELL_LEVEL_IF_ALL_SLOTS_ARE_USED":"Stufen zeigen, wenn alle Slots aufgebraucht sind",
"SHOW_TARGET_AC_ON_ATTACKS":"Zeige Ziel-RK bei Angriffen",
"SHOW_TARGET_NAME_ON_ATTACKS":"Zeige Ziel-Name bei Angriffen",
"SHOW_TOTALS":"Show totals",
"SHOW_UNPREPARED_SPELLS":"Show unprepared spells",
"SILVER_PIECES":"Silver pieces",
"SHOW_TOTALS":"Gesamtbonus anzeigen",
"SHOW_UNPREPARED_SPELLS":"Nicht vorbereitete Zauber zeigen",
"SILVER_PIECES":"Silbermünzen",
"SIZE":"Größe",
"SKILL":"Fertigkeit",
"SKILLS":"Fertigkeiten",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Sachverstand",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Befähigt",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Nicht befähigt",
"SKIN":"Hautfarbe",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Fingerfertigkeit",
"SMALL":"Klein",
"SOCIETY":"Society",
"SORCERER":"Hexenmeister",
"SOURCE":"Source",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SOURCE":"Quelle",
"SOURCE_TO_TARGET":"Quelle &rarr; Ziel",
"SPECIAL":"Speziell",
"SPECIAL_EFFECTS":"Spezialeffekte",
"SPEED":"Geschw.",
"SPELL":"Zauber",
"SPELLCASTING":"Zaubern",
@@ -600,27 +609,30 @@
"STEALTH":"Heimlichkeit",
"STR":"Str",
"STRENGTH":"Stärke",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Erfolge",
"SURVIVAL":"Überleben",
"SWIM":"Schwimmen",
"TARGET":"Ziel",
"TEXT_SIZE":"Text size",
"TARGET_TO_SOURCE":"Ziel &rarr; Quelle",
"TEXT_SIZE":"Textgröße",
"THUNDER":"thunder",
"TINY":"Sehr klein",
"TOTAL":"Gesamt",
"TOTAL_GOLD_VALUE":"Total gold value",
"TO_TRACKER":"Schicken Tracker",
"TO_TRACKER":"Zum Tracker schicken",
"TRACKER":"Tracker",
"TRAITS":"Traits",
"TRANSMUTATION":"Verwandlung",
"TREMORSENSE":"Erschütterungssinn",
"TRUESIGHT":"Wahrsicht",
"TURN_OFF_FILTERING":"If you are unable to see recently added spells turn off \"filters\"",
"TURN_OFF_FILTERING":"Wenn neu hinzugefügte Zauber nicht sichtbar sind, deaktiviere \"Filter\"",
"TYPE":"Typ",
"UNARMORED":"Ungepanzerten",
"UNPROFICIENT":"Fehlt Tüchtig",
"UNTIL_DISPELLED":"Until dispelled",
"UNTIL_DISPELLED_OR_TRIGGERED":"Until dispelled or triggered",
"UNARMORED":"Ungepanzert",
"UNPROFICIENT":"Nicht befähigt",
"UNTIL_DISPELLED":"Bis gebannt",
"UNTIL_DISPELLED_OR_TRIGGERED":"Bis gebannt oder ausgelöst",
"USED":"Used",
"USES":"Uses",
"USE_CUSTOM_SAVING_THROWS":"Use custom saving throws",
@@ -630,8 +642,8 @@
"WARLOCK":"Hexer",
"WARLOCK_SPELL_SLOTS":"Hexer Zauberslots",
"WEIGHT":"Gewicht",
"WHISPERED_TO_GM":"Raunte der GM",
"WILL":"Will",
"WHISPERED_TO_GM":"Geflüstert an den GM",
"WILL":"Willen",
"WIS":"Wei",
"WISDOM":"Weisheit",
"WIZARD":"Zauberer",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+18 -6
View File
@@ -44,7 +44,7 @@
"AC_ARMORED":"Armored AC",
"AC_UNARMORED":"Unarmored AC",
"AC_UNARMORED_ABILITY":"Unarmored ability",
"ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS":"Add half proficiency<br>to unproficient saving throws",
"ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS":"Add half proficiency to unproficient saving throws",
"ADVANTAGE":"Advantage",
"AGE":"Age",
"ALIGNMENT":"Alignment",
@@ -67,9 +67,8 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"AVERAGE_OF_ABILITIES":"Average of the highest 1 or 2 abilities",
"BACKGROUND":"Background",
"BARBARIAN":"Barbarian",
"BARD":"Bard",
@@ -350,7 +349,7 @@
"CORE":"Core",
"CRIT":"Crit",
"CRIT_ATTACHER_TOOLTIP":"Select one or more other categories and crit to have this message only show when a crit occurs for that category. This will not work for freeform.",
"CRIT_DAMAGE_TOOLTIP":"Determines the damage to roll for a crit. Normal weapon damage is not included.",
"CRIT_DAMAGE_TOOLTIP":"The damage field is rolled on a crit. This field defaults to the same as damage, but can be edited to another value",
"CRIT_RANGE":"Crit range",
"CURRENT":"Current",
"CUSTOM":"Custom",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+25 -13
View File
@@ -67,9 +67,8 @@
"ATTACHERS":"Attaches",
"ATTACK":"Attaque",
"ATTACKS":"Attaques",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Enlever le (dés)avantage après chaque jet",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"AVERAGE_OF_ABILITIES":"Average of the highest 1 or 2 abilities",
"BACKGROUND":"Biographie",
"BARBARIAN":"Barbare",
"BARD":"Barde",
@@ -332,15 +331,15 @@
"CON":"Con",
"CONC":"Conc",
"CONCENTRATION":"Concentration",
"CONCENTRATION_UP_TO_10_MINUTES":"Concentration, up to 10 minute",
"CONCENTRATION_UP_TO_12_HOURS":"Concentration, up to 12 hours",
"CONCENTRATION_UP_TO_1_HOUR":"Concentration, up to 1 hour",
"CONCENTRATION_UP_TO_1_MINUTE":"Concentration, up to 1 minute",
"CONCENTRATION_UP_TO_1_ROUND":"Concentration, up to 1 round",
"CONCENTRATION_UP_TO_24_HOURS":"Concentration, up to 24 hours",
"CONCENTRATION_UP_TO_2_HOURS":"Concentration, up to 2 hours",
"CONCENTRATION_UP_TO_6_ROUNDS":"Concentration, up to 6 rounds",
"CONCENTRATION_UP_TO_8_HOURS":"Concentration, up to 8 hours",
"CONCENTRATION_UP_TO_10_MINUTES":"up to 10 minute",
"CONCENTRATION_UP_TO_12_HOURS":"up to 12 hours",
"CONCENTRATION_UP_TO_1_HOUR":"up to 1 hour",
"CONCENTRATION_UP_TO_1_MINUTE":"up to 1 minute",
"CONCENTRATION_UP_TO_1_ROUND":"up to 1 round",
"CONCENTRATION_UP_TO_24_HOURS":"up to 24 hours",
"CONCENTRATION_UP_TO_2_HOURS":"up to 2 hours",
"CONCENTRATION_UP_TO_6_ROUNDS":"up to 6 rounds",
"CONCENTRATION_UP_TO_8_HOURS":"up to 8 hours",
"CONDENSE":"Condensé",
"CONDITION_IMMUNITIES":"Immunité<br>aux conditions",
"CONJURATION":"Invocation",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Mort",
"EXPERIENCE_POINTS":"Points d'Expérience",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Yeux",
"FAILURES":"Échecs",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Soigne",
"HEAVY_ARMOR":"Armure Lourde",
"HEIGHT":"Taille",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"Si la cible est",
"ILLUSION":"Illusion",
"IMPORT":"Importer",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Bonus initiative",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Armure Intermédiaire",
"MEDIUM_ARMOR_MAX_DEX":"Bonus dex max<br>(armure intermédaire)",
"MELEE":"Mêlée",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Autre",
"MISCELLANEOUS":"Divers",
"MISCELLANEOUS_NOTES":"Notes diverses",
@@ -508,8 +509,10 @@
"OTHER":"Autre",
"OTHER_ARMOR":"Autre type d'Armure",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Maîtrises & Langues",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Options d'affichage",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Carac passive",
"PC":"PJ",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Portée",
"RANGED":"Tir",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Rôdeur",
"REACH":"Allonge",
"REACTION":"Réaction",
@@ -577,12 +581,17 @@
"SIZE":"Catégorie de taille",
"SKILL":"Compétence",
"SKILLS":"Compétences",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Maîtrise",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Non Maîtrisée",
"SKIN":"Peau",
"SLASHING":"tranchant",
"SLEIGHTOFHAND":"Escamotage",
"SMALL":"Petite",
"SOCIETY":"Society",
"SORCERER":"Ensorceleur",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Cible",
"SPECIAL":"Spécial",
"SPECIAL_EFFECTS":"Effects spéciaux",
"SPEED":"Vitesse",
@@ -600,10 +609,13 @@
"STEALTH":"Discrétion",
"STR":"For",
"STRENGTH":"Force",
"STR_13":"For 13",
"STR_15":"For 15",
"SUCCESSES":"Réussites",
"SURVIVAL":"Survie",
"SWIM":"Vitesse de nage",
"TARGET":"Cible",
"TARGET_TO_SOURCE":"Cible &rarr; Source",
"TEXT_SIZE":"Taille de texte",
"THUNDER":"tonnerre",
"TINY":"Très Petite",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+25 -13
View File
@@ -67,9 +67,8 @@
"ATTACHERS":"Aggiunte",
"ATTACK":"Attacco",
"ATTACKS":"Attacchi",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Ripristina (s)vantaggio automaticamente",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"AVERAGE_OF_ABILITIES":"Average of the highest 1 or 2 abilities",
"BACKGROUND":"Background",
"BARBARIAN":"Barbaro",
"BARD":"Bardo",
@@ -332,15 +331,15 @@
"CON":"Cos",
"CONC":"Conc.",
"CONCENTRATION":"Concentrazione",
"CONCENTRATION_UP_TO_10_MINUTES":"Concentration, up to 10 minute",
"CONCENTRATION_UP_TO_12_HOURS":"Concentration, up to 12 hours",
"CONCENTRATION_UP_TO_1_HOUR":"Concentration, up to 1 hour",
"CONCENTRATION_UP_TO_1_MINUTE":"Concentration, up to 1 minute",
"CONCENTRATION_UP_TO_1_ROUND":"Concentration, up to 1 round",
"CONCENTRATION_UP_TO_24_HOURS":"Concentration, up to 24 hours",
"CONCENTRATION_UP_TO_2_HOURS":"Concentration, up to 2 hours",
"CONCENTRATION_UP_TO_6_ROUNDS":"Concentration, up to 6 rounds",
"CONCENTRATION_UP_TO_8_HOURS":"Concentration, up to 8 hours",
"CONCENTRATION_UP_TO_10_MINUTES":"fino a 10 minuti",
"CONCENTRATION_UP_TO_12_HOURS":"fino a 12 ore",
"CONCENTRATION_UP_TO_1_HOUR":"fino a 1 ora",
"CONCENTRATION_UP_TO_1_MINUTE":"fino a 1 minuto",
"CONCENTRATION_UP_TO_1_ROUND":"fino a 1 round",
"CONCENTRATION_UP_TO_24_HOURS":"fino a 24 ore",
"CONCENTRATION_UP_TO_2_HOURS":"fino a 2 ore",
"CONCENTRATION_UP_TO_6_ROUNDS":"fino a 6 round",
"CONCENTRATION_UP_TO_8_HOURS":"fino a 8 ore",
"CONDENSE":"Riduci",
"CONDITION_IMMUNITIES":"Immunità alle condizioni",
"CONJURATION":"Invocazione",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Morte",
"EXPERIENCE_POINTS":"Punti esperienza",
"EXPERTISE":"Perizia",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extra",
"EYES":"Occhi",
"FAILURES":"Fallimenti",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Cura di",
"HEAVY_ARMOR":"Armatura pesante",
"HEIGHT":"Altezza",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Nascondi info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Nasc. testo azione",
"HIDE_INFO_ATTACK":"Nasc. attacco",
"HIDE_INFO_DAMAGE":"Nasc. danni",
"HIDE_INFO_EFFECT":"Nasc. effetto",
"HIDE_INFO_FREETEXT":"Nasc. testo",
"HIDE_INFO_NOTE":"Controllare la documentazione. È necessaria un'estenzione nel browser per cambiare il css per mostrare certe parti",
"HIDE_INFO_RECHARGE":"Nasc. ricarica",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"Se il bersaglio è",
"ILLUSION":"Illusione",
"IMPORT":"Importa",
"INFLUENCE":"Influence",
"INITIATIVE":"Iniziativa",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Bonus Iniziativa",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Armatura media",
"MEDIUM_ARMOR_MAX_DEX":"Armatura media max DES",
"MELEE":"Mischia",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Varie",
"MISCELLANEOUS":"Varie",
"MISCELLANEOUS_NOTES":"Note",
@@ -508,8 +509,10 @@
"OTHER":"Altro",
"OTHER_ARMOR":"Altra armatura",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Altre competenze e lingue",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladino",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Prova passiva di caratteristica",
"PC":"PG",
"PERCEPTION":"Percezione",
@@ -533,6 +536,7 @@
"RADIANT":"radiante",
"RANGE":"Portata",
"RANGED":"A distanza",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Portata",
"REACTION":"Reazione",
@@ -577,12 +581,17 @@
"SIZE":"Taglia",
"SKILL":"Abilità",
"SKILLS":"Abilità",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Perizia",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Competente",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Non competente",
"SKIN":"Pelle",
"SLASHING":"tagliente",
"SLEIGHTOFHAND":"Agilità di mano",
"SMALL":"Piccola",
"SOCIETY":"Society",
"SORCERER":"Stregone",
"SOURCE":"Fonte",
"SOURCE_TO_TARGET":"Fonte &rarr; Bersaglio",
"SPECIAL":"Speciale",
"SPECIAL_EFFECTS":"Effetti speciali",
"SPEED":"Velocità",
@@ -600,10 +609,13 @@
"STEALTH":"Furtività",
"STR":"For",
"STRENGTH":"Forza",
"STR_13":"For 13",
"STR_15":"For 15",
"SUCCESSES":"Successi",
"SURVIVAL":"Sopravvivenza",
"SWIM":"Nuotare",
"TARGET":"Bersaglio",
"TARGET_TO_SOURCE":"Bersaglio &rarr; Fonte",
"TEXT_SIZE":"Dimensione testo",
"THUNDER":"tuono",
"TINY":"Minuscola",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Нападки",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Эксперт",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Глаза",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Рост",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Другое",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Результат",
"PALADIN":"Паладин",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Следопыт",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Размер",
"SKILL":"Skill",
"SKILLS":"Навыки",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Кожа",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Чародей",
"SOURCE":"Источник",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Сила",
"STRENGTH":"Сила",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+15 -3
View File
@@ -67,7 +67,6 @@
"ATTACHERS":"Attachers",
"ATTACK":"Attack",
"ATTACKS":"Attacks",
"ATTACKS_VS_A_SAVING_THROW":"Attacks vs a saving throw",
"AUTO_REVERT_ADV":"Automatically revert (dis)advantage",
"AVERAGE_OF_ABILITIES":"Average of abilities",
"BACKGROUND":"Background",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"Death",
"EXPERIENCE_POINTS":"Experience points",
"EXPERTISE":"Expertise",
"EXPERTISE_AS_ADVANTAGE":"Expertise as Advantage when importing",
"EXTRAS":"Extras",
"EYES":"Eyes",
"FAILURES":"Failures",
@@ -428,13 +428,12 @@
"HEAL_FOR":"Heal for",
"HEAVY_ARMOR":"Heavy Armor",
"HEIGHT":"Height",
"HIDE_AC":"Hide AC",
"HIDE_INFO":"Hide info",
"HIDE_INFO_ABILITY_CHECKS":"Hide ability checks",
"HIDE_INFO_ACTION_FREETEXT":"Hide action freetext",
"HIDE_INFO_ATTACK":"Hide attack",
"HIDE_INFO_DAMAGE":"Hide damage",
"HIDE_INFO_EFFECT":"Hide effect",
"HIDE_INFO_FREETEXT":"Hide freetext",
"HIDE_INFO_NOTE":"Please see the documentation. You'll need to use a browser extension to change the css to show certain parts",
"HIDE_INFO_RECHARGE":"Hide recharge",
"HIDE_INFO_SAVING_THROWS":"Hide saving throws",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"If the target is",
"ILLUSION":"Illusion",
"IMPORT":"Import",
"INFLUENCE":"Influence",
"INITIATIVE":"Initiative",
"INITIATIVE_ABILITY":"Initiative ability",
"INITIATIVE_BONUS":"Initiative bonus",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"Medium Armor",
"MEDIUM_ARMOR_MAX_DEX":"Medium armor max dex",
"MELEE":"Melee",
"MELEE_WEAPON":"Melee weapon (thrown)",
"MISC":"Misc",
"MISCELLANEOUS":"Miscellaneous",
"MISCELLANEOUS_NOTES":"Miscellaneous notes",
@@ -508,8 +509,10 @@
"OTHER":"Other",
"OTHER_ARMOR":"Other Armor",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"Other Proficiencies & Languages",
"OTHER_TYPE":"Other (AoE, Cone, Line)",
"OUTPUT":"Output",
"PALADIN":"Paladin",
"PASSIVE":"Passive",
"PASSIVE_ABILITY_CHECK":"Passive ability check",
"PC":"PC",
"PERCEPTION":"Perception",
@@ -533,6 +536,7 @@
"RADIANT":"radiant",
"RANGE":"Range",
"RANGED":"Ranged",
"RANGED_WEAPON":"Ranged weapon",
"RANGER":"Ranger",
"REACH":"Reach",
"REACTION":"Reaction",
@@ -577,12 +581,17 @@
"SIZE":"Size",
"SKILL":"Skill",
"SKILLS":"Skills",
"SKILL_SELECT_EXPERTISE":"&cross;&nbsp;&nbsp;&nbsp;&nbsp;Expertise",
"SKILL_SELECT_PROFICIENT":"&check;&nbsp;&nbsp;&nbsp;&nbsp;Proficient",
"SKILL_SELECT_UNPROFICIENT":"&#8212;&nbsp;&nbsp;&nbsp;Unproficient",
"SKIN":"Skin",
"SLASHING":"slashing",
"SLEIGHTOFHAND":"Sleight of Hand",
"SMALL":"Small",
"SOCIETY":"Society",
"SORCERER":"Sorcerer",
"SOURCE":"Source",
"SOURCE_TO_TARGET":"Source &rarr; Target",
"SPECIAL":"Special",
"SPECIAL_EFFECTS":"Special effects",
"SPEED":"Speed",
@@ -600,10 +609,13 @@
"STEALTH":"Stealth",
"STR":"Str",
"STRENGTH":"Strength",
"STR_13":"Str 13",
"STR_15":"Str 15",
"SUCCESSES":"Successes",
"SURVIVAL":"Survival",
"SWIM":"Swim",
"TARGET":"Target",
"TARGET_TO_SOURCE":"Target &rarr; Source",
"TEXT_SIZE":"Text size",
"THUNDER":"thunder",
"TINY":"Tiny",
+18 -6
View File
@@ -44,7 +44,7 @@
"AC_ARMORED":"crwdns6862:0crwdne6862:0",
"AC_UNARMORED":"crwdns6863:0crwdne6863:0",
"AC_UNARMORED_ABILITY":"crwdns6864:0crwdne6864:0",
"ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS":"crwdns6865:0crwdne6865:0",
"ADD_HALF_PROFICIENCY_TO_UNPROFICIENT_SAVING_THROWS":"crwdns8213:0crwdne8213:0",
"ADVANTAGE":"crwdns6866:0crwdne6866:0",
"AGE":"crwdns6867:0crwdne6867:0",
"ALIGNMENT":"crwdns6868:0crwdne6868:0",
@@ -67,9 +67,8 @@
"ATTACHERS":"crwdns6881:0crwdne6881:0",
"ATTACK":"crwdns6882:0crwdne6882:0",
"ATTACKS":"crwdns6883:0crwdne6883:0",
"ATTACKS_VS_A_SAVING_THROW":"crwdns7781:0crwdne7781:0",
"AUTO_REVERT_ADV":"crwdns6884:0crwdne6884:0",
"AVERAGE_OF_ABILITIES":"crwdns8197:0crwdne8197:0",
"AVERAGE_OF_ABILITIES":"crwdns8214:0crwdne8214:0",
"BACKGROUND":"crwdns6885:0crwdne6885:0",
"BARBARIAN":"crwdns6886:0crwdne6886:0",
"BARD":"crwdns6887:0crwdne6887:0",
@@ -350,7 +349,7 @@
"CORE":"crwdns7143:0crwdne7143:0",
"CRIT":"crwdns7144:0crwdne7144:0",
"CRIT_ATTACHER_TOOLTIP":"crwdns7145:0crwdne7145:0",
"CRIT_DAMAGE_TOOLTIP":"crwdns7146:0crwdne7146:0",
"CRIT_DAMAGE_TOOLTIP":"crwdns8215:0crwdne8215:0",
"CRIT_RANGE":"crwdns7147:0crwdne7147:0",
"CURRENT":"crwdns7148:0crwdne7148:0",
"CUSTOM":"crwdns7149:0crwdne7149:0",
@@ -399,6 +398,7 @@
"EXHAUSTION_LEVEL_6":"crwdns7189:0crwdne7189:0",
"EXPERIENCE_POINTS":"crwdns7190:0crwdne7190:0",
"EXPERTISE":"crwdns7191:0crwdne7191:0",
"EXPERTISE_AS_ADVANTAGE":"crwdns8216:0crwdne8216:0",
"EXTRAS":"crwdns7192:0crwdne7192:0",
"EYES":"crwdns7193:0crwdne7193:0",
"FAILURES":"crwdns7194:0crwdne7194:0",
@@ -428,13 +428,12 @@
"HEAL_FOR":"crwdns7214:0crwdne7214:0",
"HEAVY_ARMOR":"crwdns7215:0crwdne7215:0",
"HEIGHT":"crwdns7216:0crwdne7216:0",
"HIDE_AC":"crwdns7805:0crwdne7805:0",
"HIDE_INFO":"crwdns7806:0crwdne7806:0",
"HIDE_INFO_ABILITY_CHECKS":"crwdns7807:0crwdne7807:0",
"HIDE_INFO_ACTION_FREETEXT":"crwdns7808:0crwdne7808:0",
"HIDE_INFO_ATTACK":"crwdns7809:0crwdne7809:0",
"HIDE_INFO_DAMAGE":"crwdns7810:0crwdne7810:0",
"HIDE_INFO_EFFECT":"crwdns7811:0crwdne7811:0",
"HIDE_INFO_FREETEXT":"crwdns8217:0crwdne8217:0",
"HIDE_INFO_NOTE":"crwdns7812:0crwdne7812:0",
"HIDE_INFO_RECHARGE":"crwdns7813:0crwdne7813:0",
"HIDE_INFO_SAVING_THROWS":"crwdns7814:0crwdne7814:0",
@@ -456,6 +455,7 @@
"IF_THE_TARGET_IS":"crwdns7433:0crwdne7433:0",
"ILLUSION":"crwdns7238:0crwdne7238:0",
"IMPORT":"crwdns7239:0crwdne7239:0",
"INFLUENCE":"crwdns8218:0crwdne8218:0",
"INITIATIVE":"crwdns7240:0crwdne7240:0",
"INITIATIVE_ABILITY":"crwdns8207:0crwdne8207:0",
"INITIATIVE_BONUS":"crwdns7241:0crwdne7241:0",
@@ -490,6 +490,7 @@
"MEDIUM_ARMOR":"crwdns7268:0crwdne7268:0",
"MEDIUM_ARMOR_MAX_DEX":"crwdns7269:0crwdne7269:0",
"MELEE":"crwdns7270:0crwdne7270:0",
"MELEE_WEAPON":"crwdns8219:0crwdne8219:0",
"MISC":"crwdns7271:0crwdne7271:0",
"MISCELLANEOUS":"crwdns7272:0crwdne7272:0",
"MISCELLANEOUS_NOTES":"crwdns7273:0crwdne7273:0",
@@ -508,8 +509,10 @@
"OTHER":"crwdns7284:0crwdne7284:0",
"OTHER_ARMOR":"crwdns7285:0crwdne7285:0",
"OTHER_PROFICIENCIES_AND_LANGUAGES":"crwdns7286:0crwdne7286:0",
"OTHER_TYPE":"crwdns8220:0crwdne8220:0",
"OUTPUT":"crwdns7287:0crwdne7287:0",
"PALADIN":"crwdns7289:0crwdne7289:0",
"PASSIVE":"crwdns8221:0crwdne8221:0",
"PASSIVE_ABILITY_CHECK":"crwdns7441:0crwdne7441:0",
"PC":"crwdns7290:0crwdne7290:0",
"PERCEPTION":"crwdns7291:0crwdne7291:0",
@@ -533,6 +536,7 @@
"RADIANT":"crwdns7308:0crwdne7308:0",
"RANGE":"crwdns7309:0crwdne7309:0",
"RANGED":"crwdns7310:0crwdne7310:0",
"RANGED_WEAPON":"crwdns8222:0crwdne8222:0",
"RANGER":"crwdns7311:0crwdne7311:0",
"REACH":"crwdns7312:0crwdne7312:0",
"REACTION":"crwdns7313:0crwdne7313:0",
@@ -577,12 +581,17 @@
"SIZE":"crwdns7346:0crwdne7346:0",
"SKILL":"crwdns7347:0crwdne7347:0",
"SKILLS":"crwdns7348:0crwdne7348:0",
"SKILL_SELECT_EXPERTISE":"crwdns8223:0crwdne8223:0",
"SKILL_SELECT_PROFICIENT":"crwdns8224:0crwdne8224:0",
"SKILL_SELECT_UNPROFICIENT":"crwdns8225:0crwdne8225:0",
"SKIN":"crwdns7349:0crwdne7349:0",
"SLASHING":"crwdns7350:0crwdne7350:0",
"SLEIGHTOFHAND":"crwdns7351:0crwdne7351:0",
"SMALL":"crwdns7352:0crwdne7352:0",
"SOCIETY":"crwdns8226:0crwdne8226:0",
"SORCERER":"crwdns7354:0crwdne7354:0",
"SOURCE":"crwdns7355:0crwdne7355:0",
"SOURCE_TO_TARGET":"crwdns8227:0crwdne8227:0",
"SPECIAL":"crwdns7430:0crwdne7430:0",
"SPECIAL_EFFECTS":"crwdns7356:0crwdne7356:0",
"SPEED":"crwdns7357:0crwdne7357:0",
@@ -600,10 +609,13 @@
"STEALTH":"crwdns7369:0crwdne7369:0",
"STR":"crwdns7370:0crwdne7370:0",
"STRENGTH":"crwdns7371:0crwdne7371:0",
"STR_13":"crwdns8228:0crwdne8228:0",
"STR_15":"crwdns8229:0crwdne8229:0",
"SUCCESSES":"crwdns7372:0crwdne7372:0",
"SURVIVAL":"crwdns7373:0crwdne7373:0",
"SWIM":"crwdns7374:0crwdne7374:0",
"TARGET":"crwdns7375:0crwdne7375:0",
"TARGET_TO_SOURCE":"crwdns8230:0crwdne8230:0",
"TEXT_SIZE":"crwdns7376:0crwdne7376:0",
"THUNDER":"crwdns7377:0crwdne7377:0",
"TINY":"crwdns7378:0crwdne7378:0",
+577
View File
@@ -0,0 +1,577 @@
/*----------- Repeating Blocks -------------*/
.charsheet .repcontrol_add {
display: block;
background:#7F2108;
color:white;
text-shadow:0px 0px 2px #000,0px 0px 2px #000,0px 0px 2px #000;
box-shadow:none;
float:left!important;
margin-bottom:0px;
font-size:0.9em;
height:2.2em;
font-family: Copperplate, 'Copperplate Gothic Light', fantasy;
}
.charsheet .repcontrol_edit
{
display: inline-block;
background:#7F2108;
color:white;
text-shadow:0px 0px 2px #000,0px 0px 2px #000,0px 0px 2px #000;
box-shadow:none;
float:none!important;
margin-bottom:5px;
font-size:0.9em;
height:2.2em;
font-family: Copperplate, 'Copperplate Gothic Light', fantasy;
}
.charsheet .repcontrol_del {
background:red;
color:white;
text-shadow:0px 0px 2px #000,0px 0px 2px #000,0px 0px 2px #000;
box-shadow:none;
float:none!important;
margin-bottom:5px;
font-size:0.9em;
height:2.2em;
}
.charsheet .repcontrol_move {
display: inline-block;
background:#08667f;
color:white;
text-shadow:0px 0px 2px #000,0px 0px 2px #000,0px 0px 2px #000;
box-shadow:none;
float:none!important;
margin-bottom:5px;
font-size:0.9em;
height:1.4em;
padding-top:3px;
padding-bottom:3px;
}
/*----------- End of Repeating Blocks -------------*//*=======================Tabs=======================*/
div.sheet-tab-content {
display: none;
}
input.sheet-tab1:checked ~ div.sheet-tab1,
input.sheet-tab2:checked ~ div.sheet-tab2,
input.sheet-tab3:checked ~ div.sheet-tab3,
input.sheet-tab4:checked ~ div.sheet-tab4,
input.sheet-tab5:checked ~ div.sheet-tab5,
input.sheet-tab6:checked ~ div.sheet-tab6,
input.sheet-tab7:checked ~ div.sheet-tab7 {
display: block;
}
input.sheet-tab {
width: 130px;
height: 20px;
position: relative;
left: 6px;
margin: 0px ;
cursor: pointer;
z-index: 1;
border-radius: 5px 5px 5px 5px;
}
input.sheet-tab::before
{
content: attr(title);
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
color:white;
text-shadow:0px 0px 0.5em black;
text-align: center;
display: inline-block;
background: #fff;
background: -moz-linear-gradient(to top, #fff, #B35439, #fff);
background: -webkit-linear-gradient(to top, #fff, #B35439, #fff);
background: -ms-linear-gradient(to top, #fff, #B35439, #fff);
background: -o-linear-gradient(to top, #fff, #B35439, #fff);
background: linear-gradient(to top, #fff, #B35439, #fff);
width: 130px;
height: 20px;
font-size: 16px;
font-weight:700;
border-radius: 15px 15px 15px 15px;
border:1px solid black;
}
input.sheet-tab:checked::before
{
background: #dcdcdc;
background: -moz-linear-gradient(to top, #B35439, #000, #B35439);
background: -webkit-linear-gradient(to top, #B35439, #000, #B35439);
background: -ms-linear-gradient(to top, #B35439, #000, #B35439);
background: -o-linear-gradient(to top, #B35439, #000, #B35439);
background: linear-gradient(to top, #B35439, #000, #B35439);
/* border-bottom-color: #fff; */
text-shadow:0px 0px 0.5em black,0px 0px 0.5em black;
}
input.sheet-tab:not(:first-child)::before
{
border-left: none;
}
div.sheet-tab-content {
width: 835px;
background:white;
box-shadow: inset 0px 0px 10px #B35439, inset 0px 0px 8px #B35439,inset 0px 0px 4px #B35439;
padding: 5px;
border-radius:15px;
margin-right:auto;
margin-left:auto;
}
div.sheet-top_bar {
width: 835px;
background:white;
box-shadow: inset 0px 0px 10px #B35439, inset 0px 0px 8px #B35439,inset 0px 0px 4px #B35439;
padding: 5px;
border-radius:15px;
margin-right:auto;
margin-left:auto;
}
/*=======================End of tabs=======================*/
/*----------- Font Face -------------*/
@font-face {
font-family: 'GreatVibesRegular';
src: url('http://openfontlibrary.org/assets/fonts/rebecca/d32a4d9e4887fccf9ce200538290cd10/53e7427de4aaa693950c7a9c35de80e2/GreatVibesRegular.otf');
font-weight: normal;
font-style: normal;
}
/*----------- End of Font Face -------------*/
/*----------- Banner -------------*/
.sheet-banner {
background: url('http://www.atlas-games.com/images/ArM5LogoColor.jpg');
background-size: 100%;
background-repeat: no-repeat;
background-position: right bottom;
}
.sheet-banner-content {
margin: 0;
height: 100px;
width: 200px;
}
/*----------- End of Banner -------------*/
/*----------- background -------------*/
.charsheet {
background:black;
width:850px;
}
/*----------- End of background -------------*/
/*----------- Text -------------*/
.sheet-heading {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
font-weight:bold;
font-size:1.3em;
}
.sheet-heading_1 {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
font-size:1.3em;
line-height:1.4em;
border-top: none;
border-bottom: none;
border-left: none;
border-right: none;
width:200px;
}
textarea.sheet-textarea_3:hover,textarea.sheet-textarea_3:focus,
textarea.sheet-textarea_2:hover,textarea.sheet-textarea_2:focus,
textarea.sheet-textarea_1:hover,textarea.sheet-textarea_1:focus,
.sheet-number_1:hover, .sheet-number_1:focus,
.sheet-heading_2:hover, .sheet-heading_2:focus,
.sheet-heading_3:hover, .sheet-heading_3:focus,
.sheet-heading_1:hover, .sheet-heading_1:focus {
box-shadow: inset -9px -8px 18px -4px #B35439;
text-shadow: 0px 0px 5px white, 0px 0px 5px white, 0px 0px 5px white;
}
.sheet-heading_2 {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
font-size:1.1em;
line-height:1.2em;
border: none;
width:160px;
}
.sheet-heading_3 {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
font-size:1.1em;
line-height:1.2em;
border: none;
width:200px;
}
.sheet-heading_4 {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
font-size:1.1em;
line-height:1.2em;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 1px solid black;
width:120px;
}
.sheet-number_1 {
width:60px;
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
font-size:1.3em;
line-height:1.4em;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 1px solid black;
box-shadow: none;
background:transparent;
}
.sheet-number_2 {
width:40px;
font-family: Copperplate, 'Copperplate Gothic Light', fantasy;
font-size:1.1em;
line-height:1.2em;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 1px solid black;
box-shadow: none;
background:transparent;
}
.sheet-number_2:disabled {
background: black;
color:white;
}
.sheet-counter {
width:90px;
font-family: Copperplate, 'Copperplate Gothic Light', fantasy;
font-size:1.1em;
line-height:1.2em;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 1px solid black;
box-shadow: none;
background:transparent;
text-shadow: 0px 0px 10px white;
color:black;
font-weight:700;
}
input.sheet-counter[type=number]::-webkit-inner-spin-button,
input.sheet-counter[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.sheet-heading_label {
margin-left:0px;
margin-bottom:-6px;
padding-left: 10px;
border: 1px solid #B35439;
border-radius: 15px 15px 0px 0px;
background:#B35439;
text-shadow: 0px 0px 5px white, 0px 0px 5px white, 0px 0px 5px white;
width:155px;
}
/*----------- End of Text -------------*/
/*----------- Tables -------------*/
.sheet-table_1 th {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
}
.sheet-table_2 {
border: 1px solid black;
margin-top:5px;
margin-bottom:5px;
}
.sheet-table_2 th {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
text-align:left;
}
/*----------- End of Tables -------------*/
/*----------- textarea -------------*/
textarea.sheet-textarea_1 {
width: 200px;
resize:vertical;
height:90px;
border:1px dotted #d3d3d3;
border-radius:15px;
}
textarea.sheet-textarea_2 {
width: 400px;
resize:vertical;
height:45px;
border:1px dotted #d3d3d3;
border-radius:15px;
}
textarea.sheet-textarea_3 {
width: 180px;
resize:vertical;
height:30px;
border:1px dotted #d3d3d3;
border-radius:15px;
}
/*----------- End of textarea -------------*/
/*----------- Select -------------*/
select.sheet-select_1 {
-webkit-appearance: none;
padding-top:0px;
padding-right:0px;
appearance: none;
margin-bottom: 0;
width:110px;
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
}
select {
-moz-appearance: none;
}
select *.sheet-italic {
font-style:italic;
}
/*----------- End of Select -------------*/
/*----------- Hide Things -------------*/
.sheet-hidden {
display: none;
}
input.sheet-hider:checked ~ div.sheet-hide {
display: none;
}
/*----------- End of Hide Things -------------*/
/*----------- Checkbox -------------*/
/* Hide actual checkbox */
input.sheet-checkbox_3[type="checkbox"],
input.sheet-checkbox_2[type="checkbox"],
input.sheet-checkbox_1[type="checkbox"] {
opacity: 0;
width: 16px;
height: 16px;
position: relative;
top: 0px;
left: 8px;
margin:0px;
cursor: pointer;
z-index: 1;
}
/* Fake checkbox */
input.sheet-checkbox_2[type="checkbox"] + span::before,
input.sheet-checkbox_1[type="checkbox"] + span::before {
margin-right: 4px;
border: solid 1px #a8a8a8;
line-height: 14px;
text-align: center;
display: inline-block;
vertical-align: middle;
-moz-box-shadow: 0 0 2px #ccc;
-webkit-box-shadow: 0 0 2px #ccc;
box-shadow: 0 0 2px #ccc;
background: #f6f6f6;
background: -moz-radial-gradient(#f6f6f6, #dfdfdf);
background: -webkit-radial-gradient(#f6f6f6, #dfdfdf);
background: -ms-radial-gradient(#f6f6f6, #dfdfdf);
background: -o-radial-gradient(#f6f6f6, #dfdfdf);
background: radial-gradient(#f6f6f6, #dfdfdf);
}
/* Fake checkbox */
input.sheet-checkbox_2[type="checkbox"] + span::before,
input.sheet-checkbox_1[type="checkbox"] + span::before {
content: "";
width: 14px;
height: 14px;
font-size: 12px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
input.sheet-checkbox_1[type="checkbox"] + span::before {
position: relative;
top: 0px;
left: 0px;
margin:-10px;
}
input.sheet-checkbox_2[type="checkbox"] + span::before {
position: relative;
top: 0px;
left: 0px;
margin:-10px;
}
input.sheet-checkbox_1[type="checkbox"]:checked + span::before {
content: "✓";
}
input.sheet-checkbox_2[type="checkbox"]:checked + span::before {
content: "x";
color:red;
} /* Fake checkbox */
input.sheet-checkbox_3[type="checkbox"] + span::before {
margin-right: 4px;
border: solid 1px #a8a8a8;
line-height: 14px;
text-align: center;
display: inline-block;
vertical-align: middle;
-moz-box-shadow: 0 0 2px #ccc;
-webkit-box-shadow: 0 0 2px #ccc;
box-shadow: 0 0 2px #ccc;
background: #f6f6f6;
}
/* Fake checkbox */
input.sheet-checkbox_3[type="checkbox"] + span::before {
content: "";
width: 14px;
height: 14px;
font-size: 12px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
/*----------- Radio -------------*/
/* Hide actual radio */
input.sheet-radio_2[type="radio"],
input.sheet-radio_1[type="radio"] {
opacity: 0;
width: 16px;
height: 16px;
position: relative;
top: 0px;
left: 8px;
margin:0px;
cursor: pointer;
z-index: 1;
}
/* Fake checkbox */
input.sheet-radio_2[type="radio"] + span::before,
input.sheet-radio_1[type="radio"] + span::before {
margin-right: 4px;
border: solid 1px #a8a8a8;
line-height: 14px;
text-align: center;
display: inline-block;
vertical-align: middle;
position: relative;
top: 0px;
left: 0px;
margin:-8px;
-moz-box-shadow: 0 0 2px #ccc;
-webkit-box-shadow: 0 0 2px #ccc;
box-shadow: 0 0 2px #ccc;
background: #f6f6f6;
background: -moz-radial-gradient(#f6f6f6, #dfdfdf);
background: -webkit-radial-gradient(#f6f6f6, #dfdfdf);
background: -ms-radial-gradient(#f6f6f6, #dfdfdf);
background: -o-radial-gradient(#f6f6f6, #dfdfdf);
background: radial-gradient(#f6f6f6, #dfdfdf);
}
input.sheet-radio_1[type="radio"] + span::before {
position: relative;
top: 0px;
left: -8px;
margin:0px;
}
input.sheet-radio_2[type="radio"] + span::before {
position: relative;
top: 0px;
left: 0px;
margin:-10px;
}
/* Fake checkbox */
input.sheet-radio_2[type="radio"] + span::before,
input.sheet-radio_1[type="radio"] + span::before {
content: "";
width: 14px;
height: 14px;
font-size: 12px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
input.sheet-radio_2[type="radio"]:checked + span::before,
input.sheet-radio_1[type="radio"]:checked + span::before {
content: "x";
}
/*----------- End of Checkbox -------------*/
/*----------- Buttons -------------*/
button.sheet-button_1:before {
content: "" !important;
}
button.sheet-botch:before{
content: "" !important;
display: none;
}
button.sheet-botch {
font-family: 'GreatVibesRegular', "Shadows Into Light", cursive;
color:white;
text-shadow:0px 0px 0.5em black;
text-align: center;
display: inline-block;
background: #fff;
background: -moz-linear-gradient(to top, #fff, #08667f, #fff);
background: -webkit-linear-gradient(to top, #fff, #08667f, #fff);
background: -ms-linear-gradient(to top, #fff, #08667f, #fff);
background: -o-linear-gradient(to top, #fff, #08667f, #fff);
background: linear-gradient(to top, #fff, #08667f, #fff);
width: 130px;
height: 24px;
font-size: 16px;
line-height:18px;
font-weight:700;
border-radius: 15px 15px 15px 15px;
border:1px solid black;
}
button.sheet-botch:hover {
background: #fff;
background: -moz-linear-gradient(to top, #08667f, #fff, #08667f);
background: -webkit-linear-gradient(to top, #08667f, #fff, #08667f);
background: -ms-linear-gradient(to top, #08667f, #fff, #08667f);
background: -o-linear-gradient(to top, #08667f, #fff, #08667f);
background: linear-gradient(to top, #08667f, #fff, #08667f);
}
button.sheet-botch:active {
background: #fff;
background: -moz-linear-gradient(to left, #08667f, #fff, #08667f);
background: -webkit-linear-gradient(to left, #08667f, #fff, #08667f);
background: -ms-linear-gradient(to left, #08667f, #fff, #08667f);
background: -o-linear-gradient(to left, #08667f, #fff, #08667f);
background: linear-gradient(to left, #08667f, #fff, #08667f);
}
/*----------- End of Buttons -------------*/
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

+8
View File
@@ -0,0 +1,8 @@
{
"html": "Ars_Magica_5th.html",
"css": "Ars_Magica_5th.css",
"authors": "Coal Powered Puppet.",
"roll20userid": "492849",
"preview": "Ars_Magica_5th.png",
"instructions": "#Ars Magica 5th \r \r **For use with Ars Magica 5th edition** \r \r Chrome Users must load unsafe scripts to see ultra-cool Font. \r\r If there's something you want added, or you'd like to report a bug, please contact the author of this sheet. "
}
+461
View File
@@ -0,0 +1,461 @@
.sheet-characteristic-roll{
font-size: 0.8em !important;
margin-left: 3px;
margin-right: 3px;
font-weight: bold;
margin-bottom: 0px;
}
.sheet-skills-header{
margin-bottom: 8px;
text-align: center;
color: #FFF;
background-color: #000;
}
.charsheet{
background-color: lightgray;
}
/*Hide stuff*/
.charsheet div.sheet-skills-magic1{
display: none;
}
.charsheet input.sheet-toggle-magic1:checked ~ div.sheet-skills-magic1 {
display: inline;
}
.charsheet div.sheet-strike-rank{
display: none;
}
.charsheet input.sheet-showstrike-rank:checked ~ div.sheet-strike-rank {
display: inline;
}
.charsheet span.sheet-strike-rank{
display: inline;
}
.charsheet input.sheet-showstrike-rank:checked ~ span.sheet-strike-rank {
display: none;
}
/*
input.sheet-showstrike-rank:checked ~ .repcontainer[data-groupname="repeating_Hand-to-Hand"] sheet-strike-rank {
display: inline;
}
div[data-groupname="repeating_Hand-to-Hand"] .sheet-strike-rank
{
display: inline-block;
border: 5px solid green;
}
*/
.sheet-melee-toggle { display: none; }
.sheet-check-melee-toggle:checked ~ [data-groupname=repeating_melee] > .repitem .sheet-melee-toggle { display: inline; }
.sheet-example-toggle { display: none; }
.sheet-check-toggle:checked ~ [data-groupname=repeating_example] > .repitem .sheet-example-toggle { display: inline; }
.sheet-repeat-strike-rank{ display: none; border: 5px soild pink; }
.sheet-showstrike-rank:checked ~ [data-groupname=repeating_Hand-to-Hand] > .repitem .sheet-repeat-strike-rank { display: inline; }
/*
input.sheet-collapse-example::checked ~ .repcontainer[data-groupname=repeating_example] .repeating-content {
display: none;
}
*/
/*
.charsheet div.sheet-skills-alphabetical{
display: inline;
}
.charsheet input.sheet-toggle-alphabetical:not(:checked) ~ div.sheet-skills-alphabetical {
display: none;
*/
.charsheet div.sheet-skills-alphabetical{
display: none;
}
.charsheet input.sheet-toggle-alphabetical:checked ~ div.sheet-skills-alphabetical {
display: inline;
}
.charsheet div.sheet-skills-by-category{
display: none;
}
.charsheet input.sheet-toggle-categories:checked ~ div.sheet-skills-by-category {
display: inline;
}
.charsheet div.sheet-strike-rank{
display: none;
}
.charsheet input.sheet-showstrike-rank:checked ~ div.sheet-strike-rank {
display: inline;
}
.charsheet div.sheet-hpbl {
display: none;
}
.charsheet input.sheet-showhbpl:checked ~ div.sheet-hpbl {
display: block;
}
.charsheet div.sheet-hitloc{
display: none;
}
.charsheet input.sheet-showhitloc:checked ~ div.sheet-hitloc {
display: inline;
}
.charsheet div.sheet-edufld{
display: none;
}
.charsheet input.sheet-showedufld:checked ~ div.sheet-edufld {
display: inline;
}
.charsheet div.sheet-mjrwnd{
display: none;
}
.charsheet input.sheet-showmjrwnd:checked ~ div.sheet-mjrwnd {
display: inline;
}
/* Configuration Window*/
.charsheet .sheet-cdiv {
width:810px;
/*border: 1px dotted;*/
padding-right: 15px;
padding-left: 15px;
}
.sheet-HideConfig:checked ~ *.sheet-config {
display:none;
}
.charsheet span.sheet-is-config::after { /*Close Config: grayish background with black text*/
content: "^";
}
.charsheet .sheet-HideConfig:checked + span.sheet-is-config::after { /*Show Configuration: Black background with grayish text*/
content: "v";
}
.charsheet span.sheet-is-config {
text-align: center;
display: inline-block;
width: 5%;
height: 16px;
font-size: 9px;
/*font-family: "Pictos";*/
/*background: #65763c;*/
background: black; /*#93537c;*/
color: white; /*white;*/
font-weight: bold;
border-radius: 4px;
margin-left: -5%;
}
.charsheet input.sheet-HideConfig {
width: 5%;
height: 16px;
cursor: pointer;
margin-left: auto;
margin-top: auto;
/*position: absolute;
right: 20%;*/
opacity: 0;
z-index: 9999;
}
.charsheet .sheet-HideConfig:checked + span.sheet-is-config {
background: black;
border-radius: 4px;
color: white;
}
.charsheet label.sheet-configitem {
margin-left: 10px;
width: 50px;
font-size: .9em;
font-weight: normal
}
/*End Configuration Window*/
.sheet-section-header{
text-align: center;
color: #FFF;
background-color: #000;
}
.sheet-col h3{
margin-bottom: 10px;
}
.repcontrol{
margin-right: 7px;
}
div.repcontrol button
{
width: 20px;
height: 20px;
color: transparent;
text-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
}
div.repcontrol button.repcontrol_add::before,
div.repcontrol button.repcontrol_edit::before
{
font-family: Pictos;
position: relative;
color: #000;
}
/* +Add */
div.repcontrol button.repcontrol_add::before
{
content: "&"; /* & in Pictos is a + sign, while + is a plus inside a circle */
left: -5px;
top: -4px;
}
/* Modify */
div.repcontrol button.repcontrol_edit::before
{
text-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
content: "x"; /* x in Pictos is a crossed hammer and wrench */
left: -5px;
top: -4px;
}
/* Done */
div.repcontrol.editmode button.repcontrol_edit::before
{
content: "3"; /* 3 in Pictos is a check mark */
}
.sheet-big-col{
width: calc(60% - 20px) !important;
}
.sheet-small-col{
width: calc(40% - 20px) !important;
}
.sheet-characteristics
{
border: 3px solid black;
width: 100%
}
.sheet-characteristics p
{
margin-left: 3px;
margin-right: 7px;
font-weight: bold;
margin-bottom: 0px;
}
button[type="roll"].sheet-plain
{
width:100%;
}
button[type="roll"].sheet-plain-major-wound
{
background: #000;
background: -webkit-linear-gradient(#000, #000);
background: linear-gradient(#000, #000);
border-radius: 5px;
color: #fff;
display: inline-block;
text-align: center;
text-shadow: 1px 1px 0 #000;
font-size: 1.0em;
}
button[type="roll"].sheet-plain-major-wound::before
{
content: "";
width: 117px;
color: #fff ;
background-color: #000
}
button[type="roll"].sheet-plain::before
{
content: "";
}
.sheet-hit-location-selection {
color: #ffffff;
background-color: #000000;
width:100%
}
.sheet-hit-location-selection td{
padding-left: 20px;
}
.sheet-hit-location-selection select{
color: #ffffff;
background-color: #000000;
margin-top: 3px;
}
.sheet-loc-text{
text-align:left;
}
.sheet-header-text{
font-size: 10px;
}
.sheet-armor-name{
width:100px;
}
.sheet-template_value{
text-align: right;
}
.sheet-rolltemplate-HL-Missle th {
text-align: centre;
color: #ffffff;
background-color: #000000;
}
.sheet-rolltemplate-HL-Missle table {
width: 230px;
padding: 2px;
border: 1px solid;
background-color: #ffffff;
}
.sheet-rolltemplate-HL-Melee th {
text-align: centre;
color: #ffffff;
background-color: #000000;
}
.sheet-rolltemplate-HL-Melee table {
width: 230px;
padding: 2px;
border: 1px solid;
background-color: #ffffff;
}
.sheet-rolltemplate-skillRoll th {
text-align: centre;
color: #ffffff;
background-color: #000000;
}
.sheet-rolltemplate-skillRoll table {
width: 230px;
padding: 2px;
border: 1px solid;
background-color: #ffffff;
}
.sheet-rolltemplate-melee-roll th {
text-align: centre;
color: #ffffff;
background-color: #000000;
}
.sheet-rolltemplate-melee-roll table {
width: 230px;
padding: 2px;
border: 1px solid;
background-color: #ffffff;
}
.sheet-rolltemplate-melee-roll .template_value{
text-align: right;
}
.charsheet .sheet-cat_header{
font-size:1.3em;
}
.charsheet .sheet-chkfiller{
width:12px;
}
.charsheet .sheet-skillname{
width:154px;
}
.charsheet .sheet-repeat-skillname{
width:151px;
}
.charsheet button[type=roll].sheet-textButton {
background-color: transparent;
color: black;
border: none;
font-size: 1.25em;
font-weight: bold;
text-align: right;
background-image: none;
text-shadow: none;
box-shadow: none;
padding: 0px;
margin: 0px;
/*margin-top: -5px;*/
/*width: 70%;*/
}
.charsheet span.sheet-diceroll {
font-family: "dicefontd20";
}
.charsheet button[type=roll].sheet-textButton::before,
.charsheet button[type=roll].sheet-powerButton::before {
content: "" !important;
}
.charsheet input[type=text].sheet-standard {
border-top: none;
border-right: none;
border-left: none;
border-bottom: dotted 1px black;
color: black;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Some files were not shown because too many files have changed in this diff Show More