daggerheart/module/helpers/handlebarsHelper.mjs
WBHarry 261a3a68b0
[PR] [Feature] Party Sheet (#1230)
* start development

* finish party members tab

* start resources tab

* finish resources tab

* finish inventory tab and add inital template to projects tab

* add resource buttons actions methods

* add group roll dialog

* Main implementation

* Fixed costs

* Minor fixes and tweaks for the party sheet (#1239)

* Minor fixes and tweaks for the party sheet

* Fix scroll restoration for party sheet tabs

* Finished GroupRoll

* Removed/commented-out not yet implemented things

* Commented out Difficulty since it's not used yet

* Re-render party when members update (#1242)

* Fixed so style applies in preview chat message

* Added the clown car

* Fixed so items can be dropped into the Party sheet

* Added delete icon to inventory

* Fixed TokenHUD token property useage. Fixed skipping roll message

* Added visible modifier to GroupRoll leader result

* Leader roll displays the large result display right away after rolling

* Corrected tokenHUD for non-player-tokens

* Fixed clowncar tokenData

* Fixed TagTeam roll message and sound

* Removed final TagTeamRoll roll sound

* [PR] [Party Sheets] Sidebar character sheet changes (#1249)

* Something experimenting

* I am silly (wearning Dunce hat)

* Stressful task

* Armor functional to be hit

* CSS Changes to accomadate pip boy

* last minute change to resource section for better visual feeling

* restoring old css for toggle

* Added setting to toggle pip/number display

* toggle functionality added

* Fixed light-mode in characterSheet

* Fixed multi-row resource pips display for character

* Fixed separators

* Added pip-display to Adversary and Companion. Some fixing on armor display

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>

* Fixed party height and resource armor update

* Fixed deletebutton padding

* Only showing expand-me icon on InventoryItem if there is a description to show

* .

* Fixed menu icon to be beige instead of white in dark mode

---------

Co-authored-by: moliloo <dev.murilobrito@gmail.com>
Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>
Co-authored-by: Nikhil Nagarajan <potter.nikhil@gmail.com>
2025-11-11 16:02:45 +01:00

102 lines
3.5 KiB
JavaScript

import { itemAbleRollParse } from './utils.mjs';
export default class RegisterHandlebarsHelpers {
static registerHelpers() {
Handlebars.registerHelper({
add: this.add,
includes: this.includes,
times: this.times,
damageFormula: this.damageFormula,
formulaValue: this.formulaValue,
damageSymbols: this.damageSymbols,
rollParsed: this.rollParsed,
hasProperty: foundry.utils.hasProperty,
getProperty: foundry.utils.getProperty,
setVar: this.setVar,
empty: this.empty,
pluralize: this.pluralize,
positive: this.positive,
isNullish: this.isNullish
});
}
static add(a, b) {
const aNum = Number.parseInt(a);
const bNum = Number.parseInt(b);
return (Number.isNaN(aNum) ? 0 : aNum) + (Number.isNaN(bNum) ? 0 : bNum);
}
static includes(list, item) {
return list.includes(item);
}
static times(nr, block) {
var accum = '';
for (var i = 0; i < nr; ++i) accum += block.fn(i);
return accum;
}
static damageFormula(attack, actor) {
const traitTotal = actor.system.traits?.[attack.roll.trait]?.value;
const instances = [
attack.damage.parts.map(x => Roll.replaceFormulaData(x.value.getFormula(), actor)).join(' + '),
traitTotal
].filter(x => x);
return instances.join(traitTotal > 0 ? ' + ' : ' - ');
}
static formulaValue(formula, item) {
if (isNaN(formula)) {
const data = item.getRollData.bind(item)(),
roll = new Roll(Roll.replaceFormulaData(formula, data)).evaluateSync();
formula = roll.total;
}
return formula;
}
static damageSymbols(damageParts) {
const symbols = [...new Set(damageParts.reduce((a, c) => a.concat([...c.type]), []))].map(
p => CONFIG.DH.GENERAL.damageTypes[p].icon
);
return new Handlebars.SafeString(Array.from(symbols).map(symbol => `<i class="fa-solid ${symbol}"></i>`));
}
static rollParsed(value, actor, item, numerical) {
const isNumerical = typeof numerical === 'boolean' ? numerical : false;
const result = itemAbleRollParse(value, actor?.getRollData() ?? {}, item);
return isNumerical ? (!result ? 0 : Number(result)) : result;
}
static setVar(name, value) {
this[name] = value;
}
static empty(object) {
if (!(typeof object === 'object')) return true;
return Object.keys(object).length === 0;
}
/**
* Pluralize helper that returns the appropriate localized string based on count
* @param {number} count - The number to check for plurality
* @param {string} baseKey - The base localization key (e.g., "DAGGERHEART.GENERAL.Target")
* @returns {string} The localized singular or plural string
*
* Usage: {{pluralize currentTargets.length "DAGGERHEART.GENERAL.Target"}}
* Returns: "Target" if count is exactly 1, "Targets" if count is 0, 2+, or invalid
*/
static pluralize(count, baseKey) {
const numericCount = Number(count);
const isSingular = !isNaN(numericCount) && numericCount === 1;
const key = isSingular ? `${baseKey}.single` : `${baseKey}.plural`;
return game.i18n.localize(key);
}
static positive(a) {
return Math.abs(Number(a));
}
static isNullish(a) {
return a === null || a === undefined;
}
}