204 lines
6.1 KiB
JavaScript
204 lines
6.1 KiB
JavaScript
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 || ""
|
|
}
|
|
});
|
|
}
|
|
}
|