Other fixes for damage buttons from chat

This commit is contained in:
2026-05-20 10:53:22 +02:00
parent 6cf0880ad3
commit 9ccb0f90f0
33 changed files with 362 additions and 148 deletions
+92 -21
View File
@@ -2161,34 +2161,66 @@ i.lethalfantasy {
color: #d4af37; color: #d4af37;
} }
.lethalfantasy .attack-result .attack-result-damage { .lethalfantasy .attack-result .attack-result-damage {
display: flex; display: grid;
flex-wrap: wrap; grid-template-columns: repeat(2, 1fr);
gap: 6px; gap: 8px;
justify-content: center; }
.lethalfantasy .attack-result .attack-result-damage.single-btn {
grid-template-columns: 1fr;
max-width: 280px;
margin: 0 auto;
}
.lethalfantasy .attack-result .attack-result-damage.spell-damage {
grid-template-columns: 1fr;
width: 100%;
} }
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn { .lethalfantasy .attack-result .attack-result-damage .roll-damage-btn {
padding: 8px 10px; padding: 10px 14px;
background: linear-gradient(to bottom, #8b0000 0%, #660000 100%); background: linear-gradient(to bottom, #8b0000 0%, #660000 100%);
border: 1px solid #ff0000; border: 1px solid #4b0000;
border-radius: 6px; border-radius: 6px;
color: #f0e6d2; color: #f0e6d2;
font-weight: 600; font-weight: 600;
font-size: calc(var(--font-size-standard) * 0.9); font-size: calc(var(--font-size-standard) * 0.9);
text-align: center;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
position: relative;
overflow: hidden;
}
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
transition: left 0.5s;
}
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn:hover::before {
left: 100%;
}
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn i {
font-size: calc(var(--font-size-standard) * 1.1);
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
flex-shrink: 0;
} }
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn:hover { .lethalfantasy .attack-result .attack-result-damage .roll-damage-btn:hover {
background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%); background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.15);
transform: translateY(-2px); transform: translateY(-2px);
border-color: #5b0000;
} }
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn:active { .lethalfantasy .attack-result .attack-result-damage .roll-damage-btn:active {
transform: translateY(0); transform: translateY(0);
} box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4), inset 0 1px 3px rgba(0, 0, 0, 0.3);
.lethalfantasy .attack-result .attack-result-damage .roll-damage-btn i {
margin-right: 6px;
} }
.lethalfantasy .equipment-content { .lethalfantasy .equipment-content {
font-family: var(--font-primary); font-family: var(--font-primary);
@@ -3963,35 +3995,74 @@ i.lethalfantasy {
} }
.message .attack-result .attack-result-damage, .message .attack-result .attack-result-damage,
.attack-result .attack-result-damage { .attack-result .attack-result-damage {
display: flex; display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px; gap: 8px;
justify-content: center; }
.message .attack-result .attack-result-damage.single-btn,
.attack-result .attack-result-damage.single-btn {
grid-template-columns: 1fr;
max-width: 280px;
margin: 0 auto;
}
.message .attack-result .attack-result-damage.spell-damage,
.attack-result .attack-result-damage.spell-damage {
grid-template-columns: 1fr;
width: 100%;
} }
.message .attack-result .attack-result-damage .roll-damage-btn, .message .attack-result .attack-result-damage .roll-damage-btn,
.attack-result .attack-result-damage .roll-damage-btn { .attack-result .attack-result-damage .roll-damage-btn {
padding: 10px 16px; padding: 10px 14px;
background: linear-gradient(to bottom, #8b0000 0%, #660000 100%); background: linear-gradient(to bottom, #8b0000 0%, #660000 100%);
border: 1px solid #ff0000; border: 1px solid #4b0000;
border-radius: 6px; border-radius: 6px;
color: #f0e6d2; color: #f0e6d2;
font-weight: 600; font-weight: 600;
font-size: calc(var(--font-size-standard) * 0.9);
text-align: center;
white-space: nowrap;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
position: relative;
overflow: hidden;
}
.message .attack-result .attack-result-damage .roll-damage-btn::before,
.attack-result .attack-result-damage .roll-damage-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
transition: left 0.5s;
}
.message .attack-result .attack-result-damage .roll-damage-btn:hover::before,
.attack-result .attack-result-damage .roll-damage-btn:hover::before {
left: 100%;
}
.message .attack-result .attack-result-damage .roll-damage-btn i,
.attack-result .attack-result-damage .roll-damage-btn i {
font-size: calc(var(--font-size-standard) * 1.1);
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
flex-shrink: 0;
} }
.message .attack-result .attack-result-damage .roll-damage-btn:hover, .message .attack-result .attack-result-damage .roll-damage-btn:hover,
.attack-result .attack-result-damage .roll-damage-btn:hover { .attack-result .attack-result-damage .roll-damage-btn:hover {
background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%); background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.15);
transform: translateY(-2px); transform: translateY(-2px);
border-color: #5b0000;
} }
.message .attack-result .attack-result-damage .roll-damage-btn:active, .message .attack-result .attack-result-damage .roll-damage-btn:active,
.attack-result .attack-result-damage .roll-damage-btn:active { .attack-result .attack-result-damage .roll-damage-btn:active {
transform: translateY(0); transform: translateY(0);
} box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4), inset 0 1px 3px rgba(0, 0, 0, 0.3);
.message .attack-result .attack-result-damage .roll-damage-btn i,
.attack-result .attack-result-damage .roll-damage-btn i {
margin-right: 6px;
} }
#token-hud .hp-loss-wrap { #token-hud .hp-loss-wrap {
position: absolute; position: absolute;
+3 -3
View File
@@ -369,7 +369,7 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
action: "applyDR", action: "applyDR",
label: game.i18n.localize("LETHALFANTASY.Combat.spellApplyDR"), label: game.i18n.localize("LETHALFANTASY.Combat.spellApplyDR"),
icon: "fa-solid fa-shield", icon: "fa-solid fa-shield",
callback: (event, button, dialog) => Number(dialog.querySelector("[name='manualDr']")?.value) || 0 callback: (event, button) => Number(button.form?.elements?.manualDr?.value) || 0
}, },
{ {
action: "cancel", action: "cancel",
@@ -393,7 +393,7 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
actorName: actor.name, actorName: actor.name,
actorImage: actor.img actorImage: actor.img
} }
const roll = new LethalFantasyRoll(damageFormula, {}, rollOpts) const roll = new documents.LethalFantasyRoll(damageFormula, {}, rollOpts)
await roll.evaluate() await roll.evaluate()
roll.options.rollTotal = roll.total roll.options.rollTotal = roll.total
if (game?.dice3d) await game.dice3d.showForRoll(roll, game.user, true) if (game?.dice3d) await game.dice3d.showForRoll(roll, game.user, true)
@@ -408,7 +408,7 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
} }
// Pour les monstres, utiliser prepareMonsterRoll // Pour les monstres, utiliser prepareMonsterRoll
if (isMonster || actor.type === "monster") { if (isMonster === "true" || actor.type === "monster") {
await actor.system.prepareMonsterRoll("monster-damage", weaponId, undefined, undefined, damageModifier) await actor.system.prepareMonsterRoll("monster-damage", weaponId, undefined, undefined, damageModifier)
return return
} }
+76 -2
View File
@@ -22,6 +22,7 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
divinityPointsMinus: LethalFantasyCharacterSheet.#onDivinityPointsMinus, divinityPointsMinus: LethalFantasyCharacterSheet.#onDivinityPointsMinus,
aetherPointsPlus: LethalFantasyCharacterSheet.#onAetherPointsPlus, aetherPointsPlus: LethalFantasyCharacterSheet.#onAetherPointsPlus,
aetherPointsMinus: LethalFantasyCharacterSheet.#onAetherPointsMinus, aetherPointsMinus: LethalFantasyCharacterSheet.#onAetherPointsMinus,
rollSpellDamage: LethalFantasyCharacterSheet.#onRollSpellDamage,
}, },
} }
@@ -70,10 +71,10 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "LETHALFANTASY.Label.biography" }, biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "LETHALFANTASY.Label.biography" },
} }
if (this.actor.system.biodata.magicUser) { if (this.actor.system.biodata.magicUser) {
tabs.spells = { id: "spells", group: "sheet", icon: "fa-sharp-duotone fa-solid fa-wand-magic-sparkles", label: "LETHALFANTASY.Label.spells" } tabs.spells = { id: "spells", group: "sheet", icon: "fa-solid fa-wand-magic-sparkles", label: "LETHALFANTASY.Label.spells" }
} }
if (this.actor.system.biodata.clericUser) { if (this.actor.system.biodata.clericUser) {
tabs.miracles = { id: "miracles", group: "sheet", icon: "fa-sharp-duotone fa-solid fa-hands-praying", label: "LETHALFANTASY.Label.miracles" } tabs.miracles = { id: "miracles", group: "sheet", icon: "fa-solid fa-hands-praying", label: "LETHALFANTASY.Label.miracles" }
} }
for (const v of Object.values(tabs)) { for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id v.active = this.tabGroups[v.group] === v.id
@@ -219,6 +220,79 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
this.actor.update({ "system.aetherPoints.value": points }) this.actor.update({ "system.aetherPoints.value": points })
} }
/**
* Handles spell damage roll from the spell sheet tab.
* Shows a DR dialog then rolls the appropriate damage formula.
* @param {PointerEvent} event
* @param {HTMLElement} target
*/
static async #onRollSpellDamage(event, target) {
if (this.isEditMode) return
const itemId = target.dataset.itemId
const tier = target.dataset.damageTier
const spell = this.actor.items.get(itemId)
if (!spell) return
const formulaMap = {
standard: spell.system.damageDice,
overpowered: spell.system.damageDiceOverpowered,
overpowered2: spell.system.damageDiceOverpowered2,
}
const formula = formulaMap[tier]
if (!formula) return
const manualDR = await foundry.applications.api.DialogV2.wait({
window: { title: game.i18n.localize("LETHALFANTASY.Combat.spellDRDialogTitle") },
classes: ["lethalfantasy"],
position: { width: 320 },
content: `<div style="padding:0.5rem 0">
<p style="margin-bottom:0.6rem">${game.i18n.localize("LETHALFANTASY.Combat.spellDRDialogMsg")}</p>
<div style="display:flex;align-items:center;gap:0.5rem">
<label style="font-weight:bold">${game.i18n.localize("LETHALFANTASY.Combat.spellDRLabel")}</label>
<input type="number" name="manualDr" value="0" min="0" style="width:5rem"/>
</div>
</div>`,
buttons: [
{
action: "noDR",
label: game.i18n.localize("LETHALFANTASY.Combat.spellNoDR"),
icon: "fa-solid fa-wand-magic-sparkles",
callback: () => 0
},
{
action: "applyDR",
label: game.i18n.localize("LETHALFANTASY.Combat.spellApplyDR"),
icon: "fa-solid fa-shield",
callback: (event, button) => Number(button.form?.elements?.manualDr?.value) || 0
},
{
action: "cancel",
label: game.i18n.localize("LETHALFANTASY.Combat.proceedNo"),
callback: () => null
}
],
rejectClose: false
})
if (manualDR === null) return
const rollOpts = {
type: "spell-damage",
rollType: "spell-damage",
rollName: `${spell.name}${formula}`,
isDamage: true,
rollData: { isDamage: true },
manualDR,
actorId: this.actor.id,
actorName: this.actor.name,
actorImage: this.actor.img
}
const roll = new LethalFantasyRoll(formula, {}, rollOpts)
await roll.evaluate()
roll.options.rollTotal = roll.total
if (game?.dice3d) await game.dice3d.showForRoll(roll, game.user, true)
await roll.toMessage()
}
static #onCreateEquipment(event, target) { static #onCreateEquipment(event, target) {
} }
+13 -13
View File
@@ -392,7 +392,7 @@ export default class LethalFantasyRoll extends Roll {
label: label, label: label,
callback: (event, button, dialog) => { callback: (event, button, dialog) => {
console.log("Roll context", event, button, dialog) console.log("Roll context", event, button, dialog)
let position = dialog.position let position = dialog?.position
game.user.setFlag(SYSTEM.id, "roll-dialog-pos", foundry.utils.duplicate(position)) game.user.setFlag(SYSTEM.id, "roll-dialog-pos", foundry.utils.duplicate(position))
const output = Array.from(button.form.elements).reduce((obj, input) => { const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value if (input.name) obj[input.name] = input.value
@@ -403,22 +403,22 @@ export default class LethalFantasyRoll extends Roll {
}, },
], ],
actions: { actions: {
"selectGranted": (event, button, dialog) => { "selectGranted": (event, button) => {
hasGrantedDice = event.target.checked hasGrantedDice = event.target.checked
}, },
"selectBeyondSkill": (event, button, dialog) => { "selectBeyondSkill": (event, button) => {
beyondSkill = button.checked beyondSkill = button.checked
}, },
"selectPointBlank": (event, button, dialog) => { "selectPointBlank": (event, button) => {
pointBlank = button.checked pointBlank = button.checked
}, },
"selectLetItFly": (event, button, dialog) => { "selectLetItFly": (event, button) => {
letItFly = button.checked letItFly = button.checked
}, },
"saveSpellCheck": (event, button, dialog) => { "saveSpellCheck": (event, button) => {
saveSpell = button.checked saveSpell = button.checked
}, },
"gotoToken": (event, button, dialog) => { "gotoToken": (event, button) => {
let tokenId = $(button).data("tokenId") let tokenId = $(button).data("tokenId")
let token = canvas.tokens?.get(tokenId) let token = canvas.tokens?.get(tokenId)
if (token) { if (token) {
@@ -710,7 +710,7 @@ export default class LethalFantasyRoll extends Roll {
buttons: [ buttons: [
{ {
label: label, label: label,
callback: (event, button, dialog) => { callback: (event, button) => {
const output = Array.from(button.form.elements).reduce((obj, input) => { const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value if (input.name) obj[input.name] = input.value
return obj return obj
@@ -778,7 +778,7 @@ export default class LethalFantasyRoll extends Roll {
buttons.push({ buttons.push({
action: "roll", action: "roll",
label: "Roll progression dice", label: "Roll progression dice",
callback: (event, button, dialog) => { callback: (event, button) => {
let pos = $('#combat-action-dialog').position() let pos = $('#combat-action-dialog').position()
game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", pos) game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", pos)
return "rollProgressionDice" return "rollProgressionDice"
@@ -804,7 +804,7 @@ export default class LethalFantasyRoll extends Roll {
buttons.push({ buttons.push({
action: "roll", action: "roll",
label: label, label: label,
callback: (event, button, dialog) => { callback: (event, button) => {
let pos = $('#combat-action-dialog').position() let pos = $('#combat-action-dialog').position()
game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", foundry.utils.duplicate(pos)) game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", foundry.utils.duplicate(pos))
return "rollLethargyDice" return "rollLethargyDice"
@@ -815,7 +815,7 @@ export default class LethalFantasyRoll extends Roll {
buttons.push({ buttons.push({
action: "roll", action: "roll",
label: "Select action", label: "Select action",
callback: (event, button, dialog) => { callback: (event, button) => {
let pos = $('#combat-action-dialog').position() let pos = $('#combat-action-dialog').position()
game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", foundry.utils.duplicate(pos)) game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", foundry.utils.duplicate(pos))
const output = Array.from(button.form.elements).reduce((obj, input) => { const output = Array.from(button.form.elements).reduce((obj, input) => {
@@ -830,7 +830,7 @@ export default class LethalFantasyRoll extends Roll {
buttons.push({ buttons.push({
action: "cancel", action: "cancel",
label: "Other action, not listed here", label: "Other action, not listed here",
callback: (event, button, dialog) => { callback: (event, button) => {
let pos = $('#combat-action-dialog').position() let pos = $('#combat-action-dialog').position()
game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", foundry.utils.duplicate(pos)) game.user.setFlag(SYSTEM.id, "combat-action-dialog-pos", foundry.utils.duplicate(pos))
return null; return null;
@@ -1077,7 +1077,7 @@ export default class LethalFantasyRoll extends Roll {
buttons: [ buttons: [
{ {
label: label, label: label,
callback: (event, button, dialog) => { callback: (event, button) => {
const output = Array.from(button.form.elements).reduce((obj, input) => { const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value if (input.name) obj[input.name] = input.value
return obj return obj
+2 -2
View File
@@ -854,7 +854,7 @@ export default class LethalFantasyUtils {
` `
} else if (data.attackRollType === "monster-attack") { } else if (data.attackRollType === "monster-attack") {
damageButton = ` damageButton = `
<div class="attack-result-damage"> <div class="attack-result-damage single-btn">
<button class="roll-damage-btn" data-attacker-id="${data.attackerId}" data-defender-id="${data.defenderId}" data-defender-token-id="${data.defenderTokenId || ""}" data-extra-shield-dr="${data.shieldDamageReduction || 0}" data-attack-key="${data.attackRollKey}" data-damage-type="monster"> <button class="roll-damage-btn" data-attacker-id="${data.attackerId}" data-defender-id="${data.defenderId}" data-defender-token-id="${data.defenderTokenId || ""}" data-extra-shield-dr="${data.shieldDamageReduction || 0}" data-attack-key="${data.attackRollKey}" data-damage-type="monster">
<i class="fa-solid fa-burst"></i> Damage <i class="fa-solid fa-burst"></i> Damage
</button> </button>
@@ -881,7 +881,7 @@ export default class LethalFantasyUtils {
<i class="fa-solid fa-wand-magic-sparkles"></i> ${t.label} (${escapedFormula}) <i class="fa-solid fa-wand-magic-sparkles"></i> ${t.label} (${escapedFormula})
</button>` </button>`
}).join("") }).join("")
damageButton = `<div class="attack-result-damage">${buttons}</div>` damageButton = `<div class="attack-result-damage spell-damage">${buttons}</div>`
} }
} }
} }
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000603 MANIFEST-000607
+3 -8
View File
@@ -1,8 +1,3 @@
2026/05/19-10:50:35.862031 7f5a477fe6c0 Recovering log #601 2026/05/20-00:10:37.079181 7f0b1e7ee6c0 Recovering log #605
2026/05/19-10:50:35.923479 7f5a477fe6c0 Delete type=3 #599 2026/05/20-00:10:37.089613 7f0b1e7ee6c0 Delete type=3 #603
2026/05/19-10:50:35.923537 7f5a477fe6c0 Delete type=0 #601 2026/05/20-00:10:37.089671 7f0b1e7ee6c0 Delete type=0 #605
2026/05/19-10:51:28.990207 7f5a467fc6c0 Level-0 table #606: started
2026/05/19-10:51:28.990237 7f5a467fc6c0 Level-0 table #606: 0 bytes OK
2026/05/19-10:51:28.997402 7f5a467fc6c0 Delete type=0 #604
2026/05/19-10:51:28.997604 7f5a467fc6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
2026/05/19-10:51:28.997650 7f5a467fc6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
+8 -8
View File
@@ -1,8 +1,8 @@
2026/05/18-17:40:11.769288 7f5a477fe6c0 Recovering log #597 2026/05/19-10:50:35.862031 7f5a477fe6c0 Recovering log #601
2026/05/18-17:40:11.780605 7f5a477fe6c0 Delete type=3 #595 2026/05/19-10:50:35.923479 7f5a477fe6c0 Delete type=3 #599
2026/05/18-17:40:11.780699 7f5a477fe6c0 Delete type=0 #597 2026/05/19-10:50:35.923537 7f5a477fe6c0 Delete type=0 #601
2026/05/18-20:25:54.228818 7f5a467fc6c0 Level-0 table #602: started 2026/05/19-10:51:28.990207 7f5a467fc6c0 Level-0 table #606: started
2026/05/18-20:25:54.230037 7f5a467fc6c0 Level-0 table #602: 0 bytes OK 2026/05/19-10:51:28.990237 7f5a467fc6c0 Level-0 table #606: 0 bytes OK
2026/05/18-20:25:54.236369 7f5a467fc6c0 Delete type=0 #600 2026/05/19-10:51:28.997402 7f5a467fc6c0 Delete type=0 #604
2026/05/18-20:25:54.251050 7f5a467fc6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997604 7f5a467fc6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
2026/05/18-20:25:54.251106 7f5a467fc6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997650 7f5a467fc6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000600 MANIFEST-000604
+3 -8
View File
@@ -1,8 +1,3 @@
2026/05/19-10:50:35.962917 7f5a46ffd6c0 Recovering log #598 2026/05/20-00:10:37.107483 7f0b1efef6c0 Recovering log #602
2026/05/19-10:50:36.018914 7f5a46ffd6c0 Delete type=3 #596 2026/05/20-00:10:37.117907 7f0b1efef6c0 Delete type=3 #600
2026/05/19-10:50:36.018977 7f5a46ffd6c0 Delete type=0 #598 2026/05/20-00:10:37.117968 7f0b1efef6c0 Delete type=0 #602
2026/05/19-10:51:28.983427 7f5a467fc6c0 Level-0 table #603: started
2026/05/19-10:51:28.983464 7f5a467fc6c0 Level-0 table #603: 0 bytes OK
2026/05/19-10:51:28.990020 7f5a467fc6c0 Delete type=0 #601
2026/05/19-10:51:28.997591 7f5a467fc6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
2026/05/19-10:51:28.997639 7f5a467fc6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
+8 -8
View File
@@ -1,8 +1,8 @@
2026/05/18-17:40:11.793894 7f5a94bff6c0 Recovering log #594 2026/05/19-10:50:35.962917 7f5a46ffd6c0 Recovering log #598
2026/05/18-17:40:11.804447 7f5a94bff6c0 Delete type=3 #592 2026/05/19-10:50:36.018914 7f5a46ffd6c0 Delete type=3 #596
2026/05/18-17:40:11.804549 7f5a94bff6c0 Delete type=0 #594 2026/05/19-10:50:36.018977 7f5a46ffd6c0 Delete type=0 #598
2026/05/18-20:25:54.236611 7f5a467fc6c0 Level-0 table #599: started 2026/05/19-10:51:28.983427 7f5a467fc6c0 Level-0 table #603: started
2026/05/18-20:25:54.236652 7f5a467fc6c0 Level-0 table #599: 0 bytes OK 2026/05/19-10:51:28.983464 7f5a467fc6c0 Level-0 table #603: 0 bytes OK
2026/05/18-20:25:54.243997 7f5a467fc6c0 Delete type=0 #597 2026/05/19-10:51:28.990020 7f5a467fc6c0 Delete type=0 #601
2026/05/18-20:25:54.251069 7f5a467fc6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997591 7f5a467fc6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
2026/05/18-20:25:54.264439 7f5a467fc6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997639 7f5a467fc6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000605 MANIFEST-000609
+3 -8
View File
@@ -1,8 +1,3 @@
2026/05/19-10:50:35.772455 7f5a46ffd6c0 Recovering log #603 2026/05/20-00:10:37.061485 7f0b1efef6c0 Recovering log #607
2026/05/19-10:50:35.837426 7f5a46ffd6c0 Delete type=3 #601 2026/05/20-00:10:37.071572 7f0b1efef6c0 Delete type=3 #605
2026/05/19-10:50:35.837512 7f5a46ffd6c0 Delete type=0 #603 2026/05/20-00:10:37.071684 7f0b1efef6c0 Delete type=0 #607
2026/05/19-10:51:28.969686 7f5a467fc6c0 Level-0 table #608: started
2026/05/19-10:51:28.969769 7f5a467fc6c0 Level-0 table #608: 0 bytes OK
2026/05/19-10:51:28.976467 7f5a467fc6c0 Delete type=0 #606
2026/05/19-10:51:28.997558 7f5a467fc6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
2026/05/19-10:51:28.997616 7f5a467fc6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
+8 -8
View File
@@ -1,8 +1,8 @@
2026/05/18-17:40:11.749971 7f5a46ffd6c0 Recovering log #599 2026/05/19-10:50:35.772455 7f5a46ffd6c0 Recovering log #603
2026/05/18-17:40:11.761423 7f5a46ffd6c0 Delete type=3 #597 2026/05/19-10:50:35.837426 7f5a46ffd6c0 Delete type=3 #601
2026/05/18-17:40:11.761520 7f5a46ffd6c0 Delete type=0 #599 2026/05/19-10:50:35.837512 7f5a46ffd6c0 Delete type=0 #603
2026/05/18-20:25:54.219239 7f5a467fc6c0 Level-0 table #604: started 2026/05/19-10:51:28.969686 7f5a467fc6c0 Level-0 table #608: started
2026/05/18-20:25:54.219522 7f5a467fc6c0 Level-0 table #604: 0 bytes OK 2026/05/19-10:51:28.969769 7f5a467fc6c0 Level-0 table #608: 0 bytes OK
2026/05/18-20:25:54.228610 7f5a467fc6c0 Delete type=0 #602 2026/05/19-10:51:28.976467 7f5a467fc6c0 Delete type=0 #606
2026/05/18-20:25:54.251028 7f5a467fc6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997558 7f5a467fc6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
2026/05/18-20:25:54.251085 7f5a467fc6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997616 7f5a467fc6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000300 MANIFEST-000304
+3 -8
View File
@@ -1,8 +1,3 @@
2026/05/19-10:50:36.147771 7f5a46ffd6c0 Recovering log #298 2026/05/20-00:10:37.136939 7f0b1efef6c0 Recovering log #302
2026/05/19-10:50:36.209801 7f5a46ffd6c0 Delete type=3 #296 2026/05/20-00:10:37.146957 7f0b1efef6c0 Delete type=3 #300
2026/05/19-10:50:36.209908 7f5a46ffd6c0 Delete type=0 #298 2026/05/20-00:10:37.147030 7f0b1efef6c0 Delete type=0 #302
2026/05/19-10:51:29.021338 7f5a467fc6c0 Level-0 table #303: started
2026/05/19-10:51:29.021378 7f5a467fc6c0 Level-0 table #303: 0 bytes OK
2026/05/19-10:51:29.027529 7f5a467fc6c0 Delete type=0 #301
2026/05/19-10:51:29.027761 7f5a467fc6c0 Manual compaction at level-0 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
2026/05/19-10:51:29.027787 7f5a467fc6c0 Manual compaction at level-1 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
+8 -8
View File
@@ -1,8 +1,8 @@
2026/05/18-17:40:11.831491 7f5a94bff6c0 Recovering log #294 2026/05/19-10:50:36.147771 7f5a46ffd6c0 Recovering log #298
2026/05/18-17:40:11.842913 7f5a94bff6c0 Delete type=3 #292 2026/05/19-10:50:36.209801 7f5a46ffd6c0 Delete type=3 #296
2026/05/18-17:40:11.843005 7f5a94bff6c0 Delete type=0 #294 2026/05/19-10:50:36.209908 7f5a46ffd6c0 Delete type=0 #298
2026/05/18-20:25:54.257813 7f5a467fc6c0 Level-0 table #299: started 2026/05/19-10:51:29.021338 7f5a467fc6c0 Level-0 table #303: started
2026/05/18-20:25:54.257869 7f5a467fc6c0 Level-0 table #299: 0 bytes OK 2026/05/19-10:51:29.021378 7f5a467fc6c0 Level-0 table #303: 0 bytes OK
2026/05/18-20:25:54.264186 7f5a467fc6c0 Delete type=0 #297 2026/05/19-10:51:29.027529 7f5a467fc6c0 Delete type=0 #301
2026/05/18-20:25:54.267118 7f5a467fc6c0 Manual compaction at level-0 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end) 2026/05/19-10:51:29.027761 7f5a467fc6c0 Manual compaction at level-0 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
2026/05/18-20:25:54.296812 7f5a467fc6c0 Manual compaction at level-1 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end) 2026/05/19-10:51:29.027787 7f5a467fc6c0 Manual compaction at level-1 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000599 MANIFEST-000603
+3 -8
View File
@@ -1,8 +1,3 @@
2026/05/19-10:50:36.056028 7f5a47fff6c0 Recovering log #597 2026/05/20-00:10:37.121340 7f0b1e7ee6c0 Recovering log #601
2026/05/19-10:50:36.115465 7f5a47fff6c0 Delete type=3 #595 2026/05/20-00:10:37.132435 7f0b1e7ee6c0 Delete type=3 #599
2026/05/19-10:50:36.115585 7f5a47fff6c0 Delete type=0 #597 2026/05/20-00:10:37.132491 7f0b1e7ee6c0 Delete type=0 #601
2026/05/19-10:51:28.976707 7f5a467fc6c0 Level-0 table #602: started
2026/05/19-10:51:28.976754 7f5a467fc6c0 Level-0 table #602: 0 bytes OK
2026/05/19-10:51:28.983222 7f5a467fc6c0 Delete type=0 #600
2026/05/19-10:51:28.997577 7f5a467fc6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
2026/05/19-10:51:28.997627 7f5a467fc6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
+8 -8
View File
@@ -1,8 +1,8 @@
2026/05/18-17:40:11.812004 7f5a47fff6c0 Recovering log #593 2026/05/19-10:50:36.056028 7f5a47fff6c0 Recovering log #597
2026/05/18-17:40:11.823277 7f5a47fff6c0 Delete type=3 #591 2026/05/19-10:50:36.115465 7f5a47fff6c0 Delete type=3 #595
2026/05/18-17:40:11.823388 7f5a47fff6c0 Delete type=0 #593 2026/05/19-10:50:36.115585 7f5a47fff6c0 Delete type=0 #597
2026/05/18-20:25:54.244177 7f5a467fc6c0 Level-0 table #598: started 2026/05/19-10:51:28.976707 7f5a467fc6c0 Level-0 table #602: started
2026/05/18-20:25:54.244222 7f5a467fc6c0 Level-0 table #598: 0 bytes OK 2026/05/19-10:51:28.976754 7f5a467fc6c0 Level-0 table #602: 0 bytes OK
2026/05/18-20:25:54.250810 7f5a467fc6c0 Delete type=0 #596 2026/05/19-10:51:28.983222 7f5a467fc6c0 Delete type=0 #600
2026/05/18-20:25:54.251096 7f5a467fc6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997577 7f5a467fc6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
2026/05/18-20:25:54.264461 7f5a467fc6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end) 2026/05/19-10:51:28.997627 7f5a467fc6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
+48 -12
View File
@@ -301,36 +301,72 @@
} }
.attack-result-damage { .attack-result-damage {
display: flex; display: grid;
flex-wrap: wrap; grid-template-columns: repeat(2, 1fr);
gap: 6px; gap: 8px;
justify-content: center;
&.single-btn {
grid-template-columns: 1fr;
max-width: 280px;
margin: 0 auto;
}
&.spell-damage {
grid-template-columns: 1fr;
width: 100%;
}
.roll-damage-btn { .roll-damage-btn {
padding: 8px 10px; padding: 10px 14px;
background: linear-gradient(to bottom, #8b0000 0%, #660000 100%); background: linear-gradient(to bottom, #8b0000 0%, #660000 100%);
border: 1px solid #ff0000; border: 1px solid #4b0000;
border-radius: 6px; border-radius: 6px;
color: #f0e6d2; color: #f0e6d2;
font-weight: 600; font-weight: 600;
font-size: calc(var(--font-size-standard) * 0.9); font-size: calc(var(--font-size-standard) * 0.9);
text-align: center;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
transition: left 0.5s;
}
&:hover::before {
left: 100%;
}
i {
font-size: calc(var(--font-size-standard) * 1.1);
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
flex-shrink: 0;
}
&:hover { &:hover {
background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%); background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.15);
transform: translateY(-2px); transform: translateY(-2px);
border-color: #5b0000;
} }
&:active { &:active {
transform: translateY(0); transform: translateY(0);
} box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4), inset 0 1px 3px rgba(0, 0, 0, 0.3);
i {
margin-right: 6px;
} }
} }
} }
+49 -10
View File
@@ -1285,33 +1285,72 @@
} }
.attack-result-damage { .attack-result-damage {
display: flex; display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px; gap: 8px;
justify-content: center;
&.single-btn {
grid-template-columns: 1fr;
max-width: 280px;
margin: 0 auto;
}
&.spell-damage {
grid-template-columns: 1fr;
width: 100%;
}
.roll-damage-btn { .roll-damage-btn {
padding: 10px 16px; padding: 10px 14px;
background: linear-gradient(to bottom, #8b0000 0%, #660000 100%); background: linear-gradient(to bottom, #8b0000 0%, #660000 100%);
border: 1px solid #ff0000; border: 1px solid #4b0000;
border-radius: 6px; border-radius: 6px;
color: #f0e6d2; color: #f0e6d2;
font-weight: 600; font-weight: 600;
font-size: calc(var(--font-size-standard) * 0.9);
text-align: center;
white-space: nowrap;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
transition: left 0.5s;
}
&:hover::before {
left: 100%;
}
i {
font-size: calc(var(--font-size-standard) * 1.1);
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
flex-shrink: 0;
}
&:hover { &:hover {
background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%); background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.15);
transform: translateY(-2px); transform: translateY(-2px);
border-color: #5b0000;
} }
&:active { &:active {
transform: translateY(0); transform: translateY(0);
} box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4), inset 0 1px 3px rgba(0, 0, 0, 0.3);
i {
margin-right: 6px;
} }
} }
} }
+19
View File
@@ -37,6 +37,25 @@
<i class="fa-duotone fa-solid fa-stars" data-roll-type="spell-power" data-roll-key="{{item.id}}"></i> <i class="fa-duotone fa-solid fa-stars" data-roll-type="spell-power" data-roll-key="{{item.id}}"></i>
</a> </a>
{{#if item.system.damageDice}}
<a data-action="rollSpellDamage" data-item-id="{{item.id}}" data-damage-tier="standard"
data-tooltip="Spell Damage (Standard)">
<i class="fa-solid fa-wand-magic-sparkles"></i>S
</a>
{{/if}}
{{#if item.system.damageDiceOverpowered}}
<a data-action="rollSpellDamage" data-item-id="{{item.id}}" data-damage-tier="overpowered"
data-tooltip="Spell Damage (Overpowered)">
<i class="fa-solid fa-wand-magic-sparkles"></i>O
</a>
{{/if}}
{{#if item.system.damageDiceOverpowered2}}
<a data-action="rollSpellDamage" data-item-id="{{item.id}}" data-damage-tier="overpowered2"
data-tooltip="Spell Damage (Overpowered 2)">
<i class="fa-solid fa-wand-magic-sparkles"></i>O2
</a>
{{/if}}
<div class="controls"> <div class="controls">
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}" <a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>