190 lines
7.0 KiB
JavaScript
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
|
|
};
|
|
});
|
|
}
|
|
}
|