feat: luck bonus, inventory slots bonus, multi-enhancements, magic skill modifier
Release Creation / build (release) Successful in 1m25s
Release Creation / build (release) Successful in 1m25s
- Add luck.bonus field to character DataModel; included in prepareDerivedData (luck.max = fate.rank + bonus); shown as editable +bonus field next to luck max in edit mode (same UX as grit bonus) - Add inventory.slotsBonus field to character DataModel; Equipment tab now shows an editable "Bonus Slots" input that adds to the calculated max slots (10 + Might×2 + bonus) - Replace single Enhancement <select> in spell cast dialog with a checkbox list; multiple enhancements can now be selected simultaneously — stress costs, pool penalties, and boolean flags (redDice, noStress) are aggregated across all active enhancements - Include skills.magic.modifier in basePool for both spell and miracle dialogs and in baseDice in rollSpellCast / rollMiracleCast; modifier is shown in the dialog pool-info line and in the chat card when non-zero - Fix: pool-reduction indicator in rollSpellCast now compares against intRank + magicRank + magicMod (was missing magicMod)
This commit is contained in:
+11
-7
@@ -463,7 +463,7 @@ export async function rollWeaponDamage(actor, weapon, options = {}) {
|
||||
export async function rollSpellCast(actor, spell, options = {}) {
|
||||
const {
|
||||
dv = spell.system.difficultyValue,
|
||||
enhancement = "none",
|
||||
enhancements = ["none"],
|
||||
stressCost = 0,
|
||||
poolPenalty = 0,
|
||||
redDice = false,
|
||||
@@ -484,8 +484,9 @@ export async function rollSpellCast(actor, spell, options = {}) {
|
||||
|
||||
const intRank = actorSys.attributes.intelligence.rank
|
||||
const magicRank = actorSys.skills.magic.rank
|
||||
const magicMod = actorSys.skills.magic.modifier ?? 0
|
||||
const luckDicePerPoint = luckIsHuman ? 3 : 2
|
||||
const baseDice = intRank + magicRank + bonus + poolPenalty + elementalBonus + grimPenalty + (luckSpend * luckDicePerPoint)
|
||||
const baseDice = intRank + magicRank + magicMod + bonus + poolPenalty + elementalBonus + grimPenalty + (luckSpend * luckDicePerPoint)
|
||||
// poolSize: voluntary reduction (p.101) — clamped to [1, baseDice]
|
||||
const totalDice = poolSize !== null
|
||||
? Math.max(1, Math.min(poolSize + bonus + poolPenalty + elementalBonus + grimPenalty + (luckSpend * luckDicePerPoint), baseDice))
|
||||
@@ -523,9 +524,11 @@ export async function rollSpellCast(actor, spell, options = {}) {
|
||||
: game.i18n.localize("OATHHAMMER.Roll.Failure")
|
||||
|
||||
const modParts = []
|
||||
if (poolSize !== null && poolSize < intRank + magicRank) modParts.push(`🎲 ${poolSize}d ${game.i18n.localize("OATHHAMMER.Dialog.PoolSizeReduced")}`)
|
||||
if (poolSize !== null && poolSize < intRank + magicRank + magicMod) modParts.push(`🎲 ${poolSize}d ${game.i18n.localize("OATHHAMMER.Dialog.PoolSizeReduced")}`)
|
||||
if (bonus !== 0) modParts.push(`${bonus > 0 ? "+" : ""}${bonus} ${game.i18n.localize("OATHHAMMER.Dialog.Modifier")}`)
|
||||
if (poolPenalty !== 0) modParts.push(`${poolPenalty} ${game.i18n.localize("OATHHAMMER.Enhancement." + _cap(enhancement))}`)
|
||||
const activeEnhs = enhancements.filter(k => k !== "none")
|
||||
if (poolPenalty !== 0 || (activeEnhs.length && !poolPenalty))
|
||||
modParts.push(`${poolPenalty !== 0 ? poolPenalty + "d " : ""}[${activeEnhs.join(", ")}]`)
|
||||
if (elementalBonus > 0) modParts.push(`+${elementalBonus} ${game.i18n.localize("OATHHAMMER.Dialog.ElementMet")}`)
|
||||
if (grimPenalty < 0) modParts.push(`${grimPenalty} ${game.i18n.localize("OATHHAMMER.Dialog.GrimoireNo")}`)
|
||||
if (luckSpend > 0) modParts.push(`+${luckSpend * luckDicePerPoint} ${game.i18n.localize("OATHHAMMER.Dialog.LuckSpend")} (${luckSpend}LP${luckIsHuman ? " 👤" : ""})`)
|
||||
@@ -547,7 +550,7 @@ export async function rollSpellCast(actor, spell, options = {}) {
|
||||
<span>${spell.name} (DV ${dv})</span>
|
||||
</div>
|
||||
<div class="oh-roll-info">
|
||||
<span>${attrLabel} ${intRank} + ${skillLabel} ${magicRank}</span>
|
||||
<span>${attrLabel} ${intRank} + ${skillLabel} ${magicRank}${magicMod !== 0 ? ` ${magicMod > 0 ? "+" : ""}${magicMod}` : ""}</span>
|
||||
<span>${colorEmoji} ${totalDice}d6 (${threshold}+)</span>
|
||||
</div>
|
||||
${modLine}
|
||||
@@ -603,8 +606,9 @@ export async function rollMiracleCast(actor, miracle, options = {}) {
|
||||
|
||||
const wpRank = actorSys.attributes.willpower.rank
|
||||
const magicRank = actorSys.skills.magic.rank
|
||||
const magicMod = actorSys.skills.magic.modifier ?? 0
|
||||
const luckDicePerPoint = luckIsHuman ? 3 : 2
|
||||
const totalDice = Math.max(wpRank + magicRank + bonus + (luckSpend * luckDicePerPoint), 1)
|
||||
const totalDice = Math.max(wpRank + magicRank + magicMod + bonus + (luckSpend * luckDicePerPoint), 1)
|
||||
const threshold = colorOverride === "black" ? 2 : colorOverride === "red" ? 3 : 4
|
||||
const colorEmoji = colorOverride === "black" ? "⬛" : colorOverride === "red" ? "🔴" : "⬜"
|
||||
|
||||
@@ -646,7 +650,7 @@ export async function rollMiracleCast(actor, miracle, options = {}) {
|
||||
<span>${miracle.name} (${dvNote})</span>
|
||||
</div>
|
||||
<div class="oh-roll-info">
|
||||
<span>${attrLabel} ${wpRank} + ${skillLabel} ${magicRank}</span>
|
||||
<span>${attrLabel} ${wpRank} + ${skillLabel} ${magicRank}${magicMod !== 0 ? ` ${magicMod > 0 ? "+" : ""}${magicMod}` : ""}</span>
|
||||
<span>${colorEmoji} ${totalDice}d6 (${threshold}+)</span>
|
||||
</div>
|
||||
${modLine}
|
||||
|
||||
Reference in New Issue
Block a user