diff --git a/src/module/data/attribute.mjs b/src/module/data/attribute.mjs new file mode 100644 index 00000000..3c21f65f --- /dev/null +++ b/src/module/data/attribute.mjs @@ -0,0 +1,10 @@ +export const ATTRIBUTE = { + "mu": "Mut", + "kl": "Klugheit", + "in": "Intuition", + "ch": "Charisma", + "ff": "Fingerfertigkeit", + "ge": "Gewandtheit", + "ko": "Konstitution", + "kk": "Körperkraft" +} \ No newline at end of file diff --git a/src/module/data/skill.mjs b/src/module/data/skill.mjs index 4385777b..94540111 100644 --- a/src/module/data/skill.mjs +++ b/src/module/data/skill.mjs @@ -25,7 +25,7 @@ export class SkillDataModel extends BaseItem { wert: new NumberField(), }, {required: false}), // Required skills at a given level talent: new HTMLField({required: true}), - behinderung: new NumberField({required: false}), // BE-X + behinderung: new StringField({required: false}), // BE-X komplexität: new NumberField({required: false}), // In case of languages } } diff --git a/src/module/dialog/talentDialog.mjs b/src/module/dialog/talentDialog.mjs new file mode 100644 index 00000000..ff7865c1 --- /dev/null +++ b/src/module/dialog/talentDialog.mjs @@ -0,0 +1,211 @@ +import {LiturgyData} from "../data/miracle/liturgydata.mjs"; +import {Talent} from "../data/talent.mjs"; +import {ATTRIBUTE} from "../data/attribute.mjs"; + +const {ApplicationV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class TalentDialog extends HandlebarsApplicationMixin(ApplicationV2) { + + static DEFAULT_OPTIONS = { + classes: ['dsa41', 'dialog', 'talent'], + tag: "form", + position: { + width: 480, + height: 800 + }, + window: { + resizable: false, + title: "Talent nutzen" + }, + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: TalentDialog.#onSubmitForm + }, + actions: { + use: TalentDialog.#use, + } + } + + + static PARTS = { + form: { + template: 'systems/DSA_4-1/templates/dialog/talent-dialog.hbs', + } + } + + static data = {} + + /** + * + * @type {Actor} + * @private + */ + _actor = null + + constructor(actor, talentId) { + super() + this._actor = actor + this._talent = this._actor.itemTypes["Skill"].find(p => p._id === talentId) + this._circumstance = 0 + this._mods = [] + } + + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + this._circumstance = formData.object["circumstance"] + this._mods = [] + Object.entries(formData.object).filter(([key, value]) => key.startsWith("mods.")).forEach(([key, value]) => { + const [_, suffix] = key.split("mods.") + if (value != null) { + this._mods.push({ + name: suffix, + value: value + }) + } + + }) + this.render({parts: ["form"]}) + } + + + static async #use(event, target) { + + const taw = this._talent.system.taw + + let modValue = this._circumstance + this._mods.forEach(mod => { + modValue += Number(mod.value) + }) + + const payload = { + name: this._talent.name, + taw: taw, + mod: modValue, + eigenschaft1: this._talent.system.probe[0].toLowerCase(), + eigenschaft2: this._talent.system.probe[1].toLowerCase(), + eigenschaft3: this._talent.system.probe[2].toLowerCase(), + eigenschaften: {} + } + + payload.eigenschaften[this._talent.system.probe[0].toLowerCase()] = this._actor.system.attribute[this._talent.system.probe[0].toLowerCase()].aktuell + payload.eigenschaften[this._talent.system.probe[1].toLowerCase()] = this._actor.system.attribute[this._talent.system.probe[1].toLowerCase()].aktuell + payload.eigenschaften[this._talent.system.probe[2].toLowerCase()] = this._actor.system.attribute[this._talent.system.probe[2].toLowerCase()].aktuell + + const result = await new Talent(payload).evaluate("publicroll") + + result.evaluatedRoll.toMessage({ + speaker: ChatMessage.getSpeaker({actor: this._actor}), + flavor: `Talent: ${this._talent.name}
TaP*: ${result.tap}
${result.meisterlich ? "Meisterlich" : ""}${result.patzer ? "Petzer" : ""}
${this._talent.system.talent}`, + }) + + this.close() + } + + _configureRenderOptions(options) { + super._configureRenderOptions(options) + + if (options.window) { + if (this._talent) { + options.window.title = this._talent.name + } + + options.position.height = 640 + + } + + + return options + } + + + async _prepareContext(options) { + const context = await super._prepareContext(options) + context.actor = this._actor + context.talent = this._talent + context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice') + + context.text = context.talent.system.talent + + context.dice = [] + context.talent.system.probe.forEach(p => { + context.dice.push({ + wert: this._actor.system.attribute[p.toLowerCase()].aktuell, + name: p, + tooltip: ATTRIBUTE[p.toLowerCase()], + }) + }) + + context.mods = [] // ADV, DDV, SF that may influence this talent atleast BE + + const categories = ["Advantage", "SpecialAbility"] + categories.forEach(category => this._actor.itemTypes[category].forEach(adv => { + + const mods = adv.system.getActiveMod() + + mods?.forEach(mod => { + + if (mod.talent === adv.name) { + context.mods.push({ + name: adv.name, + value: mod.value, + mod: adv.name + "talent", + active: this._mods.find(mod => mod.name === adv.name + "talent") + }) + } + + if (mod.name) { + context.talent.system.probe.forEach(p => { + if (mod.name === `attribute.${p.toLowerCase()}.mod`) { + context.mods.push({ + name: adv.name, + value: mod.value, + mod: adv.name + "eigenschaft", + active: this._mods.find(mod => mod.name === adv.name + "eigenschaft") + }) + } + }) + } + + }) + + })) + + if (context.talent.system.behinderung) { // can be null + const eBE = context.talent.system.behinderung + + if (eBE === "situationsbedingt") { + context.mods.push({ + name: `Behinderung`, + value: -this._actor.system.be, + mod: "Behinderung", + active: this._mods.find(mod => mod.name === "Behinderung") + + }) + } else { + const be = eval(this._actor.system.be + eBE) // eBE can be *X, +X, -X + context.mods.push({ + name: `Behinderung (eBE${eBE})`, + value: -be, + mod: "Behinderung", + active: this._mods.find(mod => mod.name === "Behinderung") + }) + } + + } + + + context.taw = this._talent.system.taw + context.circumstance = this._circumstance + context.penalty = 0 + this._mods.forEach(mod => { + context.penalty += Number(mod.value) + }) + + context.modResult = context.taw + context.circumstance + context.penalty + context.displayModResult = context.modResult > 0 ? `+${context.modResult}` : context.modResult + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index e183890d..9d26d1c5 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -13,6 +13,7 @@ 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"; +import {TalentDialog} from "../dialog/talentDialog.mjs"; const {HandlebarsApplicationMixin, DocumentSheetV2} = foundry.applications.api const {ActorSheetV2} = foundry.applications.sheets @@ -103,10 +104,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { */ static #rollSkill(event) { const {id} = event.target.dataset - const skill = this.document.items.get(id) - if (skill?.system?.roll) { - skill.system.roll("publicroll") - } + + new TalentDialog(this.document, id).render(true) } /** @@ -481,7 +480,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { { eigenschaft: "ge", name: "GE", - tooltip: "Geschicklichkeit", + tooltip: "Gewandtheit", wert: context.derived.attribute.ge.aktuell ?? 0, }, { diff --git a/src/style/molecules/_attribute-die.scss b/src/style/molecules/_attribute-die.scss index 918be118..c5ec248a 100644 --- a/src/style/molecules/_attribute-die.scss +++ b/src/style/molecules/_attribute-die.scss @@ -97,7 +97,7 @@ } } - .Geschicklichkeit { + .Gewandtheit { .die svg path { fill: colours.$attribute-die-dx-color; diff --git a/src/style/organisms/_dialog.scss b/src/style/organisms/_dialog.scss new file mode 100644 index 00000000..2c4d6c87 --- /dev/null +++ b/src/style/organisms/_dialog.scss @@ -0,0 +1,103 @@ +@use "../molecules/attribute-die"; + +.dsa41.dialog.talent, .dsa41.dialog.eigenschaft { + + 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 { + width: 48px; + } + } + } + + .scroll-y { + flex: 1; + overflow: hidden; + overflow-y: auto; + } + + table#mods { + + tr { + th:first-child { + width: 48px; + } + } + + .remove-mod { + width: 32px; + height: 32px; + } + + } + + .editor { + + display: grid; + grid-template-columns: 48px 1fr; + + #mod_rank { + display: inline-block; + width: 48px; + } + + select { + + } + + } + + .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; + } + } +} diff --git a/src/style/styles.scss b/src/style/styles.scss index 803314b5..6c95fc74 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -33,4 +33,5 @@ @use "organisms/merchant-sheet"; @use "organisms/resting-dialog"; @use "organisms/battle-dialog"; -@use "organisms/liturgy-sheet"; \ No newline at end of file +@use "organisms/liturgy-sheet"; +@use "organisms/dialog"; \ No newline at end of file diff --git a/src/templates/dialog/talent-dialog.hbs b/src/templates/dialog/talent-dialog.hbs new file mode 100644 index 00000000..e8c0cfc2 --- /dev/null +++ b/src/templates/dialog/talent-dialog.hbs @@ -0,0 +1,57 @@ +
+ +
+ +
+ + {{#each dice}} + + {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} + + {{/each}} + +
+ +
+ +
+ {{{this.text}}} +
+ + + {{#each this.mods}} + + + + + + {{/each}} +
+ + + {{this.name}} + + {{this.value}} +
+ +
+ Erschwernisse +
+ + + +
+ +
+ + + + +
\ No newline at end of file