diff --git a/lang/en.json b/lang/en.json
index 787cce2..7bd6632 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -93,7 +93,7 @@
}
},
"developmentPoints": {
- "label": "Development points",
+ "label": "Development points",
"total": {
"label": "Total"
},
@@ -191,7 +191,7 @@
}
},
"developmentPoints": {
- "label": "Development points",
+ "label": "Development points",
"total": {
"label": "Total"
},
@@ -281,6 +281,9 @@
}
},
"Label": {
+ "combatAction": "Combat action",
+ "currentAction": "Current ongoing action",
+ "selectAction": "Select an action",
"spell-power": "Spell - Power",
"spell-attack": "Spell - Attack",
"miracle-power": "Miracle - Power",
@@ -430,7 +433,7 @@
},
"materialComponent": {
"label": "Material component"
- },
+ },
"catalyst": {
"label": "Catalyst"
},
@@ -485,7 +488,9 @@
"rollFromWeapon": "Roll from an equipped weapon",
"rollTypeNotFound": "Roll type not found",
"skillNotFound": "Skill not found",
- "messageProgressionOK": "{name} can attack this second with {weapon}.",
+ "messageProgressionOK": "{name} can perform a new action !",
+ "messageLethargyOK": "Lethargy ended.
{name} can perform a new action !",
+ "messageLethargyKO": "Lethargy stil ongoing ...",
"messageProgressionKO": "{name} can't attack this second.",
"messageProgressionOKMonster": "{name} can attack this second with {weapon}.",
"messageProgressionKOMonster": "{name} can't attack this second."
@@ -704,7 +709,7 @@
},
"materialComponent": {
"label": "Material component"
- },
+ },
"catalyst": {
"label": "Catalyst"
}
diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs
index ba16d59..8806b72 100644
--- a/module/applications/sheets/character-sheet.mjs
+++ b/module/applications/sheets/character-sheet.mjs
@@ -232,32 +232,6 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
super._onRender();
}
- getBestWeaponClassSkill(skills, rollType, multiplier = 1.0) {
- let maxValue = 0
- let goodSkill = skills[0]
- for (let s of skills) {
- if (rollType === "weapon-attack") {
- if (s.system.weaponBonus.attack > maxValue) {
- maxValue = Number(s.system.weaponBonus.attack)
- goodSkill = s
- }
- }
- if (rollType === "weapon-defense") {
- if (s.system.weaponBonus.defense > maxValue) {
- maxValue = Number(s.system.weaponBonus.defense)
- goodSkill = s
- }
- }
- if (rollType.includes("weapon-damage")) {
- if (s.system.weaponBonus.damage > maxValue) {
- maxValue = Number(s.system.weaponBonus.damage)
- goodSkill = s
- }
- }
- }
- goodSkill.weaponSkillModifier = maxValue * multiplier
- return goodSkill
- }
/**
* Handles the roll action triggered by user interaction.
@@ -277,118 +251,11 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
async _onRoll(event, target) {
if (this.isEditMode) return
const rollType = event.target.dataset.rollType
- let rollTarget
- let rollKey = event.target.dataset.rollKey
- switch (rollType) {
- case "granted":
- rollTarget = {
- name: rollKey,
- formula: foundry.utils.duplicate(this.document.system.granted[rollKey]),
- rollKey: rollKey
- }
- if ( rollTarget.formula === "" || rollTarget.formula === undefined) {
- rollTarget.formula = 0
- }
- break;
- case "challenge":
- rollTarget = foundry.utils.duplicate(this.document.system.challenges[rollKey])
- rollTarget.rollKey = rollKey
- break
- case "save":
- rollTarget = foundry.utils.duplicate(this.document.system.saves[rollKey])
- rollTarget.rollKey = rollKey
- rollTarget.rollDice = event.target.dataset?.rollDice
- break
- case "spell":
- rollTarget = this.actor.items.find((i) => i.type === "spell" && i.id === rollKey)
- rollTarget.rollKey = rollKey
- break
- case "miracle":
- rollTarget = this.actor.items.find((i) => i.type === "miracle" && i.id === rollKey)
- rollTarget.rollKey = rollKey
- break
- case "skill":
- rollTarget = this.actor.items.find((i) => i.type === "skill" && i.id === rollKey)
- rollTarget.rollKey = rollKey
- if (rollTarget.system.category === "weapon") {
- ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.rollFromWeapon"))
- return
- }
- break
- case "miracle-attack":
- case "miracle-power":
- rollTarget = this.actor.items.find((i) => i.type === "miracle" && i.id === rollKey)
- rollTarget.rollKey = rollKey
- break
- case "spell-attack":
- case "spell-power":
- rollTarget = this.actor.items.find((i) => i.type === "spell" && i.id === rollKey)
- rollTarget.rollKey = rollKey
- break
- case "shield-roll":
- rollTarget = this.actor.items.find((i) => i.type === "shield" && i.id === rollKey)
- let shieldSkill = this.actor.items.find((i) => i.type === "skill" && i.name.toLowerCase() === rollTarget.name.toLowerCase())
- rollTarget.skill = shieldSkill
- rollTarget.rollKey = rollKey
- break;
- case "weapon-damage-small":
- case "weapon-damage-medium":
- case "weapon-attack":
- case "weapon-defense":
- let weapon = this.actor.items.find((i) => i.type === "weapon" && i.id === rollKey)
- let skill
- let skills = this.actor.items.filter((i) => i.type === "skill" && i.name.toLowerCase() === weapon.name.toLowerCase())
- if (skills.length > 0) {
- skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
- } else {
- skills = this.actor.items.filter((i) => i.type === "skill" && i.name.toLowerCase().replace(" skill", "") === weapon.name.toLowerCase())
- if (skills.length > 0) {
- skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
- } else {
- skills = this.actor.items.filter((i) => i.type === "skill" && i.system.weaponClass === weapon.system.weaponClass)
- if (skills.length > 0) {
- skill = this.getBestWeaponClassSkill(skills, rollType, 0.5)
- } else {
- skills = this.actor.items.filter((i) => i.type === "skill" && i.system.weaponClass.includes(SYSTEM.WEAPON_CATEGORIES[weapon.system.weaponClass]))
- if (skills.length > 0) {
- skill = this.getBestWeaponClassSkill(skills, rollType, 0.25)
- } else {
- ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
- return
- }
- }
- }
- }
- if (!weapon || !skill) {
- console.error("Weapon or skill not found", weapon, skill)
- ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
- return
- }
- rollTarget = skill
- rollTarget.weapon = weapon
- rollTarget.weaponSkillModifier = skill.weaponSkillModifier
- rollTarget.rollKey = rollKey
- rollTarget.combat = foundry.utils.duplicate(this.actor.system.combat)
- if ( rollType === "weapon-damage-small" || rollType === "weapon-damage-medium") {
- rollTarget.grantedDice = this.actor.system.granted.damageDice
- }
- if ( rollType === "weapon-attack") {
- rollTarget.grantedDice = this.actor.system.granted.attackDice
- }
- if ( rollType === "weapon-defense") {
- rollTarget.grantedDice = this.actor.system.granted.defenseDice
- }
- break
- default:
- ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
- break
- }
+ let rollKey = event.target.dataset.rollKey;
+ let rollDice = event.target.dataset?.rollDice;
+
+ this.actor.prepareRoll(rollType, rollKey, rollDice)
- // In all cases
- rollTarget.magicUser = this.actor.system.biodata.magicUser
- rollTarget.actorModifiers = foundry.utils.duplicate(this.actor.system.modifiers)
- rollTarget.actorLevel = this.actor.system.biodata.level
- await this.document.system.roll(rollType, rollTarget)
}
// #endregion
}
diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs
index c2870ea..0e2a2f1 100644
--- a/module/documents/actor.mjs
+++ b/module/documents/actor.mjs
@@ -41,4 +41,144 @@ export default class LethalFantasyActor extends Actor {
}
}
+ getBestWeaponClassSkill(skills, rollType, multiplier = 1.0) {
+ let maxValue = 0
+ let goodSkill = skills[0]
+ for (let s of skills) {
+ if (rollType === "weapon-attack") {
+ if (s.system.weaponBonus.attack > maxValue) {
+ maxValue = Number(s.system.weaponBonus.attack)
+ goodSkill = s
+ }
+ }
+ if (rollType === "weapon-defense") {
+ if (s.system.weaponBonus.defense > maxValue) {
+ maxValue = Number(s.system.weaponBonus.defense)
+ goodSkill = s
+ }
+ }
+ if (rollType.includes("weapon-damage")) {
+ if (s.system.weaponBonus.damage > maxValue) {
+ maxValue = Number(s.system.weaponBonus.damage)
+ goodSkill = s
+ }
+ }
+ }
+ goodSkill.weaponSkillModifier = maxValue * multiplier
+ return goodSkill
+ }
+
+ async prepareRoll(rollType, rollKey, rollDice ) {
+ let rollTarget
+ switch (rollType) {
+ case "granted":
+ rollTarget = {
+ name: rollKey,
+ formula: foundry.utils.duplicate(this.system.granted[rollKey]),
+ rollKey: rollKey
+ }
+ if ( rollTarget.formula === "" || rollTarget.formula === undefined) {
+ rollTarget.formula = 0
+ }
+ break;
+ case "challenge":
+ rollTarget = foundry.utils.duplicate(this.system.challenges[rollKey])
+ rollTarget.rollKey = rollKey
+ break
+ case "save":
+ rollTarget = foundry.utils.duplicate(this.system.saves[rollKey])
+ rollTarget.rollKey = rollKey
+ rollTarget.rollDice = rollDice
+ break
+ case "spell":
+ rollTarget = this.items.find((i) => i.type === "spell" && i.id === rollKey)
+ rollTarget.rollKey = rollKey
+ break
+ case "miracle":
+ rollTarget = this.items.find((i) => i.type === "miracle" && i.id === rollKey)
+ rollTarget.rollKey = rollKey
+ break
+ case "skill":
+ rollTarget = this.items.find((i) => i.type === "skill" && i.id === rollKey)
+ rollTarget.rollKey = rollKey
+ if (rollTarget.system.category === "weapon") {
+ ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.rollFromWeapon"))
+ return
+ }
+ break
+ case "spell-attack":
+ case "spell-power":
+ case "miracle-attack":
+ case "miracle-power":
+ rollTarget = this.items.find((i) => (i.type === "miracle" || i.type == "spell") && i.id === rollKey)
+ rollTarget.rollKey = rollKey
+ break
+ case "shield-roll": {
+ rollTarget = this.items.find((i) => i.type === "shield" && i.id === rollKey)
+ let shieldSkill = this.items.find((i) => i.type === "skill" && i.name.toLowerCase() === rollTarget.name.toLowerCase())
+ rollTarget.skill = shieldSkill
+ rollTarget.rollKey = rollKey
+ }
+ break;
+ case "weapon-damage-small":
+ case "weapon-damage-medium":
+ case "weapon-attack":
+ case "weapon-defense": {
+ let weapon = this.items.find((i) => i.type === "weapon" && i.id === rollKey)
+ let skill
+ let skills = this.items.filter((i) => i.type === "skill" && i.name.toLowerCase() === weapon.name.toLowerCase())
+ if (skills.length > 0) {
+ skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
+ } else {
+ skills = this.items.filter((i) => i.type === "skill" && i.name.toLowerCase().replace(" skill", "") === weapon.name.toLowerCase())
+ if (skills.length > 0) {
+ skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
+ } else {
+ skills = this.items.filter((i) => i.type === "skill" && i.system.weaponClass === weapon.system.weaponClass)
+ if (skills.length > 0) {
+ skill = this.getBestWeaponClassSkill(skills, rollType, 0.5)
+ } else {
+ skills = this.items.filter((i) => i.type === "skill" && i.system.weaponClass.includes(SYSTEM.WEAPON_CATEGORIES[weapon.system.weaponClass]))
+ if (skills.length > 0) {
+ skill = this.getBestWeaponClassSkill(skills, rollType, 0.25)
+ } else {
+ ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
+ return
+ }
+ }
+ }
+ }
+ if (!weapon || !skill) {
+ console.error("Weapon or skill not found", weapon, skill)
+ ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
+ return
+ }
+ rollTarget = skill
+ rollTarget.weapon = weapon
+ rollTarget.weaponSkillModifier = skill.weaponSkillModifier
+ rollTarget.rollKey = rollKey
+ rollTarget.combat = foundry.utils.duplicate(this.system.combat)
+ if ( rollType === "weapon-damage-small" || rollType === "weapon-damage-medium") {
+ rollTarget.grantedDice = this.system.granted.damageDice
+ }
+ if ( rollType === "weapon-attack") {
+ rollTarget.grantedDice = this.system.granted.attackDice
+ }
+ if ( rollType === "weapon-defense") {
+ rollTarget.grantedDice = this.system.granted.defenseDice
+ }
+ }
+ break
+ default:
+ ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
+ break
+ }
+
+ // In all cases
+ rollTarget.magicUser = this.system.biodata.magicUser
+ rollTarget.actorModifiers = foundry.utils.duplicate(this.system.modifiers)
+ rollTarget.actorLevel = this.system.biodata.level
+ await this.system.roll(rollType, rollTarget)
+ }
+
}
diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs
index 9f4cc1a..905c03f 100644
--- a/module/documents/roll.mjs
+++ b/module/documents/roll.mjs
@@ -247,7 +247,7 @@ export default class LethalFantasyRoll extends Roll {
hasChangeDice = false
hasMaxValue = false
hasExplode = false
- options.rollTarget.value = 0
+ options.rollTarget.value = 0
} else if (options.rollType.includes("weapon-damage")) {
options.rollName = options.rollTarget.name
@@ -602,6 +602,230 @@ export default class LethalFantasyRoll extends Roll {
}
+ static async promptCombatAction(options = {}) {
+
+ const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
+ const fieldRollMode = new foundry.data.fields.StringField({
+ choices: rollModes,
+ blank: false,
+ default: "public",
+ })
+
+ let combatant = game.combats.get(options.combatId)?.combatants?.get(options.combatantId)
+ if (!combatant) {
+ console.error("No combatant found for this combat")
+ return
+ }
+ let currentAction = combatant.getFlag(SYSTEM.id, "currentAction")
+
+ let dialogContext = {
+ progressionDiceId: "",
+ fieldRollMode,
+ rollModes,
+ currentAction,
+ ...options
+ }
+
+ const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/combat-action-dialog.hbs", dialogContext)
+
+ let buttons = []
+ if (currentAction) {
+ if (currentAction.type === "weapon") {
+ buttons.push({
+ action: "roll",
+ label: "Roll progression dice",
+ callback: (event, button, dialog) => {
+ return "rollProgressionDice"
+ },
+ })
+ } else if (currentAction.type === "spell" || currentAction.type === "miracle") {
+ let label = ""
+ if ( currentAction.castingDone) {
+ label = "Roll lethargy dice"
+ } else {
+ label = "Wait casting time"
+ }
+ buttons.push({
+ action: "roll",
+ label: label,
+ callback: (event, button, dialog) => {
+ return "rollLethargyDice"
+ },
+ })
+ }
+ } else {
+ buttons.push({
+ action: "roll",
+ label: "Select action",
+ callback: (event, button, dialog) => {
+ const output = Array.from(button.form.elements).reduce((obj, input) => {
+ if (input.name) obj[input.name] = input.value
+ return obj
+ }, {})
+ return output
+ },
+ },
+ )
+ }
+ buttons.push({
+ action: "cancel",
+ label: "Other action, not listed here",
+ callback: (event, button, dialog) => {
+ return null;
+ }
+ })
+
+ const rollContext = await foundry.applications.api.DialogV2.wait({
+ window: { title: "Combat Action Dialog" },
+ classes: ["lethalfantasy"],
+ content,
+ buttons,
+ rejectClose: false // Click on Close button will not launch an error
+ })
+
+ console.log("RollContext", dialogContext, rollContext)
+ // If action is cancelled, exit
+ if (rollContext === null || rollContext === "cancel") {
+ await combatant.setFlag(SYSTEM.id, "currentAction", "")
+ let message = `${combatant.name} : Other action, progression reset`
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ return
+ }
+
+ // Setup the current action
+ if (!currentAction || currentAction === "") {
+ // Get the item from the returned selectedChoice value
+ let selectedChoice = rollContext.selectedChoice
+ let rangedMode
+ if (selectedChoice.match("simpleAim")) {
+ selectedChoice = selectedChoice.replace("simpleAim", "")
+ rangedMode = "simpleAim"
+ }
+ if (selectedChoice.match("carefulAim")) {
+ selectedChoice = selectedChoice.replace("carefulAim", "")
+ rangedMode = "carefulAim"
+ }
+ if (selectedChoice.match("focusedAim")) {
+ selectedChoice = selectedChoice.replace("focusedAim", "")
+ rangedMode = "focusedAim"
+ }
+ let selectedItem = combatant.actor.items.find(i => i.id === selectedChoice)
+ // Setup flag for combat action usage
+ let actionItem = foundry.utils.duplicate(selectedItem)
+ actionItem.progressionCount = 1
+ actionItem.rangedMode = rangedMode
+ actionItem.castingTime = 1
+ actionItem.castingDone = false
+ // Set the flag on the combatant
+ await combatant.setFlag(SYSTEM.id, "currentAction", actionItem)
+ let message = `${combatant.name} action : ${selectedItem.name}`
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+
+ combatant.actor.prepareRoll(actionItem.type === "weapon" ? "weapon-attack" : "spell-attack", selectedChoice)
+ return
+ }
+
+ if (currentAction) {
+ if (rollContext === "rollLethargyDice") {
+ if ( !currentAction.castingDone) {
+ if ( currentAction.castingTime <= currentAction.system.castingTime) {
+ let message = `Casting time : ${currentAction.name}, count : ${currentAction.castingTime}/${currentAction.system.castingTime}`
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ currentAction.castingTime += 1
+ await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
+ return
+ } else {
+ let message = `Spell ${currentAction.name} has ben casted !`
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ currentAction.castingTime = 1
+ currentAction.castingDone = true
+ await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
+ return
+ }
+ } else {
+ // Roll lethargy dice
+ let dice = LethalFantasyUtils.getLethargyDice(currentAction.system.level)
+ let roll = new Roll(dice)
+ await roll.evaluate()
+ let max = roll.dice[0].faces - 1
+ let toCompare = Math.min(options.rollProgressionCount, max)
+ if (roll.total <= toCompare) {
+ // Notify that the player can act now with a chat message
+ let message = game.i18n.format("LETHALFANTASY.Notifications.messageLethargyOK", { name: combatant.actor.name, weapon: currentAction.name, roll: roll.total })
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ // Update the combatant progression count
+ await combatant.setFlag(SYSTEM.id, "currentAction", "")
+ // Display the action selection window again
+ combatant.actor.system.rollProgressionDice(options.combatId, options.combatantId )
+ } else {
+ // Notify that the player cannot act now with a chat message
+ currentAction.progressionCount += 1
+ combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
+ let message = game.i18n.format("LETHALFANTASY.Notifications.messageLethargyKO", { name: combatant.actor.name, weapon: currentAction.name, roll: roll.total })
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ }
+ }
+ }
+
+ if (rollContext === "rollProgressionDice") {
+ let formula = currentAction.system.combatProgressionDice
+ if (currentAction?.rangedMode) {
+ let toSplit = currentAction.system.speed[currentAction.rangedMode]
+ let split = toSplit.split("+")
+ currentAction.rangedLoad = Number(split[0]) || 0
+ formula = split[1]
+ console.log("Ranged Mode", currentAction.rangedMode, currentAction.rangedLoad, formula)
+ }
+ // Range weapon loading
+ if (!currentAction.weaponLoaded && currentAction.rangedLoad) {
+ if (currentAction.progressionCount <= currentAction.rangedLoad) {
+ let message = `Ranged weapon ${currentAction.name} is loading, loading count : ${currentAction.progressionCount}/${currentAction.rangedLoad}`
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ currentAction.progressionCount += 1
+ await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
+ } else {
+ let message = `Ranged weapon ${currentAction.name} is loaded !`
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ currentAction.weaponLoaded = true
+ currentAction.progressionCount = 1
+ await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
+ }
+ return
+ }
+
+ // Melee mode
+ let isMonster = combatant.actor.type === "monster"
+ // Get the dice and roll it if
+ let roll = new Roll(formula)
+ await roll.evaluate()
+
+ let max = roll.dice[0].faces - 1
+ max = Math.min(currentAction.progressionCount, max)
+ let msg = await roll.toMessage({ flavor: `Progression Roll for ${currentAction.name}, progression count : ${currentAction.progressionCount}/${max}` }, { rollMode: rollContext.visibility })
+ if (game?.dice3d) {
+ await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
+ }
+
+ if (roll.total <= max) {
+ // Notify that the player can act now with a chat message
+ let message = game.i18n.format("LETHALFANTASY.Notifications.messageProgressionOK", { isMonster, name: combatant.actor.name, weapon: currentAction.name, roll: roll.total })
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ // Update the combatant progression count
+ await combatant.setFlag(SYSTEM.id, "currentAction", "")
+ // Display the action selection window again
+ combatant.actor.system.rollProgressionDice(options.combatId, options.combatantId )
+ } else {
+ // Notify that the player cannot act now with a chat message
+ currentAction.progressionCount += 1
+ combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
+ let message = game.i18n.format("LETHALFANTASY.Notifications.messageProgressionKO", { isMonster, name: combatant.actor.name, weapon: currentAction.name, roll: roll.total })
+ ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
+ }
+ }
+ }
+ }
+
+
static async promptProgressionDice(options = {}) {
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
@@ -654,11 +878,11 @@ export default class LethalFantasyRoll extends Roll {
rejectClose: false // Click on Close button will not launch an error
})
- console.log("RollContext", dialogContext,rollContext)
+ console.log("RollContext", dialogContext, rollContext)
let combat = game.combats.get(options.combatId)
let actor = game.actors.get(options.actorId)
- if ( rollContext === "casting") {
+ if (rollContext === "casting") {
combat.setCasting(options.combatantId)
let message = `Starting casting a spell !`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: actor }) })
@@ -677,25 +901,25 @@ export default class LethalFantasyRoll extends Roll {
// Get the weapons from the actor items
let rangedMode
let searchId = rollContext.progressionDiceId
- if ( searchId.match("simpleAim")) {
+ if (searchId.match("simpleAim")) {
searchId = searchId.replace("simpleAim", "")
- rangedMode = "simpleAim"
+ rangedMode = "simpleAim"
}
- if ( searchId.match("carefulAim")) {
+ if (searchId.match("carefulAim")) {
searchId = searchId.replace("carefulAim", "")
- rangedMode = "carefulAim"
+ rangedMode = "carefulAim"
}
- if ( searchId.match("focusedAim")) {
+ if (searchId.match("focusedAim")) {
searchId = searchId.replace("focusedAim", "")
- rangedMode = "focusedAim"
+ rangedMode = "focusedAim"
}
if (searchId.match("spell")) {
searchId = searchId.replace("spell", "")
let spell = actor.items.find(i => i.type === "spell" && i.id === searchId)
- let dice = LethalFantasyUtils.getLethargyDice(spell.system.level)
+ let dice = LethalFantasyUtils.getLethargyDice(spell.system.level)
if (combat.isCasting(options.combatantId)) {
- if (options.rollProgressionCount <= spell.system.castingTime ) {
+ if (options.rollProgressionCount <= spell.system.castingTime) {
let message = `Spell casting time : ${spell.name}, count : ${options.rollProgressionCount}/${spell.system.castingTime}`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: actor }) })
return
@@ -707,7 +931,7 @@ export default class LethalFantasyRoll extends Roll {
combat.resetProgression(options.combatantId)
return
}
- } else{
+ } else {
let formula = dice
let roll = new Roll(formula)
await roll.evaluate()
@@ -740,7 +964,7 @@ export default class LethalFantasyRoll extends Roll {
console.log("Ranged Mode", rangedMode, rangedLoad, formula, options.rollProgressionCount)
}
- if (rangedLoad && options.rollProgressionCount <= rangedLoad ) {
+ if (rangedLoad && options.rollProgressionCount <= rangedLoad) {
let message = `Ranged weapon ${weapon.name} is loading, loading count : ${options.rollProgressionCount}/${rangedLoad}`
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: actor }) })
return
diff --git a/module/models/character.mjs b/module/models/character.mjs
index f6ccfa2..567ca3a 100644
--- a/module/models/character.mjs
+++ b/module/models/character.mjs
@@ -73,7 +73,7 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
{ description: "", value: 0, duration: 0 }, { description: "", value: 0, duration: 0 }, { description: "", value: 0, duration: 0 }, { description: "", value: 0, duration: 0 },
{ description: "", value: 0, duration: 0 }, { description: "", value: 0, duration: 0 }], min: 8
}),
- damageResistance: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
+ damageResistance: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
})
schema.perception = new fields.SchemaField({
@@ -299,11 +299,11 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
let spells = this.parent.items.filter(i => i.type === "spell" || i.type === "miracle")
for (let s of spells) {
let dice = LethalFantasyUtils.getLethargyDice(s.system.level)
- weaponsChoices.push({ id: `spell${s.id}`, name: `${s.name} (Time: ${s.system.castingTime}, Lethargy: ${dice})`, combatProgressionDice: `${s.system.castingTime}+${dice}` })
+ weaponsChoices.push({ id: s.id, name: `${s.name} (Time: ${s.system.castingTime}, Lethargy: ${dice})`, combatProgressionDice: `${s.system.castingTime}+${dice}` })
}
}
- let roll = await LethalFantasyRoll.promptProgressionDice({
+ let roll = await LethalFantasyRoll.promptCombatAction({
actorId: this.parent.id,
actorName: this.parent.name,
actorImage: this.parent.img,
diff --git a/packs-system/lf-equipment/000209.log b/packs-system/lf-equipment/000217.log
similarity index 100%
rename from packs-system/lf-equipment/000209.log
rename to packs-system/lf-equipment/000217.log
diff --git a/packs-system/lf-equipment/CURRENT b/packs-system/lf-equipment/CURRENT
index c692fd1..68076bd 100644
--- a/packs-system/lf-equipment/CURRENT
+++ b/packs-system/lf-equipment/CURRENT
@@ -1 +1 @@
-MANIFEST-000207
+MANIFEST-000215
diff --git a/packs-system/lf-equipment/LOG b/packs-system/lf-equipment/LOG
index e4b75c2..f2a64fe 100644
--- a/packs-system/lf-equipment/LOG
+++ b/packs-system/lf-equipment/LOG
@@ -1,8 +1,8 @@
-2025/04/16-08:18:09.103824 7f5c83fff6c0 Recovering log #205
-2025/04/16-08:18:09.114815 7f5c83fff6c0 Delete type=3 #203
-2025/04/16-08:18:09.114932 7f5c83fff6c0 Delete type=0 #205
-2025/04/16-08:32:26.394277 7f5c81bff6c0 Level-0 table #210: started
-2025/04/16-08:32:26.394334 7f5c81bff6c0 Level-0 table #210: 0 bytes OK
-2025/04/16-08:32:26.400532 7f5c81bff6c0 Delete type=0 #208
-2025/04/16-08:32:26.400730 7f5c81bff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
-2025/04/16-08:32:26.400790 7f5c81bff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
+2025/04/17-17:21:12.564483 7f5c837fe6c0 Recovering log #213
+2025/04/17-17:21:12.575284 7f5c837fe6c0 Delete type=3 #211
+2025/04/17-17:21:12.575342 7f5c837fe6c0 Delete type=0 #213
+2025/04/17-17:34:42.493086 7f5c81bff6c0 Level-0 table #218: started
+2025/04/17-17:34:42.493111 7f5c81bff6c0 Level-0 table #218: 0 bytes OK
+2025/04/17-17:34:42.499036 7f5c81bff6c0 Delete type=0 #216
+2025/04/17-17:34:42.518959 7f5c81bff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
+2025/04/17-17:34:42.519032 7f5c81bff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-equipment/LOG.old b/packs-system/lf-equipment/LOG.old
index 4ca40b4..252cbd7 100644
--- a/packs-system/lf-equipment/LOG.old
+++ b/packs-system/lf-equipment/LOG.old
@@ -1,8 +1,8 @@
-2025/04/15-20:28:27.909693 7f5c827fc6c0 Recovering log #201
-2025/04/15-20:28:27.920405 7f5c827fc6c0 Delete type=3 #199
-2025/04/15-20:28:27.920498 7f5c827fc6c0 Delete type=0 #201
-2025/04/15-20:29:29.823399 7f5c81bff6c0 Level-0 table #206: started
-2025/04/15-20:29:29.823453 7f5c81bff6c0 Level-0 table #206: 0 bytes OK
-2025/04/15-20:29:29.855733 7f5c81bff6c0 Delete type=0 #204
-2025/04/15-20:29:29.869881 7f5c81bff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
-2025/04/15-20:29:29.899952 7f5c81bff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
+2025/04/16-20:52:43.295244 7f5c837fe6c0 Recovering log #209
+2025/04/16-20:52:43.351254 7f5c837fe6c0 Delete type=3 #207
+2025/04/16-20:52:43.351376 7f5c837fe6c0 Delete type=0 #209
+2025/04/16-22:34:18.463926 7f5c81bff6c0 Level-0 table #214: started
+2025/04/16-22:34:18.463971 7f5c81bff6c0 Level-0 table #214: 0 bytes OK
+2025/04/16-22:34:18.470667 7f5c81bff6c0 Delete type=0 #212
+2025/04/16-22:34:18.477404 7f5c81bff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
+2025/04/16-22:34:18.477430 7f5c81bff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-equipment/MANIFEST-000207 b/packs-system/lf-equipment/MANIFEST-000215
similarity index 72%
rename from packs-system/lf-equipment/MANIFEST-000207
rename to packs-system/lf-equipment/MANIFEST-000215
index 3d9dc7f..b6db18a 100644
Binary files a/packs-system/lf-equipment/MANIFEST-000207 and b/packs-system/lf-equipment/MANIFEST-000215 differ
diff --git a/packs-system/lf-gifts/000208.log b/packs-system/lf-gifts/000216.log
similarity index 100%
rename from packs-system/lf-gifts/000208.log
rename to packs-system/lf-gifts/000216.log
diff --git a/packs-system/lf-gifts/CURRENT b/packs-system/lf-gifts/CURRENT
index b04a015..f0a2cf1 100644
--- a/packs-system/lf-gifts/CURRENT
+++ b/packs-system/lf-gifts/CURRENT
@@ -1 +1 @@
-MANIFEST-000206
+MANIFEST-000214
diff --git a/packs-system/lf-gifts/LOG b/packs-system/lf-gifts/LOG
index 13b6914..a042dc7 100644
--- a/packs-system/lf-gifts/LOG
+++ b/packs-system/lf-gifts/LOG
@@ -1,8 +1,8 @@
-2025/04/16-08:18:09.118755 7f5c82ffd6c0 Recovering log #204
-2025/04/16-08:18:09.129516 7f5c82ffd6c0 Delete type=3 #202
-2025/04/16-08:18:09.129610 7f5c82ffd6c0 Delete type=0 #204
-2025/04/16-08:32:26.380608 7f5c81bff6c0 Level-0 table #209: started
-2025/04/16-08:32:26.380651 7f5c81bff6c0 Level-0 table #209: 0 bytes OK
-2025/04/16-08:32:26.386680 7f5c81bff6c0 Delete type=0 #207
-2025/04/16-08:32:26.400698 7f5c81bff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
-2025/04/16-08:32:26.400776 7f5c81bff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
+2025/04/17-17:21:12.578876 7f5c82ffd6c0 Recovering log #212
+2025/04/17-17:21:12.589060 7f5c82ffd6c0 Delete type=3 #210
+2025/04/17-17:21:12.589120 7f5c82ffd6c0 Delete type=0 #212
+2025/04/17-17:34:42.486913 7f5c81bff6c0 Level-0 table #217: started
+2025/04/17-17:34:42.486964 7f5c81bff6c0 Level-0 table #217: 0 bytes OK
+2025/04/17-17:34:42.492952 7f5c81bff6c0 Delete type=0 #215
+2025/04/17-17:34:42.518936 7f5c81bff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
+2025/04/17-17:34:42.519016 7f5c81bff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-gifts/LOG.old b/packs-system/lf-gifts/LOG.old
index 457df4c..3eda976 100644
--- a/packs-system/lf-gifts/LOG.old
+++ b/packs-system/lf-gifts/LOG.old
@@ -1,8 +1,8 @@
-2025/04/15-20:28:27.924832 7f5c83fff6c0 Recovering log #200
-2025/04/15-20:28:27.935942 7f5c83fff6c0 Delete type=3 #198
-2025/04/15-20:28:27.936056 7f5c83fff6c0 Delete type=0 #200
-2025/04/15-20:29:29.646786 7f5c81bff6c0 Level-0 table #205: started
-2025/04/15-20:29:29.646851 7f5c81bff6c0 Level-0 table #205: 0 bytes OK
-2025/04/15-20:29:29.673575 7f5c81bff6c0 Delete type=0 #203
-2025/04/15-20:29:29.759542 7f5c81bff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
-2025/04/15-20:29:29.759654 7f5c81bff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
+2025/04/16-20:52:43.355491 7f5c82ffd6c0 Recovering log #208
+2025/04/16-20:52:43.412989 7f5c82ffd6c0 Delete type=3 #206
+2025/04/16-20:52:43.413142 7f5c82ffd6c0 Delete type=0 #208
+2025/04/16-22:34:18.450390 7f5c81bff6c0 Level-0 table #213: started
+2025/04/16-22:34:18.450439 7f5c81bff6c0 Level-0 table #213: 0 bytes OK
+2025/04/16-22:34:18.457055 7f5c81bff6c0 Delete type=0 #211
+2025/04/16-22:34:18.477378 7f5c81bff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
+2025/04/16-22:34:18.477422 7f5c81bff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-gifts/MANIFEST-000206 b/packs-system/lf-gifts/MANIFEST-000206
deleted file mode 100644
index 61daa16..0000000
Binary files a/packs-system/lf-gifts/MANIFEST-000206 and /dev/null differ
diff --git a/packs-system/lf-gifts/MANIFEST-000214 b/packs-system/lf-gifts/MANIFEST-000214
new file mode 100644
index 0000000..59553a3
Binary files /dev/null and b/packs-system/lf-gifts/MANIFEST-000214 differ
diff --git a/packs-system/lf-skills/000208.log b/packs-system/lf-skills/000216.log
similarity index 100%
rename from packs-system/lf-skills/000208.log
rename to packs-system/lf-skills/000216.log
diff --git a/packs-system/lf-skills/CURRENT b/packs-system/lf-skills/CURRENT
index b04a015..f0a2cf1 100644
--- a/packs-system/lf-skills/CURRENT
+++ b/packs-system/lf-skills/CURRENT
@@ -1 +1 @@
-MANIFEST-000206
+MANIFEST-000214
diff --git a/packs-system/lf-skills/LOG b/packs-system/lf-skills/LOG
index 585c1e4..58658fd 100644
--- a/packs-system/lf-skills/LOG
+++ b/packs-system/lf-skills/LOG
@@ -1,8 +1,8 @@
-2025/04/16-08:18:09.087776 7f5c837fe6c0 Recovering log #204
-2025/04/16-08:18:09.098866 7f5c837fe6c0 Delete type=3 #202
-2025/04/16-08:18:09.098959 7f5c837fe6c0 Delete type=0 #204
-2025/04/16-08:32:26.386837 7f5c81bff6c0 Level-0 table #209: started
-2025/04/16-08:32:26.386877 7f5c81bff6c0 Level-0 table #209: 0 bytes OK
-2025/04/16-08:32:26.394093 7f5c81bff6c0 Delete type=0 #207
-2025/04/16-08:32:26.400713 7f5c81bff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
-2025/04/16-08:32:26.400808 7f5c81bff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
+2025/04/17-17:21:12.549824 7f5c827fc6c0 Recovering log #212
+2025/04/17-17:21:12.560061 7f5c827fc6c0 Delete type=3 #210
+2025/04/17-17:21:12.560203 7f5c827fc6c0 Delete type=0 #212
+2025/04/17-17:34:42.505447 7f5c81bff6c0 Level-0 table #217: started
+2025/04/17-17:34:42.505471 7f5c81bff6c0 Level-0 table #217: 0 bytes OK
+2025/04/17-17:34:42.518767 7f5c81bff6c0 Delete type=0 #215
+2025/04/17-17:34:42.518998 7f5c81bff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
+2025/04/17-17:34:42.519066 7f5c81bff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-skills/LOG.old b/packs-system/lf-skills/LOG.old
index 6978d65..b033783 100644
--- a/packs-system/lf-skills/LOG.old
+++ b/packs-system/lf-skills/LOG.old
@@ -1,8 +1,8 @@
-2025/04/15-20:28:27.891776 7f5c82ffd6c0 Recovering log #200
-2025/04/15-20:28:27.903632 7f5c82ffd6c0 Delete type=3 #198
-2025/04/15-20:28:27.903749 7f5c82ffd6c0 Delete type=0 #200
-2025/04/15-20:29:29.673732 7f5c81bff6c0 Level-0 table #205: started
-2025/04/15-20:29:29.673787 7f5c81bff6c0 Level-0 table #205: 0 bytes OK
-2025/04/15-20:29:29.697981 7f5c81bff6c0 Delete type=0 #203
-2025/04/15-20:29:29.759583 7f5c81bff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
-2025/04/15-20:29:29.759670 7f5c81bff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
+2025/04/16-20:52:43.231833 7f5c83fff6c0 Recovering log #208
+2025/04/16-20:52:43.289908 7f5c83fff6c0 Delete type=3 #206
+2025/04/16-20:52:43.290001 7f5c83fff6c0 Delete type=0 #208
+2025/04/16-22:34:18.457209 7f5c81bff6c0 Level-0 table #213: started
+2025/04/16-22:34:18.457243 7f5c81bff6c0 Level-0 table #213: 0 bytes OK
+2025/04/16-22:34:18.463651 7f5c81bff6c0 Delete type=0 #211
+2025/04/16-22:34:18.477393 7f5c81bff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
+2025/04/16-22:34:18.477438 7f5c81bff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-skills/MANIFEST-000206 b/packs-system/lf-skills/MANIFEST-000206
deleted file mode 100644
index edaa1fb..0000000
Binary files a/packs-system/lf-skills/MANIFEST-000206 and /dev/null differ
diff --git a/packs-system/lf-skills/MANIFEST-000214 b/packs-system/lf-skills/MANIFEST-000214
new file mode 100644
index 0000000..6cf961a
Binary files /dev/null and b/packs-system/lf-skills/MANIFEST-000214 differ
diff --git a/packs-system/lf-vulnerabilities/000208.log b/packs-system/lf-vulnerabilities/000216.log
similarity index 100%
rename from packs-system/lf-vulnerabilities/000208.log
rename to packs-system/lf-vulnerabilities/000216.log
diff --git a/packs-system/lf-vulnerabilities/CURRENT b/packs-system/lf-vulnerabilities/CURRENT
index b04a015..f0a2cf1 100644
--- a/packs-system/lf-vulnerabilities/CURRENT
+++ b/packs-system/lf-vulnerabilities/CURRENT
@@ -1 +1 @@
-MANIFEST-000206
+MANIFEST-000214
diff --git a/packs-system/lf-vulnerabilities/LOG b/packs-system/lf-vulnerabilities/LOG
index 4aa1d49..6493586 100644
--- a/packs-system/lf-vulnerabilities/LOG
+++ b/packs-system/lf-vulnerabilities/LOG
@@ -1,8 +1,8 @@
-2025/04/16-08:18:09.132463 7f5c827fc6c0 Recovering log #204
-2025/04/16-08:18:09.143030 7f5c827fc6c0 Delete type=3 #202
-2025/04/16-08:18:09.143156 7f5c827fc6c0 Delete type=0 #204
-2025/04/16-08:32:26.374134 7f5c81bff6c0 Level-0 table #209: started
-2025/04/16-08:32:26.374198 7f5c81bff6c0 Level-0 table #209: 0 bytes OK
-2025/04/16-08:32:26.380413 7f5c81bff6c0 Delete type=0 #207
-2025/04/16-08:32:26.400678 7f5c81bff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
-2025/04/16-08:32:26.400747 7f5c81bff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
+2025/04/17-17:21:12.592168 7f5c83fff6c0 Recovering log #212
+2025/04/17-17:21:12.602692 7f5c83fff6c0 Delete type=3 #210
+2025/04/17-17:21:12.602743 7f5c83fff6c0 Delete type=0 #212
+2025/04/17-17:34:42.499156 7f5c81bff6c0 Level-0 table #217: started
+2025/04/17-17:34:42.499188 7f5c81bff6c0 Level-0 table #217: 0 bytes OK
+2025/04/17-17:34:42.505329 7f5c81bff6c0 Delete type=0 #215
+2025/04/17-17:34:42.518977 7f5c81bff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
+2025/04/17-17:34:42.519047 7f5c81bff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-vulnerabilities/LOG.old b/packs-system/lf-vulnerabilities/LOG.old
index 303ec44..7baf091 100644
--- a/packs-system/lf-vulnerabilities/LOG.old
+++ b/packs-system/lf-vulnerabilities/LOG.old
@@ -1,8 +1,8 @@
-2025/04/15-20:28:27.940175 7f5c837fe6c0 Recovering log #200
-2025/04/15-20:28:27.952060 7f5c837fe6c0 Delete type=3 #198
-2025/04/15-20:28:27.952156 7f5c837fe6c0 Delete type=0 #200
-2025/04/15-20:29:29.698145 7f5c81bff6c0 Level-0 table #205: started
-2025/04/15-20:29:29.698204 7f5c81bff6c0 Level-0 table #205: 0 bytes OK
-2025/04/15-20:29:29.733235 7f5c81bff6c0 Delete type=0 #203
-2025/04/15-20:29:29.759616 7f5c81bff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
-2025/04/15-20:29:29.759685 7f5c81bff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
+2025/04/16-20:52:43.416942 7f5c827fc6c0 Recovering log #208
+2025/04/16-20:52:43.474631 7f5c827fc6c0 Delete type=3 #206
+2025/04/16-20:52:43.474742 7f5c827fc6c0 Delete type=0 #208
+2025/04/16-22:34:18.470873 7f5c81bff6c0 Level-0 table #213: started
+2025/04/16-22:34:18.470925 7f5c81bff6c0 Level-0 table #213: 0 bytes OK
+2025/04/16-22:34:18.477241 7f5c81bff6c0 Delete type=0 #211
+2025/04/16-22:34:18.477414 7f5c81bff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
+2025/04/16-22:34:18.477446 7f5c81bff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
diff --git a/packs-system/lf-vulnerabilities/MANIFEST-000206 b/packs-system/lf-vulnerabilities/MANIFEST-000214
similarity index 71%
rename from packs-system/lf-vulnerabilities/MANIFEST-000206
rename to packs-system/lf-vulnerabilities/MANIFEST-000214
index 17f943b..f5d21f4 100644
Binary files a/packs-system/lf-vulnerabilities/MANIFEST-000206 and b/packs-system/lf-vulnerabilities/MANIFEST-000214 differ
diff --git a/templates/combat-action-dialog.hbs b/templates/combat-action-dialog.hbs
new file mode 100644
index 0000000..0efb03c
--- /dev/null
+++ b/templates/combat-action-dialog.hbs
@@ -0,0 +1,25 @@
+