mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-09-11 17:42:29 +00:00
381 lines
17 KiB
JavaScript
381 lines
17 KiB
JavaScript
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 };
|