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

202 lines
7.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Donjon & Cie - Systeme FoundryVTT
*
* Donjon & Cie est un jeu de role edite par John Doe.
* Ce systeme FoundryVTT est une implementation independante et n'est pas
* affilie a John Doe.
*
* @author LeRatierBretonnien
* @copyright 20252026 LeRatierBretonnien
* @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
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
};
});
}
}