Fix release numbering

This commit is contained in:
2026-06-14 23:25:24 +02:00
parent 709e69fac8
commit e43487b727
35 changed files with 391 additions and 152 deletions
+95 -12
View File
@@ -16,6 +16,14 @@ export default class CthulhuEternalUtils {
config: true,
onChange: _ => window.location.reload()
});
game.settings.register("fvtt-cthulhu-eternal", "settings-nudge", {
name: game.i18n.localize("CTHULHUETERNAL.Settings.nudge"),
hint: game.i18n.localize("CTHULHUETERNAL.Settings.nudgeHint"),
default: true,
scope: "world",
type: Boolean,
config: true
});
game.settings.register("fvtt-cthulhu-eternal", "roll-opposed-store", {
name: "Roll Opposed Store",
hint: "Whether to store opposed roll results for later use",
@@ -536,17 +544,63 @@ export default class CthulhuEternalUtils {
})
}
static async nudgeToSuccess(rollMessage) {
if (!game.settings.get("fvtt-cthulhu-eternal", "settings-nudge")) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Settings.nudgeDisabled"))
return
}
const rollOptions = rollMessage.rolls[0]?.options
if (!rollOptions) return
const actor = game.actors.get(rollOptions.actorId)
if (!actor) return
const rollTotal = rollMessage.rolls[0].total
const targetScore = rollOptions.rollData?.targetScore ?? rollOptions.targetScore
const wpCostToSucceed = Math.ceil((rollTotal - targetScore) / 5)
if (actor.system.wp.value < wpCostToSucceed) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Label.notEnoughWP"))
return
}
const dialogContext = foundry.utils.duplicate(rollOptions)
dialogContext.nudgedValue = targetScore
dialogContext.wpCost = wpCostToSucceed
dialogContext.isNudgedRoll = true
dialogContext.isNudge = false
const roll = new CthulhuEternalRoll(String(targetScore))
await roll.evaluate()
roll.options = dialogContext
roll.displayRollResult(roll, dialogContext, dialogContext.rollData)
roll.toMessage()
actor.system.modifyWP(-wpCostToSucceed)
// Original roll was a failure with skill progression — nudge succeeded, so unmark progression
if (rollOptions.skillMarkedForProgress && rollOptions.rollItem?._id) {
const skillItem = actor.items.get(rollOptions.rollItem._id)
if (skillItem) await skillItem.update({ "system.rollFailed": false })
}
await rollMessage.delete()
}
static async nudgeRoll(rollMessage) {
if (!game.settings.get("fvtt-cthulhu-eternal", "settings-nudge")) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Settings.nudgeDisabled"))
return
}
let dialogContext = rollMessage.rolls[0]?.options
let actor = game.actors.get(dialogContext.actorId)
const rollTotal = rollMessage.rolls[0].total
dialogContext.wpValue = actor.system.wp.value
dialogContext.rollResultIndex = rollMessage.rolls[0].total - 1
dialogContext.minValue = Math.max(rollMessage.rolls[0].total - (dialogContext.wpValue * 5), 1)
dialogContext.maxValue = Math.min(rollMessage.rolls[0].total + (dialogContext.wpValue * 5), 100)
// Rule: 1 WP can decrease the roll by 15. Only decrease is allowed.
dialogContext.minValue = Math.max(rollTotal - (dialogContext.wpValue * 5), 1)
dialogContext.maxValue = rollTotal
dialogContext.rollResultIndex = rollTotal - dialogContext.minValue // index of current value in nudgeOptions
dialogContext.wpCost = 0
// Build options table for the select operator between minValue and maxValue
dialogContext.nudgedValue = rollTotal // default: no change for the select: values from minValue to maxValue (current roll)
dialogContext.nudgeOptions = Array.from({ length: dialogContext.maxValue - dialogContext.minValue + 1 }, (_, i) => dialogContext.minValue + i)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/nudge-dialog.hbs", dialogContext)
@@ -565,6 +619,9 @@ export default class CthulhuEternalUtils {
if (input.name) obj[input.name] = input.value
return obj
}, {})
// Compute nudgedValue from the selected index (selectOptions uses 0-based indices for arrays)
dialogContext.nudgedValue = dialogContext.minValue + Number(output.modifiedValue)
dialogContext.wpCost = Math.ceil(Math.abs(rollTotal - dialogContext.nudgedValue) / 5)
return output
},
},
@@ -579,7 +636,7 @@ export default class CthulhuEternalUtils {
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
$(".nudged-score-select").change(event => {
dialogContext.nudgedValue = Number(event.target.value) + 1
dialogContext.nudgedValue = dialogContext.minValue + Number(event.target.value)
dialogContext.wpCost = Math.ceil(Math.abs(rollMessage.rolls[0].total - dialogContext.nudgedValue) / 5)
$("#nudged-wp-cost").val(dialogContext.wpCost)
})
@@ -591,6 +648,11 @@ export default class CthulhuEternalUtils {
return
}
if (actor.system.wp.value < dialogContext.wpCost) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Label.notEnoughWP"))
return
}
const roll = new CthulhuEternalRoll(String(dialogContext.nudgedValue))
await roll.evaluate()
roll.options = dialogContext
@@ -601,6 +663,13 @@ export default class CthulhuEternalUtils {
actor.system.modifyWP(-dialogContext.wpCost)
// If original roll had skill progression and nudge converts it to success, unmark progression
const nudgedTargetScore = dialogContext.rollData?.targetScore ?? dialogContext.targetScore
if (dialogContext.skillMarkedForProgress && dialogContext.nudgedValue <= nudgedTargetScore && dialogContext.rollItem?._id) {
const skillItem = actor.items.get(dialogContext.rollItem._id)
if (skillItem) await skillItem.update({ "system.rollFailed": false })
}
// Delete the initial roll message
await rollMessage.delete()
@@ -642,15 +711,29 @@ export default class CthulhuEternalUtils {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noActorFound"))
return
}
// Remove the chat message
this.removeChatMessageId(message.id)
// Get the targetted actorId from the button's data attribute
let targetCombatantId = event.currentTarget.dataset.combatantId
let combatant = game.combat.combatants.get(targetCombatantId)
let targetActor = combatant.token?.actor || game.actors.get(combatant.actorId)
// Resolve the target actor: prefer canvas token (works for both combat and scene tokens)
const targetTokenId = event.currentTarget.dataset.tokenId
const targetActorId = event.currentTarget.dataset.actorId
let targetActor
if (targetTokenId) {
const token = canvas.tokens.get(targetTokenId)
targetActor = token?.actor
}
if (!targetActor && targetActorId) {
targetActor = game.actors.get(targetActorId)
}
// Legacy fallback: combatant lookup
if (!targetActor) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noTargetActorFound") + targetCombatantId)
const combatantId = event.currentTarget.dataset.combatantId
if (combatantId && game.combat) {
const combatant = game.combat.combatants.get(combatantId)
targetActor = combatant?.token?.actor || game.actors.get(combatant?.actorId)
}
}
if (!targetActor) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noTargetActorFound"))
return
}
targetActor.applyWounds(woundData)