Final fixes and code review checks
Release Creation / build (release) Successful in 39s

This commit is contained in:
2026-06-12 08:19:42 +02:00
parent 37badf2619
commit cbeaaeec99
13 changed files with 137 additions and 180 deletions
+25 -43
View File
@@ -4,7 +4,6 @@
*/ */
import { SYSTEM } from "./module/config/system.mjs" import { SYSTEM } from "./module/config/system.mjs"
globalThis.SYSTEM = SYSTEM // Expose the SYSTEM object to the global scope
// Import modules // Import modules
import * as models from "./module/models/_module.mjs" import * as models from "./module/models/_module.mjs"
@@ -14,15 +13,24 @@ import * as applications from "./module/applications/_module.mjs"
import { LethalFantasyCombatTracker, LethalFantasyCombat } from "./module/applications/combat.mjs" import { LethalFantasyCombatTracker, LethalFantasyCombat } from "./module/applications/combat.mjs"
import { Macros } from "./module/macros.mjs" import { Macros } from "./module/macros.mjs"
import { setupTextEnrichers } from "./module/enrichers.mjs" import { setupTextEnrichers } from "./module/enrichers.mjs"
import { default as LethalFantasyUtils } from "./module/utils.mjs" import LethalFantasyUtils, { log } from "./module/utils.mjs"
export class ClassCounter { static printHello() { console.log("Hello") } static sendJsonPostRequest(e, s) { const t = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify(s) }; return fetch(e, t).then((e => { if (!e.ok) throw new Error("La requête a échoué avec le statut " + e.status); return e.json() })).catch((e => { throw console.error("Erreur envoi de la requête:", e), e })) } static registerUsageCount(e = game.system.id, s = {}) { if (game.user.isGM) { game.settings.register(e, "world-key", { name: "Unique world key", scope: "world", config: !1, default: "", type: String }); let t = game.settings.get(e, "world-key"); null != t && "" != t && "NONE" != t && "none" != t.toLowerCase() || (t = foundry.utils.randomID(32), game.settings.set(e, "world-key", t)); let a = { name: e, system: game.system.id, worldKey: t, version: game.system.version, language: game.settings.get("core", "language"), remoteAddr: game.data.addresses.remote, nbInstalledModules: game.modules.size, nbActiveModules: game.modules.filter((e => e.active)).length, nbPacks: game.world.packs.size, nbUsers: game.users.size, nbScenes: game.scenes.size, nbActors: game.actors.size, nbPlaylist: game.playlists.size, nbTables: game.tables.size, nbCards: game.cards.size, optionsData: s, foundryVersion: `${game.release.generation}.${game.release.build}` }; this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php", a) } } }
Hooks.once("init", function () { Hooks.once("init", function () {
globalThis.SYSTEM = SYSTEM
globalThis.pendingDefenses = new Map()
console.info("Lethal Fantasy RPG | Initializing System") console.info("Lethal Fantasy RPG | Initializing System")
console.info(SYSTEM.ASCII) console.info(SYSTEM.ASCII)
game.settings.register(game.system.id, "debug", {
name: "Debug logging",
scope: "client",
config: true,
default: false,
type: Boolean,
})
globalThis.lethalFantasy = game.system globalThis.lethalFantasy = game.system
globalThis.log = log
game.system.CONST = SYSTEM game.system.CONST = SYSTEM
// Expose the system API // Expose the system API
@@ -54,12 +62,10 @@ Hooks.once("init", function () {
miracle: models.LethalFantasyMiracle miracle: models.LethalFantasyMiracle
} }
// Register sheet application classes // Register sheet application classes (V2)
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
foundry.documents.collections.Actors.registerSheet("lethalFantasy", applications.LethalFantasyCharacterSheet, { types: ["character"], makeDefault: true }) foundry.documents.collections.Actors.registerSheet("lethalFantasy", applications.LethalFantasyCharacterSheet, { types: ["character"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("lethalFantasy", applications.LethalFantasyMonsterSheet, { types: ["monster"], makeDefault: true }) foundry.documents.collections.Actors.registerSheet("lethalFantasy", applications.LethalFantasyMonsterSheet, { types: ["monster"], makeDefault: true })
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasySkillSheet, { types: ["skill"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasySkillSheet, { types: ["skill"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyGiftSheet, { types: ["gift"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyGiftSheet, { types: ["gift"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyVulnerabilitySheet, { types: ["vulnerability"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyVulnerabilitySheet, { types: ["vulnerability"], makeDefault: true })
@@ -76,14 +82,6 @@ Hooks.once("init", function () {
// Dice system configuration // Dice system configuration
CONFIG.Dice.rolls.push(documents.LethalFantasyRoll) CONFIG.Dice.rolls.push(documents.LethalFantasyRoll)
game.settings.register("lethalFantasy", "worldKey", {
name: "Unique world key",
scope: "world",
config: false,
type: String,
default: "",
})
// Activate socket handler // Activate socket handler
game.socket.on(`system.${SYSTEM.id}`, LethalFantasyUtils.handleSocketEvent) game.socket.on(`system.${SYSTEM.id}`, LethalFantasyUtils.handleSocketEvent)
@@ -113,10 +111,6 @@ Hooks.once("ready", function () {
// Initialiser la table des résultats D30 // Initialiser la table des résultats D30
documents.D30Roll.initialize() documents.D30Roll.initialize()
if (!SYSTEM.DEV_MODE) {
registerWorldCount("lethalFantasy")
}
// Saignement piloté par le combat tracker // Saignement piloté par le combat tracker
_registerBleedingHooks() _registerBleedingHooks()
@@ -333,7 +327,7 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
? (rollTargetData?._id || rollTargetData?.id) ? (rollTargetData?._id || rollTargetData?.id)
: (rollTargetData?.weapon?.id || rollTargetData?.weapon?._id) : (rollTargetData?.weapon?.id || rollTargetData?.weapon?._id)
const attackRollKey = rollTargetData?.rollKey const attackRollKey = rollTargetData?.rollKey
console.log(`[LF] request-defense-btn | attackRollType=${attackRollType} defender=${defenderName} defenderType=${combatant.actor?.type}`) log(`[LF] request-defense-btn | attackRollType=${attackRollType} defender=${defenderName} defenderType=${combatant.actor?.type}`)
const attackD30result = message.rolls[0]?.options?.D30result || null const attackD30result = message.rolls[0]?.options?.D30result || null
const attackD30message = message.rolls[0]?.options?.D30message || null const attackD30message = message.rolls[0]?.options?.D30message || null
const attackDiceResults = message.rolls[0]?.options?.diceResults || null const attackDiceResults = message.rolls[0]?.options?.diceResults || null
@@ -552,7 +546,7 @@ Hooks.on("preCreateChatMessage", (message) => {
[`flags.${SYSTEM.id}.attackData`]: game.lethalFantasy.nextDefenseData [`flags.${SYSTEM.id}.attackData`]: game.lethalFantasy.nextDefenseData
}) })
console.log("Added attack data to defense message:", game.lethalFantasy.nextDefenseData) log("Added attack data to defense message:", game.lethalFantasy.nextDefenseData)
// Nettoyer // Nettoyer
delete game.lethalFantasy.nextDefenseData delete game.lethalFantasy.nextDefenseData
@@ -563,7 +557,7 @@ Hooks.on("preCreateChatMessage", (message) => {
Hooks.on("createChatMessage", async (message) => { Hooks.on("createChatMessage", async (message) => {
const rollType = message.rolls[0]?.options?.rollType const rollType = message.rolls[0]?.options?.rollType
console.log("Defense hook checking message, rollType:", rollType) log("Defense hook checking message, rollType:", rollType)
// Vérifier si c'est un message de défense // Vérifier si c'est un message de défense
if (rollType !== "weapon-defense" && rollType !== "monster-defense" && rollType !== "save") return if (rollType !== "weapon-defense" && rollType !== "monster-defense" && rollType !== "save") return
@@ -571,10 +565,10 @@ Hooks.on("createChatMessage", async (message) => {
// Récupérer les données d'attaque depuis les flags // Récupérer les données d'attaque depuis les flags
const attackData = message.flags?.[SYSTEM.id]?.attackData const attackData = message.flags?.[SYSTEM.id]?.attackData
console.log("Defense message confirmed, attackData:", attackData) log("Defense message confirmed, attackData:", attackData)
if (!attackData) { if (!attackData) {
console.log("No attack data found in message flags") log("No attack data found in message flags")
return return
} }
@@ -596,7 +590,7 @@ Hooks.on("createChatMessage", async (message) => {
let defenseRoll = message.rolls[0]?.options?.rollTotal || message.rolls[0]?.total || 0 let defenseRoll = message.rolls[0]?.options?.rollTotal || message.rolls[0]?.total || 0
const defenseD30message = message.rolls[0]?.options?.D30message || null const defenseD30message = message.rolls[0]?.options?.D30message || null
console.log("Processing defense:", { attackRoll, defenseRoll, attackerId, defenderId }) log("Processing defense:", { attackRoll, defenseRoll, attackerId, defenderId })
// Attendre l'animation 3D // Attendre l'animation 3D
if (game?.dice3d) { if (game?.dice3d) {
@@ -1058,7 +1052,7 @@ Hooks.on("createChatMessage", async (message) => {
)) ))
if (shouldCreateMessage) { if (shouldCreateMessage) {
console.log("Creating comparison message", { attackerHandledBonus, defenderHandledBonus, isDefenderOwner: defender.isOwner }) log("Creating comparison message", { attackerHandledBonus, defenderHandledBonus, isDefenderOwner: defender.isOwner })
await LethalFantasyUtils.compareAttackDefense({ await LethalFantasyUtils.compareAttackDefense({
attackerName, attackerName,
@@ -1080,7 +1074,7 @@ Hooks.on("createChatMessage", async (message) => {
attackD30message attackD30message
}) })
} else { } else {
console.log("Skipping message creation", { attackerHandledBonus, defenderHandledBonus }) log("Skipping message creation", { attackerHandledBonus, defenderHandledBonus })
} }
}) })
@@ -1161,7 +1155,7 @@ Hooks.on("createChatMessage", async (message) => {
const defenderId = message.rolls[0]?.options?.defenderId const defenderId = message.rolls[0]?.options?.defenderId
const isDamage = message.rolls[0]?.options?.rollData?.isDamage const isDamage = message.rolls[0]?.options?.rollData?.isDamage
console.log("Auto-damage hook:", { defenderId, isDamage, rollType: message.rolls[0]?.options?.rollType }) log("Auto-damage hook:", { defenderId, isDamage, rollType: message.rolls[0]?.options?.rollType })
if (!defenderId || !isDamage) return if (!defenderId || !isDamage) return
@@ -1186,11 +1180,11 @@ Hooks.on("createChatMessage", async (message) => {
} }
if (!shouldApplyDamage) { if (!shouldApplyDamage) {
console.log("Auto-damage hook: Not responsible for applying damage, skipping") log("Auto-damage hook: Not responsible for applying damage, skipping")
return return
} }
console.log("Auto-damage hook: Applying damage as responsible user") log("Auto-damage hook: Applying damage as responsible user")
// Attendre l'animation 3D avant d'appliquer les dégâts // Attendre l'animation 3D avant d'appliquer les dégâts
if (game?.dice3d) { if (game?.dice3d) {
@@ -1401,16 +1395,4 @@ Hooks.on("hotbarDrop", (bar, data, slot) => {
*/ */
Hooks.on("renderChatLog", (_chatLog, html) => applications.injectDiceTray(_chatLog, html)) Hooks.on("renderChatLog", (_chatLog, html) => applications.injectDiceTray(_chatLog, html))
/**
* Register world usage statistics
* @param {string} registerKey
*/
async function registerWorldCount(registerKey) {
if (game.user.isGM) {
try {
ClassCounter.registerUsageCount(game.system.id, {})
} catch {
console.log("No usage log ")
}
}
}
+13 -41
View File
@@ -24,30 +24,29 @@ export class LethalFantasyCombatTracker extends foundry.applications.sidebar.tab
async _prepareContext(options) { async _prepareContext(options) {
let data = await super._prepareContext(options); let data = await super._prepareContext(options);
console?.log("Combat Tracker Data", data); log("Combat Tracker Data", data);
/*for (let u of data.turns) { /*for (let u of data.turns) {
let c = game.combat.combatants.get(u.id); let c = game.combat.combatants.get(u.id);
u.progressionCount = c.system.progressionCount u.progressionCount = c.system.progressionCount
u.isMonster = c.actor.type === "monster" u.isMonster = c.actor.type === "monster"
} }
console.log("Combat Data", data);*/ log("Combat Data", data);*/
return data; return data;
} }
static #initiativePlus(ev) { static async #initiativePlus(ev) {
ev.preventDefault(); ev.preventDefault();
let cId = ev.target.closest(".combatant").dataset.combatantId; let cId = ev.target.closest(".combatant").dataset.combatantId;
let c = game.combat.combatants.get(cId); let c = game.combat.combatants.get(cId);
c.update({ 'initiative': c.initiative + 1 }); await c.update({ 'initiative': c.initiative + 1 });
console.log("Initiative Plus");
} }
static #initiativeMinus(ev) { static async #initiativeMinus(ev) {
ev.preventDefault(); ev.preventDefault();
let cId = ev.target.closest(".combatant").dataset.combatantId; let cId = ev.target.closest(".combatant").dataset.combatantId;
let c = game.combat.combatants.get(cId); let c = game.combat.combatants.get(cId);
let newInit = Math.max(c.initiative - 1, 0); let newInit = Math.max(c.initiative - 1, 0);
c.update({ 'initiative': newInit }); await c.update({ 'initiative': newInit });
} }
/** /**
@@ -58,33 +57,6 @@ export class LethalFantasyCombatTracker extends foundry.applications.sidebar.tab
ev.preventDefault(); ev.preventDefault();
await game.combat.rollMonsterProgression(); await game.combat.rollMonsterProgression();
} }
activateListeners(html) {
super.activateListeners(html);
// Display Combat settings
html.find(".initiative-plus").click(ev => {
ev.preventDefault();
let cId = ev.currentTarget.closest(".combatant").dataset.combatantId;
let c = game.combat.combatants.get(cId);
c.update({ 'initiative': c.initiative + 1 });
});
html.find(".initiative-minus").click(ev => {
ev.preventDefault();
let cId = ev.currentTarget.closest(".combatant").dataset.combatantId;
let c = game.combat.combatants.get(cId);
c.update({ 'initiative': c.initiative - 1 });
console.log("Initiative Minus");
});
}
/* -------------------------------------------- */
static get defaultOptions() {
let path = "systems/fvtt-lethal-fantasy/templates/combat-tracker.hbs";
return foundry.utils.mergeObject(super.defaultOptions, {
template: path,
});
}
} }
export class LethalFantasyCombat extends Combat { export class LethalFantasyCombat extends Combat {
@@ -94,7 +66,7 @@ export class LethalFantasyCombat extends Combat {
* @returns {Combatant[]} * @returns {Combatant[]}
*/ */
setupTurns() { setupTurns() {
console?.log("Setup Turns...."); log("Setup Turns....");
this.turns ||= []; this.turns ||= [];
// Determine the turn order and the current turn // Determine the turn order and the current turn
@@ -164,19 +136,19 @@ export class LethalFantasyCombat extends Combat {
} }
} }
resetProgression(cId) { async resetProgression(cId) {
let c = this.combatants.get(cId); let c = this.combatants.get(cId);
c.update({ 'system.progressionCount': 0 }); await c.update({ 'system.progressionCount': 0 });
} }
setCasting(cId) { async setCasting(cId) {
let c = this.combatants.get(cId); let c = this.combatants.get(cId);
c.setFlag(SYSTEM.id, "casting", true); await c.setFlag(SYSTEM.id, "casting", true);
} }
resetCasting(cId) { async resetCasting(cId) {
let c = this.combatants.get(cId); let c = this.combatants.get(cId);
c.setFlag(SYSTEM.id, "casting", false); await c.setFlag(SYSTEM.id, "casting", false);
} }
isCasting(cId) { isCasting(cId) {
@@ -78,7 +78,6 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
/** @override */ /** @override */
_onRender(context, options) { _onRender(context, options) {
this.#dragDrop.forEach((d) => d.bind(this.element)) this.#dragDrop.forEach((d) => d.bind(this.element))
// Add listeners to rollable elements
const rollables = this.element.querySelectorAll(".rollable") const rollables = this.element.querySelectorAll(".rollable")
rollables.forEach((d) => d.addEventListener("click", this._onRoll.bind(this))) rollables.forEach((d) => d.addEventListener("click", this._onRoll.bind(this)))
} }
@@ -234,12 +233,12 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
const attr = target.dataset.edit const attr = target.dataset.edit
const current = foundry.utils.getProperty(this.document, attr) const current = foundry.utils.getProperty(this.document, attr)
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {} const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
const fp = new FilePicker({ const fp = new foundry.applications.ux.FilePicker.implementation({
current, current,
type: "image", type: "image",
redirectToRoot: img ? [img] : [], redirectToRoot: img ? [img] : [],
callback: (path) => { callback: async (path) => {
this.document.update({ [attr]: path }) await this.document.update({ [attr]: path })
}, },
top: this.position.top + 40, top: this.position.top + 40,
left: this.position.left + 10, left: this.position.left + 10,
@@ -261,7 +260,7 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
item = await fromUuid(uuid) item = await fromUuid(uuid)
if (!item) item = this.document.items.get(id) if (!item) item = this.document.items.get(id)
if (!item) return if (!item) return
item.sheet.render(true) item.sheet.render({ force: true })
} }
/** /**
@@ -284,8 +283,8 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
* @private * @private
* @static * @static
*/ */
static #onCreateSpell(event, target) { static async #onCreateSpell(event, target) {
const item = this.document.createEmbeddedDocuments("Item", [{ name: "Nouveau sortilège", type: "spell" }]) await this.document.createEmbeddedDocuments("Item", [{ name: "Nouveau sortilège", type: "spell" }])
} }
// #endregion // #endregion
@@ -177,12 +177,12 @@ export default class LethalFantasyItemSheet extends HandlebarsApplicationMixin(f
const attr = target.dataset.edit const attr = target.dataset.edit
const current = foundry.utils.getProperty(this.document, attr) const current = foundry.utils.getProperty(this.document, attr)
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {} const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
const fp = new FilePicker({ const fp = new foundry.applications.ux.FilePicker.implementation({
current, current,
type: "image", type: "image",
redirectToRoot: img ? [img] : [], redirectToRoot: img ? [img] : [],
callback: (path) => { callback: async (path) => {
this.document.update({ [attr]: path }) await this.document.update({ [attr]: path })
}, },
top: this.position.top + 40, top: this.position.top + 40,
left: this.position.left + 10, left: this.position.left + 10,
+16 -17
View File
@@ -180,44 +180,44 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
await this.document.system.rollInitiative() await this.document.system.rollInitiative()
} }
static #onArmorHitPointsPlus(event, target) { static async #onArmorHitPointsPlus(event, target) {
let armorHP = this.actor.system.combat.armorHitPoints let armorHP = this.actor.system.combat.armorHitPoints
armorHP += 1 armorHP += 1
this.actor.update({ "system.combat.armorHitPoints": armorHP }) await this.actor.update({ "system.combat.armorHitPoints": armorHP })
} }
static #onArmorHitPointsMinus(event, target) { static async #onArmorHitPointsMinus(event, target) {
let armorHP = this.actor.system.combat.armorHitPoints let armorHP = this.actor.system.combat.armorHitPoints
armorHP -= 1 armorHP -= 1
this.actor.update({ "system.combat.armorHitPoints": Math.max(armorHP, 0) }) await this.actor.update({ "system.combat.armorHitPoints": Math.max(armorHP, 0) })
} }
static #onDivinityPointsPlus(event, target) { static async #onDivinityPointsPlus(event, target) {
let points = this.actor.system.divinityPoints.value let points = this.actor.system.divinityPoints.value
points += 1 points += 1
points = Math.min(points, this.actor.system.divinityPoints.max) points = Math.min(points, this.actor.system.divinityPoints.max)
this.actor.update({ "system.divinityPoints.value": points }) await this.actor.update({ "system.divinityPoints.value": points })
} }
static #onDivinityPointsMinus(event, target) { static async #onDivinityPointsMinus(event, target) {
let points = this.actor.system.divinityPoints.value let points = this.actor.system.divinityPoints.value
points -= 1 points -= 1
points = Math.max(points, 0) points = Math.max(points, 0)
this.actor.update({ "system.divinityPoints.value": points }) await this.actor.update({ "system.divinityPoints.value": points })
} }
static #onAetherPointsPlus(event, target) { static async #onAetherPointsPlus(event, target) {
let points = this.actor.system.aetherPoints.value let points = this.actor.system.aetherPoints.value
points += 1 points += 1
points = Math.min(points, this.actor.system.aetherPoints.max) points = Math.min(points, this.actor.system.aetherPoints.max)
this.actor.update({ "system.aetherPoints.value": points }) await this.actor.update({ "system.aetherPoints.value": points })
} }
static #onAetherPointsMinus(event, target) { static async #onAetherPointsMinus(event, target) {
let points = this.actor.system.aetherPoints.value let points = this.actor.system.aetherPoints.value
points -= 1 points -= 1
points = Math.max(points, 0) points = Math.max(points, 0)
this.actor.update({ "system.aetherPoints.value": points }) await this.actor.update({ "system.aetherPoints.value": points })
} }
/** /**
@@ -293,10 +293,9 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
} }
_onRender(context, options) { _onRender(context, options) {
// Inputs with class `item-quantity`
const woundDescription = this.element.querySelectorAll('.wound-data') const woundDescription = this.element.querySelectorAll('.wound-data')
for (const input of woundDescription) { for (const input of woundDescription) {
input.addEventListener("change", (e) => { input.addEventListener("change", async (e) => {
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
const newValue = e.currentTarget.value const newValue = e.currentTarget.value
@@ -304,11 +303,11 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
const fieldName = e.currentTarget.dataset.name const fieldName = e.currentTarget.dataset.name
let tab = foundry.utils.duplicate(this.actor.system.hp.wounds) let tab = foundry.utils.duplicate(this.actor.system.hp.wounds)
tab[index][fieldName] = newValue tab[index][fieldName] = newValue
console.log(tab, index, fieldName, newValue) log(tab, index, fieldName, newValue)
this.actor.update({ "system.hp.wounds": tab }); await this.actor.update({ "system.hp.wounds": tab });
}) })
} }
super._onRender(); super._onRender(context, options);
} }
+1 -1
View File
@@ -91,7 +91,7 @@ export default class LethalFantasyMonsterSheet extends LethalFantasyActorSheet {
*/ */
async _onDrop(event) { async _onDrop(event) {
if (!this.isEditable || !this.isEditMode) return if (!this.isEditable || !this.isEditMode) return
const data = TextEditor.getDragEventData(event) const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
// Handle different data types // Handle different data types
switch (data.type) { switch (data.type) {
+2 -2
View File
@@ -72,7 +72,7 @@ export default class LethalFantasyActor extends Actor {
/* *************************************************/ /* *************************************************/
async applyDamage(hpLoss) { async applyDamage(hpLoss) {
let hp = this.system.hp.value + hpLoss let hp = this.system.hp.value + hpLoss
this.update({ "system.hp.value": hp }) await this.update({ "system.hp.value": hp })
} }
/* *************************************************/ /* *************************************************/
@@ -163,7 +163,7 @@ export default class LethalFantasyActor extends Actor {
/* *************************************************/ /* *************************************************/
async prepareRoll(rollType, rollKey, rollDice, defenderId, defenderTokenId, extraShieldDr = 0, d30Effects = {}) { async prepareRoll(rollType, rollKey, rollDice, defenderId, defenderTokenId, extraShieldDr = 0, d30Effects = {}) {
console.log("Preparing roll", rollType, rollKey, rollDice, defenderId) log("Preparing roll", rollType, rollKey, rollDice, defenderId)
let rollTarget let rollTarget
switch (rollType) { switch (rollType) {
case "granted": case "granted":
+3 -1
View File
@@ -1,3 +1,5 @@
import { log } from "../utils.mjs"
/** /**
* Classe pour gérer les résultats du D30 dans Lethal Fantasy * Classe pour gérer les résultats du D30 dans Lethal Fantasy
*/ */
@@ -41,7 +43,7 @@ export default class D30Roll {
this.resultsTable = data.d30_dice_results this.resultsTable = data.d30_dice_results
this.definitions = data.definitions this.definitions = data.definitions
console.log("D30Roll | D30 results table loaded successfully") log("D30Roll | D30 results table loaded successfully")
} catch (error) { } catch (error) {
console.error("D30Roll | Error loading D30 table:", error) console.error("D30Roll | Error loading D30 table:", error)
ui.notifications.error("Unable to load D30 results table") ui.notifications.error("Unable to load D30 results table")
+22 -22
View File
@@ -392,7 +392,7 @@ export default class LethalFantasyRoll extends Roll {
{ {
label: label, label: label,
callback: (event, button, dialog) => { callback: (event, button, dialog) => {
console.log("Roll context", event, button, dialog) log("Roll context", event, button, dialog)
let position = dialog?.position let position = dialog?.position
game.user.setFlag(SYSTEM.id, "roll-dialog-pos", foundry.utils.duplicate(position)) game.user.setFlag(SYSTEM.id, "roll-dialog-pos", foundry.utils.duplicate(position))
const output = Array.from(button.form.elements).reduce((obj, input) => { const output = Array.from(button.form.elements).reduce((obj, input) => {
@@ -435,7 +435,7 @@ export default class LethalFantasyRoll extends Roll {
// If the user cancels the dialog, exit // If the user cancels the dialog, exit
if (rollContext === null) return if (rollContext === null) return
console.log("rollContext", rollContext, hasGrantedDice) log("rollContext", rollContext, hasGrantedDice)
rollContext.saveSpell = saveSpell // Update fucking flag rollContext.saveSpell = saveSpell // Update fucking flag
let fullModifier = 0 let fullModifier = 0
@@ -552,7 +552,7 @@ export default class LethalFantasyRoll extends Roll {
if (rollContext.favor === "favor") { if (rollContext.favor === "favor") {
rollFavor = new this(baseFormula, options.data, rollData) rollFavor = new this(baseFormula, options.data, rollData)
await rollFavor.evaluate() await rollFavor.evaluate()
console.log("Rolling with favor", rollFavor) log("Rolling with favor", rollFavor)
if (game?.dice3d) { if (game?.dice3d) {
game.dice3d.showForRoll(rollFavor, game.user, true) game.dice3d.showForRoll(rollFavor, game.user, true)
} }
@@ -861,12 +861,12 @@ export default class LethalFantasyRoll extends Roll {
rejectClose: false // Click on Close button will not launch an error rejectClose: false // Click on Close button will not launch an error
}) })
console.log("RollContext", dialogContext, rollContext) log("RollContext", dialogContext, rollContext)
// If action is cancelled, exit // If action is cancelled, exit
if (rollContext === null || rollContext === "cancel") { if (rollContext === null || rollContext === "cancel") {
await combatant.setFlag(SYSTEM.id, "currentAction", "") await combatant.setFlag(SYSTEM.id, "currentAction", "")
let message = `${combatant.name} : Other action, progression reset` let message = `${combatant.name} : Other action, progression reset`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
return return
} }
@@ -924,7 +924,7 @@ export default class LethalFantasyRoll extends Roll {
// Set the flag on the combatant // Set the flag on the combatant
await combatant.setFlag(SYSTEM.id, "currentAction", actionItem) await combatant.setFlag(SYSTEM.id, "currentAction", actionItem)
let message = `${combatant.name} action : ${selectedItem.name}, start rolling progression dice or casting time` let message = `${combatant.name} action : ${selectedItem.name}, start rolling progression dice or casting time`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
rollContext = (actionItem.type === "weapon") ? "rollProgressionDice" : "rollLethargyDice" // Set the roll context to rollProgressionDice rollContext = (actionItem.type === "weapon") ? "rollProgressionDice" : "rollLethargyDice" // Set the roll context to rollProgressionDice
currentAction = actionItem currentAction = actionItem
} }
@@ -935,14 +935,14 @@ export default class LethalFantasyRoll extends Roll {
let time = currentAction.type === "spell" ? currentAction.system.castingTime : currentAction.system.prayerTime let time = currentAction.type === "spell" ? currentAction.system.castingTime : currentAction.system.prayerTime
if (currentAction.castingTime < time) { if (currentAction.castingTime < time) {
let message = `Casting time : ${currentAction.name}, count : ${currentAction.castingTime}/${time}` let message = `Casting time : ${currentAction.name}, count : ${currentAction.castingTime}/${time}`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
currentAction.castingTime += 1 currentAction.castingTime += 1
await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction)) await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
return return
} else { } else {
// Last counting second — announce ready and transition immediately (no extra second consumed) // Last counting second — announce ready and transition immediately (no extra second consumed)
let message = `Casting time : ${currentAction.name}, count : ${time}/${time} — ready to cast next second !` let message = `Casting time : ${currentAction.name}, count : ${time}/${time} — ready to cast next second !`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
currentAction.castingTime = 1 currentAction.castingTime = 1
currentAction.spellStatus = "toBeCasted" currentAction.spellStatus = "toBeCasted"
await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction)) await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
@@ -982,7 +982,7 @@ export default class LethalFantasyRoll extends Roll {
isLethargy: true isLethargy: true
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
// Update the combatant progression count // Update the combatant progression count
await combatant.setFlag(SYSTEM.id, "currentAction", "") await combatant.setFlag(SYSTEM.id, "currentAction", "")
// Display the action selection window again // Display the action selection window again
@@ -1002,7 +1002,7 @@ export default class LethalFantasyRoll extends Roll {
isLethargy: true isLethargy: true
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
} }
} }
} }
@@ -1014,18 +1014,18 @@ export default class LethalFantasyRoll extends Roll {
let split = toSplit.split("+") let split = toSplit.split("+")
currentAction.rangedLoad = Number(split[0]) || 0 currentAction.rangedLoad = Number(split[0]) || 0
formula = split[1] formula = split[1]
console.log("Ranged Mode", currentAction.rangedMode, currentAction.rangedLoad, formula) log("Ranged Mode", currentAction.rangedMode, currentAction.rangedLoad, formula)
} }
// Range weapon loading // Range weapon loading
if (!currentAction.weaponLoaded && currentAction.rangedLoad) { if (!currentAction.weaponLoaded && currentAction.rangedLoad) {
if (currentAction.progressionCount < currentAction.rangedLoad) { if (currentAction.progressionCount < currentAction.rangedLoad) {
let message = `Ranged weapon ${currentAction.name} is loading, loading count : ${currentAction.progressionCount}/${currentAction.rangedLoad}` let message = `Ranged weapon ${currentAction.name} is loading, loading count : ${currentAction.progressionCount}/${currentAction.rangedLoad}`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
currentAction.progressionCount += 1 currentAction.progressionCount += 1
await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction)) await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
} else { } else {
let message = `Ranged weapon ${currentAction.name} is loaded !` let message = `Ranged weapon ${currentAction.name} is loaded !`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
currentAction.weaponLoaded = true currentAction.weaponLoaded = true
currentAction.progressionCount = 1 currentAction.progressionCount = 1
await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction)) await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
@@ -1057,13 +1057,13 @@ export default class LethalFantasyRoll extends Roll {
rollResult: roll.total rollResult: roll.total
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
await combatant.setFlag(SYSTEM.id, "currentAction", "") await combatant.setFlag(SYSTEM.id, "currentAction", "")
combatant.actor.prepareRoll(currentAction.type === "weapon" ? "weapon-attack" : "spell-attack", currentAction._id) combatant.actor.prepareRoll(currentAction.type === "weapon" ? "weapon-attack" : "spell-attack", currentAction._id)
} else { } else {
// Notify that the player cannot act now with a chat message // Notify that the player cannot act now with a chat message
currentAction.progressionCount += 1 currentAction.progressionCount += 1
combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction)) await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
const messageContent = await foundry.applications.handlebars.renderTemplate( const messageContent = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs", "systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
{ {
@@ -1074,7 +1074,7 @@ export default class LethalFantasyRoll extends Roll {
progressionCount: currentAction.progressionCount progressionCount: currentAction.progressionCount
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
} }
} }
} }
@@ -1130,7 +1130,7 @@ export default class LethalFantasyRoll extends Roll {
// If the user cancels the dialog, exit // If the user cancels the dialog, exit
if (rollContext === null) return if (rollContext === null) return
console.log("RollContext", rollContext) log("RollContext", rollContext)
// Add disfavor/favor option if point blank range // Add disfavor/favor option if point blank range
if (rollContext.range === "pointblank") { if (rollContext.range === "pointblank") {
rollContext.movement = rollContext.movement.replace("kh", "") rollContext.movement = rollContext.movement.replace("kh", "")
@@ -1426,7 +1426,7 @@ export default class LethalFantasyRoll extends Roll {
/** @override */ /** @override */
async render(chatOptions = {}) { async render(chatOptions = {}) {
let chatData = await this._getChatCardData(chatOptions.isPrivate) let chatData = await this._getChatCardData(chatOptions.isPrivate)
console.log("ChatData", chatData) log("ChatData", chatData)
return await foundry.applications.handlebars.renderTemplate(this.constructor.CHAT_TEMPLATE, chatData) return await foundry.applications.handlebars.renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
} }
@@ -1464,15 +1464,15 @@ export default class LethalFantasyRoll extends Roll {
// Récupérer les informations de l'arme pour les attaques réussies // Récupérer les informations de l'arme pour les attaques réussies
let weaponDamageOptions = null let weaponDamageOptions = null
console.log("Roll type:", this.type, "rollTarget:", this.rollTarget, "Has weapon:", !!this.rollTarget?.weapon) log("Roll type:", this.type, "rollTarget:", this.rollTarget, "Has weapon:", !!this.rollTarget?.weapon)
if (this.type === "weapon-attack" && this.rollTarget?.weapon) { if (this.type === "weapon-attack" && this.rollTarget?.weapon) {
const weapon = this.rollTarget.weapon const weapon = this.rollTarget.weapon
weaponDamageOptions = { weaponDamageOptions = {
weaponId: weapon._id || weapon.id, weaponId: weapon.id,
weaponName: weapon.name, weaponName: weapon.name,
damageM: weapon.system?.damage?.damageM damageM: weapon.system?.damage?.damageM
} }
console.log("Weapon damage options:", weaponDamageOptions) log("Weapon damage options:", weaponDamageOptions)
} else if (this.type === "monster-attack" && this.rollTarget) { } else if (this.type === "monster-attack" && this.rollTarget) {
weaponDamageOptions = { weaponDamageOptions = {
weaponId: this.rollTarget.rollKey, weaponId: this.rollTarget.rollKey,
@@ -1481,7 +1481,7 @@ export default class LethalFantasyRoll extends Roll {
damageModifier: this.rollTarget.damageModifier, damageModifier: this.rollTarget.damageModifier,
isMonster: true isMonster: true
} }
console.log("Monster damage options:", weaponDamageOptions) log("Monster damage options:", weaponDamageOptions)
} }
const cardData = { const cardData = {
+5 -5
View File
@@ -32,20 +32,20 @@ export class Macros {
dropData.rollType === "save" dropData.rollType === "save"
? `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}', '=');` ? `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}', '=');`
: `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');` : `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');`
const rollName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${game.i18n.localize(`TENEBRIS.Manager.${dropData.rollTarget}`)}` const rollName = `${game.i18n.localize("LETHALFANTASY.Label.jet")} ${game.i18n.localize(`LETHALFANTASY.Label.${dropData.rollTarget}`)}`
this.createMacro(slot, rollName, rollCommand, "icons/svg/d20-grey.svg") this.createMacro(slot, rollName, rollCommand, "icons/svg/d20-grey.svg")
break break
case "rollDamage": case "rollDamage":
const weapon = game.actors.get(dropData.actorId).items.get(dropData.rollTarget) const weapon = game.actors.get(dropData.actorId).items.get(dropData.rollTarget)
const rollDamageCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');` const rollDamageCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');`
const rollDamageName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${weapon.name}` const rollDamageName = `${game.i18n.localize("LETHALFANTASY.Label.jet")} ${weapon.name}`
this.createMacro(slot, rollDamageName, rollDamageCommand, weapon.img) this.createMacro(slot, rollDamageName, rollDamageCommand, weapon.img)
break break
case "rollAttack": case "rollAttack":
const rollAttackCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollValue}', '${dropData.rollTarget}');` const rollAttackCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollValue}', '${dropData.rollTarget}');`
const rollAttackName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${dropData.rollTarget}` const rollAttackName = `${game.i18n.localize("LETHALFANTASY.Label.jet")} ${dropData.rollTarget}`
this.createMacro(slot, rollAttackName, rollAttackCommand, "icons/svg/d20-grey.svg") this.createMacro(slot, rollAttackName, rollAttackCommand, "icons/svg/d20-grey.svg")
break break
@@ -57,7 +57,7 @@ export class Macros {
/** /**
* Create a macro * Create a macro
* All macros are flaged with a tenebris.macro flag at true * All macros are flaged with a lethalFantasy.macro flag at true
* @param {*} slot * @param {*} slot
* @param {*} name * @param {*} name
* @param {*} command * @param {*} command
@@ -72,7 +72,7 @@ export class Macros {
type: "script", type: "script",
img: img, img: img,
command: command, command: command,
flags: { "tenebris.macro": true }, flags: { "lethalFantasy.macro": true },
}, },
{ displaySheet: false }, { displaySheet: false },
) )
+3 -3
View File
@@ -383,7 +383,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
rollResult: roll.total rollResult: roll.total
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
let token = combatant?.token let token = combatant?.token
this.prepareMonsterRoll("monster-attack", key, undefined, token?.id) this.prepareMonsterRoll("monster-attack", key, undefined, token?.id)
if (token?.object) { if (token?.object) {
@@ -407,7 +407,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
rollResult: roll.total rollResult: roll.total
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
let token = combatant?.token let token = combatant?.token
this.prepareMonsterRoll("monster-attack-hth", key, undefined, token?.id) this.prepareMonsterRoll("monster-attack-hth", key, undefined, token?.id)
if (token?.object) { if (token?.object) {
@@ -426,7 +426,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
rollResult: roll.total rollResult: roll.total
} }
) )
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) }) await ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
} }
} }
+3 -2
View File
@@ -1,6 +1,7 @@
import { SYSTEM } from "../config/system.mjs" import { SYSTEM } from "../config/system.mjs"
import { WEAPON_TYPE } from "../config/weapon.mjs"
export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { export default class LethalFantasyWeapon extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields const fields = foundry.data.fields
const schema = {} const schema = {}
@@ -62,7 +63,7 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
static LOCALIZATION_PREFIXES = ["LETHALFANTASY.Weapon"] static LOCALIZATION_PREFIXES = ["LETHALFANTASY.Weapon"]
get weaponCategory() { get weaponCategory() {
return game.i18n.localize(CATEGORY[this.weaponType].label) return game.i18n.localize(WEAPON_TYPE[this.weaponType] || this.weaponType)
} }
} }
+35 -33
View File
@@ -1,8 +1,9 @@
import { SYSTEM } from "./config/system.mjs" import { SYSTEM } from "./config/system.mjs"
// Map temporaire pour stocker les données d'attaque en attente de défense export function log(...args) {
if (!globalThis.pendingDefenses) { if (game?.settings?.get(game.system.id, "debug")) {
globalThis.pendingDefenses = new Map() console.log(...args)
}
} }
export default class LethalFantasyUtils { export default class LethalFantasyUtils {
@@ -28,6 +29,7 @@ export default class LethalFantasyUtils {
static setHookListeners() { static setHookListeners() {
Hooks.on('renderTokenHUD', async (hud, html, token) => { Hooks.on('renderTokenHUD', async (hud, html, token) => {
if (html.querySelector(".lethal-hp-loss-hud")) return
// HP Loss Button (existing) // HP Loss Button (existing)
const lossHPButton = await foundry.applications.handlebars.renderTemplate('systems/fvtt-lethal-fantasy/templates/loss-hp-hud.hbs', {}) const lossHPButton = await foundry.applications.handlebars.renderTemplate('systems/fvtt-lethal-fantasy/templates/loss-hp-hud.hbs', {})
$(html).find('div.left').append(lossHPButton); $(html).find('div.left').append(lossHPButton);
@@ -50,14 +52,14 @@ export default class LethalFantasyUtils {
$(html).find('.hp-loss-wrap')[2].classList.add('hp-loss-hud-disabled'); $(html).find('.hp-loss-wrap')[2].classList.add('hp-loss-hud-disabled');
} }
}) })
$(html).find('.loss-hp-hud-click').click((event) => { $(html).find('.loss-hp-hud-click').click(async (event) => {
event.preventDefault(); event.preventDefault();
let hpLoss = event.currentTarget.dataset.hpValue; let hpLoss = event.currentTarget.dataset.hpValue;
if (token) { if (token) {
let tokenFull = canvas.tokens.placeables.find(t => t.id === token._id); let tokenFull = canvas.tokens.placeables.find(t => t.id === token.id);
console.log(tokenFull, token) log(tokenFull, token)
let actor = tokenFull.actor; let actor = tokenFull.actor;
actor.applyDamage(Number(hpLoss)); await actor.applyDamage(Number(hpLoss));
$(html).find('.hp-loss-wrap')[0].classList.remove('hp-loss-hud-active'); $(html).find('.hp-loss-wrap')[0].classList.remove('hp-loss-hud-active');
$(html).find('.hp-loss-wrap')[0].classList.add('hp-loss-hud-disabled'); $(html).find('.hp-loss-wrap')[0].classList.add('hp-loss-hud-disabled');
$(html).find('.hp-loss-wrap')[1].classList.remove('hp-loss-hud-active'); $(html).find('.hp-loss-wrap')[1].classList.remove('hp-loss-hud-active');
@@ -89,14 +91,14 @@ export default class LethalFantasyUtils {
$(html).find('.hp-gain-wrap')[2].classList.add('hp-gain-hud-disabled'); $(html).find('.hp-gain-wrap')[2].classList.add('hp-gain-hud-disabled');
} }
}) })
$(html).find('.gain-hp-hud-click').click((event) => { $(html).find('.gain-hp-hud-click').click(async (event) => {
event.preventDefault(); event.preventDefault();
let hpGain = event.currentTarget.dataset.hpValue; let hpGain = event.currentTarget.dataset.hpValue;
if (token) { if (token) {
let tokenFull = canvas.tokens.placeables.find(t => t.id === token._id); let tokenFull = canvas.tokens.placeables.find(t => t.id === token.id);
console.log(tokenFull, token) log(tokenFull, token)
let actor = tokenFull.actor; let actor = tokenFull.actor;
actor.applyDamage(Number(hpGain)); // Positive value to add HP await actor.applyDamage(Number(hpGain)); // Positive value to add HP
$(html).find('.hp-gain-wrap')[0].classList.remove('hp-gain-hud-active'); $(html).find('.hp-gain-wrap')[0].classList.remove('hp-gain-hud-active');
$(html).find('.hp-gain-wrap')[0].classList.add('hp-gain-hud-disabled'); $(html).find('.hp-gain-wrap')[0].classList.add('hp-gain-hud-disabled');
$(html).find('.hp-gain-wrap')[1].classList.remove('hp-gain-hud-active'); $(html).find('.hp-gain-wrap')[1].classList.remove('hp-gain-hud-active');
@@ -120,16 +122,16 @@ export default class LethalFantasyUtils {
wrap.classList.add('luck-grit-hud-disabled'); wrap.classList.add('luck-grit-hud-disabled');
} }
}) })
$(html).find('.luck-grit-btn').click((event) => { $(html).find('.luck-grit-btn').click(async (event) => {
event.preventDefault(); event.preventDefault();
if (token) { if (token) {
let tokenFull = canvas.tokens.placeables.find(t => t.id === token._id); let tokenFull = canvas.tokens.placeables.find(t => t.id === token.id);
let actor = tokenFull.actor; let actor = tokenFull.actor;
const resource = event.currentTarget.dataset.resource; const resource = event.currentTarget.dataset.resource;
const amount = Number(event.currentTarget.dataset.amount); const amount = Number(event.currentTarget.dataset.amount);
const current = Number(foundry.utils.getProperty(actor.system, `${resource}.current`)) || 0; const current = Number(foundry.utils.getProperty(actor.system, `${resource}.current`)) || 0;
const newValue = Math.max(0, current + amount); const newValue = Math.max(0, current + amount);
actor.update({ [`system.${resource}.current`]: newValue }); await actor.update({ [`system.${resource}.current`]: newValue });
$(html).find('.luck-grit-wrap')[0].classList.remove('luck-grit-hud-active'); $(html).find('.luck-grit-wrap')[0].classList.remove('luck-grit-hud-active');
$(html).find('.luck-grit-wrap')[0].classList.add('luck-grit-hud-disabled'); $(html).find('.luck-grit-wrap')[0].classList.add('luck-grit-hud-disabled');
} }
@@ -138,8 +140,8 @@ export default class LethalFantasyUtils {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static handleSocketEvent(msg = {}) { static async handleSocketEvent(msg = {}) {
console.log(`handleSocketEvent !`, msg) log(`handleSocketEvent !`, msg)
let actor let actor
switch (msg.type) { switch (msg.type) {
case "applyDamage": case "applyDamage":
@@ -149,18 +151,18 @@ export default class LethalFantasyUtils {
? canvas.tokens?.placeables?.find(t => t.id === msg.tokenId)?.actor ? canvas.tokens?.placeables?.find(t => t.id === msg.tokenId)?.actor
: (game.combat?.combatants?.find(c => c.actorId === msg.actorId)?.actor : (game.combat?.combatants?.find(c => c.actorId === msg.actorId)?.actor
?? game.actors.get(msg.actorId)) ?? game.actors.get(msg.actorId))
if (actor) actor.applyDamage(msg.damage) if (actor) await actor.applyDamage(msg.damage)
} }
break break
case "rollInitiative": case "rollInitiative":
if (msg.userId && msg.userId !== game.user.id) break if (msg.userId && msg.userId !== game.user.id) break
actor = game.actors.get(msg.actorId) actor = game.actors.get(msg.actorId)
actor.system.rollInitiative(msg.combatId, msg.combatantId) await actor.system.rollInitiative(msg.combatId, msg.combatantId)
break break
case "rollProgressionDice": case "rollProgressionDice":
if (msg.userId && msg.userId !== game.user.id) break if (msg.userId && msg.userId !== game.user.id) break
actor = game.actors.get(msg.actorId) actor = game.actors.get(msg.actorId)
actor.system.rollProgressionDice(msg.combatId, msg.combatantId, msg.rollProgressionCount) await actor.system.rollProgressionDice(msg.combatId, msg.combatantId, msg.rollProgressionCount)
break break
case "requestDefense": case "requestDefense":
// Vérifier si le message est destiné à cet utilisateur // Vérifier si le message est destiné à cet utilisateur
@@ -184,7 +186,7 @@ export default class LethalFantasyUtils {
const slot = wounds.findIndex(w => !w.value && !w.duration) const slot = wounds.findIndex(w => !w.value && !w.duration)
if (slot !== -1) { if (slot !== -1) {
wounds[slot] = { value: msg.damage, duration: msg.damage, description: "Bleeding" } wounds[slot] = { value: msg.damage, duration: msg.damage, description: "Bleeding" }
actor.update({ "system.hp.wounds": wounds }) await actor.update({ "system.hp.wounds": wounds })
} }
} }
} }
@@ -497,7 +499,7 @@ export default class LethalFantasyUtils {
const isMonster = defender.type === "monster" const isMonster = defender.type === "monster"
console.log(`[LF] showDefenseRequest | attackRollType=${attackRollType} isMonster=${isMonster} defender=${defender?.name}`) log(`[LF] showDefenseRequest | attackRollType=${attackRollType} isMonster=${isMonster} defender=${defender?.name}`)
// Spell/miracle attacks use saving throws instead of weapon defense // Spell/miracle attacks use saving throws instead of weapon defense
const isSpellAttack = attackRollType === "spell-attack" || attackRollType === "miracle-attack" const isSpellAttack = attackRollType === "spell-attack" || attackRollType === "miracle-attack"
@@ -559,9 +561,9 @@ export default class LethalFantasyUtils {
defenderTokenId defenderTokenId
} }
if (isMonster) { if (isMonster) {
defender.system.prepareMonsterRoll("save", result) await defender.system.prepareMonsterRoll("save", result)
} else { } else {
defender.prepareRoll("save", result) await defender.prepareRoll("save", result)
} }
} }
return return
@@ -637,7 +639,7 @@ export default class LethalFantasyUtils {
isRanged: msg.isRanged isRanged: msg.isRanged
} }
defender.system.prepareMonsterRoll("monster-defense", result) await defender.system.prepareMonsterRoll("monster-defense", result)
} }
return return
} }
@@ -744,9 +746,9 @@ export default class LethalFantasyUtils {
isRanged: msg.isRanged isRanged: msg.isRanged
} }
console.log("Storing defense data for character:", defender.id) log("Storing defense data for character:", defender.id)
defender.prepareRoll("weapon-defense", result) await defender.prepareRoll("weapon-defense", result)
} }
} }
@@ -1285,7 +1287,7 @@ export default class LethalFantasyUtils {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async compareAttackDefense(data) { static async compareAttackDefense(data) {
console.log("compareAttackDefense called with:", data) log("compareAttackDefense called with:", data)
// Compute D30 effects from the attack D30 message directly. // Compute D30 effects from the attack D30 message directly.
// This is more reliable than depending on the caller-provided values, which are // This is more reliable than depending on the caller-provided values, which are
@@ -1300,11 +1302,11 @@ export default class LethalFantasyUtils {
const outcome = data.outcome || (data.attackRoll > data.defenseRoll ? "hit" : "miss") const outcome = data.outcome || (data.attackRoll > data.defenseRoll ? "hit" : "miss")
const isAttackWin = outcome !== "miss" const isAttackWin = outcome !== "miss"
console.log("isAttackWin:", isAttackWin, "attackRoll:", data.attackRoll, "defenseRoll:", data.defenseRoll) log("isAttackWin:", isAttackWin, "attackRoll:", data.attackRoll, "defenseRoll:", data.defenseRoll)
let damageButton = "" let damageButton = ""
if (isAttackWin && (data.attackWeaponId || data.attackRollKey)) { if (isAttackWin && (data.attackWeaponId || data.attackRollKey)) {
console.log("Creating damage button. defenderId:", data.defenderId) log("Creating damage button. defenderId:", data.defenderId)
// Déterminer le type de dégâts à lancer // Déterminer le type de dégâts à lancer
if (data.attackRollType === "weapon-attack") { if (data.attackRollType === "weapon-attack") {
damageButton = ` damageButton = `
@@ -1385,12 +1387,12 @@ export default class LethalFantasyUtils {
</div> </div>
` `
console.log("Creating combat result message...") log("Creating combat result message...")
await ChatMessage.create({ await ChatMessage.create({
content: resultMessage, content: resultMessage,
speaker: { alias: "Combat System" } speaker: { alias: "Combat System" }
}) })
console.log("Combat result message created!") log("Combat result message created!")
} }
static registerHandlebarsHelpers() { static registerHandlebarsHelpers() {
@@ -1527,7 +1529,7 @@ export default class LethalFantasyUtils {
return eval(expr); return eval(expr);
}) })
Handlebars.registerHelper('isOwnerOrGM', function (actor) { Handlebars.registerHelper('isOwnerOrGM', function (actor) {
console.log("Testing actor", actor.isOwner, game.userId) log("Testing actor", actor.isOwner, game.userId)
return actor.isOwner || game.isGM; return actor.isOwner || game.isGM;
}) })
Handlebars.registerHelper('upperCase', function (text) { Handlebars.registerHelper('upperCase', function (text) {
@@ -1665,7 +1667,7 @@ export default class LethalFantasyUtils {
} }
) )
ChatMessage.create({ await ChatMessage.create({
user: game.user.id, user: game.user.id,
speaker: { alias: targetActor.name }, speaker: { alias: targetActor.name },
mode: "gm", mode: "gm",