5 Commits

Author SHA1 Message Date
uberwald f67d9079dd FIx for spells/miracles
Release Creation / build (release) Successful in 2m33s
2026-04-30 23:10:13 +02:00
uberwald ecc2c22372 Merge branch 'main' of https://www.uberwald.me/gitea/uberwald/fvtt-oath-hammer 2026-04-30 23:09:04 +02:00
uberwald 1641be6516 FIx for spells/miracles 2026-04-30 23:08:23 +02:00
uberwald ef41116006 Actualiser .gitea/workflows/release.yaml
Release Creation / build (release) Successful in 1m16s
2026-04-20 15:51:51 +02:00
uberwald 83566ba8fb Actualiser .gitea/workflows/release.yaml 2026-04-20 14:32:02 +02:00
7 changed files with 63 additions and 28 deletions
+13 -13
View File
@@ -26,8 +26,8 @@ jobs:
env: env:
version: ${{steps.get_version.outputs.version-without-v}} version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}} url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/public/fvtt-oath-hammer/releases/download/latest/system.json manifest: https://www.uberwald.me/gitea/uberwald/fvtt-oath-hammer/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/public/fvtt-oath-hammer/releases/download/${{github.event.release.tag_name}}/fvtt-oath-hammer.zip download: https://www.uberwald.me/gitea/uberwald/fvtt-oath-hammer/releases/download/${{github.event.release.tag_name}}/fvtt-oath-hammer.zip
# Build CSS from LESS sources # Build CSS from LESS sources
- name: Setup Node.js - name: Setup Node.js
@@ -45,7 +45,7 @@ jobs:
apt update -y apt update -y
apt install -y zip apt install -y zip
- run: zip -r ./fvtt-oath-hammer.zip system.json README.md LICENSE.md assets/ css/ lang/ module/ oath-hammer.mjs templates/ - run: zip -r ./fvtt-oath-hammer.zip system.json README.md LICENSE.md assets/ css/ lang/ module/ oath-hammer.mjs packs/ templates/
- name: setup go - name: setup go
uses: https://github.com/actions/setup-go@v4 uses: https://github.com/actions/setup-go@v4
@@ -61,13 +61,13 @@ jobs:
system.json system.json
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}" api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
#- name: Publish to Foundry server - name: Publish to Foundry server
#uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1 uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
#with: with:
#token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }} token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
#id: 'fvtt-oath-hammer' id: "fvtt-oath-hammer"
#version: ${{github.event.release.tag_name}} version: ${{github.event.release.tag_name}}
#manifest: 'https://www.uberwald.me/gitea/public/fvtt-oath-hammer/releases/download/latest/system.json' manifest: "https://www.uberwald.me/gitea/uberwald/fvtt-oath-hammer/releases/download/latest/system.json"
#notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-oath-hammer.zip' notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-oath-hammer.zip"
#compatibility-minimum: '13' compatibility-minimum: "13"
#compatibility-verified: '14' compatibility-verified: "14"
+2 -2
View File
@@ -250,7 +250,7 @@
"Oaths": "Oaths", "Oaths": "Oaths",
"Weapons": "Weapons", "Weapons": "Weapons",
"Attacks": "Attacks", "Attacks": "Attacks",
"Armor": "Armor & Shields", "Armor": "Armor",
"Ammunition": "Ammunition", "Ammunition": "Ammunition",
"ItemSlots": "Item Slots", "ItemSlots": "Item Slots",
"Spells": "Spells", "Spells": "Spells",
@@ -444,7 +444,7 @@
"ExplodeOn5": "Explode on 5+", "ExplodeOn5": "Explode on 5+",
"ExplodeOn5Hint": "trait bonus — 5s & 6s explode", "ExplodeOn5Hint": "trait bonus — 5s & 6s explode",
"DiceColor": "Dice Color", "DiceColor": "Dice Color",
"DiceColorHint": "equipment traits can upgrade dice", "DiceColorHint": "White (4+), Red (3+), or Black (2+) thresholds",
"AttackTitle": "Attack: {weapon}", "AttackTitle": "Attack: {weapon}",
"DamageTitle": "Damage: {weapon}", "DamageTitle": "Damage: {weapon}",
"Attack": "Attack", "Attack": "Attack",
+12 -3
View File
@@ -6,9 +6,10 @@ export default class OathHammerMiracleDialog {
const sys = miracle.system const sys = miracle.system
const actorSys = actor.system const actorSys = actor.system
const wpRank = actorSys.attributes.willpower.rank const wpRank = actorSys.attributes.willpower.rank
const magicRank = actorSys.skills.magic.rank const magicRank = actorSys.skills.magic.rank
const basePool = wpRank + magicRank const magicColor = actorSys.skills.magic.colorDiceType ?? "white"
const basePool = wpRank + magicRank
const isRitual = sys.isRitual const isRitual = sys.isRitual
const dv = isRitual ? (sys.difficultyValue || 1) : null const dv = isRitual ? (sys.difficultyValue || 1) : null
@@ -18,6 +19,12 @@ export default class OathHammerMiracleDialog {
return key ? game.i18n.localize(key) : sys.divineTradition return key ? game.i18n.localize(key) : sys.divineTradition
})() })()
const colorOptions = [
{ value: "white", label: game.i18n.localize("OATHHAMMER.ColorDice.White"), selected: magicColor === "white" },
{ value: "red", label: game.i18n.localize("OATHHAMMER.ColorDice.Red"), selected: magicColor === "red" },
{ value: "black", label: game.i18n.localize("OATHHAMMER.ColorDice.Black"), selected: magicColor === "black" },
]
// Miracle count options — DV = miracle number today // Miracle count options — DV = miracle number today
const miracleCountOptions = Array.from({ length: 10 }, (_, i) => ({ const miracleCountOptions = Array.from({ length: 10 }, (_, i) => ({
value: i + 1, value: i + 1,
@@ -55,6 +62,7 @@ export default class OathHammerMiracleDialog {
magicRank, magicRank,
basePool, basePool,
miracleCountOptions, miracleCountOptions,
colorOptions,
bonusOptions, bonusOptions,
availableLuck, availableLuck,
isHuman, isHuman,
@@ -93,6 +101,7 @@ export default class OathHammerMiracleDialog {
return { return {
dv: computedDV, dv: computedDV,
isRitual, isRitual,
colorOverride: result.colorOverride ?? magicColor,
bonus: parseInt(result.bonus) || 0, bonus: parseInt(result.bonus) || 0,
visibility: result.visibility ?? game.settings.get("core", "rollMode"), visibility: result.visibility ?? game.settings.get("core", "rollMode"),
explodeOn5: result.explodeOn5 === "true", explodeOn5: result.explodeOn5 === "true",
+12 -3
View File
@@ -25,9 +25,10 @@ export default class OathHammerSpellDialog {
const sys = spell.system const sys = spell.system
const actorSys = actor.system const actorSys = actor.system
const intRank = actorSys.attributes.intelligence.rank const intRank = actorSys.attributes.intelligence.rank
const magicRank = actorSys.skills.magic.rank const magicRank = actorSys.skills.magic.rank
const basePool = intRank + magicRank const magicColor = actorSys.skills.magic.colorDiceType ?? "white"
const basePool = intRank + magicRank
const currentStress = actorSys.arcaneStress.value const currentStress = actorSys.arcaneStress.value
const stressThreshold = actorSys.arcaneStress.threshold const stressThreshold = actorSys.arcaneStress.threshold
@@ -41,6 +42,12 @@ export default class OathHammerSpellDialog {
return entry ? game.i18n.localize(entry.label) : (sys.tradition ?? "") return entry ? game.i18n.localize(entry.label) : (sys.tradition ?? "")
})() })()
const colorOptions = [
{ value: "white", label: game.i18n.localize("OATHHAMMER.ColorDice.White"), selected: magicColor === "white" },
{ value: "red", label: game.i18n.localize("OATHHAMMER.ColorDice.Red"), selected: magicColor === "red" },
{ value: "black", label: game.i18n.localize("OATHHAMMER.ColorDice.Black"), selected: magicColor === "black" },
]
const enhancementOptions = Object.entries(SPELL_ENHANCEMENTS).map(([key, def]) => ({ const enhancementOptions = Object.entries(SPELL_ENHANCEMENTS).map(([key, def]) => ({
value: key, value: key,
label: game.i18n.localize(def.label), label: game.i18n.localize(def.label),
@@ -87,6 +94,7 @@ export default class OathHammerSpellDialog {
magicRank, magicRank,
basePool, basePool,
poolSizeOptions, poolSizeOptions,
colorOptions,
currentStress, currentStress,
stressThreshold, stressThreshold,
isOverThreshold, isOverThreshold,
@@ -134,6 +142,7 @@ export default class OathHammerSpellDialog {
poolPenalty: enh.penalty, poolPenalty: enh.penalty,
redDice: enh.redDice, redDice: enh.redDice,
noStress: enh.noStress, noStress: enh.noStress,
colorOverride: result.colorOverride ?? magicColor,
elementalBonus: parseInt(result.elementalBonus) || 0, elementalBonus: parseInt(result.elementalBonus) || 0,
bonus: parseInt(result.bonus) || 0, bonus: parseInt(result.bonus) || 0,
poolSize: Math.min(Math.max(1, parseInt(result.poolSize) || basePool), basePool), poolSize: Math.min(Math.max(1, parseInt(result.poolSize) || basePool), basePool),
+8 -7
View File
@@ -468,6 +468,7 @@ export async function rollSpellCast(actor, spell, options = {}) {
poolPenalty = 0, poolPenalty = 0,
redDice = false, redDice = false,
noStress = false, noStress = false,
colorOverride = "white",
elementalBonus = 0, elementalBonus = 0,
bonus = 0, bonus = 0,
poolSize = null, poolSize = null,
@@ -489,8 +490,8 @@ export async function rollSpellCast(actor, spell, options = {}) {
const totalDice = poolSize !== null const totalDice = poolSize !== null
? Math.max(1, Math.min(poolSize + bonus + poolPenalty + elementalBonus + grimPenalty + (luckSpend * luckDicePerPoint), baseDice)) ? Math.max(1, Math.min(poolSize + bonus + poolPenalty + elementalBonus + grimPenalty + (luckSpend * luckDicePerPoint), baseDice))
: Math.max(baseDice, 1) : Math.max(baseDice, 1)
const threshold = redDice ? 3 : 4 const threshold = colorOverride === "black" ? 2 : colorOverride === "red" ? 3 : 4
const colorEmoji = redDice ? "🔴" : "⬜" const colorEmoji = colorOverride === "black" ? "⬛" : colorOverride === "red" ? "🔴" : "⬜"
const { roll, rolls, successes, diceResults } = await _rollPool(totalDice, threshold, explodeOn5) const { roll, rolls, successes, diceResults } = await _rollPool(totalDice, threshold, explodeOn5)
const diceHtml = _diceHtml(diceResults, threshold) const diceHtml = _diceHtml(diceResults, threshold)
@@ -560,13 +561,12 @@ export async function rollSpellCast(actor, spell, options = {}) {
` `
const rollMode = visibility ?? game.settings.get("core", "rollMode") const rollMode = visibility ?? game.settings.get("core", "rollMode")
const spellColorType = redDice ? "red" : "white"
const msgData = { const msgData = {
speaker: ChatMessage.getSpeaker({ actor }), speaker: ChatMessage.getSpeaker({ actor }),
content, content,
rolls: rolls, rolls: rolls,
sound: CONFIG.sounds.dice, sound: CONFIG.sounds.dice,
flags: { "fvtt-oath-hammer": { luckRoll: _luckFlagData(actor, threshold, spellColorType, dv, false, explodeOn5) } }, flags: { "fvtt-oath-hammer": { luckRoll: _luckFlagData(actor, threshold, colorOverride, dv, false, explodeOn5) } },
} }
ChatMessage.applyRollMode(msgData, rollMode) ChatMessage.applyRollMode(msgData, rollMode)
await ChatMessage.create(msgData) await ChatMessage.create(msgData)
@@ -590,6 +590,7 @@ export async function rollMiracleCast(actor, miracle, options = {}) {
const { const {
dv = 1, dv = 1,
isRitual = false, isRitual = false,
colorOverride = "white",
bonus = 0, bonus = 0,
visibility, visibility,
explodeOn5 = false, explodeOn5 = false,
@@ -604,8 +605,8 @@ export async function rollMiracleCast(actor, miracle, options = {}) {
const magicRank = actorSys.skills.magic.rank const magicRank = actorSys.skills.magic.rank
const luckDicePerPoint = luckIsHuman ? 3 : 2 const luckDicePerPoint = luckIsHuman ? 3 : 2
const totalDice = Math.max(wpRank + magicRank + bonus + (luckSpend * luckDicePerPoint), 1) const totalDice = Math.max(wpRank + magicRank + bonus + (luckSpend * luckDicePerPoint), 1)
const threshold = 4 const threshold = colorOverride === "black" ? 2 : colorOverride === "red" ? 3 : 4
const colorEmoji = "⬜" const colorEmoji = colorOverride === "black" ? "⬛" : colorOverride === "red" ? "🔴" : "⬜"
const { roll, rolls, successes, diceResults } = await _rollPool(totalDice, threshold, explodeOn5) const { roll, rolls, successes, diceResults } = await _rollPool(totalDice, threshold, explodeOn5)
const diceHtml = _diceHtml(diceResults, threshold) const diceHtml = _diceHtml(diceResults, threshold)
@@ -664,7 +665,7 @@ export async function rollMiracleCast(actor, miracle, options = {}) {
content, content,
rolls: rolls, rolls: rolls,
sound: CONFIG.sounds.dice, sound: CONFIG.sounds.dice,
flags: { "fvtt-oath-hammer": { luckRoll: _luckFlagData(actor, threshold, "white", dv, false, explodeOn5) } }, flags: { "fvtt-oath-hammer": { luckRoll: _luckFlagData(actor, threshold, colorOverride, dv, false, explodeOn5) } },
} }
ChatMessage.applyRollMode(msgData, rollMode) ChatMessage.applyRollMode(msgData, rollMode)
await ChatMessage.create(msgData) await ChatMessage.create(msgData)
+8
View File
@@ -45,6 +45,14 @@
</div> </div>
{{/unless}} {{/unless}}
<div class="roll-option-row">
<label>{{localize "OATHHAMMER.Dialog.DiceColor"}}</label>
<select name="colorOverride">
{{#each colorOptions}}<option value="{{value}}"{{#if selected}} selected{{/if}}>{{label}}</option>{{/each}}
</select>
<span class="roll-option-hint">{{localize "OATHHAMMER.Dialog.DiceColorHint"}}</span>
</div>
<div class="roll-option-row"> <div class="roll-option-row">
<label>{{localize "OATHHAMMER.Dialog.Modifier"}}</label> <label>{{localize "OATHHAMMER.Dialog.Modifier"}}</label>
<select name="bonus"> <select name="bonus">
+8
View File
@@ -44,6 +44,14 @@
</div> </div>
{{/if}} {{/if}}
<div class="roll-option-row">
<label>{{localize "OATHHAMMER.Dialog.DiceColor"}}</label>
<select name="colorOverride">
{{#each colorOptions}}<option value="{{value}}"{{#if selected}} selected{{/if}}>{{label}}</option>{{/each}}
</select>
<span class="roll-option-hint">{{localize "OATHHAMMER.Dialog.DiceColorHint"}}</span>
</div>
<div class="roll-option-row"> <div class="roll-option-row">
<label>{{localize "OATHHAMMER.Dialog.Enhancement"}}</label> <label>{{localize "OATHHAMMER.Dialog.Enhancement"}}</label>
<select name="enhancement" class="enhancement-select"> <select name="enhancement" class="enhancement-select">