225 lines
8.8 KiB
JavaScript
225 lines
8.8 KiB
JavaScript
/**
|
||
* 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 2025–2026 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";
|
||
import { DonjonEtCieUtility } from "./donjon-et-cie-utility.mjs";
|
||
|
||
import { DonjonEtCieActor } from "./donjon-et-cie-actor.mjs";
|
||
import { DonjonEtCieItem } from "./donjon-et-cie-item.mjs";
|
||
import * as models from "./models/index.mjs";
|
||
import * as sheets from "./applications/sheets/_module.mjs";
|
||
import { DonjonEtCieRollDialog } from "./applications/donjon-et-cie-roll-dialog.mjs";
|
||
import { DonjonEtCieRolls } from "./donjon-et-cie-rolls.mjs";
|
||
import { DonjonEtCieMacros } from "./donjon-et-cie-macros.mjs";
|
||
|
||
const WELCOME_MESSAGE_SETTING = "welcomeMessageVersion";
|
||
|
||
function injectActorDirectoryMissionPackButton(app, element) {
|
||
if (!game.user.isGM) return;
|
||
|
||
const root = app?.element ?? element?.[0] ?? element;
|
||
if (!(root instanceof HTMLElement)) return;
|
||
|
||
const headerActions = root.querySelector(".directory-header .header-actions");
|
||
if (!(headerActions instanceof HTMLElement)) return;
|
||
if (headerActions.querySelector(".dnc-mission-pack-button")) return;
|
||
|
||
const button = document.createElement("button");
|
||
button.type = "button";
|
||
button.className = "dnc-mission-pack-button";
|
||
button.title = game.i18n.localize("DNC.Macro.MissionPack.SidebarButton");
|
||
button.setAttribute("aria-label", game.i18n.localize("DNC.Macro.MissionPack.SidebarButton"));
|
||
button.innerHTML = `<i class="fa-solid fa-box-open" inert></i><span>${game.i18n.localize("DNC.Macro.MissionPack.SidebarButton")}</span>`;
|
||
button.addEventListener("click", () => {
|
||
void game.system.donjonEtCie.macros.openMissionPackDialog();
|
||
});
|
||
headerActions.append(button);
|
||
}
|
||
|
||
function onChatActionClick(event) {
|
||
const button = event.target.closest("[data-action='rollChatDamage'], [data-action='rollSpellChaos'], [data-action='applyDamage']");
|
||
if (!(button instanceof HTMLElement)) return;
|
||
|
||
event.preventDefault();
|
||
|
||
void (async () => {
|
||
if (button.dataset.action === "rollSpellChaos") {
|
||
const actorUuid = button.dataset.actorUuid;
|
||
const itemUuid = button.dataset.itemUuid;
|
||
if (!actorUuid || !itemUuid) return;
|
||
const [actor, item] = await Promise.all([fromUuid(actorUuid), fromUuid(itemUuid)]);
|
||
return DonjonEtCieRolls.rollSpellChaos(actor, item);
|
||
}
|
||
|
||
if (button.dataset.action === "applyDamage") {
|
||
const card = button.closest(".dnc-chat-card-damage");
|
||
const select = card?.querySelector("[data-role='damage-target']");
|
||
const targetUuid = select instanceof HTMLSelectElement ? select.value : "";
|
||
if (!targetUuid) {
|
||
ui.notifications.warn(game.i18n.localize("DNC.Chat.SelectTarget"));
|
||
return null;
|
||
}
|
||
|
||
const target = await fromUuid(targetUuid);
|
||
if (!target) {
|
||
ui.notifications.warn(game.i18n.localize("DNC.Chat.TargetUnavailable"));
|
||
return null;
|
||
}
|
||
|
||
return DonjonEtCieRolls.applyDamage(target, {
|
||
damage: Number(button.dataset.damage ?? 0),
|
||
useArmor: button.dataset.useArmor === "true",
|
||
sourceLabel: button.dataset.sourceLabel ?? ""
|
||
});
|
||
}
|
||
|
||
const itemUuid = button.dataset.itemUuid;
|
||
if (!itemUuid) return;
|
||
const item = await fromUuid(itemUuid);
|
||
return item?.rollDamage?.();
|
||
})();
|
||
}
|
||
|
||
function registerSystemSettings() {
|
||
game.settings.register("fvtt-donjon-et-cie", WELCOME_MESSAGE_SETTING, {
|
||
name: "Version du message de bienvenue",
|
||
hint: "Usage interne pour eviter de republier le message de bienvenue a chaque chargement.",
|
||
scope: "world",
|
||
config: false,
|
||
type: String,
|
||
default: ""
|
||
});
|
||
}
|
||
|
||
async function getHelpJournalLink() {
|
||
const pack = [...game.packs.values()].find((candidate) => candidate.metadata.name === "system-help");
|
||
if (!pack) return null;
|
||
|
||
const index = await pack.getIndex();
|
||
const entry = index.find((document) => document.name === "Aide du systeme");
|
||
if (!entry?._id) return null;
|
||
|
||
const journal = await pack.getDocument(entry._id);
|
||
if (!journal?.uuid) return null;
|
||
|
||
return `@UUID[${journal.uuid}]{${game.i18n.localize("DNC.Welcome.HelpLinkLabel")}}`;
|
||
}
|
||
|
||
async function maybeCreateWelcomeMessage() {
|
||
if (!game.user.isGM) return;
|
||
|
||
const currentVersion = String(game.system.version ?? "");
|
||
const shownVersion = String(game.settings.get("fvtt-donjon-et-cie", WELCOME_MESSAGE_SETTING) ?? "");
|
||
if (shownVersion === currentVersion) return;
|
||
|
||
const helpJournalLink = await getHelpJournalLink();
|
||
const content = await foundry.applications.handlebars.renderTemplate(
|
||
"systems/fvtt-donjon-et-cie/templates/chat/welcome-card.hbs",
|
||
{
|
||
title: game.i18n.localize("DNC.Welcome.Title"),
|
||
subtitle: game.i18n.format("DNC.Welcome.Subtitle", { version: currentVersion }),
|
||
intro: game.i18n.localize("DNC.Welcome.Intro"),
|
||
bullets: [
|
||
game.i18n.localize("DNC.Welcome.BulletActors"),
|
||
game.i18n.localize("DNC.Welcome.BulletItems"),
|
||
game.i18n.localize("DNC.Welcome.BulletMissionPack")
|
||
],
|
||
helpLabel: game.i18n.localize("DNC.Welcome.HelpLabel"),
|
||
helpLink: helpJournalLink,
|
||
helpFallback: game.i18n.localize("DNC.Welcome.HelpFallback"),
|
||
footer: game.i18n.localize("DNC.Welcome.Footer"),
|
||
creditsLabel: game.i18n.localize("DNC.Welcome.CreditsLabel"),
|
||
creditsText: game.i18n.localize("DNC.Welcome.CreditsText"),
|
||
officialLabel: game.i18n.localize("DNC.Welcome.OfficialLabel"),
|
||
officialUrl: "https://johndoe-rpg.com/catalogue/donjon-cie/",
|
||
officialLinkText: game.i18n.localize("DNC.Welcome.OfficialLinkText")
|
||
}
|
||
);
|
||
|
||
await ChatMessage.create({
|
||
speaker: {
|
||
alias: game.system.title
|
||
},
|
||
user: game.user.id,
|
||
content: await TextEditor.enrichHTML(content, { async: true })
|
||
});
|
||
|
||
await game.settings.set("fvtt-donjon-et-cie", WELCOME_MESSAGE_SETTING, currentVersion);
|
||
}
|
||
|
||
Hooks.once("init", async () => {
|
||
const startupBanner =
|
||
`▗▄▄▄ ▗▄▖ ▗▖ ▗▖ ▗▖ ▗▄▖ ▗▖ ▗▖ ▗▄▄▄▖▗▄▄▄▖ ▗▄▄▖▗▄▄▄▖▗▞▀▚▖
|
||
▐▌ █ ▐▌ ▐▌▐▛▚▖▐▌ ▐▌▐▌ ▐▌▐▛▚▖▐▌ ▐▌ █ ▐▌ █ ▐▛▀▀▘
|
||
▐▌ █ ▐▌ ▐▌▐▌ ▝▜▌ ▐▌▐▌ ▐▌▐▌ ▝▜▌ ▐▛▀▀▘ █ ▐▌ █ ▝▚▄▄▖
|
||
▐▙▄▄▀ ▝▚▄▞▘▐▌ ▐▌▗▄▄▞▘▝▚▄▞▘▐▌ ▐▌ ▐▙▄▄▖ █ ▝▚▄▄▖▗▄█▄▖
|
||
`;
|
||
|
||
console.log(`%c${startupBanner}`, "font-family: monospace; white-space: pre; line-height: 1.1;");
|
||
console.log("Initialisation du systeme Donjon & Cie");
|
||
|
||
registerSystemSettings();
|
||
await DonjonEtCieUtility.preloadHandlebarsTemplates();
|
||
|
||
CONFIG.Combat.initiative = {
|
||
formula: "1d20 + @system.caracteristiques.dexterite.value + @system.combat.initiativeBonus",
|
||
decimals: 0
|
||
};
|
||
|
||
CONFIG.Actor.documentClass = DonjonEtCieActor;
|
||
CONFIG.Actor.dataModels = {
|
||
employe: models.EmployeDataModel,
|
||
pnj: models.PnjDataModel
|
||
};
|
||
|
||
CONFIG.Item.documentClass = DonjonEtCieItem;
|
||
CONFIG.Item.dataModels = {
|
||
trait: models.TraitDataModel,
|
||
langue: models.LangueDataModel,
|
||
capacite: models.CapaciteDataModel,
|
||
sortilege: models.SortilegeDataModel,
|
||
arme: models.ArmeDataModel,
|
||
armure: models.ArmureDataModel,
|
||
equipement: models.EquipementDataModel,
|
||
consommable: models.ConsommableDataModel,
|
||
entrainement: models.EntrainementDataModel
|
||
};
|
||
|
||
game.system.donjonEtCie = {
|
||
config: DONJON_ET_CIE,
|
||
models,
|
||
sheets,
|
||
rolls: DonjonEtCieRolls,
|
||
dialogs: DonjonEtCieRollDialog,
|
||
utility: DonjonEtCieUtility,
|
||
macros: DonjonEtCieMacros
|
||
};
|
||
|
||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-donjon-et-cie", sheets.DonjonEtCieEmployeSheet, { types: ["employe"], makeDefault: true });
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-donjon-et-cie", sheets.DonjonEtCiePNJSheet, { types: ["pnj"], makeDefault: true });
|
||
|
||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||
for (const type of ["trait", "langue", "capacite", "sortilege", "arme", "armure", "equipement", "consommable", "entrainement"]) {
|
||
foundry.documents.collections.Items.registerSheet("fvtt-donjon-et-cie", sheets.DonjonEtCieItemSheet, { types: [type], makeDefault: true });
|
||
}
|
||
});
|
||
|
||
Hooks.once("ready", () => {
|
||
document.addEventListener("click", onChatActionClick);
|
||
void maybeCreateWelcomeMessage();
|
||
});
|
||
|
||
Hooks.on("renderActorDirectory", (app, element) => {
|
||
injectActorDirectoryMissionPackButton(app, element);
|
||
});
|