From 307307d2714e60b9ebb3607208476757dda26543 Mon Sep 17 00:00:00 2001
From: Sven Balzer <4653051+Kyuusokuna@users.noreply.github.com>
Date: Wed, 30 Oct 2024 17:57:25 +0100
Subject: [PATCH] add tooltips for attributes and combat rolls
---
src/ActorSheet.hbs | 12 +-
src/Tooltips/Attacke.hbs | 19 ++++
src/Tooltips/Attribute.hbs | 9 ++
src/Tooltips/Parade.hbs | 19 ++++
src/Tooltips/Trefferpunkte.hbs | 7 ++
src/main.css | 14 ++-
src/main.mjs | 199 +++++++++++++++++++++++++--------
7 files changed, 219 insertions(+), 60 deletions(-)
create mode 100644 src/Tooltips/Attacke.hbs
create mode 100644 src/Tooltips/Attribute.hbs
create mode 100644 src/Tooltips/Parade.hbs
create mode 100644 src/Tooltips/Trefferpunkte.hbs
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}}
+
+ {{#if (ne modifikator_attacke 0)}}
+ + {{modifikator_attacke}}
+ {{/if}}
+
+ {{#if (ne parierwaffe_attacke 0)}}
+ + {{parierwaffe_attacke}}
+ {{/if}}
+
+ {{#if (ne schild_attacke 0)}}
+ + {{schild_attacke}}
+ {{/if}}
+
+ {{#if (lt tp_kk 0)}}
+ + {{tp_kk}}
+ {{/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}}
+ {{#if (ne advancement 0)}}
+ + {{advancement}}
+ {{/if}}
+ {{#if (ne modifier 0)}}
+ + {{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}}
+
+ {{#if (ne modifikator_parade 0)}}
+ + {{modifikator_parade}}
+ {{/if}}
+
+ {{#if (ne parierwaffe_parade 0)}}
+ + {{parierwaffe_parade}}
+ {{/if}}
+
+ {{#if (ne schild_parade 0)}}
+ + {{schild_parade}}
+ {{/if}}
+
+ {{#if (lt tp_kk 0)}}
+ + {{tp_kk}}
+ {{/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}}
+
+ {{#if (ne tp_kk 0)}}
+ + {{tp_kk}}
+ {{/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";
}
}