const { TypeDataModel } = foundry.abstract; const { SchemaField, NumberField, StringField, BooleanField } = foundry.data.fields; const { ActorSheetV2, ItemSheetV2 } = foundry.applications.sheets; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; const { OperatorTerm, NumericTerm } = foundry.dice.terms; Hooks.once("init", async function() { CONFIG.Combat.initiative.formula = "1d6 + @computed.ini_basiswert[INI-Basiswert]"; 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; DocumentSheetConfig.unregisterSheet(Actor, "core", ActorSheet); DocumentSheetConfig.registerSheet(Actor, "dsa41", DSA41_ActorSheet, { makeDefault: true, types: [ "Player", ] }); DocumentSheetConfig.unregisterSheet(Item, "core", ItemSheet); DocumentSheetConfig.registerSheet(Item, "dsa41", DSA41_ItemSheetV2, { makeDefault: true, types: [ "Gegenstand", "Ruestung", "Bewaffnung", ] }); await loadTemplates({ "editable-input": "systems/dsa-4th-edition/src/EditableInput.hbs", "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", "fernkampf_attacke_tooltip": "systems/dsa-4th-edition/src/Tooltips/FernkampfAttacke.hbs", "fernkampf_trefferpunkte_tooltip": "systems/dsa-4th-edition/src/Tooltips/FernkampfTrefferpunkte.hbs", "trefferpunkte_dialog": "systems/dsa-4th-edition/src/Dialog/Trefferpunkte.hbs", "fernkampf_angriff_dialog": "systems/dsa-4th-edition/src/Dialogs/FernkampfAngriff.hbs", "fernkampf_trefferpunkte_dialog": "systems/dsa-4th-edition/src/Dialogs/FernkampfTrefferpunkte.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 NumericTerm) { for (let j = i + 1; j < terms.length - 1; j += 2) { let operator = terms[j]; let next = terms[j + 1]; if (!(operator instanceof OperatorTerm && next instanceof 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 OperatorTerm && (term.operator == "+" || term.operator == "-")) { is_combinable = true; } else { is_combinable = false; } } output.push(term); } output = Roll.simplifyTerms(output); return Roll.getFormula(output); } class AttributeField extends SchemaField { constructor() { return super({ initial: new NumberField({ integer: true, initial: 8, min: 0 }), advancement: new NumberField({ integer: true, initial: 0, min: 0 }), modifier: new NumberField({ integer: true, initial: 0 }), }); } } class CombatTalentField extends SchemaField { constructor() { return super({ talentwert: new NumberField({ integer: true, initial: 0 }), attacke: new NumberField({ integer: true, initial: 0 }), parade: new NumberField({ integer: true, initial: 0 }), }); } } class DSA41_CharacterDocument extends Actor { } class DSA41_CharacterData extends TypeDataModel { static defineSchema() { return { race: new StringField(), culture: new StringField(), profession: new StringField(), attributes: new SchemaField({ courage: new AttributeField(), cleverness: new AttributeField(), intuition: new AttributeField(), charisma: new AttributeField(), dexterity: new AttributeField(), agility: new AttributeField(), constitution: new AttributeField(), strength: new AttributeField(), }), kampf_talente: new SchemaField({ anderthalbhaender: new CombatTalentField(), armbrust: new CombatTalentField(), belagerungswaffen: new CombatTalentField(), blasrohr: new CombatTalentField(), bogen: new CombatTalentField(), diskus: new CombatTalentField(), dolche: new CombatTalentField(), fechtwaffen: new CombatTalentField(), hiebwaffen: new CombatTalentField(), infanteriewaffen: new CombatTalentField(), kettenstaebe: new CombatTalentField(), kettenwaffen: new CombatTalentField(), lanzenreiten: new CombatTalentField(), peitsche: new CombatTalentField(), raufen: new CombatTalentField(), ringen: new CombatTalentField(), saebel: new CombatTalentField(), schleuder: new CombatTalentField(), schwerter: new CombatTalentField(), speere: new CombatTalentField(), staebe: new CombatTalentField(), wurfbeile: new CombatTalentField(), wurfmesser: new CombatTalentField(), wurfspeere: new CombatTalentField(), zweihandflegel: new CombatTalentField(), zweihand_hiebwaffen: new CombatTalentField(), zweihandschwerter: new CombatTalentField(), }), talente: new SchemaField({ koerperliche: new SchemaField({ akrobatik: new NumberField({ integer: true, initial: 0 }), athletik: new NumberField({ integer: true, initial: 0 }), fliegen: new NumberField({ integer: true, initial: 0 }), gaukeleien: new NumberField({ integer: true, initial: 0 }), klettern: new NumberField({ integer: true, initial: 0 }), koerperbeherrschung: new NumberField({ integer: true, initial: 0 }), reiten: new NumberField({ integer: true, initial: 0 }), schleichen: new NumberField({ integer: true, initial: 0 }), schwimmen: new NumberField({ integer: true, initial: 0 }), selbstbeherrschung: new NumberField({ integer: true, initial: 0 }), sich_verstecken: new NumberField({ integer: true, initial: 0 }), singen: new NumberField({ integer: true, initial: 0 }), sinnenschärfe: new NumberField({ integer: true, initial: 0 }), skifahren: new NumberField({ integer: true, initial: 0 }), stimmen_imitieren: new NumberField({ integer: true, initial: 0 }), tanzen: new NumberField({ integer: true, initial: 0 }), taschendiebstahl: new NumberField({ integer: true, initial: 0 }), zechen: new NumberField({ integer: true, initial: 0 }), }), gesellschaftliche: new SchemaField({ betoeren: new NumberField({ integer: true, initial: 0 }), etikette: new NumberField({ integer: true, initial: 0 }), gassenwissen: new NumberField({ integer: true, initial: 0 }), lehren: new NumberField({ integer: true, initial: 0 }), menschenkenntnis: new NumberField({ integer: true, initial: 0 }), schauspielerei: new NumberField({ integer: true, initial: 0 }), schriftlicher_ausdruck: new NumberField({ integer: true, initial: 0 }), sich_verkleiden: new NumberField({ integer: true, initial: 0 }), ueberreden: new NumberField({ integer: true, initial: 0 }), ueberzeugen: new NumberField({ integer: true, initial: 0 }), }), natur: new SchemaField({ faehrtensuchen: new NumberField({ integer: true, initial: 0 }), fallenstellen: new NumberField({ integer: true, initial: 0 }), fesseln: new NumberField({ integer: true, initial: 0 }), fischen: new NumberField({ integer: true, initial: 0 }), orientierung: new NumberField({ integer: true, initial: 0 }), wettervorhersage: new NumberField({ integer: true, initial: 0 }), wildnisleben: new NumberField({ integer: true, initial: 0 }), }), wissens: new SchemaField({ anatomie: new NumberField({ integer: true, initial: 0 }), baukunst: new NumberField({ integer: true, initial: 0 }), brett_kartenspiel: new NumberField({ integer: true, initial: 0 }), geographie: new NumberField({ integer: true, initial: 0 }), geschichtswissen: new NumberField({ integer: true, initial: 0 }), gesteinskunde: new NumberField({ integer: true, initial: 0 }), goetter_kulte: new NumberField({ integer: true, initial: 0 }), heraldik: new NumberField({ integer: true, initial: 0 }), huettenkunde: new NumberField({ integer: true, initial: 0 }), kriegskunst: new NumberField({ integer: true, initial: 0 }), kryptographie: new NumberField({ integer: true, initial: 0 }), magiekunde: new NumberField({ integer: true, initial: 0 }), mechanik: new NumberField({ integer: true, initial: 0 }), pflanzenkunde: new NumberField({ integer: true, initial: 0 }), philosophie: new NumberField({ integer: true, initial: 0 }), rechnen: new NumberField({ integer: true, initial: 0 }), rechtskunde: new NumberField({ integer: true, initial: 0 }), sagen_legenden: new NumberField({ integer: true, initial: 0 }), schaetzen: new NumberField({ integer: true, initial: 0 }), sprachenkunde: new NumberField({ integer: true, initial: 0 }), staatskunst: new NumberField({ integer: true, initial: 0 }), sternkunde: new NumberField({ integer: true, initial: 0 }), tierkunde: new NumberField({ integer: true, initial: 0 }), }), sprachen: new SchemaField({ lesen_schreiben: new NumberField({ integer: true, initial: 0 }), muttersprache: new NumberField({ integer: true, initial: 0 }), fremdsprache: new NumberField({ integer: true, initial: 0 }), }), handwerks: new SchemaField({ abrichten: new NumberField({ integer: true, initial: 0 }), ackerbau: new NumberField({ integer: true, initial: 0 }), alchimie: new NumberField({ integer: true, initial: 0 }), bergbau: new NumberField({ integer: true, initial: 0 }), bogenbau: new NumberField({ integer: true, initial: 0 }), boote_fahren: new NumberField({ integer: true, initial: 0 }), brauer: new NumberField({ integer: true, initial: 0 }), drucker: new NumberField({ integer: true, initial: 0 }), fahrzeug_lenken: new NumberField({ integer: true, initial: 0 }), falschspiel: new NumberField({ integer: true, initial: 0 }), feinmechanik: new NumberField({ integer: true, initial: 0 }), feuersteinbearbeitung: new NumberField({ integer: true, initial: 0 }), fleischer: new NumberField({ integer: true, initial: 0 }), gerber: new NumberField({ integer: true, initial: 0 }), glaskunst: new NumberField({ integer: true, initial: 0 }), grobschmied: new NumberField({ integer: true, initial: 0 }), handel: new NumberField({ integer: true, initial: 0 }), hauswirtschaft: new NumberField({ integer: true, initial: 0 }), heilkunde_gift: new NumberField({ integer: true, initial: 0 }), heilkunde_krankheiten: new NumberField({ integer: true, initial: 0 }), heilkunde_seele: new NumberField({ integer: true, initial: 0 }), heilkunde_wunden: new NumberField({ integer: true, initial: 0 }), holzbearbeitung: new NumberField({ integer: true, initial: 0 }), instrumentenbauer: new NumberField({ integer: true, initial: 0 }), kartographie: new NumberField({ integer: true, initial: 0 }), kochen: new NumberField({ integer: true, initial: 0 }), kristallzucht: new NumberField({ integer: true, initial: 0 }), lederarbeiten: new NumberField({ integer: true, initial: 0 }), malen_zeichnen: new NumberField({ integer: true, initial: 0 }), maurer: new NumberField({ integer: true, initial: 0 }), metallguss: new NumberField({ integer: true, initial: 0 }), musizieren: new NumberField({ integer: true, initial: 0 }), schloesser_knacken: new NumberField({ integer: true, initial: 0 }), schnapps_brennen: new NumberField({ integer: true, initial: 0 }), schneidern: new NumberField({ integer: true, initial: 0 }), seefahrt: new NumberField({ integer: true, initial: 0 }), seiler: new NumberField({ integer: true, initial: 0 }), steinmetz: new NumberField({ integer: true, initial: 0 }), juwelier: new NumberField({ integer: true, initial: 0 }), stellmacher: new NumberField({ integer: true, initial: 0 }), stoffe_faerben: new NumberField({ integer: true, initial: 0 }), taetowieren: new NumberField({ integer: true, initial: 0 }), toepfern: new NumberField({ integer: true, initial: 0 }), viehzucht: new NumberField({ integer: true, initial: 0 }), webkunst: new NumberField({ integer: true, initial: 0 }), winzer: new NumberField({ integer: true, initial: 0 }), zimmermann: new NumberField({ integer: true, initial: 0 }), }), }), } } async prepareDerivedData() { super.prepareDerivedData(); this.computed = { attributes: {}, attributes_without_modifiers: {}, kampf: { talente: {}, waffen: {}, fernkampf_waffen: {}, ruestungen: {}, ruestungen_gesamt: { 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, }, }, }; for (const [attribute, values] of Object.entries(this.attributes)) { 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.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) { this.computed.kampf.ruestungen[item._id] = { item: item }; this.computed.kampf.ruestungen_gesamt.kopf += item.system.kopf; this.computed.kampf.ruestungen_gesamt.brust += item.system.brust; this.computed.kampf.ruestungen_gesamt.ruecken += item.system.ruecken; this.computed.kampf.ruestungen_gesamt.bauch += item.system.bauch; this.computed.kampf.ruestungen_gesamt.linker_arm += item.system.linker_arm; this.computed.kampf.ruestungen_gesamt.rechter_arm += item.system.rechter_arm; this.computed.kampf.ruestungen_gesamt.linkes_bein += item.system.linkes_bein; this.computed.kampf.ruestungen_gesamt.rechtes_bein += item.system.rechtes_bein; this.computed.kampf.ruestungen_gesamt.gesamt_ruestungsschutz += item.system.gesamt_ruestungsschutz; this.computed.kampf.ruestungen_gesamt.gesamt_behinderung += item.system.gesamt_behinderung; } for (let [key, value] of Object.entries(this.computed.kampf.ruestungen_gesamt)) { this.computed.kampf.ruestungen_gesamt[key] = Math.round(value); } for(const [name, values] of Object.entries(this.kampf_talente)) { this.computed.kampf.talente[name] = {}; this.computed.kampf.talente[name].attacke = this.computed.at_basiswert + values.attacke; this.computed.kampf.talente[name].parade = this.computed.pa_basiswert + values.parade; } const equipped_bewaffnung = this.parent.items.filter((x) => x.type === "Bewaffnung"); const equipped_nahkampfwaffen = equipped_bewaffnung.filter((x) => x.system.nahkampfwaffe.aktiv); const equipped_parierwaffen = equipped_bewaffnung.filter((x) => x.system.parierwaffe.aktiv); const equipped_schilde = equipped_bewaffnung.filter((x) => x.system.schild.aktiv); const equipped_fernkampfwaffen = equipped_bewaffnung.filter((x) => x.system.fernkampfwaffe.aktiv); for(const item of equipped_nahkampfwaffen) { if (item.system.nahkampfwaffe.aktiv) { let computed = this.computed.kampf.waffen[item._id] = { item: item, attacke: 0, parade: 0, trefferpunkte: "", trefferpunkte_display: "", basis_attacke: 0, basis_parade: 0, 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, }; computed.basis_attacke = this.computed.at_basiswert; computed.basis_parade = this.computed.pa_basiswert; const talent = item.system.nahkampfwaffe.kampftalente; computed.talent_attacke = this.kampf_talente[talent]?.attacke ?? 0; computed.talent_parade = this.kampf_talente[talent]?.parade ?? 0; computed.modifikator_attacke = item.system.nahkampfwaffe.modifikator_attacke; computed.modifikator_parade = item.system.nahkampfwaffe.modifikator_parade; 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; 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; computed.schild_attacke += schild.system.schild.modifikator_attacke; computed.schild_parade += schild.system.schild.modifikator_parade; } computed.attacke = computed.basis_attacke + computed.talent_attacke + computed.modifikator_attacke + computed.parierwaffe_attacke + computed.schild_attacke + Math.min(computed.tp_kk, 0); computed.parade = computed.basis_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); } } for (const item of equipped_fernkampfwaffen) { let computed = this.computed.kampf.fernkampf_waffen[item._id] = { item: item, attacke: 0, trefferpunkte: "", trefferpunkte_display: "", basis_attacke: 0, talent_attacke: 0, }; computed.basis_attacke = this.computed.fk_basiswert; const talent = item.system.nahkampfwaffe.kampftalente; computed.talent_attacke = this.kampf_talente[talent]?.attacke ?? 0; computed.attacke = computed.basis_attacke + computed.talent_attacke; computed.trefferpunkte = get_minified_formula(item.system.fernkampfwaffe.basis); computed.trefferpunkte_display = computed.trefferpunkte.replace(/[\+\-]/, (op) => "
" + op); } } } class DSA41_GegenstandData extends TypeDataModel { static defineSchema() { return { gewicht: new NumberField({ integer: false, initial: 0, min: 0 }), preis: new NumberField({ integer: true, initial: 0, min: 0 }), }; } } class DSA41_RuestungData extends TypeDataModel { static defineSchema() { return { gewicht: new NumberField({ integer: false, initial: 0, min: 0 }), preis: new NumberField({ integer: true, initial: 0, min: 0 }), kopf: new NumberField({ integer: true, initial: 0, min: 0 }), brust: new NumberField({ integer: true, initial: 0, min: 0 }), ruecken: new NumberField({ integer: true, initial: 0, min: 0 }), bauch: new NumberField({ integer: true, initial: 0, min: 0 }), linker_arm: new NumberField({ integer: true, initial: 0, min: 0 }), rechter_arm: new NumberField({ integer: true, initial: 0, min: 0 }), linkes_bein: new NumberField({ integer: true, initial: 0, min: 0 }), rechtes_bein: new NumberField({ integer: true, initial: 0, min: 0 }), gesamt_ruestungsschutz: new NumberField({ integer: false, initial: 0, min: 0 }), gesamt_behinderung: new NumberField({ integer: false, initial: 0, min: 0 }), }; } } class DSA41_BewaffnungData extends TypeDataModel { static defineSchema() { return { gewicht: new NumberField({ integer: false, initial: 0, min: 0 }), preis: new NumberField({ integer: true, initial: 0, min: 0 }), angelegt: new BooleanField(), nahkampfwaffe: new SchemaField({ aktiv: new BooleanField(), basis: new StringField(), schwellenwert: new NumberField({ integer: true, initial: 0, min: 0 }), schadensschritte: new NumberField({ integer: true, initial: 0, min: 0 }), modifikator_attacke: new NumberField({ integer: true, initial: 0 }), modifikator_parade: new NumberField({ integer: true, initial: 0 }), initiative: new NumberField({ integer: true, initial: 0 }), bruchfaktor: new NumberField({ integer: true, initial: 0 }), distanzklasse: new StringField(), kampftalente: new StringField(), laenge: new NumberField({ integer: true, initial: 0, min: 0 }), zweihaendig: new BooleanField(), werfbar: new BooleanField(), improvisiert: new BooleanField(), priviligiert: new BooleanField(), }), parierwaffe: new SchemaField({ aktiv: new BooleanField(), modifikator_attacke: new NumberField({ integer: true, initial: 0 }), modifikator_parade: new NumberField({ integer: true, initial: 0 }), initiative: new NumberField({ integer: true, initial: 0 }), bruchfaktor: new NumberField({ integer: true, initial: 0 }), }), schild: new SchemaField({ aktiv: new BooleanField(), groesse: new StringField(), modifikator_attacke: new NumberField({ integer: true, initial: 0 }), modifikator_parade: new NumberField({ integer: true, initial: 0 }), initiative: new NumberField({ integer: true, initial: 0 }), bruchfaktor: new NumberField({ integer: true, initial: 0 }), }), fernkampfwaffe: new SchemaField({ aktiv: new BooleanField(), basis: new StringField({ initial: "1d6 + 1" }), laden: new NumberField({ integer: true, initial: 0 }), reichweite1: new NumberField({ integer: true, initial: 0 }), reichweite2: new NumberField({ integer: true, initial: 0 }), reichweite3: new NumberField({ integer: true, initial: 0 }), reichweite4: new NumberField({ integer: true, initial: 0 }), reichweite5: new NumberField({ integer: true, initial: 0 }), modifikator1: new NumberField({ integer: true, initial: 0, nullable: true }), modifikator2: new NumberField({ integer: true, initial: 0, nullable: true }), modifikator3: new NumberField({ integer: true, initial: 0, nullable: true }), modifikator4: new NumberField({ integer: true, initial: 0, nullable: true }), modifikator5: new NumberField({ integer: true, initial: 0, nullable: true }), munitionskosten: new NumberField({ integer: true, initial: 0 }), munitionsgewicht: new NumberField({ integer: true, initial: 0 }), }), }; } } function DSA41_ApplicationMixin(BaseApplication) { class DSA41_Application extends HandlebarsApplicationMixin(BaseApplication) { static DEFAULT_OPTIONS= { classes: [ "DSA41" ], window: { resizable: true }, form: { submitOnChange: true }, }; async _prepareContext(options) { return this; } } return DSA41_Application; } class DSA41_Dialog extends DSA41_ApplicationMixin(ApplicationV2) { static PARTS = { Parade: { template: "systems/dsa-4th-edition/src/Dialogs/Parade.hbs" }, Trefferpunkte: { template: "systems/dsa-4th-edition/src/Dialogs/Trefferpunkte.hbs" }, FernkampfAngriff: { template: "systems/dsa-4th-edition/src/Dialogs/FernkampfAngriff.hbs" }, FernkampfTrefferpunkte: { template: "systems/dsa-4th-edition/src/Dialogs/FernkampfTrefferpunkte.hbs" }, footer: { template: "templates/generic/form-footer.hbs" }, }; static DEFAULT_OPTIONS = { classes: [ "DSA41", "Dialog" ], window: { title: "Dialog", minimizable: false, resizable: false }, tag: "form", form: { closeOnSubmit: false, submitOnChange: true, } }; get formData() { const data = Object.fromEntries( new FormData(this.element).entries().map(([key, value])=>{ if (typeof value != "string") return [key, value]; return isNaN(value) ? [key, value] : [key, Number(value)]; }) ); return data; } buttons = [{ type: "submit", label: "Confirm" }]; static async wait(dialog_type, options) { return new Promise((resolve, reject) => { const dialog = new this({ dialog_type: dialog_type, form: { handler: (event, form, formData) => { if (event.type != "submit") { dialog.render({ force: false }); return; } dialog.close(); resolve(dialog.formData); } }, ...options, }); dialog.render({ force: true }); }); } _configureRenderOptions(options) { super._configureRenderOptions(options); options.parts = [ this.options.dialog_type, "footer" ]; } _onFirstRender(context, options) { this.render(options) } } class DSA41_ActorSheet extends DSA41_ApplicationMixin(ActorSheetV2) { static PARTS = { ActorSheet: { template: "systems/dsa-4th-edition/src/ActorSheet.hbs" }, }; static DEFAULT_OPTIONS = { position: { width: "800", height: "650" }, actions: { "roll": async function(event, target) { var roll_formula = event.target.closest("[data-roll]").dataset.roll; const roll_type = event.target.closest("[data-roll-type]").dataset.rollType; const success_value = event.target.closest("[data-success-value]")?.dataset.successValue; const item_id = event.target.closest("[data-item-id]")?.dataset.itemId; const item = this.document.items.get(item_id); let flavor = game.i18n.localize("DSA41.roll_types." + roll_type); if (typeof success_value !== 'undefined') { flavor += " <= " + success_value; } if (roll_type == "parade") { const item = this.document.system.computed.kampf.waffen[item_id]; const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + item.name; const data = await DSA41_Dialog.wait("Parade", { window: { title: title }, item: item }); if (data.crit == "on") { roll_formula = "round((" + roll_formula + ") / 2)"; } let roll = new Roll(roll_formula + " + " + data.modifikator, this.document.system); roll.toMessage({ speaker: ChatMessage.getSpeaker({ actor: this.document }), flavor: flavor, }); return; } if (roll_type == "trefferpunkte") { const item = this.document.system.computed.kampf.waffen[item_id]; const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + item.name; const data = await DSA41_Dialog.wait("Trefferpunkte", { window: { title: title }, item: item }); if (data.crit == "on") { roll_formula = "2 * (" + item.item.system.nahkampfwaffe.basis + ")" + " + " + item.tp_kk; } let roll = new Roll(roll_formula + " + " + data.modifikator, this.document.system); roll.toMessage({ speaker: ChatMessage.getSpeaker({ actor: this.document }), flavor: flavor, }); return; } if (roll_type == "fernkampf-attacke") { const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + item.name; const data = await DSA41_Dialog.wait("FernkampfAngriff", { window: { title: title }, item: this.document.system.computed.kampf.fernkampf_waffen[item_id] }); const groessen_modifikator = Math.max(data.ziel_groesse + data.deckung + data.ziel_bewegung, -2); const andere_modifikator = data.entfernung + data.wind + data.modifikator; const total_modifikator = groessen_modifikator + andere_modifikator; let roll = new Roll(roll_formula + " + " + total_modifikator, this.document.system); roll.toMessage({ speaker: ChatMessage.getSpeaker({ actor: this.document }), flavor: game.i18n.localize("DSA41.roll_types." + roll_type), }); return; } if (roll_type == "fernkampf-trefferpunkte") { const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + item.name; const data = await DSA41_Dialog.wait("FernkampfTrefferpunkte", { window: { title: title }, item: this.document.system.computed.kampf.fernkampf_waffen[item_id] }); const entfernung = item.system.fernkampfwaffe[data.entfernung]; if (data.crit == "on") { roll_formula = "2 * (" + roll_formula + ")"; } let roll = new Roll(roll_formula + " + " + (entfernung + data.modifikator), this.document.system); roll.toMessage({ speaker: ChatMessage.getSpeaker({ actor: this.document }), flavor: game.i18n.localize("DSA41.roll_types." + roll_type), }); return; } let roll = new Roll(roll_formula, this.document.system); roll.toMessage({ speaker: ChatMessage.getSpeaker({ actor: this.document }), flavor: flavor, }); }, "item-open": async function(event, target) { const item_id = event.target.closest("[data-item-id]").dataset.itemId; const item = this.document.items.get(item_id); item.sheet.render(true) }, "item-delete": async function(event, target) { const item_id = event.target.closest("[data-item-id]").dataset.itemId; const item = this.document.items.get(item_id); item.delete(); }, }, }; _onFirstRender(context, options) { super._onFirstRender(context, options); const content = this.element.querySelector(".window-content"); content.addEventListener("drop", async (event) => { event.preventDefault(); const data = TextEditor.getDragEventData(event); switch (data.type) { case "Item": { const item = await Item.implementation.fromDropData(data); await this.actor.createEmbeddedDocuments("Item", [item.toObject()]); } break; } }); } tabGroups = { primary: "tab1" }; } class DSA41_ItemSheetV2 extends DSA41_ApplicationMixin(ItemSheetV2) { static PARTS = { Bewaffnung: { template: "systems/dsa-4th-edition/src/ItemSheets/Bewaffnung.hbs" }, Gegenstand: { template: "systems/dsa-4th-edition/src/ItemSheets/Gegenstand.hbs" }, Ruestung: { template: "systems/dsa-4th-edition/src/ItemSheets/Ruestung.hbs" }, }; static DEFAULT_OPTIONS = { position: { width: "600", height: "auto" }, }; tabGroups = { primary: "tab1" }; _configureRenderOptions(options) { super._configureRenderOptions(options); options.parts = [ this.options.document.type ]; } }