adjust dialog flow to match spell casting in 4.1

pull/67/head
macniel 2025-11-30 11:21:26 +01:00
parent 50c28cb380
commit c51e281530
4 changed files with 108 additions and 16 deletions

View File

@ -48,7 +48,8 @@
"notReadyReason": { "notReadyReason": {
"title": "Zauber kann aus folgenden Gründen nicht gewirkt werden:", "title": "Zauber kann aus folgenden Gründen nicht gewirkt werden:",
"noRepresentation": "Keine Repräsentation gewählt", "noRepresentation": "Keine Repräsentation gewählt",
"tooManySpoMods": "Zu viele Spontane Modifikationen ausgewählt" "tooManySpoMods": "Zu viele Spontane Modifikationen ausgewählt",
"noZFPDataAvailable": "Noch keine Zauberprobe gewürfelt"
} }
}, },
"ITEM_BROWSER": { "ITEM_BROWSER": {

View File

@ -1,6 +1,7 @@
import {ATTRIBUTE} from "../data/attribute.mjs"; import {ATTRIBUTE} from "../data/attribute.mjs";
import {spoModData, leadingAttribute} from "../data/spellData/spellData.mjs"; import {spoModData, leadingAttribute} from "../data/spellData/spellData.mjs";
import {evaluateRoll} from "../globals/DSARoll.mjs";
const { const {
ApplicationV2, ApplicationV2,
@ -27,6 +28,7 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
}, },
actions: { actions: {
cast: SpellDialog.#cast, cast: SpellDialog.#cast,
diceRoll: SpellDialog.#diceRoll
} }
} }
@ -50,7 +52,7 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
_variants = {} _variants = {}
_costModel = {} _costModel = {}
_castTimeModel = {} _castTimeModel = {}
_spomods = {} _spoMods = {}
displayModResult = 0 displayModResult = 0
constructor(actor, spellId) { constructor(actor, spellId) {
@ -62,7 +64,7 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
this.mod = 0 this.mod = 0
this._costMutators = {} this._costMutators = {}
this._castTimeMutators = {} this._castTimeMutators = {}
this._selectedRepresentation = null this._selectedRepresentation = this._spell.getFlag("DSA_4-1", "representation")
this._spellDie = null this._spellDie = null
this._variants = {} this._variants = {}
this._costModel = this._spell.system.kosten.find(c => c.repräsentation === context.selectedRepresentation) ?? this._spell.system.kosten.find(c => c.repräsentation === "") this._costModel = this._spell.system.kosten.find(c => c.repräsentation === context.selectedRepresentation) ?? this._spell.system.kosten.find(c => c.repräsentation === "")
@ -73,6 +75,15 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
this._castTimeModel.variables.forEach(v => this._castTimeMutators[v] = 0) this._castTimeModel.variables.forEach(v => this._castTimeMutators[v] = 0)
this.cost = this.normalizeCastingCost() ?? 0 this.cost = this.normalizeCastingCost() ?? 0
this.castingTime = this.#normalizeCastingTime(this._spell) this.castingTime = this.#normalizeCastingTime(this._spell)
this.zfp = null
if (this._selectedRepresentation) {
this._costModel = this._spell.system.kosten.find(c => c.repräsentation === context.selectedRepresentation) ?? this._spell.system.kosten.find(c => c.repräsentation === "")
this._castTimeModel = this._spell.system.zauberdauer
this._castTimeMutators = {}
this._costMutators = {}
this._costModel.variables.forEach(v => this._costMutators[v] = 0)
this._castTimeModel.variables.forEach(v => this._castTimeMutators[v] = 0)
}
} }
/** /**
@ -87,8 +98,8 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
event.preventDefault() event.preventDefault()
console.log(formData.object) console.log(formData.object)
// handle changes in variable Inputs // handle changes in variable Inputs
this._selectedRepresentation = formData.object.representation this._selectedRepresentation = formData.object.representation ?? this._selectedRepresentation
this._variants = foundry.utils.expandObject(formData.object)["variants"] this._variants = foundry.utils.expandObject(formData.object)["variants"] ?? {}
if (this._spell.system.probe.includes("*")) { // ATTRIBUTO if (this._spell.system.probe.includes("*")) { // ATTRIBUTO
if (this._variants["Mut"]) { if (this._variants["Mut"]) {
this._spellDie = "MU" this._spellDie = "MU"
@ -145,15 +156,22 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
this.castingTime = this.#normalizeCastingTime(this._spell, this._castTimeMutators) this.castingTime = this.#normalizeCastingTime(this._spell, this._castTimeMutators)
this._spomods = foundry.utils.expandObject(formData.object)["spoMods"] // eval probeMod
if (formData.object["checkMod"]) {
this.mod -= formData.object["checkMod"]
this._checkModValue = formData.object["checkMod"]
}
// eval spomods // eval spomods
this._spoMods = foundry.utils.expandObject(formData.object)["spoMods"] ?? {}
let totalMod = this.mod let totalMod = this.mod
let totalCost = this.cost let totalCost = this.cost
let totalCastingTime = Number(this.castingTime) let totalCastingTime = Number(this.castingTime)
Object.entries(this._spomods).forEach(([modName, times]) => { Object.entries(this._spoMods).forEach(([modName, times]) => {
const actualMod = spoModData[modName] const actualMod = spoModData[modName]
@ -181,6 +199,29 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
} }
static async #diceRoll(event, target) {
const result = await evaluateRoll(
"3d20",
{
value: this._spell.system.zfw + this.mod,
owner: this._actor
}
)
if (result.tap >= 0) { // erfolg
result.evaluated.toMessage({
speaker: ChatMessage.getSpeaker({actor: this._actor}),
flavor: ` ${result.meisterlich ? 'Meisterlich geschafft' : 'Geschafft'} mit ${result.tap} Punkten übrig`,
})
} else { // misserfolg
result.evaluated.toMessage({
speaker: ChatMessage.getSpeaker({actor: this._actor}),
flavor: ` ${result.meisterlich ? 'Gepatzt' : ''} mit ${Math.abs(result.tap)} Punkten daneben`,
})
}
this.zfp = result.tap
this.render({parts: ["form"]})
}
normalizeCastingCost() { normalizeCastingCost() {
let costFormula = this._costModel.additionalFormula let costFormula = this._costModel.additionalFormula
if (costFormula) { if (costFormula) {
@ -346,9 +387,16 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
context.costVariables = [] context.costVariables = []
} }
// probeMod
if (this._spell.system.probeMod) {
context.checkModTest = this._spell.system.probeMod
context.checkModValue = this._checkModValue
}
// SpoMods // SpoMods
context.spoModCount = Object.values(this._spomods).reduce((previousValue, currentValue) => previousValue + currentValue, 0) context.spoModCount = Object.values(this._spoMods).reduce((previousValue, currentValue) => previousValue + currentValue, 0)
context.maxSpoModCount = 0 context.maxSpoModCount = 0
if (this._selectedRepresentation) { if (this._selectedRepresentation) {
@ -367,7 +415,7 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
const mapper = (spoModName) => { const mapper = (spoModName) => {
let data = spoModData[spoModName] let data = spoModData[spoModName]
let value = this._spomods[data.name] ?? 0 let value = this._spoMods[data.name] ?? 0
let totalModValue = data.mod * value let totalModValue = data.mod * value
return { return {
...data, ...data,
@ -397,10 +445,24 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
}) })
} }
if (!context.ready) {
// if this.zfp is null then we are in the first step pre dice roll
if (this.zfp == null) {
context.ready = false
context.diceRoll = true
} else {
context.zfp = this.zfp
context.spellName = this._spell.system.name
context.variant = context.variants.filter(v => v.variantChecked).map(v => v.variantText).join("<br/><br/>")
}
if (!context.ready) { // rules have changed, it cant be cast when zfp - selected mutators is below 0
context.notReadyReasons = `<em>${game.i18n.format("SPELL_DIALOG.notReadyReason.title")}</em><ul>` context.notReadyReasons = `<em>${game.i18n.format("SPELL_DIALOG.notReadyReason.title")}</em><ul>`
if (this.zfp == null) {
context.notReadyReasons += `<li>${game.i18n.format("SPELL_DIALOG.notReadyReason.noZFPDataAvailable")}</li>`
}
if (context.spoModCount > context.maxSpoModCount) { if (context.spoModCount > context.maxSpoModCount) {
context.notReadyReasons += `<li>${game.i18n.format("SPELL_DIALOG.notReadyReason.tooManySpoMods")}</li>` context.notReadyReasons += `<li>${game.i18n.format("SPELL_DIALOG.notReadyReason.tooManySpoMods")}</li>`
@ -411,6 +473,7 @@ export class SpellDialog extends HandlebarsApplicationMixin(ApplicationV2) {
context.notReadyReasons += "</ul>" context.notReadyReasons += "</ul>"
} }
return context return context
} }

View File

@ -383,7 +383,7 @@ export class XmlImport {
} }
async #addSpellsFromCompendiumByNameToActor(spellName, zfw, representation, hauszauber, actor) { async #addSpellsFromCompendiumByNameToActor(spellName, zfw, representation, hauszauber, actor) {
const compendiumOfSpells = game.packs.get('DSA_4-1.Spells'); const compendiumOfSpells = game.packs.get('DSA_4-1.Spells')
const SCREAMING_NAME = spellName.toUpperCase() const SCREAMING_NAME = spellName.toUpperCase()
const spellId = compendiumOfSpells.index.find(spell => spell.name === SCREAMING_NAME) const spellId = compendiumOfSpells.index.find(spell => spell.name === SCREAMING_NAME)
if (spellId) { if (spellId) {
@ -392,7 +392,8 @@ export class XmlImport {
try { try {
const embeddedDocument = (await actor.createEmbeddedDocuments('Item', [spell]))[0] const embeddedDocument = (await actor.createEmbeddedDocuments('Item', [spell]))[0]
embeddedDocument.update({system: {zfw: zfw, hauszauber: hauszauber, repräsentation: representation}}); embeddedDocument.update({system: {zfw: zfw, hauszauber: hauszauber}})
embeddedDocument.setFlag("DSA_4-1", "representation", representation)
} catch (error) { } catch (error) {
console.error(`${spell} not found in items`, error) console.error(`${spell} not found in items`, error)
} }

View File

@ -1,5 +1,7 @@
<section> <section>
{{#unless zfp}}
<div class="attributes {{#if this.colorfulDice}}colorfulDice{{/if}}"> <div class="attributes {{#if this.colorfulDice}}colorfulDice{{/if}}">
<hr class="zier"/> <hr class="zier"/>
@ -50,6 +52,32 @@
</fieldset> </fieldset>
{{/if}} {{/if}}
{{#if checkModTest}}
<fieldset>
<legend>Erschwernisse</legend>
<div class="malus-and-mod">
<label><span>{{checkModTest}}</span>
<input name="checkMod" type="number" value="{{checkModValue}}">
</label>
</div>
</fieldset>
{{/if}}
<button class="actions" data-action="diceRoll"><i class="fa-solid fa-dice"></i> Zauber würfeln {{#if
displayModResult}}
[{{displayModResult}}]{{/if}}</button>
{{else}}
<fieldset>
<legend>{{spellName}}</legend>
{{{this.text}}}
{{#if variant}}
<hr/>
{{{variantText}}}
{{/if}}
</fieldset>
{{#if this.spoMods}} {{#if this.spoMods}}
<fieldset class="scroll-y"> <fieldset class="scroll-y">
<legend>Spontane Modifikation {{#if this.spoModCount}}{{#if this.maxSpoModCount}} <legend>Spontane Modifikation {{#if this.spoModCount}}{{#if this.maxSpoModCount}}
@ -98,9 +126,6 @@
<label><span>Kosten (AsP)</span> <label><span>Kosten (AsP)</span>
<output name="costs">{{castingCosts}}</output> <output name="costs">{{castingCosts}}</output>
</label> </label>
<label><span>Erschwernis</span>
<output name="penalty">{{penalty}}</output>
</label>
</div> </div>
</fieldset> </fieldset>
@ -110,4 +135,6 @@
wirken {{#if modResult}} wirken {{#if modResult}}
[{{displayModResult}}]{{/if}}</button> [{{displayModResult}}]{{/if}}</button>
{{/unless}}
</section> </section>