Fix as per CSV sheet tracking + creature explanation

This commit is contained in:
2026-05-17 17:43:33 +02:00
parent a572c66678
commit 374854cc8b
99 changed files with 2716 additions and 464 deletions
+14 -1
View File
@@ -93,6 +93,10 @@ export default class MGNEActor extends Actor {
return result
}
async rollArmorSave() {
return MGNERoll.rollArmorSave(this)
}
async rollWeapon(itemId) {
const item = this.items.get(itemId)
if (!item) return null
@@ -129,7 +133,10 @@ export default class MGNEActor extends Actor {
async rollProfileAttack() {
const attackBaseLabel = normalizeGenericActionLabel(this.system.attack?.label ?? t("MGNE.Common.Attack"), t("MGNE.Common.Attack"))
const attackLabel = formatActionLabel(attackBaseLabel, t("MGNE.Common.Attack"))
const result = await this.rollAbility("strength", {
// Creatures have no ability scores; ability value defaults to 0 via roll.mjs
const result = await MGNERoll.promptCheck({
actor: this,
abilityId: "strength",
label: attackLabel,
rollType: "attack",
})
@@ -220,6 +227,12 @@ export default class MGNEActor extends Actor {
return item.rollUsage()
}
async rollDurability(itemId) {
const item = this.items.get(itemId)
if (!item) return null
return MGNERoll.rollDurability(item)
}
async quickRest() {
const roll = await (new Roll("1d4")).evaluate()
const hp = this.system.hp?.value ?? 0
+86
View File
@@ -57,11 +57,15 @@ async function renderCard(context) {
const normalizedEyebrow = `${eyebrow}`.trim().toLowerCase()
const normalizedLabel = `${context.label ?? ""}`.trim().toLowerCase()
// Render dice tooltip HTML if a roll was provided
const diceTooltip = context._roll ? await context._roll.render() : null
return foundry.applications.handlebars.renderTemplate(`systems/${SYSTEM_ID}/templates/chat-message.hbs`, {
...context,
modeClass: context.mode ?? "generic",
eyebrow: "",
outcomeClass,
diceTooltip,
})
}
@@ -156,6 +160,7 @@ export default class MGNERoll {
damageItemId: showDamageButton ? item.id : null,
damageFormula: showDamageButton ? (item.system.damage || "1") : null,
damageCritical: showDamageButton && critical,
_roll: roll,
})
await ChatMessage.create({
@@ -181,6 +186,7 @@ export default class MGNERoll {
total: roll.total,
outcome: broken ? t("MGNE.Roll.OutcomeBroken") : t("MGNE.Roll.OutcomeSteady"),
specialText: broken ? t("MGNE.Roll.MoraleBrokenText") : "",
_roll: roll,
})
await ChatMessage.create({
@@ -236,6 +242,7 @@ export default class MGNERoll {
showApplyButton: true,
damageTotal: roll.total,
damageCritical: isCritical,
_roll: roll,
})
await ChatMessage.create({
@@ -267,6 +274,7 @@ export default class MGNERoll {
showApplyButton: true,
damageTotal: roll.total,
damageCritical: isCritical,
_roll: roll,
})
await ChatMessage.create({
@@ -278,6 +286,39 @@ export default class MGNERoll {
return { roll }
}
static async rollArmorSave(actor) {
const formula = actor.getArmorRollFormula()
const items = actor.getEquippedArmorItems()
if (formula === "0") {
ui.notifications.warn(t("MGNE.Notification.NoArmorEquipped"))
return null
}
const roll = await (new Roll(formula)).evaluate()
const armorNames = items.map(i => i.name).join(" + ")
const contentHtml = await renderCard({
mode: "armor",
actorName: actor.name,
actorImg: actor.img,
label: t("MGNE.Roll.ArmorSave"),
subtitle: armorNames,
formula: roll.formula,
total: roll.total,
outcome: f("MGNE.Roll.ArmorAbsorbed", { amount: roll.total }),
_roll: roll,
})
await ChatMessage.create({
speaker: ChatMessage.getSpeaker({ actor }),
rolls: [roll],
content: contentHtml,
})
return roll
}
static async rollUsage(item) {
const currentDie = item.system.usageDie
if (!currentDie || currentDie === "depleted") {
@@ -303,6 +344,7 @@ export default class MGNERoll {
total: roll.total,
outcome: depleted ? f("MGNE.Roll.DowngradedTo", { die: nextDie.toUpperCase() }) : t("MGNE.Roll.NoChange"),
specialText: depleted && nextDie === "depleted" ? t("MGNE.Roll.ItemNowDepleted") : "",
_roll: roll,
})
await ChatMessage.create({
@@ -314,6 +356,48 @@ export default class MGNERoll {
return { roll, depleted, nextDie }
}
static async rollDurability(item) {
const currentDie = item.system.durabilityDie
if (!currentDie || currentDie === "depleted") {
ui.notifications.warn(f("MGNE.Notification.ItemDurabilityDepleted", { item: item.name }))
return null
}
const roll = await (new Roll(`1${currentDie}`)).evaluate()
const degraded = roll.total <= 2
const nextDie = degraded ? stepDownDie(currentDie) : currentDie
const nowBroken = degraded && nextDie === "depleted"
const updates = { "system.durabilityDie": nextDie }
if (nowBroken) {
updates["system.broken"] = true
if ("equipped" in (item.system ?? {})) updates["system.equipped"] = false
}
await item.update(updates)
const contentHtml = await renderCard({
mode: "durability",
actorName: item.parent?.name ?? item.name,
actorImg: item.img,
label: f("MGNE.Roll.DurabilityLabel", { item: item.name }),
subtitle: f("MGNE.Roll.CurrentDie", { die: currentDie.toUpperCase() }),
formula: roll.formula,
total: roll.total,
outcome: degraded
? f("MGNE.Roll.DowngradedTo", { die: nextDie.toUpperCase() })
: t("MGNE.Roll.NoChange"),
specialText: nowBroken ? t("MGNE.Roll.ItemNowBroken") : "",
_roll: roll,
})
await ChatMessage.create({
speaker: ChatMessage.getSpeaker({ actor: item.parent ?? null }),
rolls: [roll],
content: contentHtml,
})
return { roll, degraded, nextDie, nowBroken }
}
static async applyDamageCard({ actor, sourceActor = null, sourceItem = null, amount, armorRoll = null, appliedDamage, newHp, breakText = "", defenseFumbleText = "", criticalArmorText = "" }) {
const contentHtml = await renderCard({
mode: "apply-damage",
@@ -335,6 +419,7 @@ export default class MGNERoll {
criticalArmorText,
breakText ? f("MGNE.Roll.BreakText", { text: breakText }) : "",
]),
_roll: armorRoll ?? null,
})
await ChatMessage.create({
@@ -359,6 +444,7 @@ export default class MGNERoll {
total: roll.total,
outcome,
specialText,
_roll: roll,
})
await ChatMessage.create({