diff --git a/src/ActorSheet.hbs b/src/ActorSheet.hbs index 82b58d4..733a57f 100644 --- a/src/ActorSheet.hbs +++ b/src/ActorSheet.hbs @@ -39,9 +39,9 @@ {{#*inline "die-value"}}
{{#if header}}
{{header}}
{{/if}} -
+
-
{{value}}
+
{{{value}}}
{{/inline}} @@ -57,7 +57,7 @@
{{#each actor.system.attributes}} - {{>die-value type=@key header=(localize (concat "DSA41.attributes.short." @key)) value=(lookup @root.actor.system.computed.attributes.with_modifiers @key) data-roll="1d20"}} + {{>die-value type=@key header=(localize (concat "DSA41.attributes.short." @key)) value=(lookup @root.actor.system.computed.attributes @key)data-roll="1d20" data-tooltip=(lookup @root.tooltips.attributes @key)}} {{/each}}
@@ -270,9 +270,9 @@
-
{{>die-value type="attacke" data-roll="1d20" value=attacke}}
-
{{>die-value type="parade" data-roll="1d20" value=parade}}
-
{{>die-value type="trefferpunkte" data-roll=trefferpunkte}}
+
{{>die-value type="attacke" data-roll="1d20" value=attacke data-tooltip=(lookup @root.tooltips.kampf.attacke item._id)}}
+
{{>die-value type="parade" data-roll="1d20" value=parade data-tooltip=(lookup @root.tooltips.kampf.parade item._id)}}
+
{{>die-value type="trefferpunkte" data-roll=trefferpunkte value=trefferpunkte_display data-tooltip=(lookup @root.tooltips.kampf.trefferpunkte item._id)}}
{{/each}} diff --git a/src/Tooltips/Attacke.hbs b/src/Tooltips/Attacke.hbs new file mode 100644 index 0000000..49f6ca6 --- /dev/null +++ b/src/Tooltips/Attacke.hbs @@ -0,0 +1,19 @@ +
+ {{talent_attacke}}{{localize "DSA41.talente.label"}} + + {{#if (ne modifikator_attacke 0)}} + + {{modifikator_attacke}}{{localize "DSA41.bewaffnung.nahkampfwaffe.modifikator"}} + {{/if}} + + {{#if (ne parierwaffe_attacke 0)}} + + {{parierwaffe_attacke}}{{localize "DSA41.bewaffnung.parierwaffe.label"}} + {{/if}} + + {{#if (ne schild_attacke 0)}} + + {{schild_attacke}}{{localize "DSA41.bewaffnung.schild.label"}} + {{/if}} + + {{#if (lt tp_kk 0)}} + + {{tp_kk}}{{localize "DSA41.attributes.long.strength"}} + {{/if}} +
diff --git a/src/Tooltips/Attribute.hbs b/src/Tooltips/Attribute.hbs new file mode 100644 index 0000000..0c15b0f --- /dev/null +++ b/src/Tooltips/Attribute.hbs @@ -0,0 +1,9 @@ +
+ {{initial}}{{localize "DSA41.attributes.initial"}} + {{#if (ne advancement 0)}} + + {{advancement}}{{localize "DSA41.attributes.advancement"}} + {{/if}} + {{#if (ne modifier 0)}} + + {{modifier}}{{localize "DSA41.attributes.modifier"}} + {{/if}} +
diff --git a/src/Tooltips/Parade.hbs b/src/Tooltips/Parade.hbs new file mode 100644 index 0000000..db7e1c8 --- /dev/null +++ b/src/Tooltips/Parade.hbs @@ -0,0 +1,19 @@ +
+ {{talent_parade}}{{localize "DSA41.talente.label"}} + + {{#if (ne modifikator_parade 0)}} + + {{modifikator_parade}}{{localize "DSA41.bewaffnung.nahkampfwaffe.modifikator"}} + {{/if}} + + {{#if (ne parierwaffe_parade 0)}} + + {{parierwaffe_parade}}{{localize "DSA41.bewaffnung.parierwaffe.label"}} + {{/if}} + + {{#if (ne schild_parade 0)}} + + {{schild_parade}}{{localize "DSA41.bewaffnung.schild.label"}} + {{/if}} + + {{#if (lt tp_kk 0)}} + + {{tp_kk}}{{localize "DSA41.attributes.long.strength"}} + {{/if}} +
diff --git a/src/Tooltips/Trefferpunkte.hbs b/src/Tooltips/Trefferpunkte.hbs new file mode 100644 index 0000000..5633451 --- /dev/null +++ b/src/Tooltips/Trefferpunkte.hbs @@ -0,0 +1,7 @@ +
+ {{item.system.nahkampfwaffe.basis}}{{localize "DSA41.bewaffnung.nahkampfwaffe.basis"}} + + {{#if (ne tp_kk 0)}} + + {{tp_kk}}{{localize "DSA41.attributes.long.strength"}} + {{/if}} +
diff --git a/src/main.css b/src/main.css index b24d4d1..ed8c131 100644 --- a/src/main.css +++ b/src/main.css @@ -87,17 +87,17 @@ .sheet .die { display: inline-grid; - text-align: center; + text-align: center; + align-items: center; color: #fff; + + width: 48px; + height: 48px; } .sheet .die > * { grid-row: 1; grid-column: 1; - - width: 48px; - height: 48px; - line-height: 48px; } .sheet .die-courage { fill: #b22319; } @@ -230,3 +230,7 @@ .actor-sheet .kampf .ruestungen > *:last-child { border: none; } + +#tooltip:has(> .dsa41-tooltip) { + /* background-color: #678ec3; */ +} diff --git a/src/main.mjs b/src/main.mjs index 1244f83..352911f 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -1,14 +1,14 @@ Hooks.once("init", function() { CONFIG.Combat.initiative.formula = "1d6 + @computed.ini_basiswert[INI-Basiswert]"; - CONFIG.Actor.dataModels.Player = DSA41_CharacterData; - CONFIG.Actor.documentClass = DSA41_CharacterDocument; + CONFIG.Actor.dataModels.Player = DSA41_CharacterData; + CONFIG.Actor.documentClass = DSA41_CharacterDocument; - CONFIG.Item. dataModels.Gegenstand = DSA41_GegenstandData; - CONFIG.Item. dataModels.Ruestung = DSA41_RuestungData; - CONFIG.Item. dataModels.Bewaffnung = DSA41_BewaffnungData; + CONFIG.Item.dataModels.Gegenstand = DSA41_GegenstandData; + CONFIG.Item.dataModels.Ruestung = DSA41_RuestungData; + CONFIG.Item.dataModels.Bewaffnung = DSA41_BewaffnungData; - //DocumentSheetConfig.unregisterSheet(Actor, "core", ActorSheet); + DocumentSheetConfig.unregisterSheet(Actor, "core", ActorSheet); DocumentSheetConfig.registerSheet(Actor, "dsa41", DSA41_ActorSheet, { makeDefault: true, types: [ @@ -16,7 +16,7 @@ Hooks.once("init", function() { ] }); - //DocumentSheetConfig.unregisterSheet(Item, "core", ItemSheet); + DocumentSheetConfig.unregisterSheet(Item, "core", ItemSheet); DocumentSheetConfig.registerSheet(Item, "dsa41", DSA41_ItemSheet, { makeDefault: true, types: [ @@ -25,8 +25,64 @@ Hooks.once("init", function() { "Bewaffnung", ] }); + + loadTemplates({ + "attribute_tooltip": "systems/dsa-4th-edition/src/Tooltips/Attribute.hbs", + + "attacke_tooltip": "systems/dsa-4th-edition/src/Tooltips/Attacke.hbs", + "parade_tooltip": "systems/dsa-4th-edition/src/Tooltips/Parade.hbs", + "trefferpunkte_tooltip": "systems/dsa-4th-edition/src/Tooltips/Trefferpunkte.hbs", + }); }); +function get_minified_formula(formula, data) { + const terms = Roll.simplifyTerms(Roll.parse(formula, data)); + let output = []; + + let is_combinable = true; + for (let i = 0; i < terms.length; i++) { + const term = terms[i]; + + if (is_combinable && term instanceof foundry.dice.terms.NumericTerm) { + for (let j = i + 1; j < terms.length - 1; j += 2) { + let operator = terms[j]; + let next = terms[j + 1]; + + if (!(operator instanceof foundry.dice.terms.OperatorTerm && next instanceof foundry.dice.terms.NumericTerm)) + break; + + switch (operator.operator) { + case "+": { + term.number += next.number; + i += 2; + } break; + + case "-": { + term.number -= next.number; + i += 2; + } break; + + default: + break; + } + } + + is_combinable = false; + } else { + if (term instanceof foundry.dice.terms.OperatorTerm && (term.operator == "+" || term.operator == "-")) { + is_combinable = true; + } else { + is_combinable = false; + } + } + + output.push(term); + } + + output = Roll.simplifyTerms(output); + return Roll.getFormula(output); +} + const { SchemaField, NumberField, StringField, BooleanField } = foundry.data.fields; class AttributeField extends foundry.data.fields.SchemaField { @@ -231,48 +287,46 @@ class DSA41_CharacterData extends foundry.abstract.TypeDataModel { } } - prepareDerivedData() { + async prepareDerivedData() { super.prepareDerivedData(); this.computed = { - attributes: { - without_modifiers: {}, - with_modifiers: {}, - }, + attributes: {}, + attributes_without_modifiers: {}, kampf: { talente: {}, waffen: {}, ruestungen: {}, ruestungen_gesamt: { - kopf: 0, - brust: 0, - ruecken: 0, - bauch: 0, - linker_arm: 0, - rechter_arm: 0, - linkes_bein: 0, + kopf: 0, + brust: 0, + ruecken: 0, + bauch: 0, + linker_arm: 0, + rechter_arm: 0, + linkes_bein: 0, rechtes_bein: 0, gesamt_ruestungsschutz: 0.0, - gesamt_behinderung: 0.0, + gesamt_behinderung: 0.0, }, }, }; for (const [attribute, values] of Object.entries(this.attributes)) { - this.computed.attributes.without_modifiers[attribute] = values.initial + values.advancement; - this.computed.attributes.with_modifiers [attribute] = values.initial + values.advancement + values.modifier; + this.computed.attributes[attribute] = values.initial + values.advancement + values.modifier; + this.computed.attributes_without_modifiers[attribute] = values.initial + values.advancement; } - this.computed.max_lebenspunkte = Math.round((this.computed.attributes.without_modifiers.constitution + this.computed.attributes.without_modifiers.constitution + this.computed.attributes.without_modifiers.strength) / 2); - this.computed.max_ausdauer = Math.round((this.computed.attributes.without_modifiers.courage + this.computed.attributes.without_modifiers.constitution + this.computed.attributes.without_modifiers.agility) / 2); - this.computed.max_atralenergie = Math.round((this.computed.attributes.without_modifiers.courage + this.computed.attributes.without_modifiers.intuition + this.computed.attributes.without_modifiers.charisma) / 2); + this.computed.max_lebenspunkte = Math.round((this.computed.attributes_without_modifiers.constitution + this.computed.attributes_without_modifiers.constitution + this.computed.attributes_without_modifiers.strength) / 2); + this.computed.max_ausdauer = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.constitution + this.computed.attributes_without_modifiers.agility) / 2); + this.computed.max_atralenergie = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.intuition + this.computed.attributes_without_modifiers.charisma) / 2); - this.computed.magieresistenz = Math.round((this.computed.attributes.without_modifiers.courage + this.computed.attributes.without_modifiers.cleverness + this.computed.attributes.without_modifiers.constitution) / 5); - this.computed.ini_basiswert = Math.round((this.computed.attributes.without_modifiers.courage + this.computed.attributes.without_modifiers.courage + this.computed.attributes.without_modifiers.intuition + this.computed.attributes.without_modifiers.agility) / 5); - this.computed.at_basiswert = Math.round((this.computed.attributes.without_modifiers.courage + this.computed.attributes.without_modifiers.agility + this.computed.attributes.without_modifiers.strength) / 5);; - this.computed.pa_basiswert = Math.round((this.computed.attributes.without_modifiers.intuition + this.computed.attributes.without_modifiers.agility + this.computed.attributes.without_modifiers.strength) / 5);; - this.computed.fk_basiswert = Math.round((this.computed.attributes.without_modifiers.intuition + this.computed.attributes.without_modifiers.dexterity + this.computed.attributes.without_modifiers.strength) / 5);; + this.computed.magieresistenz = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.cleverness + this.computed.attributes_without_modifiers.constitution) / 5); + this.computed.ini_basiswert = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.intuition + this.computed.attributes_without_modifiers.agility) / 5); + this.computed.at_basiswert = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.agility + this.computed.attributes_without_modifiers.strength) / 5);; + this.computed.pa_basiswert = Math.round((this.computed.attributes_without_modifiers.intuition + this.computed.attributes_without_modifiers.agility + this.computed.attributes_without_modifiers.strength) / 5);; + this.computed.fk_basiswert = Math.round((this.computed.attributes_without_modifiers.intuition + this.computed.attributes_without_modifiers.dexterity + this.computed.attributes_without_modifiers.strength) / 5);; const equipped_ruestungen = this.parent.items.filter((x) => x.type === "Ruestung"); for (const item of equipped_ruestungen) { @@ -307,38 +361,60 @@ class DSA41_CharacterData extends foundry.abstract.TypeDataModel { const equipped_fernkampfwaffen = equipped_bewaffnung.filter((x) => x.system.fernkampfwaffe.aktiv); for(const item of equipped_nahkampfwaffen) { - this.computed.kampf.waffen[item._id] = { item: item }; - if (item.system.nahkampfwaffe.aktiv) { + let computed = this.computed.kampf.waffen[item._id] = { + item: item, + attacke: 0, + parade: 0, + trefferpunkte: "", + trefferpunkte_display: "", + + talent_attacke: 0, + talent_parade: 0, + + modifikator_attacke: 0, + modifikator_parade: 0, + + tp_kk: 0, + + parierwaffe_attacke: 0, + parierwaffe_parade: 0, + + schild_attacke: 0, + schild_parade: 0, + }; + const talent = item.system.nahkampfwaffe.kampftalente; - this.computed.kampf.waffen[item._id].attacke = this.computed.kampf.talente[talent].attacke + item.system.nahkampfwaffe.modifikator_attacke; - this.computed.kampf.waffen[item._id].parade = this.computed.kampf.talente[talent].parade + item.system.nahkampfwaffe.modifikator_attacke; + computed.talent_attacke = this.computed.kampf.talente[talent].attacke; + computed.talent_parade = this.computed.kampf.talente[talent].parade; + + computed.modifikator_attacke = item.system.nahkampfwaffe.modifikator_attacke; + computed.modifikator_parade = item.system.nahkampfwaffe.modifikator_parade; - const tp_kk = Math.trunc((this.computed.attributes.with_modifiers.strength - item.system.nahkampfwaffe.schwellenwert) / item.system.nahkampfwaffe.schadensschritte); - - if (tp_kk >= 0) { - this.computed.kampf.waffen[item._id].trefferpunkte = item.system.nahkampfwaffe.basis + " + " + tp_kk; - } else { - this.computed.kampf.waffen[item._id].trefferpunkte = item.system.nahkampfwaffe.basis + "" + tp_kk; - - this.computed.kampf.waffen[item._id].attacke += tp_kk; - this.computed.kampf.waffen[item._id].parade += tp_kk; + if (item.system.nahkampfwaffe.schadensschritte != 0) { + computed.tp_kk = Math.trunc((this.computed.attributes.strength - item.system.nahkampfwaffe.schwellenwert) / item.system.nahkampfwaffe.schadensschritte); } for (const parierwaffe of equipped_parierwaffen) { if (parierwaffe._id === item._id) continue; - this.computed.kampf.waffen[item._id].attacke += parierwaffe.system.parierwaffe.modifikator_attacke; - this.computed.kampf.waffen[item._id].parade += parierwaffe.system.parierwaffe.modifikator_parade; + computed.parierwaffe_attacke += parierwaffe.system.parierwaffe.modifikator_attacke; + computed.parierwaffe_parade += parierwaffe.system.parierwaffe.modifikator_parade; } for (const schild of equipped_schilde) { if (schild._id === item._id) continue; - this.computed.kampf.waffen[item._id].attacke += schild.system.schild.modifikator_attacke; - this.computed.kampf.waffen[item._id].parade += schild.system.schild.modifikator_parade; + computed.schild_attacke += schild.system.schild.modifikator_attacke; + computed.schild_parade += schild.system.schild.modifikator_parade; } + + computed.attacke = computed.talent_attacke + computed.modifikator_attacke + computed.parierwaffe_attacke + computed.schild_attacke + Math.min(computed.tp_kk, 0); + computed.parade = computed.talent_parade + computed.modifikator_parade + computed.parierwaffe_parade + computed.schild_parade + Math.min(computed.tp_kk, 0); + + computed.trefferpunkte = get_minified_formula(item.system.nahkampfwaffe.basis + (computed.tp_kk != 0 ? " + " + computed.tp_kk : "")); + computed.trefferpunkte_display = computed.trefferpunkte.replace(/[\+\-]/, (op) => "
" + op); } } } @@ -461,7 +537,32 @@ class DSA41_ActorSheet extends ActorSheet { } get template() { - return "systems/dsa-4th-edition/src/ActorSheet.html"; + return "systems/dsa-4th-edition/src/ActorSheet.hbs"; + } + + async getData() { + let data = super.getData(); + + data.tooltips = { + attributes: {}, + kampf: { + attacke: {}, + parade: {}, + trefferpunkte: {}, + } + }; + + for (const [attribute, value] of Object.entries(data.actor.system.attributes)) { + data.tooltips.attributes[attribute] = await renderTemplate("attribute_tooltip", value); + } + + for (const [id, computed] of Object.entries(data.actor.system.computed.kampf.waffen)) { + data.tooltips.kampf.attacke [id] = await renderTemplate("attacke_tooltip", computed); + data.tooltips.kampf.parade [id] = await renderTemplate("parade_tooltip", computed); + data.tooltips.kampf.trefferpunkte[id] = await renderTemplate("trefferpunkte_tooltip", computed); + } + + return data; } activateListeners(html) { @@ -506,6 +607,6 @@ class DSA41_ItemSheet extends ItemSheet { } get template() { - return "systems/dsa-4th-edition/src/ItemSheets/" + this.item.type + ".html"; + return "systems/dsa-4th-edition/src/ItemSheets/" + this.item.type + ".hbs"; } }