Files
fvtt-donjon-et-cie/modules/donjon-et-cie-utility.mjs

190 lines
7.0 KiB
JavaScript

import { DONJON_ET_CIE } from "./donjon-et-cie-config.mjs";
export class DonjonEtCieUtility {
static defaultItemIcons = {
arme: "systems/fvtt-donjon-et-cie/assets/icons/system/items/arme.svg",
armure: "systems/fvtt-donjon-et-cie/assets/icons/system/items/armure.svg",
trait: "systems/fvtt-donjon-et-cie/assets/icons/system/items/trait.svg",
sortilege: "systems/fvtt-donjon-et-cie/assets/icons/system/items/sortilege.svg",
equipement: "systems/fvtt-donjon-et-cie/assets/icons/system/items/equipement.svg",
other: "systems/fvtt-donjon-et-cie/assets/icons/system/items/autre.svg"
};
static async preloadHandlebarsTemplates() {
return foundry.applications.handlebars.loadTemplates([
"systems/fvtt-donjon-et-cie/templates/actors/employe-sheet.hbs",
"systems/fvtt-donjon-et-cie/templates/actors/pnj-sheet.hbs",
"systems/fvtt-donjon-et-cie/templates/items/item-sheet.hbs",
"systems/fvtt-donjon-et-cie/templates/dialogs/characteristic-roll.hbs",
"systems/fvtt-donjon-et-cie/templates/dialogs/initiative-roll.hbs",
"systems/fvtt-donjon-et-cie/templates/dialogs/weapon-roll.hbs",
"systems/fvtt-donjon-et-cie/templates/dialogs/damage-roll.hbs",
"systems/fvtt-donjon-et-cie/templates/dialogs/spell-roll.hbs",
"systems/fvtt-donjon-et-cie/templates/dialogs/usage-roll.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/roll-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/spell-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/chaos-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/hit-dice-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/damage-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/damage-application-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/favor-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/initiative-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/usage-card.hbs",
"systems/fvtt-donjon-et-cie/templates/chat/item-card.hbs"
]);
}
static getCharacteristicEntries(system) {
return Object.entries(DONJON_ET_CIE.characteristics).map(([key, metadata]) => ({
key,
label: metadata.label,
short: metadata.short,
value: system.caracteristiques?.[key]?.value ?? 0
}));
}
static formatUsageDie(value) {
return value ? `Δ${value}` : "—";
}
static getDefaultItemIcon(type) {
return this.defaultItemIcons[type] ?? this.defaultItemIcons.other;
}
static getCurrentSceneId() {
return canvas?.scene?.id ?? game.scenes?.current?.id ?? "global";
}
static getSceneDamageTargets() {
const scene = canvas?.scene ?? game.scenes?.current;
const tokens = scene?.tokens?.contents ?? [];
return tokens
.map((token) => {
const actor = token.actor;
if (!actor || !["employe", "pnj"].includes(actor.type)) return null;
const tokenName = token.name || actor.name;
const actorName = actor.name || tokenName;
const label = tokenName === actorName ? tokenName : `${tokenName} (${actorName})`;
return {
tokenId: token.id,
tokenUuid: token.uuid,
actorUuid: actor.uuid,
label
};
})
.filter(Boolean)
.sort((a, b) => a.label.localeCompare(b.label, "fr", { sensitivity: "base" }));
}
static getMagicResourceContext(actor) {
const rank = Number(actor.system.anciennete?.rang ?? actor.system.sante?.dv ?? 0);
const focusDelta = Number(actor.system.magie?.focus?.delta ?? 0);
const focusResult = Number(actor.system.magie?.focus?.resultat ?? 0);
const focusSceneId = actor.system.magie?.focus?.sceneId ?? "";
const activeFocus = focusSceneId === this.getCurrentSceneId() ? focusResult : 0;
const chaosDelta = Number(actor.system.magie?.chaos?.delta ?? 12);
return {
rank,
focusDelta,
focusLabel: this.formatUsageDie(focusDelta),
focusSceneId,
focusStoredResult: focusResult,
focusActiveValue: activeFocus,
focusIsActive: activeFocus > 0,
focusDisplay: activeFocus > 0 ? `${activeFocus} (${this.formatUsageDie(focusDelta)})` : "—",
chaosDelta,
chaosLabel: this.formatUsageDie(chaosDelta),
chaosAvailable: chaosDelta >= 4
};
}
static getFavorLabel(key) {
return DONJON_ET_CIE.favorDepartments[key] ?? key;
}
static getFavorEntries(system) {
const favors = system.faveurs ?? {};
return Object.entries(DONJON_ET_CIE.favorDepartments).map(([key, label]) => {
const delta = Number(favors[key]?.delta ?? 0);
return {
key,
label,
delta,
deltaLabel: this.formatUsageDie(delta),
hasFavor: delta > 0
};
});
}
static getAvailableFavorOptions(actor) {
return this.getFavorEntries(actor.system)
.filter((entry) => entry.hasFavor)
.map((entry) => ({ value: entry.key, label: `${entry.label} (${entry.deltaLabel})` }));
}
static getChaosTableEntries() {
return Object.entries(DONJON_ET_CIE.chaosTable)
.map(([value, entry]) => ({ value: Number(value), ...entry }))
.sort((a, b) => a.value - b.value);
}
static degradeUsageDie(value) {
const sequence = [12, 10, 8, 6, 4];
const index = sequence.indexOf(Number(value));
if (index === -1) return 0;
return sequence[index + 1] ?? 0;
}
static sortByName(documents) {
return [...documents].sort((a, b) => a.name.localeCompare(b.name, "fr", { sensitivity: "base" }));
}
static getWeaponCharacteristicKey(category) {
return category === "distance" ? "dexterite" : "force";
}
static getWeaponCharacteristicLabel(category) {
const key = this.getWeaponCharacteristicKey(category);
return DONJON_ET_CIE.characteristics[key]?.label ?? key;
}
static enrichItemForSheet(item) {
const system = item.system;
const delta = Number(system.delta ?? 0);
return {
id: item.id,
name: item.name,
type: item.type,
img: item.img,
system,
uuid: item.uuid,
usageLabel: delta > 0 ? this.formatUsageDie(delta) : null,
protectionLabel: item.type === "armure" && Number(system.resultatProtection ?? 0) > 0 ? `Protection ${system.resultatProtection}` : null,
weaponCharacteristicLabel: item.type === "arme" ? this.getWeaponCharacteristicLabel(system.categorie) : null,
canRoll: ["arme", "sortilege"].includes(item.type),
canUse: delta > 0,
canRollDamage: Boolean(system.degats),
rollAction: item.type === "sortilege" ? "rollSpell" : "rollWeapon",
damageAction: "rollDamage",
isEquipped: Boolean(system.equipee)
};
}
static buildActorSections(actor) {
return Object.entries(DONJON_ET_CIE.actorSections).map(([key, metadata]) => {
const types = DONJON_ET_CIE.sectionTypes[key];
const items = this.sortByName(actor.items.filter((item) => types.includes(item.type))).map((item) => this.enrichItemForSheet(item));
return {
key,
label: metadata.label,
createType: metadata.createType,
items
};
});
}
}