1172 lines
51 KiB
JavaScript
1172 lines
51 KiB
JavaScript
const { TypeDataModel } = foundry.abstract;
|
|
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
|
const { DocumentSheetConfig } = foundry.applications.apps;
|
|
const { loadTemplates, renderTemplate } = foundry.applications.handlebars;
|
|
const { ActorSheetV2, ItemSheetV2 } = foundry.applications.sheets;
|
|
const { Notifications } = foundry.applications.ui;
|
|
const { SchemaField, NumberField, StringField, BooleanField } = foundry.data.fields;
|
|
const { Roll } = foundry.dice;
|
|
const { OperatorTerm, NumericTerm } = foundry.dice.terms;
|
|
const { ChatMessage } = foundry.documents;
|
|
|
|
Hooks.once("i18nInit", async function() {
|
|
const lang = game.i18n.lang;
|
|
|
|
await game.i18n.setLanguage("de");
|
|
const fallback = game.i18n.translations;
|
|
await game.i18n.setLanguage(lang);
|
|
|
|
game.i18n._fallback = foundry.utils.mergeObject(fallback, game.i18n.fallback);
|
|
});
|
|
|
|
class DSA41_Notifications extends Notifications {
|
|
notify(message, type="info", {localize=false, permanent=false, console=true}={}) {
|
|
if (permanent && message === "ERROR.RESOLUTION.Window")
|
|
return;
|
|
|
|
return super.notify(message, type, { localize, permanent, console });
|
|
}
|
|
}
|
|
|
|
Hooks.once("init", async function() {
|
|
// CONFIG.debug.applications = true;
|
|
// CONFIG.debug.combat = true;
|
|
// CONFIG.debug.dice = true;
|
|
// CONFIG.debug.documents = true;
|
|
// CONFIG.debug.hooks = true;
|
|
// CONFIG.debug.rollParsing = true;
|
|
|
|
// CONFIG.ActiveEffect.documentClass = ActiveEffect;
|
|
// CONFIG.ActiveEffect.legacyTransferral = false;
|
|
|
|
CONFIG.ui.notifications = DSA41_Notifications
|
|
|
|
CONFIG.Actor.dataModels.Player = DSA41_CharacterData;
|
|
CONFIG.Actor.documentClass = DSA41_CharacterDocument;
|
|
|
|
CONFIG.ChatMessage.documentClass = DSA41_ChatMessage;
|
|
|
|
CONFIG.Combat.initiative.formula = "1d6 + @computed.initiative.wert";
|
|
|
|
CONFIG.Item.dataModels.Gegenstand = DSA41_GegenstandData;
|
|
CONFIG.Item.dataModels.Ruestung = DSA41_RuestungData;
|
|
CONFIG.Item.dataModels.Bewaffnung = DSA41_BewaffnungData;
|
|
CONFIG.Item.dataModels.Talent = DSA41_TalentData;
|
|
CONFIG.Item.dataModels.Kampftalent = DSA41_KampftalentData;
|
|
CONFIG.Item.dataModels.Sonderfertigkeit = DSA41_SonderfertigkeitData;
|
|
CONFIG.Item.dataModels.VorNachteil = DSA41_VorNachteilData;
|
|
|
|
CONFIG.statusEffects = [];
|
|
|
|
DocumentSheetConfig.registerSheet(Actor, "dsa41", DSA41_ActorSheet, {
|
|
makeDefault: true,
|
|
types: [
|
|
"Player",
|
|
]
|
|
});
|
|
|
|
DocumentSheetConfig.registerSheet(Item, "dsa41", DSA41_ItemSheetV2, {
|
|
makeDefault: true,
|
|
types: [
|
|
"Gegenstand",
|
|
"Ruestung",
|
|
"Bewaffnung",
|
|
"Talent",
|
|
"Kampftalent",
|
|
"Sonderfertigkeit",
|
|
"VorNachteil",
|
|
]
|
|
});
|
|
|
|
Handlebars.registerHelper({
|
|
maybeLocalize: (value, options) => {
|
|
const prefix = options.hash.prefix ? options.hash.prefix.string : null;
|
|
if (prefix) {
|
|
const id = prefix + "." + value;
|
|
const localized = game.i18n.localize(id);
|
|
|
|
return id === localized ? value : localized;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
});
|
|
|
|
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",
|
|
|
|
"CHAT_HEADER": "systems/dsa-4th-edition/src/Chat/Header.hbs",
|
|
"TrefferpunkteTargets": "systems/dsa-4th-edition/src/Chat/TrefferpunkteTargets.hbs",
|
|
"talent_chat": "systems/dsa-4th-edition/src/Chat/Talent.hbs",
|
|
});
|
|
});
|
|
|
|
function get_targeted_actors() {
|
|
const targets = [];
|
|
|
|
for (const token of game.user.targets) {
|
|
if (token.actor) {
|
|
targets.push(token.actor.uuid);
|
|
}
|
|
}
|
|
|
|
return targets;
|
|
}
|
|
|
|
async function instantiateTemplate(template, context) {
|
|
const html = await renderTemplate(template, context);
|
|
|
|
const template_element = document.createElement("template");
|
|
template_element.innerHTML = html;
|
|
|
|
return template_element.content.firstChild;
|
|
}
|
|
|
|
class DSA41_ChatMessage extends ChatMessage {
|
|
get actor() {
|
|
if (this.speaker.scene && this.speaker.token) {
|
|
const scene = game.scenes.get(this.speaker.scene);
|
|
const token = scene?.tokens.get(this.speaker.token);
|
|
if (token) return token.actor;
|
|
}
|
|
|
|
return game.actors.get(this.speaker.actor);
|
|
}
|
|
|
|
async renderHTML({ canDelete, canClose=false, ...rest }={}) {
|
|
const html = await super.renderHTML({ canDelete, canClose, ...rest });
|
|
|
|
const img = this.actor?.img ?? this.author.avatar;
|
|
const name = this.alias;
|
|
const header = await instantiateTemplate("CHAT_HEADER", { img: img, name: name, author: this.author?.name ?? "" });
|
|
|
|
const sender = html.querySelector(".message-sender");
|
|
sender?.replaceChildren(header);
|
|
|
|
if (this.flags.dsa41?.type === "trefferpunkte" && this.flags.dsa41?.targets?.length != 0) {
|
|
const targets = this.flags.dsa41?.targets.map(x => fromUuidSync(x, { strict: false })).filter(x => x !== null);
|
|
const targets_list = await instantiateTemplate("TrefferpunkteTargets", targets);
|
|
|
|
html.querySelector(".message-content")?.appendChild(targets_list);
|
|
}
|
|
|
|
for (const element of html.querySelectorAll("[data-action]")) {
|
|
element.addEventListener("click", async event => {
|
|
const target = event.target;
|
|
const action = target.dataset.action;
|
|
if (action === null) return;
|
|
|
|
if (action === "apply_damage") {
|
|
const target_actor_id = target.closest("[data-actor-id]")?.dataset.actorId;
|
|
if (!target_actor_id) return;
|
|
|
|
const target_actor = fromUuidSync(target_actor_id);
|
|
if (!target_actor) return;
|
|
|
|
const dialog_data = await DSA41_Dialog.wait("Trefferzone", { window: {title: "Trefferzone"} });
|
|
const trefferzone = dialog_data.trefferzone;
|
|
|
|
const rolled_damage = this.rolls[0].total;
|
|
const target_hp = target_actor.system.lebenspunkte.aktuell;
|
|
const target_rs = target_actor.system.computed.kampf.ruestungen_gesamt[trefferzone];
|
|
|
|
const damage = Math.max(rolled_damage - target_rs, 0);
|
|
const new_hp = target_hp - damage;
|
|
|
|
target_actor.update({ "system.lebenspunkte.aktuell": new_hp });
|
|
}
|
|
});
|
|
}
|
|
|
|
return html;
|
|
}
|
|
}
|
|
|
|
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 DSA41_CharacterDocument extends Actor {
|
|
static async create(data, operation) {
|
|
const actor = await super.create(data, operation);
|
|
|
|
if (data.type === "Player") {
|
|
actor.prototypeToken.update({ actorLink: true });
|
|
|
|
const talente_compendium = game.packs.get("dsa-4th-edition.talente");
|
|
const talente = await talente_compendium.getDocuments({ name__in: [
|
|
// Basis Körperliche Talente
|
|
"Athletik",
|
|
"Klettern",
|
|
"Körperbeherrschung",
|
|
"Schleichen",
|
|
"Schwimmen",
|
|
"Selbstbeherrschung",
|
|
"Sich Verstecken",
|
|
"Singen",
|
|
"Sinnenschärfe",
|
|
"Tanzen",
|
|
"Zechen",
|
|
|
|
// Basis Gesellschaftliche Talente
|
|
"Menschenkenntnis",
|
|
"Überreden",
|
|
|
|
// Basis Natur Talente
|
|
"Fährtensuchen",
|
|
"Orientierung",
|
|
"Wildnisleben",
|
|
|
|
// Basis Wissens Talente
|
|
"Götter/Kulte",
|
|
"Rechnen",
|
|
"Sagen/Legenden",
|
|
|
|
// Basis Handwerks Talente
|
|
"Heilkunde Wunden",
|
|
"Holzbearbeitung",
|
|
"Kochen",
|
|
"Lederarbeiten",
|
|
"Malen/Zeichnen",
|
|
"Schneidern",
|
|
|
|
// Basis Kampftalente
|
|
"Dolche",
|
|
"Hiebwaffen",
|
|
"Raufen",
|
|
"Ringen",
|
|
"Säbel",
|
|
"Wurfmesser",
|
|
]});
|
|
|
|
await actor.createEmbeddedDocuments("Item", talente);
|
|
}
|
|
|
|
return actor;
|
|
}
|
|
}
|
|
|
|
class DSA41_CharacterData extends TypeDataModel {
|
|
static defineSchema() {
|
|
return {
|
|
race: new StringField(),
|
|
culture: new StringField(),
|
|
profession: new StringField(),
|
|
sozialstatus: new NumberField({ integer: true, inital: 1 }),
|
|
|
|
abenteuerpunkte: new SchemaField({
|
|
ausgegeben: new NumberField({ integer: true, initial: 0 }),
|
|
gesamt: new NumberField({ integer: true, initial: 0 }),
|
|
}),
|
|
|
|
currency: new SchemaField({
|
|
dukaten: new NumberField({ integer: true, initial: 0 }),
|
|
silbertaler: new NumberField({ integer: true, initial: 0 }),
|
|
heller: new NumberField({ integer: true, initial: 0 }),
|
|
kreuzer: new NumberField({ integer: true, initial: 0 }),
|
|
}),
|
|
|
|
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(),
|
|
}),
|
|
|
|
lebenspunkte: new SchemaField({
|
|
modifikator: new NumberField({integer: true, initial: 0}),
|
|
zukauf: new NumberField({integer: true, initial: 0}),
|
|
verlust: new NumberField({integer: true, initial: 0}),
|
|
|
|
aktuell: new NumberField({integer: true, initial: 0}),
|
|
}),
|
|
|
|
ausdauer: new SchemaField({
|
|
modifikator: new NumberField({integer: true, initial: 0}),
|
|
zukauf: new NumberField({integer: true, initial: 0}),
|
|
verlust: new NumberField({integer: true, initial: 0}),
|
|
|
|
aktuell: new NumberField({integer: true, initial: 0}),
|
|
}),
|
|
|
|
astralenergie: new SchemaField({
|
|
modifikator: new NumberField({integer: true, initial: 0}),
|
|
zukauf: new NumberField({integer: true, initial: 0}),
|
|
verlust: new NumberField({integer: true, initial: 0}),
|
|
|
|
aktuell: new NumberField({integer: true, initial: 0}),
|
|
}),
|
|
|
|
karmalenergie: new NumberField({integer: true, inital: 0}),
|
|
|
|
magieresistenz: new SchemaField({
|
|
modifikator: new NumberField({integer: true, initial: 0}),
|
|
zukauf: new NumberField({integer: true, initial: 0}),
|
|
|
|
aktuell: new NumberField({integer: true, initial: 0}),
|
|
}),
|
|
|
|
modifikator_initiative: new NumberField({integer: true, initial: 0}),
|
|
modifikator_attacke: new NumberField({integer: true, initial: 0}),
|
|
modifikator_parade: new NumberField({integer: true, initial: 0}),
|
|
modifikator_fernkampf: new NumberField({integer: true, initial: 0}),
|
|
}
|
|
}
|
|
|
|
async prepareDerivedData() {
|
|
super.prepareDerivedData();
|
|
this.computed = {
|
|
abenteuerpunkte: {},
|
|
attributes: {},
|
|
attributes_without_modifiers: {},
|
|
|
|
num_vorteile: 0,
|
|
num_nachteile: 0,
|
|
num_allgemeine_sonderfertigkeiten: 0,
|
|
num_kampf_sonderfertigkeiten: 0,
|
|
num_waffen: 0,
|
|
num_fernkampf_waffen: 0,
|
|
|
|
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,
|
|
},
|
|
},
|
|
};
|
|
|
|
this.computed.abenteuerpunkte.uebrig = this.abenteuerpunkte.gesamt - this.abenteuerpunkte.ausgegeben;
|
|
|
|
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.lebenspunkte = {};
|
|
this.computed.ausdauer = {};
|
|
this.computed.astralenergie = {};
|
|
this.computed.magieresistenz = {};
|
|
|
|
this.computed.lebenspunkte.basiswert = Math.round((this.computed.attributes_without_modifiers.constitution + this.computed.attributes_without_modifiers.constitution + this.computed.attributes_without_modifiers.strength) / 2);
|
|
this.computed.ausdauer.basiswert = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.constitution + this.computed.attributes_without_modifiers.agility) / 2);
|
|
this.computed.astralenergie.basiswert = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.intuition + this.computed.attributes_without_modifiers.charisma) / 2);
|
|
this.computed.magieresistenz.basiswert = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.cleverness + this.computed.attributes_without_modifiers.constitution) / 5);
|
|
|
|
this.computed.lebenspunkte.max = this.computed.lebenspunkte.basiswert + this.lebenspunkte.modifikator + this.lebenspunkte.zukauf - this.lebenspunkte.verlust;
|
|
this.computed.ausdauer.max = this.computed.ausdauer.basiswert + this.ausdauer.modifikator + this.ausdauer.zukauf - this.ausdauer.verlust;
|
|
this.computed.astralenergie.max = this.computed.astralenergie.basiswert + this.astralenergie.modifikator + this.astralenergie.zukauf - this.astralenergie.verlust;
|
|
this.computed.magieresistenz.max = this.computed.magieresistenz.basiswert + this.magieresistenz.modifikator + this.magieresistenz.zukauf;
|
|
|
|
this.computed.lebenspunkte.prozent = this.lebenspunkte.aktuell / this.computed.lebenspunkte.max * 100;
|
|
this.computed.ausdauer.prozent = this.ausdauer.aktuell / this.computed.ausdauer.max * 100;
|
|
this.computed.astralenergie.prozent = this.astralenergie.aktuell / this.computed.astralenergie.max * 100;
|
|
this.computed.magieresistenz.prozent = this.magieresistenz.aktuell / this.computed.magieresistenz.max * 100;
|
|
|
|
this.computed.initiative = {};
|
|
this.computed.attacke = {};
|
|
this.computed.parade = {};
|
|
this.computed.fernkampf = {};
|
|
|
|
this.computed.initiative.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.attacke.basiswert = Math.round((this.computed.attributes_without_modifiers.courage + this.computed.attributes_without_modifiers.agility + this.computed.attributes_without_modifiers.strength) / 5);
|
|
this.computed.parade.basiswert = Math.round((this.computed.attributes_without_modifiers.intuition + this.computed.attributes_without_modifiers.agility + this.computed.attributes_without_modifiers.strength) / 5);
|
|
this.computed.fernkampf.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" && x.system.angelegt === true);
|
|
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;
|
|
}
|
|
|
|
this.computed.initiative.wert = this.computed.initiative.basiswert + this.modifikator_initiative - this.computed.kampf.ruestungen_gesamt.gesamt_behinderung;
|
|
this.computed.attacke.wert = this.computed.attacke.basiswert + this.modifikator_attacke;
|
|
this.computed.parade.wert = this.computed.parade.basiswert + this.modifikator_parade;
|
|
this.computed.fernkampf.wert = this.computed.fernkampf.basiswert + this.modifikator_fernkampf;
|
|
|
|
for (let [key, value] of Object.entries(this.computed.kampf.ruestungen_gesamt)) {
|
|
this.computed.kampf.ruestungen_gesamt[key] = Math.round(value);
|
|
}
|
|
|
|
this.kampftalente = this.parent.items.filter((x) => x.type === "Kampftalent").sort((a, b) => a.name > b.name);
|
|
for(const talent of this.kampftalente) {
|
|
this.computed.kampf.talente[talent.name] = {};
|
|
this.computed.kampf.talente[talent.name].attacke = this.computed.attacke.wert + talent.system.attacke;
|
|
this.computed.kampf.talente[talent.name].parade = this.computed.parade.wert + talent.system.parade;
|
|
|
|
this.computed.kampf.talente[talent.name].talent_attacke = talent.system.attacke;
|
|
this.computed.kampf.talente[talent.name].talent_parade = talent.system.parade;
|
|
}
|
|
|
|
const equipped_bewaffnung = this.parent.items.filter((x) => x.type === "Bewaffnung" && x.system.angelegt === true);
|
|
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) {
|
|
this.computed.num_waffen += 1;
|
|
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.attacke.wert;
|
|
computed.basis_parade = this.computed.parade.wert;
|
|
|
|
const talent = item.system.nahkampfwaffe.kampftalente;
|
|
|
|
computed.talent_attacke = this.computed.kampf.talente[talent]?.talent_attacke ?? 0;
|
|
computed.talent_parade = this.computed.kampf.talente[talent]?.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) => "<br>" + op);
|
|
}
|
|
}
|
|
|
|
for (const item of equipped_fernkampfwaffen) {
|
|
this.computed.num_fernkampf_waffen += 1;
|
|
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.fernkampf.wert;
|
|
|
|
const talent = item.system.nahkampfwaffe.kampftalente;
|
|
computed.talent_attacke = this.computed.kampf.talente[talent]?.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) => "<br>" + op);
|
|
}
|
|
|
|
const talente = this.parent.items.filter((x) => x.type === "Talent").sort((a, b) => a.name > b.name);
|
|
this.talente = {
|
|
koerperliche: talente.filter((x) => x.system.kategorie === "koerperliche"),
|
|
gesellschaftliche: talente.filter((x) => x.system.kategorie === "gesellschaftliche"),
|
|
natur: talente.filter((x) => x.system.kategorie === "natur"),
|
|
wissens: talente.filter((x) => x.system.kategorie === "wissens"),
|
|
handwerks: talente.filter((x) => x.system.kategorie === "handwerks"),
|
|
};
|
|
|
|
this.computed.num_allgemeine_sonderfertigkeiten = this.parent.items.filter((x) => x.type === "Sonderfertigkeit" && x.system.kategorie === "allgemein").length;
|
|
this.computed.num_kampf_sonderfertigkeiten = this.parent.items.filter((x) => x.type === "Sonderfertigkeit" && x.system.kategorie === "kampf").length;
|
|
this.computed.num_vorteile = this.parent.items.filter((x) => x.type === "VorNachteil" && x.system.kategorie === "vorteil").length;
|
|
this.computed.num_nachteile = this.parent.items.filter((x) => x.type === "VorNachteil" && x.system.kategorie === "nachteil").length;
|
|
}
|
|
}
|
|
|
|
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 {
|
|
angelegt: new BooleanField({ initial: false }),
|
|
|
|
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 {
|
|
angelegt: new BooleanField({ initial: false }),
|
|
|
|
gewicht: new NumberField({ integer: false, initial: 0, min: 0 }),
|
|
preis: new NumberField({ integer: true, initial: 0, min: 0 }),
|
|
|
|
nahkampfwaffe: new SchemaField({
|
|
aktiv: new BooleanField({ initial: false }),
|
|
|
|
basis: new StringField({ initial: "1d4" }),
|
|
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({ initial: "" }),
|
|
kampftalente: new StringField({ initial: "" }),
|
|
|
|
laenge: new NumberField({ integer: true, initial: 0, min: 0 }),
|
|
|
|
zweihaendig: new BooleanField({ initial: false }),
|
|
werfbar: new BooleanField({ initial: false }),
|
|
improvisiert: new BooleanField({ initial: false }),
|
|
priviligiert: new BooleanField({ initial: false }),
|
|
}),
|
|
|
|
parierwaffe: new SchemaField({
|
|
aktiv: new BooleanField({ initial: false }),
|
|
|
|
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({ initial: false }),
|
|
|
|
groesse: new StringField({ initial: "klein" }),
|
|
|
|
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({ initial: false }),
|
|
|
|
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 }),
|
|
}),
|
|
};
|
|
}
|
|
}
|
|
|
|
class DSA41_TalentData extends TypeDataModel {
|
|
static defineSchema() {
|
|
return {
|
|
kategorie: new StringField({ initial: "koerperliche" }),
|
|
behinderung: new StringField({ initial: "" }),
|
|
|
|
attribute1: new StringField({ initial: "courage" }),
|
|
attribute2: new StringField({ initial: "courage" }),
|
|
attribute3: new StringField({ initial: "courage" }),
|
|
|
|
talentwert: new NumberField({ integer: true, initial: 0 }),
|
|
};
|
|
}
|
|
}
|
|
|
|
class DSA41_KampftalentData extends TypeDataModel {
|
|
static defineSchema() {
|
|
return {
|
|
kategorie: new StringField({ initial: "waffenlos" }),
|
|
behinderung: new StringField({ initial: "" }),
|
|
steigern: new StringField({ initial: "A_Star"}),
|
|
|
|
beschreibung: new StringField({ initial: "" }),
|
|
|
|
talentwert: new NumberField({ integer: true, initial: 0 }),
|
|
attacke: new NumberField({ integer: true, initial: 0 }),
|
|
parade: new NumberField({ integer: true, initial: 0 }),
|
|
};
|
|
}
|
|
}
|
|
|
|
class DSA41_SonderfertigkeitData extends TypeDataModel {
|
|
static defineSchema() {
|
|
return {
|
|
kategorie: new StringField({ initial: "allgemein" }),
|
|
kosten: new NumberField({ integer: true, initial: 0 }),
|
|
verbreitung: new NumberField({ integer: true, initial: 0 }),
|
|
|
|
beschreibung: new StringField({ initial: "" }),
|
|
};
|
|
}
|
|
}
|
|
|
|
class DSA41_VorNachteilData extends TypeDataModel {
|
|
static defineSchema() {
|
|
return {
|
|
kategorie: new StringField({ initial: "vorteil" }),
|
|
kosten: new NumberField({ integer: true, initial: 0 }),
|
|
|
|
beschreibung: new StringField({ initial: "" }),
|
|
};
|
|
}
|
|
}
|
|
|
|
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 = {
|
|
Eigenschaft: { template: "systems/dsa-4th-edition/src/Dialogs/Attribute.hbs" },
|
|
Talent: { template: "systems/dsa-4th-edition/src/Dialogs/Talent.hbs" },
|
|
|
|
Attacke: { template: "systems/dsa-4th-edition/src/Dialogs/Attacke.hbs" },
|
|
Parade: { template: "systems/dsa-4th-edition/src/Dialogs/Parade.hbs" },
|
|
Trefferpunkte: { template: "systems/dsa-4th-edition/src/Dialogs/Trefferpunkte.hbs" },
|
|
|
|
FernkampfAttacke: { template: "systems/dsa-4th-edition/src/Dialogs/FernkampfAttacke.hbs" },
|
|
FernkampfTrefferpunkte: { template: "systems/dsa-4th-edition/src/Dialogs/FernkampfTrefferpunkte.hbs" },
|
|
|
|
Trefferzone: { template: "systems/dsa-4th-edition/src/Dialogs/Trefferzone.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 == "courage" || roll_type == "cleverness" || roll_type == "intuition" || roll_type == "charisma" ||
|
|
roll_type == "dexterity" || roll_type == "agility" || roll_type == "constitution" || roll_type == "strength") {
|
|
const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + this.document.name;
|
|
const data = await DSA41_Dialog.wait("Eigenschaft", { window: { title: title }, attribute: this.document.system.attributes[roll_type] });
|
|
|
|
let flavor = game.i18n.localize("DSA41.roll_types." + roll_type);
|
|
if (typeof success_value !== 'undefined') {
|
|
flavor += " <= " + (Number(success_value) + data.modifikator);
|
|
}
|
|
|
|
let roll = new Roll(roll_formula, this.document.system);
|
|
roll.toMessage({
|
|
speaker: ChatMessage.getSpeaker({ actor: this.document }),
|
|
flavor: flavor,
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (roll_type == "talent") {
|
|
const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + item.name;
|
|
const data = await DSA41_Dialog.wait("Talent", { window: {title: title}, item: item });
|
|
|
|
const eBE = (await new Roll(item.system.behinderung || "0", { BE: this.document.system.computed.kampf.ruestungen_gesamt.gesamt_behinderung }).evaluate()).total;
|
|
data.modifikator += eBE;
|
|
|
|
const talentwert = item.system.talentwert - data.modifikator;
|
|
const roll_modifier = talentwert < 0 ? -talentwert: 0;
|
|
|
|
const roll1 = (await new Roll("1d20").evaluate()).total + roll_modifier;
|
|
const roll2 = (await new Roll("1d20").evaluate()).total + roll_modifier;
|
|
const roll3 = (await new Roll("1d20").evaluate()).total + roll_modifier;
|
|
|
|
const attribute1 = this.document.system.computed.attributes[item.system.attribute1];
|
|
const attribute2 = this.document.system.computed.attributes[item.system.attribute2];
|
|
const attribute3 = this.document.system.computed.attributes[item.system.attribute3];
|
|
|
|
const needed_taw_roll1 = Math.max(roll1 - attribute1, 0);
|
|
const needed_taw_roll2 = Math.max(roll2 - attribute2, 0);
|
|
const needed_taw_roll3 = Math.max(roll3 - attribute3, 0);
|
|
|
|
const leftover_taw = Math.max(talentwert, 0) - needed_taw_roll1 - needed_taw_roll2 - needed_taw_roll3;
|
|
|
|
const context = {
|
|
talent: item,
|
|
modifikator: -data.modifikator,
|
|
|
|
attribute1: { type: item.system.attribute1, value: attribute1 },
|
|
attribute2: { type: item.system.attribute2, value: attribute3 },
|
|
attribute3: { type: item.system.attribute3, value: attribute3 },
|
|
|
|
roll1: roll1,
|
|
roll2: roll2,
|
|
roll3: roll3,
|
|
|
|
needed_taw_roll1: -needed_taw_roll1,
|
|
needed_taw_roll2: -needed_taw_roll2,
|
|
needed_taw_roll3: -needed_taw_roll3,
|
|
|
|
leftover_taw: Math.min(leftover_taw, item.system.talentwert),
|
|
};
|
|
|
|
const message = await ChatMessage.create(
|
|
{
|
|
content: await renderTemplate("talent_chat", context),
|
|
speaker: { actor: this.actor },
|
|
sound: CONFIG.sounds.dice,
|
|
},
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if (roll_type == "attacke") {
|
|
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("Attacke", { window: { title: title }, item: item });
|
|
|
|
let flavor = game.i18n.localize("DSA41.roll_types." + roll_type);
|
|
if (typeof success_value !== 'undefined') {
|
|
flavor += " <= " + (Number(success_value) + data.modifikator);
|
|
}
|
|
|
|
let roll = new Roll(roll_formula, this.document.system);
|
|
roll.toMessage({
|
|
speaker: ChatMessage.getSpeaker({ actor: this.document }),
|
|
flavor: flavor,
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
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 });
|
|
|
|
let flavor = game.i18n.localize("DSA41.roll_types." + roll_type);
|
|
if (typeof success_value !== 'undefined') {
|
|
flavor += " <= " + (Number(success_value) + data.modifikator);
|
|
}
|
|
|
|
if (data.crit == "on") {
|
|
roll_formula = "round((" + roll_formula + ") / 2)";
|
|
}
|
|
|
|
let roll = new Roll(roll_formula, this.document.system);
|
|
roll.toMessage({
|
|
speaker: ChatMessage.getSpeaker({ actor: this.document }),
|
|
flavor: flavor,
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
|
|
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,
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (roll_type == "fernkampf-attacke") {
|
|
const title = game.i18n.localize("DSA41.roll_types." + roll_type) + ": " + item.name;
|
|
const data = await DSA41_Dialog.wait("FernkampfAttacke", { 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),
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
|
|
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),
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
let roll = new Roll(roll_formula, this.document.system);
|
|
roll.toMessage({
|
|
speaker: ChatMessage.getSpeaker({ actor: this.document }),
|
|
flavor: flavor,
|
|
flags: {
|
|
dsa41: {
|
|
type: roll_type,
|
|
targets: get_targeted_actors(),
|
|
}
|
|
},
|
|
});
|
|
},
|
|
|
|
"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();
|
|
},
|
|
|
|
"toggle_equipped": async function(event, target) {
|
|
const item_id = event.target.closest("[data-item-id]").dataset.itemId;
|
|
const item = this.document.items.get(item_id);
|
|
item.update({ "system.angelegt": !item.system.angelegt });
|
|
},
|
|
},
|
|
};
|
|
|
|
_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;
|
|
}
|
|
});
|
|
}
|
|
|
|
// allow changing embedded item fields
|
|
async _onChangeForm(formConfig, event) {
|
|
const item_id = event.target.closest("[data-item-id]")?.dataset.itemId;
|
|
const data_name = event.target.dataset.name;
|
|
if (!item_id || !data_name) return super._onChangeForm(formConfig, event);
|
|
|
|
event.stopImmediatePropagation();
|
|
const item = await this.actor.items.get(item_id);
|
|
const value = event.target.value;
|
|
item.update({ [data_name]: value });
|
|
}
|
|
|
|
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" },
|
|
Talent: { template: "systems/dsa-4th-edition/src/ItemSheets/Talent.hbs" },
|
|
Kampftalent: { template: "systems/dsa-4th-edition/src/ItemSheets/Kampftalent.hbs" },
|
|
Sonderfertigkeit: { template: "systems/dsa-4th-edition/src/ItemSheets/Sonderfertigkeit.hbs" },
|
|
VorNachteil: { template: "systems/dsa-4th-edition/src/ItemSheets/VorNachteil.hbs" },
|
|
};
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
position: { width: "600", height: "auto" },
|
|
};
|
|
|
|
tabGroups = { primary: "tab1" };
|
|
|
|
_configureRenderOptions(options) {
|
|
super._configureRenderOptions(options);
|
|
options.parts = [ this.options.document.type ];
|
|
}
|
|
}
|