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