Merge pull request 'feature/liturgy-dialog' (#63) from feature/liturgy-dialog into main

Reviewed-on: #63
pull/64/head
macniel 2025-10-30 23:10:43 +01:00
commit f1052d77b9
18 changed files with 790 additions and 326 deletions

View File

@ -47,7 +47,7 @@ async function preloadHandlebarsTemplates() {
'systems/DSA_4-1/templates/ui/partial-action-button.hbs',
'systems/DSA_4-1/templates/ui/partial-equipment-button.hbs',
'systems/DSA_4-1/templates/ui/partial-array-editor.hbs',
'systems/DSA_4-1/templates/dialog/modify-liturgy.hbs'
'systems/DSA_4-1/templates/dialog/liturgy-dialog.hbs'
]);
}
@ -290,6 +290,17 @@ Hooks.once("init", () => {
},
requiresReload: true
})
game.settings.register('DSA_4-1', 'optional_aufstufen_von_liturgien', {
name: "Optional: Aufstufen von Liturgien",
hint: "Aktiviert die Regeln zum Aufstufen von Liturgien",
scope: "world",
config: true,
type: Boolean,
default: false,
disabled: true,
requiresReload: true
})
Handlebars.registerHelper("weight", (data) => {

View File

@ -13,7 +13,9 @@ export class LiturgyDataModel extends BaseItem {
grad: new NumberField({min: 1, max: 5}),
reichweite: new StringField(),
ziel: new StringField(),
zielArt: new StringField(), // Person, Object
wirkungsdauer: new StringField(),
zauberdauer: new StringField(),
auswirkung: new SchemaField({
I: new StringField(),
II: new StringField(),

View File

@ -3,8 +3,29 @@ export class LiturgyData {
static ranks = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII"]
static #ranks = [
{index: 0, name: "O", lkp: 3, mod: 2, costKaP: 2, costKaPPermant: 0, duration: "{*} KR", strength: "{*}/2"},
{index: 1, name: "I", lkp: 3, mod: 0, costKaP: 5, costKaPPermant: 0, duration: "{*} KR", strength: "{*}/2"},
{
index: 0,
name: "O",
lkp: 3,
mod: 2,
costKaP: 2,
costKaPPermant: 0,
duration: "Augenblicklich",
castDuration: "Stoßgebet",
strength: "LkP*/2"
},
{
index: 1,
name: "I",
lkp: 3,
mod: 0,
costKaP: 5,
costKaPPermant: 0,
range: "Selbst",
castDuration: "Gebet",
duration: "LkP* KR",
strength: "LkP*/2"
},
{
index: 2,
name: "II",
@ -12,10 +33,25 @@ export class LiturgyData {
mod: -2,
costKaP: 10,
costKaPPermant: 0,
duration: "{*}*10 KR",
strength: "{*}/2+5"
range: "Berührung",
target: ["Geweihter"],
castDuration: "Andacht",
duration: "LkP*10 KR",
strength: "LkP/2+5"
},
{
index: 3,
name: "III",
lkp: 9,
mod: -4,
costKaP: 15,
costKaPPermant: 0,
range: "Sicht",
target: ["1 Person", "1 Objekt"],
castDuration: "Zeremonie",
duration: "LkP* Spielrunden",
strength: "LkP*+5"
},
{index: 3, name: "III", lkp: 9, mod: -4, costKaP: 15, costKaPPermant: 0, duration: "{*} SR", strength: "{*}+5"},
{
index: 4,
name: "IV",
@ -23,8 +59,11 @@ export class LiturgyData {
mod: -6,
costKaP: 20,
costKaPPermant: 0,
duration: "{*} Stunden",
strength: "{*}+10"
range: "Fern",
target: ["10 Personen", "10 Objekte"],
castDuration: "Zyklus",
duration: "LkP* Stunden",
strength: "LkP*+10"
},
{
index: 5,
@ -33,8 +72,9 @@ export class LiturgyData {
mod: -8,
costKaP: 25,
costKaPPermant: 1,
duration: "{*} Tage",
strength: "{*}+15"
target: ["100 Personen", "100 Objekte"],
duration: "LkP* Tage",
strength: "LkP*+15"
},
{
index: 6,
@ -43,8 +83,9 @@ export class LiturgyData {
mod: -10,
costKaP: 30,
costKaPPermant: 3,
duration: "{*} Wochen",
strength: "{*}+20"
target: ["1000 Personen", "1000 Objekte"],
duration: "LkP* Wochen",
strength: "LkP*+20"
},
{
index: 7,
@ -53,8 +94,8 @@ export class LiturgyData {
mod: -12,
costKaP: 35,
costKaPPermant: 5,
duration: "{*} Monate",
strength: "{*}+25"
duration: "LkP* Monate",
strength: "LkP*+25"
},
{
index: 8,
@ -63,9 +104,9 @@ export class LiturgyData {
mod: -14,
costKaP: 40,
costKaPPermant: 7,
duration: "{*} Jahre oder permanent",
duration: "LkP* Jahre oder permanent",
casttime: "",
strength: "{*}+30"
strength: "LkP*+30"
},
];
@ -99,16 +140,52 @@ export class LiturgyData {
}
]
static getModifiedStrength(originalString, rankIncrease) {
// TODO as "Flagge des Regenbogens" demonstrates there may be different variations of Strengths which separately needs to be adjusted
return Object.assign({}, this.#ranks[this.#ranks.findIndex(p => p.strength === originalString) + rankIncrease])
}
static getModifiedDuration(originalString, rankIncrease) {
let currentDuration = 0
let durationText = ""
let adjustedDurationText = ""
let found = false
for (let {duration} of this.#ranks) {
if (originalString.indexOf(duration) !== -1) {
durationText = duration
adjustedDurationText = this.#ranks[currentDuration + rankIncrease].duration
found = true
break
}
++currentDuration
}
if (found) {
durationText = this.#ranks[currentDuration].duration
console.log({currentDuration, durationText, adjustedDurationText})
return {currentDuration, durationText, adjustedDurationText}
}
return {currentDuration: 0, durationText: originalString, adjustedDurationText: originalString}
}
static getModifiedRank(rank) {
return Object.assign({}, LiturgyData.#ranks[rank])
}
static getRankOfLiturgy(liturgy, deity) {
const lookupData = liturgy.herkunft.find(p => p.name === deity)
const rank = lookupData?.grad;
return LiturgyData.#ranks[rank];
const rank = lookupData?.grad
return Object.assign({}, LiturgyData.#ranks[rank])
}
static lookupAlias(alias) {
return LiturgyData.#aliases.find((entry) => {
return entry.aliases.indexOf(alias) !== -1
})?.originalName ?? alias; // cant determine thus simply return the original query name
})?.originalName ?? alias // cant determine thus simply return the original query name
}
}

View File

@ -17,6 +17,7 @@ export class Talent {
* @typedef TalentData
* @property {String} name
* @property {Number} taw
* @property {Number} mod
* @property {TalentEigenschaften} eigenschaften
* @property {"mu","kl","in","ch","ff","ge","ko","kk"} eigenschaft1
* @property {"mu","kl","in","ch","ff","ge","ko","kk"} eigenschaft2
@ -55,6 +56,7 @@ export class Talent {
const dsaDieRollEvaluated = this._evaluateRoll(evaluated1.terms[0].results, {
taw: data.taw,
mod: data.mod,
werte: [data.eigenschaften[data.eigenschaft1], data.eigenschaften[data.eigenschaft2], data.eigenschaften[data.eigenschaft3]],
})
@ -66,25 +68,25 @@ export class Talent {
_evaluateRoll(rolledDice, {
taw,
mod,
lowerThreshold = 1,
upperThreshold = 20,
countToMeisterlich = 3,
countToPatzer = 3,
werte = []
}) {
let tap = taw;
let meisterlichCounter = 0;
let patzerCounter = 0;
let failCounter = 0;
rolledDice.forEach((rolledDie, index) => {
if (tap < 0 && rolledDie.result > werte[index]) {
tap -= rolledDie.result - werte[index];
if (tap < 0) { // konnte nicht vollständig ausgeglichen werden
if (mod < 0 && rolledDie.result > werte[index]) {
mod -= rolledDie.result - werte[index];
if (mod < 0) { // konnte nicht vollständig ausgeglichen werden
failCounter++;
}
} else if (rolledDie.result > werte[index]) { // taw ist bereits aufgebraucht und wert kann nicht ausgeglichen werden
tap -= rolledDie.result - werte[index];
mod -= rolledDie.result - werte[index];
failCounter++;
}
if (rolledDie.result <= lowerThreshold) meisterlichCounter++;
@ -92,7 +94,7 @@ export class Talent {
})
return {
tap,
tap: Math.min(taw, mod),
meisterlich: meisterlichCounter === countToMeisterlich,
patzer: patzerCounter === countToPatzer,
}

View File

@ -1,6 +1,40 @@
import {LiturgyData} from "../data/miracle/liturgydata.mjs";
import {Talent} from "../data/talent.mjs";
export class ModifyLiturgy {
const {ApplicationV2, HandlebarsApplicationMixin} = foundry.applications.api
export class LiturgyDialog extends HandlebarsApplicationMixin(ApplicationV2) {
static DEFAULT_OPTIONS = {
classes: ['dsa41', 'dialog', 'liturgy'],
tag: "form",
position: {
width: 480,
height: 800
},
window: {
resizable: false,
title: "Liturgie wirken"
},
form: {
submitOnChange: true,
closeOnSubmit: false,
handler: LiturgyDialog.#onSubmitForm
},
actions: {
selectVariant: LiturgyDialog.#selectVariant,
addMod: LiturgyDialog.#addModification,
removeMod: LiturgyDialog.#removeModification,
castLiturgy: LiturgyDialog.#castLiturgy,
}
}
static PARTS = {
form: {
template: 'systems/DSA_4-1/templates/dialog/liturgy-dialog.hbs',
}
}
static data = {}
static naming = {
@ -10,79 +44,266 @@ export class ModifyLiturgy {
"castduration": "Wirkzeit",
"duration": "Wirkdauer"
}
static #romanNumerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"]
/**
*
* @type {Actor}
* @private
*/
_actor = null
constructor(data) {
ModifyLiturgy.data = data;
ModifyLiturgy.data.maxmods = Math.round(data.lkp / 3);
ModifyLiturgy.data.variation = null;
}
constructor(actor, liturgyValue, liturgyId, deity) {
super()
this._actor = actor
this._liturgy = this._actor.itemTypes["Liturgy"].find(p => p._id === liturgyId)
this._deity = deity
this._maxmods = Math.round(liturgyValue / 3)
this._variations = []
Object.entries(this._liturgy.system.auswirkung).forEach(([rank, text]) => {
static renderMods(html) {
let result = '';
ModifyLiturgy.data.mods.forEach(((mod, index) => {
result += `<tr><td>${LiturgyData.ranks[mod.rank]}</td><td>${ModifyLiturgy.naming[mod.mod]}</td><td><button class="remove-mod" data-index="${index}"><i class="fa-solid fa-xmark"></i></button></td></tr>`
}))
return result;
}
handleRender(html) {
html.off('click', 'input[name="data.variation"]')
html.on('click', 'input[name="data.variation"]', (evt) => {
if (evt.currentTarget.checked) {
ModifyLiturgy.data.variation = evt.currentTarget.dataset['rank'];
ModifyLiturgy.data.mods = [];
}
this.render(html)
if (text) {
this._variations.push({
level: LiturgyDialog.#romanNumerals.findIndex(p => p === rank) + 1,
rank: rank,
effect: text
})
html.off('click', 'button[class="remove-mod"]')
html.on('click', 'button[class="remove-mod"]', (evt) => {
const {index} = evt.currentTarget.dataset;
ModifyLiturgy.data.mods.splice(index, 1);
this.render(html)
}
})
html.off('change', 'select[name="mod"]')
html.on('change', 'select[name="mod"]', (evt) => {
const value = evt.currentTarget.value;
if (value === '') return;
const currentRank = ModifyLiturgy.data.mods.length + Number(ModifyLiturgy.data.rank);
ModifyLiturgy.data.mods.push({
this._variation = this._variations[0]
this._mods = []
this._blessing = this._actor.itemTypes["Blessing"].find(p => p.system.gottheit === this._deity)
this._initialRank = 0
this._circumstance = 0
}
static async #onSubmitForm(event, form, formData) {
event.preventDefault()
this._circumstance = formData.object["circumstance"]
this.render({parts: ["form"]})
}
static #selectVariant(event, target) {
if (target.checked) {
this._variation = this._variations.find(p => p.rank === target.dataset['rank']);
this._mods = [];
}
this.render({parts: ["form"]})
event.stopPropagation()
event.preventDefault()
return false
}
static #addModification(event, target) {
event.stopPropagation()
event.preventDefault()
if (game.settings.get("DSA_4-1", "optional_aufstufen_von_liturgien")) {
const value = this.element.querySelector('select[name="mod"]').value
if (value === '') return
const currentRank = this._mods.length + (this._variation?.level ?? 0)
this._mods.push({
rank: currentRank,
displayRank: LiturgyDialog.#romanNumerals.findIndex(p => p === currentRank),
mod: value,
});
evt.currentTarget.value = "";
this.render(html)
})
this.render({parts: ["form"]})
}
return false
}
static #removeModification(event, target) {
event.stopPropagation()
event.preventDefault()
if (game.settings.get("DSA_4-1", "optional_aufstufen_von_liturgien")) {
const {index} = target.dataset
this._mods.splice(index, 1)
this.render({parts: ["form"]})
}
return false
}
static async #castLiturgy(event, target) {
const lkp = context.lkp = this._blessing.system.wert
const resultingLiturgy = this.#getLiturgyData()
const circumstance = this._circumstance
const mod = 0 + lkp + resultingLiturgy.castPenalty - circumstance
const castingTime = this.#normalizeCastingTime(this._liturgy)
//TODO push it into the sun eeerh cooldown queue
//if (castingTime > 0) {
// this._actor.system.cooldowns.push()
//} else {
const result = await new Talent({
name: this._liturgy.name,
taw: lkp,
mod: mod,
eigenschaften: {
mu: this._actor.system.attribute.mu.aktuell,
in: this._actor.system.attribute.in.aktuell,
ch: this._actor.system.attribute.ch.aktuell,
},
eigenschaft1: "mu",
eigenschaft2: "mu",
eigenschaft3: "mu"
}).evaluate("publicroll")
result.evaluatedRoll.toMessage({
speaker: ChatMessage.getSpeaker({actor: this._actor}),
flavor: `Liturgie: ${this._liturgy.name}<br/>Zauberdauer: ${castingTime > 0 ? castingTime + " Aktionen" : resultingLiturgy.castduration}<br/>LkP*: ${result.tap}<br/>${result.meisterlich ? "Meisterlich" : ""}${result.patzer ? "Petzer" : ""}<br/>${this._variation.effect}`,
})
//}
this.close()
}
#normalizeCastingTime(liturgy) {
const castingTime = liturgy.system.zauberdauer
// direct actions
const stoßgebetRegExp = /(.*) Aktionen \(Stoßgebet\)/
const gebetRegExp = /(.*) Spielrunden? \(Gebet\)/
const invalidForCooldownRegExp = /Andacht|Zeremonie|Zyklus/
if (castingTime.match(stoßgebetRegExp)) {
const [_, actions] = castingTime.match(stoßgebetRegExp)
return actions
} else if (castingTime.match(gebetRegExp)) {
const [_, actions] = castingTime.match(stoßgebetRegExp)
return actions * 20
} else if (castingTime.match(invalidForCooldownRegExp)) {
return -1
}
return -1
}
_configureRenderOptions(options) {
super._configureRenderOptions(options)
if (options.window) {
if (this._liturgy) {
options.window.title = `${this._liturgy.name} wirken`
}
if (game.settings.get("DSA_4-1", "optional_aufstufen_von_liturgien")) {
options.position.height = 800
} else {
options.position.height = 640
}
}
return options
}
#getLiturgyData() {
let baseline = this._liturgy.system
baseline.name = this._liturgy.name
if (game.settings.get("DSA_4-1", "optional_aufstufen_von_liturgien")) {
let upgradeDuration = false
let upgradeCastDuration = false
let upgradeStrength = false
this._mods.forEach(({mod}) => {
switch (mod) {
case "range":
break;
case "strength":
upgradeStrength = true
break;
case "target":
break;
case "castduration":
upgradeCastDuration = true
break;
case "duration":
upgradeDuration = true
break;
}
})
// render state
$('#mods', html).html(ModifyLiturgy.renderMods(html))
baseline.effectiveLevel = (this._variation?.level ?? 0) + this._mods.length
baseline.costKaP = LiturgyData.getModifiedRank(baseline.effectiveLevel).costKaP
baseline.costKaPPermanent = LiturgyData.getModifiedRank(baseline.effectiveLevel).costKaPPermanent
//baseline.mod = LiturgyData.getModifiedRank(baseline.effectiveLevel).mod
baseline.rank = LiturgyData.getModifiedRank(baseline.effectiveLevel).name
// estimate duration rank
// state handling
// insert mods into text
baseline.text = this._variation.effect
if (ModifyLiturgy.data.mods.length === ModifyLiturgy.data.maxmods) {
$(".editor, .editor *", html).attr('disabled', 'disabled');
$(".editor select", html).hide();
$('span#info', html).text('LkW lässt keine weitere Modifikationen zu')
$("#mod_rank", html).text(LiturgyData.ranks[ModifyLiturgy.data.mods.length + Number(ModifyLiturgy.data.rank)]);
} else if (ModifyLiturgy.data.variation == null) {
$(".editor select *", html).attr('disabled', 'disabled');
$(".editor select", html).hide();
$('span#info', html).text('Keine Variante ausgewählt')
$("#mod_rank", html).text('');
const strengthRegexp = /(LkP\*.*?)[ .]/g
//baseline.text = baseline.text.replace(strengthRegexp, LiturgyData.getModifiedRank((baseline.effectiveLevel ?? 0) + upgradeStrength).strength)
const durationRegexp = /(LkP\*?.*?)(\*10 KR| Stunden| Tage| Wochen| Monate| Jahre oder permanent)/g
const effectiveDuration = LiturgyData.getModifiedDuration(baseline.duration, upgradeDuration + upgradeStrength)
baseline.duration = baseline.duration.replace(effectiveDuration.durationText, effectiveDuration.adjustedDurationText)
} else {
$(".editor, .editor *", html).removeAttr('disabled');
$(".editor select", html).show();
$('span#info', html).text('')
$("#mod_rank", html).text('');
baseline.rank = this._variation.rank
baseline.text = this._variation.effect
baseline.target = baseline.ziel
baseline.duration = baseline.wirkungsdauer
baseline.castduration = baseline.zauberdauer
baseline.costKaP = LiturgyData.getModifiedRank(this._variation.level).costKaP
baseline.costKaPPermanent = LiturgyData.getModifiedRank(this._variation.level).costKaPPermanent
if (this._variation.level > this._liturgy.system.herkunft.find(p => p.name === this._deity).grad) {
baseline.castPenalty = LiturgyData.getModifiedRank(this._liturgy.system.herkunft.find(p => p.name === this._deity).grad).mod
} else {
baseline.castPenalty = LiturgyData.getModifiedRank(this._variation.level).mod
}
}
return baseline
}
async _prepareContext(options) {
const context = await super._prepareContext(options)
context.actor = this._actor
context.liturgy = this._liturgy
context.mods = this._mods
context.variation = this._variation
context.maxmods = this._maxmods
context.variations = this._variations
context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice')
context.mu = {wert: this._actor.system.attribute.mu.aktuell, name: "MU", tooltip: "Mut"}
context.in = {wert: this._actor.system.attribute.in.aktuell, name: "IN", tooltip: "Intuition"}
context.ch = {wert: this._actor.system.attribute.ch.aktuell, name: "CH", tooltip: "Charisma"}
context.moddingEnabled = game.settings.get("DSA_4-1", "optional_aufstufen_von_liturgien")
context.canMod = game.settings.get("DSA_4-1", "optional_aufstufen_von_liturgien") && (this._maxmods - (this._variation?.level ?? 0) - this._mods.length) >= 0
context.addingModRank = LiturgyDialog.#romanNumerals[(context._variation?.level ?? 0) + this._mods.length + 1]
context.lkp = this._blessing.system.wert
context.deity = this._blessing.system.name
context.resultingLiturgy = this.#getLiturgyData()
context.resultingCastPenalty = 0
context.circumstance = this._circumstance
if (context.resultingLiturgy.castPenalty > 0) {
context.resultingCastPenalty = `+${context.resultingLiturgy.castPenalty}`
} else {
context.resultingCastPenalty = context.resultingLiturgy.castPenalty
}
context.modResult = 0 + context.lkp + context.resultingLiturgy.castPenalty - this._circumstance
context.displayModResult = context.modResult > 0 ? "+" + context.modResult : context.modResult
return context
}
}

View File

@ -57,6 +57,7 @@ export default {
// sort by rank
const rankData = LiturgyData.getRankOfLiturgy(item.system, deity)
if (rankData) {
console.log(rankData)
let {index, name, lkp, mod, costKaP} = rankData;
insertObject["count" + name] = insertObject["count" + name] + 1;

View File

@ -11,6 +11,8 @@ import {CombatActionDialog} from "../dialog/combatAction.mjs";
import {ActionManager} from "./actions/action-manager.mjs";
import {DefenseActionDialog} from "../dialog/defenseAction.mjs";
import {RestingDialog} from "../dialog/restingDialog.mjs";
import {Character} from "../documents/character.mjs";
import {LiturgyDialog} from "../dialog/modify-liturgy.mjs";
const {HandlebarsApplicationMixin, DocumentSheetV2} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets
@ -42,6 +44,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
openCultureDocument: CharacterSheet.#openCultureDocument,
openSpeciesDocument: CharacterSheet.#openSpeciesDocument,
openCombatAction: CharacterSheet.#openCombatAction,
openLiturgyDialog: CharacterSheet.#openLiturgyDialog,
progressCooldown: CharacterSheet.#progressCooldown,
cancelCooldown: CharacterSheet.#cancelCooldown,
activateCooldown: CharacterSheet.#activateCooldown,
@ -230,6 +233,11 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
}
}
static #openLiturgyDialog(event, target) {
const {id, lkp, deity} = target.dataset
new LiturgyDialog(this.document, lkp, id, deity).render(true)
}
static #startResting(event, target) {
const dialog = new RestingDialog(this.document)

View File

@ -4,55 +4,55 @@
"Cereborns Handreichung (Handwerkssegen)",
"Hauch der Leidenschaft (Handwerkssegen)"
],
"grad": 1,
"grad": 2,
"herkunft": [
{
"name": "Praios",
"grad": 1
"grad": 2
},
{
"name": "Rondra",
"grad": 1
"grad": 2
},
{
"name": "Efferd",
"grad": 1
"grad": 2
},
{
"name": "Travia",
"grad": 1
"grad": 2
},
{
"name": "Boron",
"grad": 1
"grad": 2
},
{
"name": "Hesinde",
"grad": 1
"grad": 2
},
{
"name": "Firun",
"grad": 1
"grad": 2
},
{
"name": "Tsa",
"grad": 1
"grad": 2
},
{
"name": "Phex",
"grad": 1
"grad": 2
},
{
"name": "Peraine",
"grad": 1
"grad": 2
},
{
"name": "Ingrerimm",
"grad": 1
"grad": 2
},
{
"name": "Rahja",
"grad": 1
"grad": 2
}
],
"reichweite": "Berührung",
@ -60,6 +60,6 @@
"zauberdauer": "1 Spielrunde (Gebet)",
"wirkungsdauer": "bis zum Ende der Probe, maximal LkP* Tage",
"auswirkung": {
"I": "Mit dieser Liturgie erfährt eine Person durch den Geweihten eine göttliche Inspiration in einem Talent, das für den Geweihten ein Mirakel+ Talent ist. Der TaW der inspirierten Person steigt für eine Probe um LkP*/2+5 Punkte. Solcherart geschaffene Werkstücke können bei vielen TaP* der Talentprobe nach Maßgabe des Meisters entweder besonders kunstfertig oder aber besonders robust sein, was beim Bau von Behelfsbrücken oder dergleichen wichtig sein kann."
"II": "Mit dieser Liturgie erfährt eine Person durch den Geweihten eine göttliche Inspiration in einem Talent, das für den Geweihten ein Mirakel+ Talent ist. Der TaW der inspirierten Person steigt für eine Probe um LkP*/2+5 Punkte. Solcherart geschaffene Werkstücke können bei vielen TaP* der Talentprobe nach Maßgabe des Meisters entweder besonders kunstfertig oder aber besonders robust sein, was beim Bau von Behelfsbrücken oder dergleichen wichtig sein kann."
}
}

View File

@ -55,7 +55,7 @@
],
"reichweite": "Berührung",
"ziel": "1 Person",
"zauberdauer": "1/2 Stund (Andacht)",
"zauberdauer": "1/2 Stunde (Andacht)",
"wirkungsdauer": "permanent; kann nur durch eine Exkommunikation aufgehoben werden",
"auswirkung": {
"II": "Zwölfjährige oder Bekehrte werden mittels dieser Liturgie in den Zwölfgötterkult eingeführt, ihren Seelen steht prinzipiell eines der zwölfgöttlichen Paradiese offen. Im Zuge der Initiation erkennen Geweihte auch, ob Kinder potenzielle Novizen darstellen."

View File

@ -54,7 +54,7 @@
}
],
"reichweite": "selbst / Sicht (Variante des Feuerschutzes)",
"ziel": "Gewewihter / 1 Gegenstand (Variante des Feuerschutzes)",
"ziel": "Geweihter / 1 Gegenstand (Variante des Feuerschutzes)",
"zauberdauer": "1 Spielrunde (Gebet)",
"wirkungsdauer": "bis zum Ende der Probe, maximal LkP* Tage",
"auswirkung": {

View File

@ -1,5 +1,5 @@
{
"name": "Geburtssegen",
"name": "Glückssegen",
"alias": [],
"grad": 1,
"primärHerkunft": "Phex",

View File

@ -0,0 +1,144 @@
@use "../atoms/colours";
@use "../atoms/numbers";
@use "../atoms/assets";
@use "sass:color";
@mixin attributes {
display: flex;
position: relative;
top: -10px;
right: -10px;
.attribute {
width: 48px;
height: 48px;
position: relative;
margin-left: 2px;
.die {
svg {
position: absolute;
path {
fill: colours.$attribute-die-color;
}
}
}
.wert {
font-weight: bold;
position: absolute;
left: -1px;
width: 48px;
top: -1px;
font-size: smaller;
line-height: 48px;
vertical-align: middle;
text-align: center;
color: colours.$attribute-die-label-color;
}
.name {
position: absolute;
left: 0;
right: 0;
bottom: -12px;
line-height: 12px;
vertical-align: middle;
text-align: center;
color: colours.$attribute-label-color;
}
}
&.colorfulDice {
&.Mut {
.die svg path {
fill: colours.$attribute-die-co-color;
}
.wert {
color: colours.$attribute-die-co-text-color;
}
}
.Klugheit {
.die svg path {
fill: colours.$attribute-die-sm-color;
}
.wert {
color: colours.$attribute-die-sm-text-color;
}
}
.Intuition {
.die svg path {
fill: colours.$attribute-die-in-color;
}
.wert {
color: colours.$attribute-die-in-text-color;
}
}
.Charisma {
.die svg path {
fill: colours.$attribute-die-ch-color;
}
.wert {
color: colours.$attribute-die-ch-text-color;
}
}
.Geschicklichkeit {
.die svg path {
fill: colours.$attribute-die-dx-color;
}
.wert {
color: colours.$attribute-die-dx-text-color;
}
}
.Fingerfertigkeit {
.die svg path {
fill: colours.$attribute-die-ag-color;
}
.wert {
color: colours.$attribute-die-ag-text-color;
}
}
.Konstitution {
.die svg path {
fill: colours.$attribute-die-bd-color;
}
.wert {
color: colours.$attribute-die-bd-text-color;
}
}
.Körperkraft {
.die svg path {
fill: colours.$attribute-die-st-color;
}
.wert {
color: colours.$attribute-die-st-text-color;
}
}
}
}

View File

@ -2,6 +2,7 @@
@use "../atoms/numbers";
@use "../atoms/assets";
@use "sass:color";
@use "attribute-die";
.dsa41.sheet.actor.character {
@ -9,145 +10,9 @@
position: relative;
.attributes {
display: flex;
position: relative;
top: -10px;
right: -10px;
.attribute.rollable {
width: 48px;
height: 48px;
position: relative;
margin-left: 2px;
.die {
svg {
position: absolute;
path {
fill: colours.$attribute-die-color;
}
}
}
.wert {
font-weight: bold;
position: absolute;
left: -1px;
width: 48px;
top: -1px;
font-size: smaller;
line-height: 48px;
vertical-align: middle;
text-align: center;
color: colours.$attribute-die-label-color;
}
.name {
position: absolute;
left: 0;
right: 0;
bottom: -12px;
line-height: 12px;
vertical-align: middle;
text-align: center;
color: colours.$attribute-label-color;
}
}
&.colorfulDice {
&.Mut {
.die svg path {
fill: colours.$attribute-die-co-color;
}
.wert {
color: colours.$attribute-die-co-text-color;
}
}
.Klugheit {
.die svg path {
fill: colours.$attribute-die-sm-color;
}
.wert {
color: colours.$attribute-die-sm-text-color;
}
}
.Intuition {
.die svg path {
fill: colours.$attribute-die-in-color;
}
.wert {
color: colours.$attribute-die-in-text-color;
}
}
.Charisma {
.die svg path {
fill: colours.$attribute-die-ch-color;
}
.wert {
color: colours.$attribute-die-ch-text-color;
}
}
.Geschicklichkeit {
.die svg path {
fill: colours.$attribute-die-dx-color;
}
.wert {
color: colours.$attribute-die-dx-text-color;
}
}
.Fingerfertigkeit {
.die svg path {
fill: colours.$attribute-die-ag-color;
}
.wert {
color: colours.$attribute-die-ag-text-color;
}
}
.Konstitution {
.die svg path {
fill: colours.$attribute-die-bd-color;
}
.wert {
color: colours.$attribute-die-bd-text-color;
}
}
.Körperkraft {
.die svg path {
fill: colours.$attribute-die-st-color;
}
.wert {
color: colours.$attribute-die-st-text-color;
}
@include attribute-die.attributes
}
}
}
}
}

View File

@ -1,5 +1,29 @@
@use "../molecules/attribute-die";
.dsa41.dialog.liturgy {
section[data-application-part] {
display: flex;
flex-direction: column;
gap: 16px;
height: 100%;
.attributes {
@include attribute-die.attributes;
top: 0;
left: 0;
justify-content: center;
hr.zier {
flex: 1;
align-self: center;
border-top: 1px inset;
}
}
table {
tr {
th:first-child {
@ -8,6 +32,12 @@
}
}
.scroll-y {
flex: 1;
overflow: hidden;
overflow-y: auto;
}
table#mods {
tr {
@ -39,7 +69,35 @@
}
.dialog-buttons {
.malus-and-mod {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr;
gap: 0 8px;
label {
span {
text-align: center;
}
output {
height: 32px;
width: 100%;
line-height: 32px;
vertical-align: middle;
display: block;
padding: 0 8px;
border: 1px inset;
border-radius: 4px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
}
}
}
.actions {
align-self: center;
flex: 0;
}
}
}

View File

@ -33,8 +33,9 @@
</tr>
{{#each this.O}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}" data-action="openEmbeddedDocument">
@ -52,8 +53,9 @@
</tr>
{{#each this.I}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}" data-action="openEmbeddedDocument">
@ -72,8 +74,9 @@
</tr>
{{#each this.II}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"
@ -91,8 +94,9 @@
</tr>
{{#each this.III}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"
@ -110,8 +114,9 @@
</tr>
{{#each this.IV}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"
@ -128,8 +133,9 @@
</tr>
{{#each this.V}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"
@ -147,8 +153,9 @@
</tr>
{{#each this.VI}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"
@ -165,8 +172,9 @@
</tr>
{{#each this.VII}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"
@ -183,8 +191,9 @@
</tr>
{{#each this.VIII}}
<tr>
<td class="liturgy rollable" data-id="{{this.id}}" data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{this.deity}}">
<td class="liturgy rollable" data-action="openLiturgyDialog" data-id="{{this.id}}"
data-rank="{{this.rank}}"
data-lkp="{{../lkp}}" data-deity="{{../deity}}">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</td>
<td class="clickable" data-id="{{this.id}}"

View File

@ -0,0 +1,103 @@
<section>
<div class="attributes {{#if this.colorfulDice}}colorfulDice{{/if}}">
<hr class="zier"/>
{{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this.mu}}
{{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this.in}}
{{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this.ch}}
<hr class="zier"/>
</div>
<div class="result">
{{#if resultingLiturgy}}
<div><span>Liturgie:</span> {{resultingLiturgy.name}}</div>
<div><span>Grad:</span> {{resultingLiturgy.rank}}</div>
<div><span>Kosten:</span> {{resultingLiturgy.costKaP}} KaP {{#if resultingLiturgy.costKaPPermanent}}
(davon {{resultingLiturgy.costKaP}} permanent){{/if}}</div>
<div><span>Ziel:</span> {{resultingLiturgy.target}}</div>
<div><span>Wirkdauer:</span> {{resultingLiturgy.duration}}</div>
<div><span>Wirkzeit:</span> {{resultingLiturgy.castduration}}</div>
{{/if}}
</div>
<div class="scroll-y">
<table>
<tr>
<th>Grad</th>
<th>Wirkung</th>
</tr>
{{#each variations}}
<tr>
<th><label><input type="radio" data-action="selectVariant" data-rank="{{this.rank}}" {{checked
(eq this.rank ../variation.rank)}}>{{this.rank}}</label></th>
<td>{{this.effect}}</td>
</tr>
{{/each}}
</table>
</div>
{{#if moddingEnabled}}
<h2>Modifizieren</h2>
<table id="mods">
{{#each mods}}
<tr>
<td>{{this.displayRank}}</td>
<td>{{this.mod}}</td>
<td>
<button data-action="removeMod" data-index="{{@key}}">
<i class="fa-solid fa-xmark"></i>
</button>
</td>
</tr>
{{/each}}
</table>
<div class="editor">
<div id="mod_rank" class="rank">{{this.addingModRank}}</div>
<div class="modification">
<select name="mod" {{disabled (not canMod)}}>
<option value=""> - auswählen -</option>
<option value="range">Reichweite</option>
<option value="strength">Wirkung</option>
<option value="target">Ziele</option>
<option value="castduration">Wirkzeit</option>
<option value="duration">Wirkungsdauer</option>
</select>
<button data-action="addMod"><i class="fa fa-plus"></i></button>
<span id="info"></span>
</div>
</div>
{{/if}}
<fieldset class="modding">
<legend>Erschwernisse</legend>
<div class="malus-and-mod">
<label><span>LkP</span>
<output name="lkp" type="number">{{lkp}}</output>
</label>
<label><span>Umstände</span>
<input name="circumstance" type="number" value="{{circumstance}}">
</label>
<label><span>Modifikation</span>
<output name="penalty">{{resultingCastPenalty}}</output>
</label>
</div>
<output class="modResult"></output>
</fieldset>
<button class="actions" data-action="castLiturgy"><i class="fa-solid fa-sparkles"></i> Wirken {{#if modResult}}
[{{displayModResult}}]{{/if}}</button>
</section>

View File

@ -1,36 +0,0 @@
<table>
<tr>
<th>Grad</th>
<th>Wirkung</th>
</tr>
</th>
{{#each variations}}
<tr>
<th><label><input type="radio" name="data.variation" data-rank="{{this.rank}}">{{this.rank}}</label></th>
<td>{{this.effect}}</td>
</tr>
{{/each}}
</table>
<h2>Modifizieren</h2>
<table id="mods"></table>
<div class="editor">
<div id="mod_rank" class="rank"></div>
<div class="modification">
<select name="mod" disabled="disabled">
<option value=""> - auswählen -</option>
<option value="range">Reichweite</option>
<option value="strength">Wirkung</option>
<option value="target">Ziele</option>
<option value="castduration">Wirkzeit</option>
<option value="duration">Wirkungsdauer</option>
</select>
<span id="info"></span>
</div>
</div>
<div class="result"></div>

View File

@ -1,6 +1,5 @@
<div class="attribute rollable {{this.tooltip}}" data-name="{{this.tooltip}}" alt="{{this.tooltip}}"
data-value="{{this.wert}}"
data-label="{{this.name}}" data-roll="1d20cs<=@{{this.eigenschaft}}.aktuell">
data-value="{{this.wert}}">
<div class="die">
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }}
</div>