Add initiative rolls

This commit is contained in:
2026-03-18 16:51:10 +01:00
parent 000bf348a6
commit b2befe039e
30 changed files with 512 additions and 144 deletions

View File

@@ -97,6 +97,7 @@ export default class OathHammerWeaponDialog {
traits: traitLabels,
attackBonusOptions,
rangeOptions,
colorOptions: _colorOptions(skillColor),
rollModes,
visibility: game.settings.get("core", "rollMode"),
}
@@ -113,9 +114,14 @@ export default class OathHammerWeaponDialog {
rejectClose: false,
buttons: [{
label: game.i18n.localize("OATHHAMMER.Dialog.RollAttack"),
callback: (_ev, btn) => Object.fromEntries(
[...btn.form.elements].filter(e => e.name).map(e => [e.name, e.value])
),
callback: (_ev, btn) => {
const out = {}
for (const el of btn.form.elements) {
if (!el.name) continue
out[el.name] = el.type === "checkbox" ? String(el.checked) : el.value
}
return out
},
}],
})
@@ -124,8 +130,10 @@ export default class OathHammerWeaponDialog {
attackBonus: parseInt(result.attackBonus) || 0,
rangeCondition: parseInt(result.rangeCondition) || 0,
attrOverride: result.attrOverride || defaultAttr,
colorOverride: result.colorOverride || skillColor,
visibility: result.visibility ?? game.settings.get("core", "rollMode"),
autoAttackBonus,
explodeOn5: result.explodeOn5 === "true",
}
}
@@ -188,6 +196,12 @@ export default class OathHammerWeaponDialog {
{ value: -4, label: game.i18n.localize("OATHHAMMER.Dialog.DiminishThird"), selected: false },
]
// Default dice color: red if parry/block trait matches the default attack type, else white
const defaultDefenseColor = (
(defaultAttackType === "melee" && hasParry) ||
(defaultAttackType === "ranged" && hasBlock)
) ? "red" : "white"
const bonusOptions = Array.from({ length: 13 }, (_, i) => {
const v = i - 6
return { value: v, label: v > 0 ? `+${v}` : String(v), selected: v === 0 }
@@ -212,6 +226,7 @@ export default class OathHammerWeaponDialog {
attrOptions,
diminishOptions,
bonusOptions,
colorOptions: _colorOptions(defaultDefenseColor),
rollModes,
visibility: game.settings.get("core", "rollMode"),
}
@@ -228,9 +243,14 @@ export default class OathHammerWeaponDialog {
rejectClose: false,
buttons: [{
label: game.i18n.localize("OATHHAMMER.Dialog.RollDefense"),
callback: (_ev, btn) => Object.fromEntries(
[...btn.form.elements].filter(e => e.name).map(e => [e.name, e.value])
),
callback: (_ev, btn) => {
const out = {}
for (const el of btn.form.elements) {
if (!el.name) continue
out[el.name] = el.type === "checkbox" ? String(el.checked) : el.value
}
return out
},
}],
})
@@ -241,28 +261,24 @@ export default class OathHammerWeaponDialog {
const attrRank = attrChoice === "might" ? mightRank : agiRank
const diminishPenalty = parseInt(result.diminish) || 0
const bonus = parseInt(result.bonus) || 0
const colorOverride = result.colorOverride || defaultDefenseColor
// Resolve red dice and trait bonus based on selected attack type
let redDice = false
// Trait bonus based on selected attack type (color is now user-controlled)
let traitBonus = 0
if (attackType === "melee" && hasParry) {
redDice = true
traitBonus = parryCount >= 2 ? 1 : 0
} else if (attackType === "ranged" && hasBlock) {
redDice = true
traitBonus = 1
}
if (attackType === "melee" && hasParry) traitBonus = parryCount >= 2 ? 1 : 0
if (attackType === "ranged" && hasBlock) traitBonus = 1
return {
attackType,
attrRank,
attrChoice,
redDice,
colorOverride,
traitBonus,
armorPenalty,
diminishPenalty,
bonus,
visibility: result.visibility ?? game.settings.get("core", "rollMode"),
visibility: result.visibility ?? game.settings.get("core", "rollMode"),
explodeOn5: result.explodeOn5 === "true",
}
}
@@ -350,3 +366,11 @@ export default class OathHammerWeaponDialog {
function _cap(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
function _colorOptions(defaultColor = "white") {
return [
{ value: "white", label: "⬜ White (4+)", selected: defaultColor === "white" },
{ value: "red", label: "🔴 Red (3+)", selected: defaultColor === "red" },
{ value: "black", label: "⬛ Black (2+)", selected: defaultColor === "black" },
]
}