import { DonjonEtCieUtility } from "./donjon-et-cie-utility.mjs"; import { DonjonEtCieRollDialog } from "./applications/donjon-et-cie-roll-dialog.mjs"; export class DonjonEtCieActor extends Actor { prepareDerivedData() { super.prepareDerivedData(); const pv = this.system.sante?.pv; if (pv && pv.value > pv.max) { pv.max = pv.value; } } getCharacteristicEntries() { return DonjonEtCieUtility.getCharacteristicEntries(this.system); } getSectionData() { return DonjonEtCieUtility.buildActorSections(this); } getFavorEntries() { return DonjonEtCieUtility.getFavorEntries(this.system); } #getStoredArmorContext() { if (this.type === "pnj") { const stored = Number(this.system.defense?.armure?.resultatProtection ?? 0); return { label: "ARM", hasArmor: true, before: stored, update: async (value) => this.update({ "system.defense.armure.resultatProtection": Math.max(0, Number(value ?? 0)) }) }; } const armors = [...this.items.filter((item) => item.type === "armure")].sort((a, b) => { const equippedScore = Number(Boolean(b.system.equipee)) - Number(Boolean(a.system.equipee)); if (equippedScore) return equippedScore; const protectionScore = Number(b.system.resultatProtection ?? 0) - Number(a.system.resultatProtection ?? 0); if (protectionScore) return protectionScore; return a.name.localeCompare(b.name, "fr", { sensitivity: "base" }); }); const armor = armors.find((item) => item.system.equipee || Number(item.system.resultatProtection ?? 0) > 0) ?? null; if (!armor) { return { label: "Armure", hasArmor: false, before: 0, update: null }; } return { label: armor.name, hasArmor: true, before: Number(armor.system.resultatProtection ?? 0), update: async (value) => armor.update({ "system.resultatProtection": Math.max(0, Number(value ?? 0)) }) }; } async adjustNumericField(path, delta) { const current = Number(foundry.utils.getProperty(this, path) ?? 0); let next = current + Number(delta); if (path === "system.sante.pv.value") { const max = Number(this.system.sante?.pv?.max ?? next); next = Math.max(0, Math.min(next, max)); } else { next = Math.max(0, next); } return this.update({ [path]: next }); } async applyIncomingDamage(damage, { useArmor = false } = {}) { const incoming = Math.max(0, Number(damage ?? 0)); const pvBefore = Number(this.system.sante?.pv?.value ?? 0); const pvMax = Number(this.system.sante?.pv?.max ?? pvBefore); const armor = this.#getStoredArmorContext(); const armorBefore = useArmor ? Number(armor.before ?? 0) : 0; const armorAbsorbed = Math.min(incoming, armorBefore); const armorAfter = Math.max(armorBefore - armorAbsorbed, 0); const hpDamage = Math.max(incoming - armorAbsorbed, 0); const pvAfter = Math.max(pvBefore - hpDamage, 0); if (useArmor && armor.hasArmor && armor.update && armorAfter !== armorBefore) { await armor.update(armorAfter); } if (hpDamage !== 0) { await this.update({ "system.sante.pv.value": pvAfter }); } return { incoming, useArmor, armorLabel: armor.label, armorAvailable: armor.hasArmor, armorBefore, armorAbsorbed, armorAfter, hpDamage, pvBefore, pvAfter, pvMax }; } async rollCharacteristic(key) { return DonjonEtCieRollDialog.createCharacteristic(this, key); } async useFavorService(departmentKey) { return game.system.donjonEtCie.rolls.useFavorService(this, departmentKey); } async rollInitiative() { return DonjonEtCieRollDialog.createInitiative(this); } async rollHitDice() { return game.system.donjonEtCie.rolls.rollHitDice(this); } async rollWeapon(itemId) { const item = this.items.get(itemId); if (item) return DonjonEtCieRollDialog.createWeapon(this, item); } async rollDamage(itemId) { const item = this.items.get(itemId); if (item) return DonjonEtCieRollDialog.createDamage(this, item); } async rollSpell(itemId) { const item = this.items.get(itemId); if (item) return DonjonEtCieRollDialog.createSpell(this, item); } async rollUsage(itemId) { const item = this.items.get(itemId); if (item) return DonjonEtCieRollDialog.createUsage(item); } #createPnjResourceProxy({ label, deltaPath, protectionPath = null }) { const delta = Number(foundry.utils.getProperty(this, deltaPath) ?? 0); const protection = protectionPath ? Number(foundry.utils.getProperty(this, protectionPath) ?? 0) : 0; return { actor: this, type: protectionPath ? "armure" : "ressource", name: `${this.name} · ${label}`, system: { delta, resultatProtection: protection }, update: async (data) => { const updateData = {}; if (Object.hasOwn(data, "system.delta")) { updateData[deltaPath] = data["system.delta"]; } if (protectionPath && Object.hasOwn(data, "system.resultatProtection")) { updateData[protectionPath] = data["system.resultatProtection"]; } return Object.keys(updateData).length ? this.update(updateData) : this; } }; } async rollPnjArmor() { return DonjonEtCieRollDialog.createUsage(this.#createPnjResourceProxy({ label: "ARM", deltaPath: "system.defense.armure.delta", protectionPath: "system.defense.armure.resultatProtection" })); } async rollPnjCourage() { return DonjonEtCieRollDialog.createUsage(this.#createPnjResourceProxy({ label: "COU", deltaPath: "system.defense.courage.delta" })); } async rollPnjAttackDamage() { const attackName = this.system.attaque?.nom || "Attaque"; const attackDamage = this.system.attaque?.degats || ""; if (!attackDamage) return null; return DonjonEtCieRollDialog.createDamage(this, { name: `${this.name} · ${attackName}`, type: "attaque", system: { degats: attackDamage, portee: this.system.attaque?.notes || "" } }); } }