Files
fvtt-donjon-et-cie/modules/donjon-et-cie-main.mjs
T
uberwald 755c349078
Release Creation / build (release) Successful in 1m26s
DsN OK, objets uniques, règles de campagne
2026-05-03 21:51:35 +02:00

239 lines
9.3 KiB
JavaScript
Raw 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";
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: ""
});
game.settings.register("fvtt-donjon-et-cie", DonjonEtCieMacros.MISSION_PACK_MODE_SETTING, {
name: "Mode de paquetage de mission",
hint: "Choisit entre le tirage classique rapide et la regle optionnelle de campagne avec allocation des des par les joueurs.",
scope: "world",
config: true,
type: String,
default: "classic",
choices: {
classic: "Classique",
campaign: "Campagne"
}
});
}
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", () => {
DonjonEtCieMacros.registerSocketListeners();
document.addEventListener("click", onChatActionClick);
void maybeCreateWelcomeMessage();
});
Hooks.on("renderActorDirectory", (app, element) => {
injectActorDirectoryMissionPackButton(app, element);
});