Fix release numbering
This commit is contained in:
@@ -162,7 +162,7 @@ export default class CthulhuEternalCreatureSheet extends CthulhuEternalActorShee
|
||||
|
||||
async _onDrop(event) {
|
||||
if (!this.isEditable || !this.isEditMode) return
|
||||
const data = TextEditor.getDragEventData(event)
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
|
||||
@@ -264,7 +264,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
|
||||
async _onDrop(event) {
|
||||
if (!this.isEditable || !this.isEditMode) return
|
||||
const data = TextEditor.getDragEventData(event)
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
|
||||
@@ -81,8 +81,8 @@ export default class CthulhuEternalVehicleSheet extends CthulhuEternalActorSheet
|
||||
break
|
||||
case "description":
|
||||
context.tab = context.tabs.description
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
|
||||
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.description, { async: true })
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.notes, { async: true })
|
||||
break
|
||||
}
|
||||
return context
|
||||
@@ -104,7 +104,7 @@ export default class CthulhuEternalVehicleSheet extends CthulhuEternalActorSheet
|
||||
|
||||
async _onDrop(event) {
|
||||
if (!this.isEditable || !this.isEditMode) return
|
||||
const data = TextEditor.getDragEventData(event)
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
|
||||
+50
-38
@@ -139,11 +139,19 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
weapon.system.killRadius = choice.killRadius // Override kill radius
|
||||
}
|
||||
|
||||
let combatants = []
|
||||
let targets = []
|
||||
if (game?.combat?.combatants) {
|
||||
for (let c of game.combat.combatants) {
|
||||
if (c.actorid !== actor.id) {
|
||||
combatants.push({ id: c.id, name: c.name })
|
||||
if (c.actorId !== actor.id) {
|
||||
targets.push({ id: c.id, name: c.name, actorId: c.actorId, tokenId: c.token?.id })
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fall back to scene tokens if not in combat
|
||||
if (targets.length === 0 && canvas?.scene) {
|
||||
for (let tokenDoc of canvas.scene.tokens) {
|
||||
if (tokenDoc.actorId !== actor.id) {
|
||||
targets.push({ name: tokenDoc.name, actorId: tokenDoc.actorId, tokenId: tokenDoc.id })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,12 +170,11 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
isLethal,
|
||||
ammoUsed: weapon?.ammoUsed || 0,
|
||||
rollResult: lethalityRoll.total,
|
||||
combatants: combatants
|
||||
combatants: targets
|
||||
}
|
||||
let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-lethal-damage.hbs", msgData)
|
||||
let msg = await ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: flavor,
|
||||
content: await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-lethal-damage.hbs", msgData),
|
||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||
}, { rollMode: options.rollMode, create: true })
|
||||
await msg.setFlag("fvtt-cthulhu-eternal", "woundData", msgData)
|
||||
@@ -191,12 +198,11 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
formula,
|
||||
ammoUsed: weapon?.ammoUsed || 0,
|
||||
rollResult: damageRoll.total,
|
||||
combatants: combatants
|
||||
combatants: targets
|
||||
}
|
||||
let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-regular-damage.hbs", msgData)
|
||||
let msg = await ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: flavor,
|
||||
content: await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-regular-damage.hbs", msgData),
|
||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||
}, { rollMode: options.rollMode, create: true })
|
||||
await msg.setFlag("fvtt-cthulhu-eternal", "woundData", msgData)
|
||||
@@ -254,7 +260,8 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
let formula = "1d100"
|
||||
let hasModifier = true
|
||||
let hasMultiplier = false
|
||||
options.isNudge = true
|
||||
const nudgeEnabled = game.settings.get("fvtt-cthulhu-eternal", "settings-nudge")
|
||||
options.isNudge = nudgeEnabled
|
||||
let actor = game.actors.get(options.actorId)
|
||||
|
||||
let target = CthulhuEternalUtils.getTarget()
|
||||
@@ -271,7 +278,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
case "san":
|
||||
case "char":
|
||||
options.initialScore = options.rollItem.targetScore
|
||||
options.isNudge = (options.rollType !== "san")
|
||||
options.isNudge = nudgeEnabled && (options.rollType !== "san")
|
||||
break
|
||||
case "resource":
|
||||
hasModifier = false
|
||||
@@ -322,7 +329,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
break
|
||||
}
|
||||
|
||||
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes); //Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
||||
const rollModes = foundry.utils.duplicate(CONFIG.ChatMessage.modes ?? CONFIG.Dice.rollModes)
|
||||
const fieldRollMode = new foundry.data.fields.StringField({
|
||||
choices: rollModes,
|
||||
blank: false,
|
||||
@@ -526,6 +533,16 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
}
|
||||
rollData.resultType = resultType
|
||||
|
||||
// Compute WP cost to nudge a failure into a success (minimum roll needed = targetScore)
|
||||
if (this.options.isFailure && options.isNudge && !this.options.isNudgedRoll && rollData.targetScore > 0 && this.total > rollData.targetScore) {
|
||||
const actor = game.actors.get(options.actorId)
|
||||
const wpAvailable = actor?.system?.wp?.value ?? 0
|
||||
const wpCostToSucceed = Math.ceil((this.total - rollData.targetScore) / 5)
|
||||
this.options.wpCostToSucceed = (wpCostToSucceed <= wpAvailable) ? wpCostToSucceed : 0
|
||||
} else {
|
||||
this.options.wpCostToSucceed = 0
|
||||
}
|
||||
|
||||
this.options.isLowWP = rollData.isLowWP
|
||||
this.options.isZeroWP = rollData.isZeroWP
|
||||
this.options.isExhausted = rollData.isExhausted
|
||||
@@ -685,7 +702,19 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
* @param {boolean} [options.create=true] Whether to create the message.
|
||||
* @returns {Promise} - A promise that resolves when the message is created.
|
||||
*/
|
||||
async toMessage(messageData = {}, { rollMode, create = true } = {}) {
|
||||
async toMessage(messageData = {}, { rollMode, messageMode, create = true } = {}) {
|
||||
let rollData = this.options.rollData || this.options
|
||||
let rollItem = this.options.rollItem
|
||||
|
||||
// Determine skill progression before calling super.toMessage so _getChatCardData picks it up
|
||||
let skillMarkedForProgress = false
|
||||
if (rollData.resultType?.includes("failure") && rollItem?.type === "skill") {
|
||||
if (rollItem.system.diceEvolved && !rollItem.system.rollFailed && !rollItem.system.isAdversary) {
|
||||
skillMarkedForProgress = true
|
||||
}
|
||||
}
|
||||
this.options.skillMarkedForProgress = skillMarkedForProgress
|
||||
|
||||
let rollMsg = await super.toMessage(
|
||||
{
|
||||
isFailure: this.resultType === "failure",
|
||||
@@ -695,34 +724,17 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
realDamage: this.realDamage,
|
||||
...messageData,
|
||||
},
|
||||
{ rollMode: rollMode },
|
||||
{ messageMode: messageMode ?? rollMode },
|
||||
)
|
||||
let rollData = this.options.rollData || this.options
|
||||
let rollItem = this.options.rollItem
|
||||
await rollMsg.setFlag("fvtt-cthulhu-eternal", "rollData", rollData)
|
||||
|
||||
// Manage the skill evolution if the roll is a failure
|
||||
if (rollData.resultType.includes("failure") && rollItem.type === "skill") {
|
||||
// Is the skill able to progress
|
||||
if (rollItem.system.diceEvolved && !rollItem.system.rollFailed) {
|
||||
// If the skill is not adversary, we can evolve it
|
||||
if (!rollItem.system.isAdversary) {
|
||||
rollItem.system.rollFailed = true
|
||||
// Get the actor and update the skill
|
||||
const actor = game.actors.get(rollData.actorId)
|
||||
await actor.updateEmbeddedDocuments("Item", [{
|
||||
_id: rollItem._id,
|
||||
"system.rollFailed": true
|
||||
}])
|
||||
// Create a chat message to inform the user
|
||||
const flavor = `${rollItem.name} - ${game.i18n.localize("CTHULHUETERNAL.Label.skillFailed")}`
|
||||
await ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: `<div class="cthulhu-eternal-roll"><p>${flavor}</p></div>`,
|
||||
speaker: ChatMessage.getSpeaker({ actor: rollData.actor }),
|
||||
}, { rollMode: rollData.rollMode, create: true })
|
||||
}
|
||||
}
|
||||
// Apply skill rollFailed flag after the message is created
|
||||
if (skillMarkedForProgress) {
|
||||
const actor = game.actors.get(rollData.actorId)
|
||||
await actor.updateEmbeddedDocuments("Item", [{
|
||||
_id: rollItem._id,
|
||||
"system.rollFailed": true
|
||||
}])
|
||||
}
|
||||
|
||||
// If the roll is a SAN roll, we propose to select the SAN loss
|
||||
|
||||
@@ -74,7 +74,7 @@ export default class CthulhuEternalCreature extends foundry.abstract.TypeDataMod
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||
await roll.toMessage({}, { messageMode: roll.options.rollMode })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||
await roll.toMessage({}, { messageMode: roll.options.rollMode })
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+95
-12
@@ -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 1–5. 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)
|
||||
|
||||
Reference in New Issue
Block a user