diff --git a/gulpfile.mjs b/gulpfile.mjs index 0c1c432d..d7277532 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -43,6 +43,7 @@ const convert = function (from, to, ofType) { mkdirSync(DEST) readdirSync(SOURCE).forEach(file => { + console.log(file) let originalSource = JSON.parse(readFileSync(join(SOURCE, file), {encoding: "utf8"})); let id = randomID(); @@ -104,6 +105,10 @@ async function prepareDB() { convert("./src/packs/_source/liturgien-und-segnungen", "./src/packs/__source/liturgien", "Liturgy"); convert("./src/packs/_source/wunden", "./src/packs/__source/wunden", "ActiveEffect"); + convert("./src/packs/_source/kulturen", "./src/packs/__source/kulturen", "Culture"); + convert("./src/packs/_source/spezien", "./src/packs/__source/spezien", "Species"); + convert("./src/packs/_source/professionen", "./src/packs/__source/professionen", "Profession"); + } catch (err) { console.error(err); } diff --git a/src/main.mjs b/src/main.mjs index fa69514f..9776ffe3 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -5,12 +5,12 @@ import {SkillDataModel} from "./module/data/skill.mjs"; import {SpellDataModel} from "./module/data/spell.mjs"; import {VornachteileDataModel} from "./module/data/vornachteile.mjs"; import {Character} from "./module/documents/character.mjs"; -import {CharacterSheet} from "./module/sheets/characterSheet.mjs"; -import {VornachteilSheet} from "./module/sheets/vornachteilSheet.mjs"; +import CharacterSheet from "./module/sheets/characterSheet.mjs"; +import {AdvantageSheet} from "./module/sheets/advantageSheet.mjs"; import {GroupDataModel} from "./module/data/group.mjs"; import {GroupSheet} from "./module/sheets/groupSheet.mjs"; import {EquipmentDataModel} from "./module/data/equipment.mjs"; -import {AusruestungSheet} from "./module/sheets/equipmentSheet.mjs"; +import {EquipmentSheet} from "./module/sheets/equipmentSheet.mjs"; import {CreatureDataModel} from "./module/data/creature.mjs"; import {CreatureSheet} from "./module/sheets/creatureSheet.mjs"; import {LiturgySheet} from "./module/sheets/liturgySheet.mjs"; @@ -21,6 +21,12 @@ import {SpecialAbilitySheet} from "./module/sheets/specialAbilitySheet.mjs"; import {ActiveEffectSheet} from "./module/sheets/ActiveEffectSheet.mjs"; import {ActiveEffectDataModel} from "./module/data/activeeffect.mjs"; import {Trefferzone, Wunde, Zonenruestung, Zonenwunde} from "./module/data/Trefferzone.js"; +import {ProfessionDataModel} from "./module/data/profession.mjs"; +import {SpeciesDataModel} from "./module/data/species.mjs"; +import {CultureDataModel} from "./module/data/culture.mjs"; +import {CultureSheet} from "./module/sheets/CultureSheet.mjs"; +import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs"; +import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs"; async function preloadHandlebarsTemplates() { return foundry.applications.handlebars.loadTemplates([ @@ -35,7 +41,6 @@ async function preloadHandlebarsTemplates() { 'systems/DSA_4-1/templates/ui/partial-sf-button.hbs', 'systems/DSA_4-1/templates/ui/partial-action-button.hbs', 'systems/DSA_4-1/templates/ui/partial-equipment-button.hbs', - 'systems/DSA_4-1/templates/ui/partial-equipment-group-button.hbs', 'systems/DSA_4-1/templates/ui/partial-array-editor.hbs', 'systems/DSA_4-1/templates/dialog/modify-liturgy.hbs' ]); @@ -70,6 +75,9 @@ Hooks.once("init", () => { Blessing: BlessingDataModel, SpecialAbility: SpecialAbilityDataModel, ActiveEffect: ActiveEffectDataModel, + Profession: ProfessionDataModel, + Spezies: SpeciesDataModel, + Kultur: CultureDataModel, } CONFIG.Combat.initiative = { @@ -94,8 +102,6 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.GroupLabel.Item' }) - - // Register sheet application classes foundry.documents.collections.Items.registerSheet('dsa41.skill', SkillSheet, { types: ["Skill"], makeDefault: true, @@ -106,33 +112,58 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.SpellLabels.Item', }); - foundry.documents.collections.Items.registerSheet('dsa41.advantage', VornachteilSheet, { + foundry.documents.collections.Items.registerSheet('dsa41.advantage', AdvantageSheet, { types: ["Advantage"], makeDefault: true, label: 'DSA41.VornachteilLabels.Item' }) - foundry.documents.collections.Items.registerSheet('dsa41.equipment', AusruestungSheet, { + foundry.documents.collections.Items.registerSheet('dsa41.equipment', EquipmentSheet, { types: ["Equipment"], makeDefault: false, label: 'DSA41.AusruestungLabels.Item' }) foundry.documents.collections.Items.registerSheet('dsa41.liturgy', LiturgySheet, { - types: ["SpecialAbility"], - makeDefault: true, - label: 'DSA41.SpecialAbilityLabels.Item' - }) - foundry.documents.collections.Items.registerSheet('dsa41.specialAbility', SpecialAbilitySheet, { types: ["Liturgy"], makeDefault: true, label: 'DSA41.LiturgyLabels.Item' }) - + foundry.documents.collections.Items.registerSheet('dsa41.specialAbility', SpecialAbilitySheet, { + types: ["SpecialAbility"], + makeDefault: true, + label: 'DSA41.SpecialAbilityLabels.Item' + }) foundry.documents.collections.Items.registerSheet('dsa41.activeEffect', ActiveEffectSheet, { types: ['ActiveEffect'], makeDefault: true, - label: 'DSA41.ActiveEffectLabels.ActiveFfect' + label: 'DSA41.ActiveEffectLabels.ActiveEffect' + }) + foundry.documents.collections.Items.registerSheet('dsa41.culture', CultureSheet, { + types: ['Culture'], + makeDefault: true, + label: 'DSA41.CultureLabels.Culture' + }) + foundry.documents.collections.Items.registerSheet('dsa41.spezien', SpeciesSheet, { + types: ['Species'], + makeDefault: true, + label: 'DSA41.SpeciesLabels.Species' + }) + foundry.documents.collections.Items.registerSheet('dsa41.profession', ProfessionSheet, { + types: ['Profession'], + makeDefault: true, + label: 'DSA41.ProfessionLabels.Profession' }) + game.settings.register('DSA_4-1', 'optional_colorfuldice', { + name: "Optional: Farbige Würfel nach Paramanthus", + hint: "Färbt die Würfel je nach Attribut ein", + scope: "client", + config: true, + type: Boolean, + default: false, + onChange: value => { + }, + requiresReload: false + }) game.settings.register('DSA_4-1', 'optional_trefferzonen', { name: "Optional: Trefferzonen", hint: "Ersetzt das Wundensystem aus dem BRW durch das Trefferzonensystem aus WdH", @@ -144,7 +175,6 @@ Hooks.once("init", () => { }, requiresReload: true }) - game.settings.register('DSA_4-1', 'optional_ruestungzonen', { name: "Optional: Zonenrüstung", hint: "Ersetzt das Rüstungssystem aus dem BRW durch das Zonenrüstungssystem aus WdH", @@ -156,7 +186,6 @@ Hooks.once("init", () => { }, requiresReload: true }) - game.settings.register('DSA_4-1', 'optional_ausdauer', { name: "Optional: Ausdauerregeln", hint: "Aktiviert Regeln für das Spiel mit Ausdauer", @@ -168,7 +197,6 @@ Hooks.once("init", () => { }, requiresReload: true }) - game.settings.register('DSA_4-1', 'optional_distanzklassen', { name: "Optional: Distanzklassen", hint: "Aktiviert Regeln für das Spiel mit Distanzklassen", @@ -184,16 +212,6 @@ Hooks.once("init", () => { return preloadHandlebarsTemplates(); }) -Hooks.on('dropActorSheetData', (actor, sheet, data) => { - if (data.uuid) { - if (actor.type === "character") { - return CharacterSheet.onDroppedData(actor, sheet, data); - } else { - return GroupSheet.onDroppedData(actor, sheet, data); - } - } -}) - Hooks.once("ready", async function () { // Wait to register hotbar drop hook on ready so that modules could register earlier if they want to Hooks.on("hotbarDrop", (bar, data, slot) => { diff --git a/src/module/data/character.mjs b/src/module/data/character.mjs index b6e5eb4b..fc0ed27d 100644 --- a/src/module/data/character.mjs +++ b/src/module/data/character.mjs @@ -1,12 +1,12 @@ +import {Equipment} from "../documents/equipment.mjs"; + const { SchemaField, NumberField, StringField, HTMLField, - EmbeddedDocumentField, DocumentIdField, ArrayField, - ForeignDocumentField } = foundry.data.fields; export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { @@ -29,6 +29,8 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { familie: new HTMLField(), titel: new StringField(), stand: new StringField(), + verbindungen: new HTMLField(), + notizen: new HTMLField(), }), setEquipped: new NumberField({required: true, initial: 0, max: 3, integer: true}), ini: new SchemaField({ diff --git a/src/module/data/culture.mjs b/src/module/data/culture.mjs new file mode 100644 index 00000000..ac5f2cc4 --- /dev/null +++ b/src/module/data/culture.mjs @@ -0,0 +1,15 @@ +import BaseItem from "./base-item.mjs"; + +const {BooleanField, StringField, HTMLField} = foundry.data.fields; + +export class CultureDataModel extends BaseItem { + + static defineSchema() { + return { + description: new HTMLField(), + variant: new StringField(), + feminineDemonym: new StringField(), + masculineDemonym: new StringField() + } + } +} \ No newline at end of file diff --git a/src/module/data/equipment.mjs b/src/module/data/equipment.mjs index 7025da9a..fd2a4f33 100644 --- a/src/module/data/equipment.mjs +++ b/src/module/data/equipment.mjs @@ -1,7 +1,8 @@ import BaseItem from "./base-item.mjs"; +import {Equipment} from "../documents/equipment.mjs"; const { - ArrayField, NumberField, StringField, HTMLField + ArrayField, EmbeddedCollectionField, SchemaField, NumberField, StringField, HTMLField } = foundry.data.fields; export class EquipmentDataModel extends BaseItem { @@ -34,9 +35,25 @@ export class EquipmentDataModel extends BaseItem { rangedAttackDamage: new StringField(), rangedReloadTime: new NumberField({required: false}), - armorValue: new NumberField({required: false}), + armorValue: new SchemaField({ + total: new NumberField({required: true, initial: 0}), + armlinks: new NumberField({required: true, initial: 0}), + beinlinks: new NumberField({required: true, initial: 0}), + armrechts: new NumberField({required: true, initial: 0}), + beinrechts: new NumberField({required: true, initial: 0}), + ruecken: new NumberField({required: true, initial: 0}), + bauch: new NumberField({required: true, initial: 0}), + brust: new NumberField({required: true, initial: 0}), + kopf: new NumberField({required: true, initial: 0}), + }, {required: false}), armorHandicap: new NumberField({required: false}), + + ammunition: new SchemaField({ + max: new NumberField({required: true, initial: 1}), + count: new NumberField({required: true, initial: 1}), + }, {required: false}), } } + } diff --git a/src/module/data/group.mjs b/src/module/data/group.mjs index 9786dd34..f6ef784b 100644 --- a/src/module/data/group.mjs +++ b/src/module/data/group.mjs @@ -18,6 +18,7 @@ export class GroupDataModel extends foundry.abstract.TypeDataModel { quantity: new NumberField(), item: new DocumentIdField(Item) }), + groupId: new DocumentIdField(Actor), characters: new ArrayField( new DocumentIdField(Actor) ), @@ -25,4 +26,13 @@ export class GroupDataModel extends foundry.abstract.TypeDataModel { } } + _onCreate(data, options, userId) { + super._onCreate(data, options, userId); + Folder.implementation.createDocuments([{name: data.name, type: "Actor"}]).then(( + folder + ) => { + this.parent.update({"system.groupId": folder[0]._id}); + }) + } + } diff --git a/src/module/data/profession.mjs b/src/module/data/profession.mjs new file mode 100644 index 00000000..9b7b1cfe --- /dev/null +++ b/src/module/data/profession.mjs @@ -0,0 +1,14 @@ +import BaseItem from "./base-item.mjs"; + +const {BooleanField, StringField, HTMLField} = foundry.data.fields; + +export class ProfessionDataModel extends BaseItem { + + static defineSchema() { + return { + description: new HTMLField(), + revealed: new BooleanField(), + alias: new StringField(), + } + } +} \ No newline at end of file diff --git a/src/module/data/skill.mjs b/src/module/data/skill.mjs index 14c84a4c..4385777b 100644 --- a/src/module/data/skill.mjs +++ b/src/module/data/skill.mjs @@ -44,12 +44,89 @@ export class SkillDataModel extends BaseItem { } /** - * Handle clickable rolls. - * @param {Event} event The originating click event - * @private + * Determines the values to consult for the given type of roll (normal: talent roll, attack: AT, parry: PA + * @returns {{NORMAL: string, ATTACK: string, PARRY: string}} + * @constructor */ - async roll() { + get SKILL_MODE() { + return { + NORMAL: "NORMAL", + ATTACK: "ATTACK", + PARRY: "PARRY", + } + } + + + /** + * + * @param rollMode {["publicroll","gmroll"] } + * @param mode + * @returns {Promise} + */ + async roll(rollMode = null, mode = this.SKILL_MODE.NORMAL) { + + + + rollMode = rollMode ?? game.settings.get('core', 'rollMode'); + + switch (mode) { + case this.SKILL_MODE.NORMAL: + return this.#talentRoll(rollMode) + case this.SKILL_MODE.ATTACK: + case this.SKILL_MODE.PARRY: + return this.#combatRoll(rollMode, mode) + } + + } + + async #combatRoll(rollMode, mode) { const owner = this.parent.parent + const rollData = owner.getRollData() + + let targetNumber = 0 + + if (mode === this.SKILL_MODE.ATTACK) { + targetNumber = this.at + owner.system.at.basis + } else { + targetNumber = this.pa + owner.system.pa.basis + } + + let roll1 = new Roll(`1d20cs<${targetNumber}`, owner.getRollData()); + + let evaluated1 = (await roll1.evaluate()) + + const rolledValue = evaluated1.terms[0].results[0].result + + if (rolledValue === 1 || rolledValue === 20) { // TODO: Modify this target + // fill with actual evaluation (targetNumber should be reduced by X and roll against that again) + } + + let message = "" + if (mode === this.SKILL_MODE.ATTACK) { + if (rolledValue <= targetNumber) { + message = `Würde treffen [${rolledValue}]` + } else { + message = `Verfehlt [${rolledValue}]` + } + } else { + if (rolledValue <= targetNumber) { + message = `Würde parrieren [${rolledValue}]` + } else { + message = `Verfehlt die parade [${rolledValue}]` + } + } + + evaluated1.toMessage({ + speaker: ChatMessage.getSpeaker({actor: owner}), + flavor: message, + rollMode, + }) + + } + + async #talentRoll(rollMode) { + const owner = this.parent.parent + let roll1 = new Roll("3d20", owner.getRollData()); let evaluated1 = (await roll1.evaluate()) @@ -63,13 +140,13 @@ export class SkillDataModel extends BaseItem { evaluated1.toMessage({ speaker: ChatMessage.getSpeaker({actor: owner}), flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Meisterlich geschafft' : 'Geschafft'} mit ${dsaDieRollEvaluated.tap} Punkten übrig`, - rollMode: game.settings.get('core', 'rollMode'), + rollMode, }) } else { // misserfolg evaluated1.toMessage({ speaker: ChatMessage.getSpeaker({actor: owner}), flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Gepatzt' : ''} mit ${Math.abs(dsaDieRollEvaluated.tap)} Punkten daneben`, - rollMode: game.settings.get('core', 'rollMode'), + rollMode, }) } } diff --git a/src/module/data/species.mjs b/src/module/data/species.mjs new file mode 100644 index 00000000..4b487b7d --- /dev/null +++ b/src/module/data/species.mjs @@ -0,0 +1,15 @@ +import BaseItem from "./base-item.mjs"; + +const {BooleanField, NumberField, StringField, HTMLField} = foundry.data.fields; + +export class SpeciesDataModel extends BaseItem { + + static defineSchema() { + return { + description: new HTMLField(), + baseSpeed: new NumberField({required: true, initial: 6, integer: true}), + feminineDemonym: new StringField(), + masculineDemonym: new StringField(), + } + } +} \ No newline at end of file diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index eb1cfc8c..00bb83db 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -1,6 +1,7 @@ import {importCharacter} from "../xml-import/xml-import.mjs"; import {LiturgyData} from "../data/miracle/liturgydata.mjs"; -import {Zonenruestung, Zonenwunde} from "../data/Trefferzone.js"; +import {Zonenruestung, Zonenwunde, Wunde} from "../data/Trefferzone.js"; +import {PlayerCharacterDataModel} from "../data/character.mjs"; export class Character extends Actor { @@ -91,7 +92,7 @@ export class Character extends Actor { systemData.mr.basis = Math.round((mu + kl + ko) / 5) systemData.mr.aktuell = systemData.mr.basis + (systemData.mr.mod ?? 0); systemData.gs.basis = 6; - systemData.gs.aktuell = systemData.gs.basis + (systemData.gs.mod ?? 0); // TOOD: get GS from species + systemData.gs.aktuell = systemData.gs.basis + (systemData.gs.mod ?? 0); // TOOD: get GS from spezien if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { @@ -116,6 +117,7 @@ export class Character extends Actor { systemData.wunden.kopf = 0; systemData.wunden.brust = 0; systemData.wunden.bauch = 0; + systemData.wunden.ruecken = 0; systemData.wunden.armlinks = 0; systemData.wunden.armrechts = 0; systemData.wunden.beinlinks = 0; @@ -127,73 +129,40 @@ export class Character extends Actor { // map current set to RS and BE const ausruestung = systemData.heldenausruestung[systemData.setEquipped]; - if (ausruestung) { - if (ausruestung.brust) { - systemData.be += systemData.parent.items.get(ausruestung.brust).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.brust = systemData.parent.items.get(ausruestung.brust).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.brust).system.armorValue ?? 0 - } - } - if (ausruestung.bauch) { - systemData.be += systemData.parent.items.get(ausruestung.bauch).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.bauch = systemData.parent.items.get(ausruestung.bauch).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.bauch).system.armorValue ?? 0 - } - } - if (ausruestung.ruecken) { - systemData.be += systemData.parent.items.get(ausruestung.ruecken).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - // ruecken is not a valid trefferzone - } else { - systemData.rs += systemData.parent.items.get(ausruestung.ruecken).system.armorValue ?? 0 - } - } - if (ausruestung.armlinks) { - systemData.be += systemData.parent.items.get(ausruestung.armlinks).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.armlinks = systemData.parent.items.get(ausruestung.armlinks).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.armlinks).system.armorValue ?? 0 - } - } - if (ausruestung.armrechts) { - systemData.be += systemData.parent.items.get(ausruestung.armrechts).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.armrechts = systemData.parent.items.get(ausruestung.armrechts).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.armrechts).system.armorValue ?? 0 - } - } - if (ausruestung.beinlinks) { - systemData.be += systemData.parent.items.get(ausruestung.beinlinks).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.beinlinks = systemData.parent.items.get(ausruestung.beinlinks).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.beinlinks).system.armorValue ?? 0 - } - } - if (ausruestung.beinrechts) { - systemData.be += systemData.parent.items.get(ausruestung.beinrechts).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.beinrechts = systemData.parent.items.get(ausruestung.beinrechts).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.beinrechts).system.armorValue ?? 0 - } - } - if (ausruestung.kopf) { - systemData.be += systemData.parent.items.get(ausruestung.kopf).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.kopf = systemData.parent.items.get(ausruestung.kopf).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.kopf).system.armorValue ?? 0 - } - } + const zonesToCheck = [ + "brust", + "bauch", + "ruecken", + "kopf", + "armlinks", + "armrechts", + "beinlinks", + "beinrechts"] + + if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { + systemData.rs.gesamt = 0 + systemData.rs.brust = 0 + systemData.rs.bauch = 0 + systemData.rs.ruecken = 0 + systemData.rs.kopf = 0 + systemData.rs.armlinks = 0 + systemData.rs.armrechts = 0 + systemData.rs.beinlinks = 0 + systemData.rs.beinrechts = 0 + } else { + systemData.rs = 0 } + zonesToCheck.forEach((zone) => { + systemData.be += systemData.parent.items.get(ausruestung[zone])?.system.armorHandicap ?? 0 + if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { + zonesToCheck.forEach((itemZone) => { + systemData.rs[itemZone] += systemData.parent.items.get(ausruestung[zone])?.system.armorValue[itemZone] ?? 0 + }) + } else { + systemData.rs += systemData.parent.items.get(ausruestung[zone])?.system.armorValue.total ?? 0 + } + }) systemData.kap.max = 0; @@ -223,14 +192,10 @@ export class Character extends Actor { getRollData() { const data = super.getRollData(); + this.prepareDerivedData() if (this.type !== 'character' && this.type !== 'creature') return; - if (data.attribute) { - for (let [k, v] of Object.entries(data.attribute)) { - data[k] = foundry.utils.deepClone(v); - } - } // move sonderfertigkeiten into data, if it isn't in data the actor doesn't have that sonderfertigkeit @@ -245,6 +210,48 @@ export class Character extends Actor { return data; } + + findEquipmentOnSlot(slot, setNumber) { + return this.items.get(this.system.heldenausruestung[setNumber ?? this.system.setEquipped]?.[slot]) + } + + getEquipmentSetUpdateObject() { + const updateObject = {} + Array.from(this.system.heldenausruestung).forEach((equipmentSet, index) => { + updateObject[`system.heldenausruestung.${index}.links`] = equipmentSet.links; + updateObject[`system.heldenausruestung.${index}.rechts`] = equipmentSet.rechts; + updateObject[`system.heldenausruestung.${index}.brust`] = equipmentSet.brust; + updateObject[`system.heldenausruestung.${index}.bauch`] = equipmentSet.bauch; + updateObject[`system.heldenausruestung.${index}.ruecken`] = equipmentSet.ruecken; + updateObject[`system.heldenausruestung.${index}.kopf`] = equipmentSet.kopf; + updateObject[`system.heldenausruestung.${index}.fernkampf`] = equipmentSet.fernkampf; + updateObject[`system.heldenausruestung.${index}.munition`] = equipmentSet.munition; + updateObject[`system.heldenausruestung.${index}.armlinks`] = equipmentSet.armlinks; + updateObject[`system.heldenausruestung.${index}.armrechts`] = equipmentSet.armrechts; + updateObject[`system.heldenausruestung.${index}.beinlinks`] = equipmentSet.beinlinks; + updateObject[`system.heldenausruestung.${index}.beinrechts`] = equipmentSet.beinrechts; + + }) + return updateObject; + } + + + isWorn(itemId) { + + const slots = PlayerCharacterDataModel.getSlots() + const set = this.system.heldenausruestung[this.system.setEquipped] + if (set) { + for (const slot of slots) { + const equipmentSlotId = set[slot] + if (equipmentSlotId === itemId) { + return slot + } + } + } + + return false + } + /** * * @param amount diff --git a/src/module/documents/culture.mjs b/src/module/documents/culture.mjs new file mode 100644 index 00000000..98da9ab2 --- /dev/null +++ b/src/module/documents/culture.mjs @@ -0,0 +1,9 @@ +export class Culture extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/documents/profession.mjs b/src/module/documents/profession.mjs new file mode 100644 index 00000000..2dfb3529 --- /dev/null +++ b/src/module/documents/profession.mjs @@ -0,0 +1,9 @@ +export class Profession extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/documents/species.mjs b/src/module/documents/species.mjs new file mode 100644 index 00000000..f1e0f707 --- /dev/null +++ b/src/module/documents/species.mjs @@ -0,0 +1,9 @@ +export class Species extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/sheets/ActiveEffectSheet.mjs b/src/module/sheets/ActiveEffectSheet.mjs index ef2c1d03..9e422c6e 100644 --- a/src/module/sheets/ActiveEffectSheet.mjs +++ b/src/module/sheets/ActiveEffectSheet.mjs @@ -1,44 +1,65 @@ -export class ActiveEffectSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'activeeffect'], - width: 520, - height: 480 - }); +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class ActiveEffectSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'activeeffect'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: ActiveEffectSheet.#onSubmitForm + }, + actions: { + openEffect: ActiveEffectSheet.#openEffect, + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/activeeffect/main-sheet.hbs` + }, + } + + static async #openEffect(evt) { + evt.preventDefault() + const {id} = evt.srcElement.dataset + const effect = await this.document.effects.get(id) + effect.sheet.render(true) + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-activeeffect-sheet.hbs`; - } + async _prepareContext(options) { - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); - const effects = context.document.getEmbeddedCollection("ActiveEffect").contents; + const context = await super._prepareContext(options) + context.system = context.document.system + + const effects = context.document.getEmbeddedCollection("ActiveEffect").contents if (effects.length > 0) { - context.effectId = effects[0]._id; + context.effectId = effects[0]._id } - return context; + context.name = context.document.name + context.img = context.document.img + context.notes = context.document.system.notes + + return context } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - html.on('click', '.editEffects', (evt) => { - const {id} = evt.currentTarget.dataset; - const effect = this.object.effects.get(id); - effect.sheet.render(true); - }) - } - -} +} \ No newline at end of file diff --git a/src/module/sheets/CultureSheet.mjs b/src/module/sheets/CultureSheet.mjs new file mode 100644 index 00000000..abd78fda --- /dev/null +++ b/src/module/sheets/CultureSheet.mjs @@ -0,0 +1,54 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class CultureSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'culture'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: CultureSheet.#onSubmitForm + }, + actions: { + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/culture-sheet.hbs` + }, + } + + /** + * Handle form submission + * @this {CultureSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.system = context.document.system + + context.name = context.document.name + context.img = context.document.img + context.description = context.document.system.description + context.masculineDemonym = context.document.system.masculineDemonym + context.feminineDemonym = context.document.system.feminineDemonym + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/ProfessionSheet.mjs b/src/module/sheets/ProfessionSheet.mjs new file mode 100644 index 00000000..dbaa2465 --- /dev/null +++ b/src/module/sheets/ProfessionSheet.mjs @@ -0,0 +1,55 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class ProfessionSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'species'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: ProfessionSheet.#onSubmitForm + }, + actions: { + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/profession-sheet.hbs` + }, + } + + /** + * Handle form submission + * @this {ProfessionSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.system = context.document.system + + context.name = context.document.name + context.img = context.document.img + context.description = context.document.system.description + context.alias = context.document.system.alias + context.isOwner = context.document.owner + context.revealed = context.document.system.revealed + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/SpeciesSheet.mjs b/src/module/sheets/SpeciesSheet.mjs new file mode 100644 index 00000000..61c2999a --- /dev/null +++ b/src/module/sheets/SpeciesSheet.mjs @@ -0,0 +1,55 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SpeciesSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'species'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SpeciesSheet.#onSubmitForm + }, + actions: { + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/species-sheet.hbs` + }, + } + + /** + * Handle form submission + * @this {SpeciesSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.system = context.document.system + + context.name = context.document.name + context.img = context.document.img + context.description = context.document.system.description + context.baseSpeed = context.document.baseSpeed + context.masculineDemonym = context.document.system.masculineDemonym + context.feminineDemonym = context.document.system.feminineDemonym + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/actions/action-manager.mjs b/src/module/sheets/actions/action-manager.mjs index 2aa31643..05205b5e 100644 --- a/src/module/sheets/actions/action-manager.mjs +++ b/src/module/sheets/actions/action-manager.mjs @@ -68,21 +68,21 @@ export class ActionManager { type: ActionManager.ATTACK, cost: ActionManager.REGULAR, source: ActionManager.DEFAULT, - eval: () => true + eval: () => this.#hatWaffeinHand() }, { name: "Schnellschuss", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.DEFAULT, - eval: () => true + eval: () => this.#hatFernkampfWaffeinHand() }, { name: "Schnellschuss (Scharfschütze)", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Scharfschütze") + eval: () => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Scharfschütze") }, { name: "Abwehraktion", @@ -110,7 +110,14 @@ export class ActionManager { type: ActionManager.ATTACK, cost: ActionManager.REGULAR, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Finte") + eval: () => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Finte") + }, + { + name: "Wuchtschlag", + type: ActionManager.ATTACK, + cost: ActionManager.REGULAR, + source: ActionManager.DEFAULT, + eval: () => true }, { name: "Wuchtschlag", @@ -162,21 +169,21 @@ export class ActionManager { type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Schnellladen (Bogen)") + eval: () => this.#hatMunition() && this.#hatFernkampfWaffeinHand("Bogen") && this.#hatSonderfertigkeit("Schnellladen (Bogen)") }, { name: "Schnellladen (Armbrust)", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Schnellladen (Armbrust)") + eval: () => this.#hatMunition() && this.#hatFernkampfWaffeinHand("Armbrust") && this.#hatSonderfertigkeit("Schnellladen (Armbrust)") }, { name: "Nachladen", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.DEFAULT, - eval: () => true + eval: () => this.#hatMunition() }, { name: "Talenteinsatz", @@ -201,6 +208,23 @@ export class ActionManager { } ] + + #hatWaffeinHand() { + const item = this.actor.findEquipmentOnSlot("links") ?? this.actor.findEquipmentOnSlot("rechts") + return item + } + + #hatMunition() { + const item = this.actor.findEquipmentOnSlot("munition") + const weapon = this.actor.findEquipmentOnSlot("fernkampf") + return item + } + + #hatFernkampfWaffeinHand(art) { + const item = this.actor.findEquipmentOnSlot("fernkampf") + return item + } + #hatSonderfertigkeitBeginnendMit(name) { return this.actor.system.sonderfertigkeiten?.find(p => p.name.startsWith(name)) != null } @@ -211,8 +235,6 @@ export class ActionManager { evaluate() { let actionArray = [...this.#freeActions, ...this.#regularActions, ...this.#continuingActions] - - return actionArray.filter(action => action.eval()); } diff --git a/src/module/sheets/advantageSheet.mjs b/src/module/sheets/advantageSheet.mjs new file mode 100644 index 00000000..62696148 --- /dev/null +++ b/src/module/sheets/advantageSheet.mjs @@ -0,0 +1,65 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class AdvantageSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'advantage'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: AdvantageSheet.#onSubmitForm + } + } + + static TABS = { + sheet: { + tabs: [ + {id: 'advantage', group: 'sheet', label: 'Vorteil'}, + ], + initial: 'advantage' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/advantage/main-sheet.hbs` + }, + advantage: { + template: `systems/DSA_4-1/templates/item/advantage/tab-advantage.hbs` + } + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + const context = await super._prepareContext(options); + const advantageData = context.document; + + context.system = advantageData.system; + context.flags = context.system.flags; + context.hasChoices = context.system.auswahl.length > 0; + context.choices = {} + context.system.auswahl.forEach(a => { + context.choices[a] = a + }) + context.hasModality = context.system.value != null + + return context; + } +} diff --git a/src/module/sheets/character/advsf.mjs b/src/module/sheets/character/advsf.mjs new file mode 100644 index 00000000..018cbf53 --- /dev/null +++ b/src/module/sheets/character/advsf.mjs @@ -0,0 +1,53 @@ +export default { + _prepareContext: async (context, options, object) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + context.advantages = [] + + actorData.itemTypes.Advantage.forEach((item) => { + context.advantages.push({ + id: item._id, + name: item.name, + value: item.system.value, + options: item.system.auswahl, + description: item.system.description, + isAdvantage: !item.system.nachteil, + isDisadvantage: item.system.nachteil, + isBadAttribute: item.system.schlechteEigenschaft + }) + } + ) + + context.specialAbilities = [] + actorData.itemTypes.SpecialAbility.forEach((item) => { + context.specialAbilities.push({ + id: item._id, + name: item.name, + }); + } + ); + + return context + }, + _onRender: (context, options, thisObject) => { + new foundry.applications.ux.DragDrop.implementation({ + dropSelector: ".advantages, .special-abilities", + permissions: { + drop: thisObject._canDragDrop.bind(thisObject) + }, + callbacks: { + drop: thisObject._onDrop.bind(thisObject), + } + }).bind(thisObject.element); + }, + _getTabConfig: (group) => { + group.tabs.push({id: "advsf", group: "sheet", label: "Vorteile"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-advsf.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/combat.mjs b/src/module/sheets/character/combat.mjs new file mode 100644 index 00000000..883cc92a --- /dev/null +++ b/src/module/sheets/character/combat.mjs @@ -0,0 +1,114 @@ +import {ActionManager} from "../actions/action-manager.mjs"; + +export default { + _prepareContext: async (context, object) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const findEquipmentOnSlot = (slot, setNumber, object) => { + return object.items.get(object.system.heldenausruestung[setNumber]?.[slot]) + } + + const am = new ActionManager(actorData) + context.actions = am.evaluate() + + + context.inidice = actorData.system.ini.wuerfel + context.inivalue = actorData.system.ini.aktuell + context.inimod = actorData.system.ini.mod + + context.aupper = Math.min((actorData.system.aup.aktuell / actorData.system.aup.max) * 100, 100) + context.lepper = Math.min((actorData.system.lep.aktuell / actorData.system.lep.max) * 100, 100) + context.keper = Math.min((actorData.system.kap.aktuell / actorData.system.kap.max) * 100, 100) + context.aspper = Math.min((actorData.system.asp.aktuell / actorData.system.asp.max) * 100, 100) + context.lepcurrent = actorData.system.lep.aktuell ?? 0 + + context.aupcurrent = actorData.system.aup.aktuell ?? 0 + + const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData) + const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData) + const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData) + context.attacks = []; + + if (fernkampf) { + const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion)) + fkitems.forEach(async skill => { + const obj = await skill + context.attacks.push({ + name: obj.name, + using: fernkampf.name, + atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`, + at: `${object.system.fk.aktuell + obj.system.at}`, + tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod + tp: `${fernkampf.system.rangedAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + }) + }) + } + if (links) { + const meitems = [] + links.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: links.name, + atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M + at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, + paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M + pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, + tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${links.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + }) + }) + } + if (rechts) { + const meitems = [] + rechts.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: rechts.name, + atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M + at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, + paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M + pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, + tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${rechts.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + }) + }) + } + + return context + + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "combat", group: "sheet", label: "Kampf"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-combat.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/effects.mjs b/src/module/sheets/character/effects.mjs new file mode 100644 index 00000000..e59e080d --- /dev/null +++ b/src/module/sheets/character/effects.mjs @@ -0,0 +1,55 @@ +export default { + _prepareContext: (context, object) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + context.isGM = game.user.isGM + context.effects = [] + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "ActiveEffect") { + const effect = item.effects[0]; + const conditions = [] + + if (effect) { + effect.changes.forEach(change => { + if (change.key.indexOf("wunden") === -1) { + const key = change.key + .replace(/system\./g, "") + .replace(/\.mod/g, "") + .replace(/attribute./g, "") + .replace(/.links/g, "(Links)") + .replace(/.rechts/g, "(Rechts)") + const value = Number(change.value) > 0 ? "+" + change.value : change.value + conditions.push( + `${key}${value}` + ) + } + }) + } + + context.effects.push({ + name: item.name, + conditions: conditions.join(" "), + id: item._id, + actor: actorData._id + }); + } + }) + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "effects", group: "sheet", label: "Effekte"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-effects.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs new file mode 100644 index 00000000..ee434403 --- /dev/null +++ b/src/module/sheets/character/equipment.mjs @@ -0,0 +1,264 @@ +import {PlayerCharacterDataModel} from "../../data/character.mjs"; + +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + context.equipments = [] + context.carryingweight = 0 + actorData.itemTypes.Equipment.forEach((item, index) => { + + // worn items are halved weight + + let effectiveWeight = item.system.weight ?? 0 + if (context.document.isWorn(item._id)) { + effectiveWeight = item.system.weight ? item.system.weight / 2 : 0 + } + + context.equipments.push({ + index: index, + id: item._id, + quantity: item.system.quantity, + name: item.name, + icon: item.img ?? "", + weight: item.system.weight, + worn: context.document.isWorn(item._id) + }) + context.carryingweight += item.system.quantity * effectiveWeight; + + }) + context.maxcarryingcapacity = actorData.system.attribute.kk.aktuell + context.carryingpercentage = Math.min((context.carryingweight / context.maxcarryingcapacity) * 100, 100); + + const maxSets = 3 + const romanNumerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"] + context.sets = [] + for (let setIndex = 0; setIndex < maxSets; setIndex++) { + + context.sets.push({ + tab: "set" + (setIndex + 1), + name: romanNumerals[setIndex], + index: setIndex, + slots: [ + { + target: "links", + id: actorData.system.heldenausruestung[setIndex]?.links, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.img + }, + { + target: "rechts", + id: actorData.system.heldenausruestung[setIndex]?.rechts, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.img + }, + { + target: "brust", + id: actorData.system.heldenausruestung[setIndex]?.brust, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.img + }, + { + target: "ruecken", + id: actorData.system.heldenausruestung[setIndex]?.ruecken, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.img + }, + { + target: "kopf", + id: actorData.system.heldenausruestung[setIndex]?.kopf, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.img + }, + { + target: "fernkampf", + id: actorData.system.heldenausruestung[setIndex]?.fernkampf, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.img + }, + { + target: "munition", + id: actorData.system.heldenausruestung[setIndex]?.munition, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.img + }, + { + target: "armlinks", + id: actorData.system.heldenausruestung[setIndex]?.armlinks, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.img + }, + { + target: "armrechts", + id: actorData.system.heldenausruestung[setIndex]?.armrechts, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.img + }, + { + target: "bauch", + id: actorData.system.heldenausruestung[setIndex]?.bauch, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.img + }, + { + target: "beinlinks", + id: actorData.system.heldenausruestung[setIndex]?.beinlinks, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.img + }, + { + target: "beinrechts", + id: actorData.system.heldenausruestung[setIndex]?.beinrechts, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.img + } + ] + }) + } + + return context + }, + _onRender: (context, options, thisObject) => { + + new foundry.applications.ux.DragDrop.implementation({ + dragSelector: ".inventory-table .equipment", + dropSelector: ".inventory-table", + permissions: { + dragstart: thisObject._canDragStart.bind(thisObject), + drop: thisObject._canDragDrop.bind(thisObject) + }, + callbacks: { + dragstart: thisObject._onDragStart.bind(thisObject), + drop: thisObject._onDrop.bind(thisObject), + dragover: thisObject._onDragOver.bind(thisObject) + } + }).bind(thisObject.element); + + new ContextMenu( + thisObject.element, + ".equipment", + [ + { + name: "Abrüsten", + icon: '', + callback: (target) => { + const {itemId} = target.dataset + const itemSlot = thisObject.document.isWorn(itemId) + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + delete updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.${itemSlot}`] + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const itemIsWorn = thisObject.document.isWorn(itemId) + return itemIsWorn + } + }, + { + name: "Ausrüsten (Munition)", + + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.munition`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + console.log(item.system.category) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Munition") != -1 + } + }, + { + name: "Ausrüsten", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + // find next unoccupied slot and enter the item + console.log(updateObject) + const nextUnoccupiedSlot = Object.entries(updateObject).find(([key, value]) => { + // but not when it is a weapon slot + console.log(key, value === null + && key.indexOf(".links") === -1 + && key.indexOf(".rechts") === -1 + && key.indexOf(".fernkampf") === -1 + && key.indexOf(".munition") === -1) + return value === null + && key.indexOf(".links") === -1 + && key.indexOf(".rechts") === -1 + && key.indexOf(".fernkampf") === -1 + && key.indexOf(".munition") === -1 + }) + updateObject[nextUnoccupiedSlot[0]] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Rüstung") != -1 + } + }, + { + name: "Ausrüsten (Rechte Hand)", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.rechts`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Nahkampfwaffe") != -1 + } + }, + { + name: "Ausrüsten (Linke Hand)", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.links`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Nahkampfwaffe") != -1 + } + }, + { + name: "Ausrüsten (Fernkampf)", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.fernkampf`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Fernkampfwaffe") != -1 + } + }, + { + name: "Aus dem Inventar entfernen", + icon: '', + callback: (target) => { + thisObject.document.deleteEmbeddedDocuments('Item', [target.dataset.itemId]) + }, + condition: (target) => { + const {itemId} = target.dataset + return !thisObject.document.isWorn(itemId) + } + } + ], {jQuery: false}); + }, + _getTabConfig: (group) => { + group.tabs.push({id: "equipment", group: "sheet", label: "Ausrüstung"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-equipment.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/liturgies.mjs b/src/module/sheets/character/liturgies.mjs new file mode 100644 index 00000000..f31add4e --- /dev/null +++ b/src/module/sheets/character/liturgies.mjs @@ -0,0 +1,110 @@ +import {LiturgyData} from "../../data/miracle/liturgydata.mjs"; + +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + + context.effects = actorData.effects ?? [] + context.liturgies = []; + context.blessings = []; + + actorData.itemTypes.Blessing.forEach((item, index) => { + context.blessings.push({ + deity: item.system.gottheit, + value: item.system.wert + }) + }) + actorData.itemTypes.Liturgy.forEach((item, index) => { + + context.blessings.forEach(({deity, value}) => { + let insertObject = context.liturgies.find(p => p.deity === deity); + if (!insertObject) { + insertObject = { + deity: deity, + lkp: value, + O: [], + I: [], + II: [], + III: [], + IV: [], + V: [], + VI: [], + VII: [], + VIII: [], + "NA": [], + countO: 1, + countI: 1, + countII: 1, + countIII: 1, + countIV: 1, + countV: 1, + countVI: 1, + countVII: 1, + countVIII: 1, + countNA: 0, + total: 3, + + } + context.liturgies.push(insertObject); + } + + // sort by rank + const rankData = LiturgyData.getRankOfLiturgy(item.system, deity) + if (rankData) { + let {index, name, lkp, mod, costKaP} = rankData; + + insertObject["count" + name] = insertObject["count" + name] + 1; + + insertObject[name].push({ + id: item._id, + name: item.name, + lkpReq: lkp, + lkpMod: mod, + costKaP, + rank: index, // get effective liturgy rank based on deity + liturgiekenntnis: deity, + }) + insertObject.total = insertObject.total + 2; + + } + }) + }) + + + // clean up counter + Object.values(context.liturgies).forEach((litObject) => { + + if (litObject.I.length === 0) litObject.countI = false; + if (litObject.II.length === 0) litObject.countII = false; + if (litObject.III.length === 0) litObject.countIII = false; + if (litObject.IV.length === 0) litObject.countIV = false; + if (litObject.V.length === 0) litObject.countV = false; + if (litObject.VI.length === 0) litObject.countVI = false; + if (litObject.VII.length === 0) litObject.countVII = false; + if (litObject.VIII.length === 0) litObject.countVIII = false; + if (litObject.NA.length === 0) litObject.countNA = false; + + + }) + + context.hasLiturgies = context.blessings.length > 0; + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group, thisObject) => { + const hasLiturgies = thisObject.document.items.filter(p => p.type === "Liturgy").length > 0 ?? false + if (hasLiturgies) { + group.tabs.push({id: "liturgies", group: "sheet", label: "Liturgien"}) + } + }, + template: `systems/DSA_4-1/templates/actor/character/tab-liturgies.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/meta.mjs b/src/module/sheets/character/meta.mjs new file mode 100644 index 00000000..de5d56fe --- /dev/null +++ b/src/module/sheets/character/meta.mjs @@ -0,0 +1,20 @@ +export default { + _prepareContext: (context, object) => { + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "meta", group: "sheet", label: "Meta"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-meta.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/skills.mjs b/src/module/sheets/character/skills.mjs new file mode 100644 index 00000000..9cf1d9d5 --- /dev/null +++ b/src/module/sheets/character/skills.mjs @@ -0,0 +1,82 @@ +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const prepareEigenschaftRoll = (actorData, name) => { + if (name && name !== "*") { + return actorData.system.attribute[name.toLowerCase()].aktuell + } else { + return 0 + } + } + + + context.skills = {}; + context.flatSkills = []; + + actorData.itemTypes.Skill.forEach((item, index) => { + + const talentGruppe = item.system.gruppe; + const eigenschaften = Object.values(item.system.probe); + const werte = [ + {name: eigenschaften[0], value: prepareEigenschaftRoll(actorData, eigenschaften[0])}, + {name: eigenschaften[1], value: prepareEigenschaftRoll(actorData, eigenschaften[1])}, + {name: eigenschaften[2], value: prepareEigenschaftRoll(actorData, eigenschaften[2])} + ] + if (context.skills[talentGruppe] == null) { + context.skills[talentGruppe] = []; + } + const obj = { + type: "talent", + gruppe: talentGruppe, + name: item.name.replace(/Sprachen kennen/g, "Sprache:").replace(/Lesen\/Schreiben/g, "Schrift: "), + taw: "" + item.system.taw, + tawPath: `system.items.${index}.taw`, + werte, + rollEigenschaft1: werte[0].value, + rollEigenschaft2: werte[1].value, + rollEigenschaft3: werte[2].value, + eigenschaft1: werte[0].name, + eigenschaft2: werte[1].name, + eigenschaft3: werte[2].name, + probe: `(${eigenschaften.join("/")})`, + id: item._id, + at: item.system.at, + pa: item.system.pa, + komplexität: item.system.komplexität + }; + + if (talentGruppe === "Kampf") { + + if (item.system.pa != null) { // has no parry value so it must be ranged talent (TODO: but it isnt as there can be combatstatistics which has no pa value assigned to) + obj.at = item.system.at + context.derived.at.aktuell + obj.pa = item.system.pa + context.derived.pa.aktuell + } else { + obj.at = item.system.at + context.derived.fk.aktuell + } + } + + context.skills[talentGruppe].push(obj); + context.flatSkills.push(obj); + } + + ) + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "skills", group: "sheet", label: "Talente"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-skills.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/social.mjs b/src/module/sheets/character/social.mjs new file mode 100644 index 00000000..c97eb622 --- /dev/null +++ b/src/module/sheets/character/social.mjs @@ -0,0 +1,20 @@ +export default { + _prepareContext: (context, object) => { + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "social", group: "sheet", label: "Soziales"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-social.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/spells.mjs b/src/module/sheets/character/spells.mjs new file mode 100644 index 00000000..920283c7 --- /dev/null +++ b/src/module/sheets/character/spells.mjs @@ -0,0 +1,55 @@ +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const cleanUpMerkmal = (merkmale) => { + return merkmale.split(",").map((merkmal) => merkmal.trim()) + } + + + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "Spell") { + const eigenschaften = item.system.probe; + const werte = [ + {name: eigenschaften[0], value: this.prepareEigenschaftRoll(actorData, eigenschaften[0])}, + {name: eigenschaften[1], value: this.prepareEigenschaftRoll(actorData, eigenschaften[1])}, + {name: eigenschaften[2], value: this.prepareEigenschaftRoll(actorData, eigenschaften[2])} + ] + context.spells.push({ + id: item._id, + name: item.name, + zfw: item.system.zfw, + hauszauber: item.system.hauszauber, + merkmal: cleanUpMerkmal(item.system.merkmal), + rollEigenschaft1: werte[0].value, + rollEigenschaft2: werte[1].value, + rollEigenschaft3: werte[2].value, + eigenschaft1: werte[0].name, + eigenschaft2: werte[1].name, + eigenschaft3: werte[2].name, + }) + } + }) + context.hasSpells = context.spells.length > 0 + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group, thisObject) => { + const hasSpells = thisObject.document.items.filter(p => p.type === "Spell").length > 0 ?? false + if (hasSpells) { + group.tabs.push({id: "spells", group: "sheet", label: "Zauber"}) + } + }, + template: `systems/DSA_4-1/templates/actor/character/tab-spells.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index af8fdb09..d0b6e6ec 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -1,1097 +1,442 @@ -import {PlayerCharacterDataModel} from "../data/character.mjs"; -import {ActionManager} from "./actions/action-manager.mjs"; -import {LiturgyData} from "../data/miracle/liturgydata.mjs"; -import {ModifyLiturgy} from "../dialog/modify-liturgy.mjs"; +import Advsf from "./character/advsf.mjs" +import Combat from "./character/combat.mjs" +import Effects from "./character/effects.mjs" +import Equipment from "./character/equipment.mjs" +import Liturgies from "./character/liturgies.mjs" +import Meta from "./character/meta.mjs" +import Skills from "./character/skills.mjs" +import Social from "./character/social.mjs"; +import Spells from "./character/spells.mjs" -export class CharacterSheet extends foundry.appv1.sheets.ActorSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'actor', 'character'], - width: 1100, - height: 480, - tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, - ], - }); - } +const {HandlebarsApplicationMixin} = foundry.applications.api +const {ActorSheetV2} = foundry.applications.sheets +const {ContextMenu} = foundry.applications.ux - /** @override */ - get template() { - return `systems/DSA_4-1/templates/actor/actor-character-sheet.hbs`; - } - static onDroppedData(actor, characterSheet, data) { - const uuid = foundry.utils.parseUuid(data.uuid); - const collection = uuid.collection.index ?? uuid.collection; - const document = CharacterSheet.getElementByName(collection, uuid.id); - const { - name, - type - } = document - console.log(name, type) - switch (type) { - case "Skill": - return characterSheet.#handleDroppedSkill(actor, document); // on false cancel this whole operation - case "Advantage": - return characterSheet.#handleDroppedAdvantage(actor, document); - case "ActiveEffect": - return characterSheet.#handleDroppedActiveEffect(actor, document); - case "Equipment": - return characterSheet.#handleDroppedEquipment(actor, document); - case "Liturgy": - return characterSheet.#handleDroppedLiturgy(actor, document); - case "SpecialAbility": - return characterSheet.#handleDroppedSpecialAbility(actor, document); - default: - return false; +class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 1100, height: 640}, + classes: ['dsa41', 'sheet', 'actor', 'character'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: CharacterSheet.#onSubmitForm + }, + window: { + resizable: true, + }, + actions: { + rollCombatSkill: CharacterSheet.#rollCombatSkill, + rollSkill: CharacterSheet.#rollSkill, + roll: CharacterSheet.#dieRoll, + editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, + openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument, + openCultureDocument: CharacterSheet.#openCultureDocument, + openSpeciesDocument: CharacterSheet.#openSpeciesDocument, + } - } - static getElementByName(collection, id) { - const array = Array.from(collection); - for (const element of array) { - if (element._id === id) { - return element; - } + static TABS = { + sheet: { + tabs: [], + initial: 'meta' } } - #addSkillsToContext(context) { - const actorData = context.data; - context.skills = {}; - context.flatSkills = []; - - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Skill") { - - const talentGruppe = item.system.gruppe; - const eigenschaften = Object.values(item.system.probe); - const werte = [ - {name: eigenschaften[0], value: this.prepareEigenschaftRoll(actorData, eigenschaften[0])}, - {name: eigenschaften[1], value: this.prepareEigenschaftRoll(actorData, eigenschaften[1])}, - {name: eigenschaften[2], value: this.prepareEigenschaftRoll(actorData, eigenschaften[2])} - ] - if (context.skills[talentGruppe] == null) { - context.skills[talentGruppe] = []; - } - const obj = { - type: "talent", - gruppe: talentGruppe, - name: item.name, - taw: "" + item.system.taw, - tawPath: `system.items.${index}.taw`, - werte, - rollEigenschaft1: werte[0].value, - rollEigenschaft2: werte[1].value, - rollEigenschaft3: werte[2].value, - eigenschaft1: werte[0].name, - eigenschaft2: werte[1].name, - eigenschaft3: werte[2].name, - probe: `(${eigenschaften.join("/")})`, - id: item._id, - at: item.system.at, - pa: item.system.pa, - komplexität: item.system.komplexität - }; - - if (talentGruppe === "Kampf") { - - if (item.system.pa != null) { // has no parry value so it must be ranged talent (TODO: but it isnt as there can be combatstatistics which has no pa value assigned to) - obj.at = item.system.at + context.derived.at.aktuell - obj.pa = item.system.pa + context.derived.pa.aktuell - } else { - obj.at = item.system.at + context.derived.fk.aktuell - } - } - - context.skills[talentGruppe].push(obj); - context.flatSkills.push(obj); - } - } - ); - } - - #cleanUpMerkmal(merkmale) { - return merkmale.split(",").map((merkmal) => merkmal.trim()) - } - - /** @override */ - async getData() { - const context = super.getData(); - - - // Use a safe clone of the actor data for further operations. - const actorData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = actorData.system; - context.flags = actorData.flags; - context.derived = context.document.system; - context.originalName = actorData.name; - context.name = context.derived.name ?? actorData.name; - context.effects = actorData.effects ?? []; - - context.maxWounds = actorData.system.wunden.max ?? 3; - context.wounds = actorData.system.wunden.aktuell ?? 0; - context.woundsFilled = []; - for (let i = 1; i <= context.maxWounds; i++) { - context.woundsFilled[i] = i <= context.wounds - } - - context.zonenruestung = game.settings.get("DSA_4-1", "optional_ruestungzonen") - context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen") - context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") - - - this.#addEffectsToContext(context) - this.#addSkillsToContext(context) - this.#addAdvantagesToContext(context) - this.#addSpecialAbilitiesToContext(context) - await this.#addAttributesToContext(context) - this.#addEquipmentsToContext(context) - await this.#addCombatStatistics(context) - this.#addActionsToContext(context) - this.#addSpellsToContext(context) - this.#addLiturgiesToContext(context) - return context; - } - - #addEffectsToContext(context) { - const actorData = context.data; - - context.isGM = game.user.isGM - context.effects = []; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "ActiveEffect") { - const effect = item.effects[0]; - const conditions = [] - - if (effect) { - effect.changes.forEach(change => { - if (change.key.indexOf("wunden") === -1) { - const key = change.key - .replace(/system\./g, "") - .replace(/\.mod/g, "") - .replace(/attribute./g, "") - .replace(/.links/g, "(Links)") - .replace(/.rechts/g, "(Rechts)") - const value = Number(change.value) > 0 ? "+" + change.value : change.value; - conditions.push( - `${key}${value}` - ) - } - }) - } - - context.effects.push({ - name: item.name, - conditions: conditions.join(" "), - id: item._id, - actor: actorData._id - }); - } - }) - } - - #addSpellsToContext(context) { - const actorData = context.data; - context.spells = []; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Spell") { - const eigenschaften = item.system.probe; - const werte = [ - {name: eigenschaften[0], value: this.prepareEigenschaftRoll(actorData, eigenschaften[0])}, - {name: eigenschaften[1], value: this.prepareEigenschaftRoll(actorData, eigenschaften[1])}, - {name: eigenschaften[2], value: this.prepareEigenschaftRoll(actorData, eigenschaften[2])} - ] - context.spells.push({ - id: item._id, - name: item.name, - zfw: item.system.zfw, - hauszauber: item.system.hauszauber, - merkmal: this.#cleanUpMerkmal(item.system.merkmal), - rollEigenschaft1: werte[0].value, - rollEigenschaft2: werte[1].value, - rollEigenschaft3: werte[2].value, - eigenschaft1: werte[0].name, - eigenschaft2: werte[1].name, - eigenschaft3: werte[2].name, - }) - } - }) - context.hasSpells = context.spells.length > 0; - } - - async #getModsOfAttribute(keyPath) { - let returnValue = []; - Array.from(this.object.appliedEffects).forEach( - (e) => - e.changes.filter(c => c.key === keyPath).forEach(change => { - returnValue.push({ - name: e.name, - value: change.value > 0 ? "+" + change.value : "" + change.value, - icon: e.icon, - }) - })) - return returnValue; - } - - async #addAttributesToContext(context) { - context.mods = { - "mu": await this.#getModsOfAttribute('system.attribute.mu.mod'), - "kl": await this.#getModsOfAttribute('system.attribute.kl.mod'), - "in": await this.#getModsOfAttribute('system.attribute.in.mod'), - "ch": await this.#getModsOfAttribute('system.attribute.ch.mod'), - "ff": await this.#getModsOfAttribute('system.attribute.ff.mod'), - "ge": await this.#getModsOfAttribute('system.attribute.ge.mod'), - "ko": await this.#getModsOfAttribute('system.attribute.ko.mod'), - "kk": await this.#getModsOfAttribute('system.attribute.kk.mod'), - "at": await this.#getModsOfAttribute('system.at.mod'), - "pa": await this.#getModsOfAttribute('system.pa.mod'), - "fk": await this.#getModsOfAttribute('system.fk.mod'), - - } - context.attributes = [ - { - eigenschaft: "mu", - name: "MU", - tooltip: "Mut", - wert: context.derived.attribute.mu.aktuell ?? 0, - }, - { - eigenschaft: "kl", - name: "KL", - tooltip: "Klugheit", - wert: context.derived.attribute.kl.aktuell ?? 0, - }, - { - eigenschaft: "in", - name: "IN", - tooltip: "Intuition", - wert: context.derived.attribute.in.aktuell ?? 0, - }, - { - eigenschaft: "ch", - name: "CH", - tooltip: "Charisma", - wert: context.derived.attribute.ch.aktuell ?? 0, - }, - { - eigenschaft: "ff", - name: "FF", - tooltip: "Fingerfertigkeit", - wert: context.derived.attribute.ff.aktuell ?? 0, - }, - { - eigenschaft: "ge", - name: "GE", - tooltip: "Geschicklichkeit", - wert: context.derived.attribute.ge.aktuell ?? 0, - }, - { - eigenschaft: "ko", - name: "KO", - tooltip: "Konstitution", - wert: context.derived.attribute.ko.aktuell ?? 0, - }, - { - eigenschaft: "kk", - name: "KK", - tooltip: "Körperkraft", - wert: context.derived.attribute.kk.aktuell ?? 0, - }, - - ]; - - } - - #addAdvantagesToContext(context) { - context.advantages = []; - const actorData = context.data; - Object.values(actorData.items).forEach((item) => { - if (item.type === "Advantage") { - context.advantages.push({ - id: item._id, - name: item.name, - value: item.system.value, - options: item.system.auswahl, - description: item.system.description, - isAdvantage: !item.system.nachteil, - isDisadvantage: item.system.nachteil, - isBadAttribute: item.system.schlechteEigenschaft - }); - } - } - ); - } - - #addSpecialAbilitiesToContext(context) { - context.specialAbilities = []; - const actorData = context.data; - Object.values(actorData.items).forEach((item) => { - if (item.type === "SpecialAbility") { - context.specialAbilities.push({ - id: item._id, - name: item.name, - }); - } - } - ); - } - - #findEquipmentOnSlot(slot, setNumber) { - return this.object.items.get(this.object.system.heldenausruestung[setNumber]?.[slot]) - } - - #addActionsToContext(context) { - const am = new ActionManager(this.object) - context.actions = am.evaluate() - } - - #isWorn(itemId) { - - const slots = PlayerCharacterDataModel.getSlots() - const set = this.object.system.heldenausruestung[this.object.system.setEquipped] - if (set) { - for (const slot of slots) { - const equipmentSlotId = set[slot] - if (equipmentSlotId === itemId) { - return slot - } - } - } - - return false - } - - async #addCombatStatistics(context) { - const actorData = context.data; - - context.inidice = actorData.system.ini.wuerfel; - context.inivalue = actorData.system.ini.aktuell; - context.inimod = actorData.system.ini.mod; - - context.aupper = Math.min((context.actor.system.aup.aktuell / context.actor.system.aup.max) * 100, 100); - context.lepper = Math.min((context.actor.system.lep.aktuell / context.actor.system.lep.max) * 100, 100); - context.keper = Math.min((context.actor.system.kap.aktuell / context.actor.system.kap.max) * 100, 100); - context.aspper = Math.min((context.actor.system.asp.aktuell / context.actor.system.asp.max) * 100, 100); - context.lepcurrent = context.actor.system.lep.aktuell ?? 0 - - context.aupcurrent = context.actor.system.aup.aktuell ?? 0 - - const fernkampf = this.#findEquipmentOnSlot("fernkampf", context.actor.system.setEquipped) - const links = this.#findEquipmentOnSlot("links", context.actor.system.setEquipped) - const rechts = this.#findEquipmentOnSlot("rechts", context.actor.system.setEquipped) - context.attacks = []; - - if (fernkampf) { - const fkitems = fernkampf.system.rangedSkills.map(async (skillInQuestion) => await this.object.items.getName(skillInQuestion)) - fkitems.forEach(async skill => { - const obj = await skill - context.attacks.push({ - name: obj.name, - using: fernkampf.name, - atroll: `1d20cs<${this.object.system.fk.aktuell + obj.system.at}`, - at: `${this.object.system.fk.aktuell + obj.system.at}`, - tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod - tp: `${fernkampf.system.rangedAttackDamage}`, - iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, - ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, - }) - }) - } - if (links) { - const meitems = links.system.meleeSkills.map(async (skillInQuestion) => await this.object.items.getName(skillInQuestion)) - meitems.forEach(async skill => { - const obj = await skill - context.attacks.push({ - name: obj.name, - using: links.name, - atroll: `1d20cs<${this.object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M - at: `${this.object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, - paroll: `1d20cs<${this.object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M - pa: `${this.object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, - tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod - tp: `${links.system.meleeAttackDamage}`, - iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, - ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`, - }) - }) - } - if (rechts) { - const meitems = rechts.system.meleeSkills.map(async (skillInQuestion) => await this.object.items.getName(skillInQuestion)) - meitems.forEach(async skill => { - const obj = await skill - console.log(this.object.system.at) - context.attacks.push({ - name: obj.name, - using: rechts.name, - atroll: `1d20cs<${this.object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M - at: `${this.object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, - paroll: `1d20cs<${this.object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M - pa: `${this.object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, - tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod - tp: `${rechts.system.meleeAttackDamage}`, - iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, - ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, - }) - }) - } - - // add weapons to sidebar - } - - prepareEigenschaftRoll(actorData, name) { - if (name && name !== "*") { - return actorData.system.attribute[name.toLowerCase()].aktuell - } else { - return 0 + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/character/main-sheet.hbs` + }, + meta: { + template: Meta.template + }, + social: { + template: Social.template + }, + advsf: { + template: Advsf.template + }, + combat: { + template: Combat.template + }, + equipment: { + template: Equipment.template + }, + skills: { + template: Skills.template + }, + spells: { + template: Spells.template + }, + liturgies: { + template: Liturgies.template + }, + effects: { + template: Effects.template } } - #addEquipmentsToContext(context) { - context.equipments = []; - const actorData = context.data; - context.carryingweight = 0; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Equipment") { - // worn items are halved weight - - let effectiveWeight = item.system.weight ?? 0 - if (this.#isWorn(item._id)) { - effectiveWeight = item.system.weight ? item.system.weight / 2 : 0 - } - - context.equipments.push({ - index: index, - id: item._id, - quantity: item.system.quantity, - name: item.name, - icon: item.img ?? "", - weight: item.system.weight, - worn: this.#isWorn(item._id) - }) - context.carryingweight += item.system.quantity * effectiveWeight; - } - }) - context.maxcarryingcapacity = actorData.system.attribute.kk.aktuell - context.carryingpercentage = Math.min((context.carryingweight / context.maxcarryingcapacity) * 100, 100); - - const maxSets = 3 - const romanNumerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"] - context.sets = [] - for (let setIndex = 0; setIndex < maxSets; setIndex++) { - - context.sets.push({ - tab: "set" + (setIndex + 1), - name: romanNumerals[setIndex], - index: setIndex, - slots: [ - { - target: "links", - id: this.object.system.heldenausruestung[setIndex]?.links, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.img - }, - { - target: "rechts", - id: this.object.system.heldenausruestung[setIndex]?.rechts, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.img - }, - { - target: "brust", - id: this.object.system.heldenausruestung[setIndex]?.brust, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.img - }, - { - target: "ruecken", - id: this.object.system.heldenausruestung[setIndex]?.ruecken, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.img - }, - { - target: "kopf", - id: this.object.system.heldenausruestung[setIndex]?.kopf, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.img - }, - { - target: "fernkampf", - id: this.object.system.heldenausruestung[setIndex]?.fernkampf, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.img - }, - { - target: "munition", - id: this.object.system.heldenausruestung[setIndex]?.munition, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.img - }, - { - target: "armlinks", - id: this.object.system.heldenausruestung[setIndex]?.armlinks, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.img - }, - { - target: "armrechts", - id: this.object.system.heldenausruestung[setIndex]?.armrechts, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.img - }, - { - target: "bauch", - id: this.object.system.heldenausruestung[setIndex]?.bauch, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.img - }, - { - target: "beinlinks", - id: this.object.system.heldenausruestung[setIndex]?.beinlinks, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.img - }, - { - target: "beinrechts", - id: this.object.system.heldenausruestung[setIndex]?.beinrechts, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.img - } - ] - }) + /** + * + * @param {PointerEvent} event + */ + static #rollSkill(event) { + const {id} = event.target.dataset + const skill = this.document.items.get(id) + if (skill?.system?.roll) { + skill.system.roll("publicroll") } } - async _onTalentRoll(event) { - event.preventDefault(); - const dataset = event.currentTarget.dataset; - console.log(dataset) - if (dataset.rolleigenschaft1) { - let roll1 = new Roll("3d20", this.actor.getRollData()); - - let evaluated1 = (await roll1.evaluate()) - - const dsaDieRollEvaluated = this._evaluateRoll(evaluated1.terms[0].results, { - taw: dataset.taw, - werte: [dataset.rolleigenschaft1, dataset.rolleigenschaft2, dataset.rolleigenschaft3], - }) - - if (dsaDieRollEvaluated.tap >= 0) { // erfolg - evaluated1.toMessage({ - speaker: ChatMessage.getSpeaker({actor: this.actor}), - flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Meisterlich geschafft' : 'Geschafft'} mit ${dsaDieRollEvaluated.tap} Punkten übrig`, - rollMode: game.settings.get('core', 'rollMode'), - }) - } else { // misserfolg - evaluated1.toMessage({ - speaker: ChatMessage.getSpeaker({actor: this.actor}), - flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Gepatzt' : ''} mit ${Math.abs(dsaDieRollEvaluated.tap)} Punkten daneben`, - rollMode: game.settings.get('core', 'rollMode'), - }) - } + /** + * + * @param {PointerEvent} event + */ + static #rollCombatSkill(event) { + const {id} = event.target.dataset + const skill = this.document.items.get(id) + if (skill?.system?.roll) { + skill.system.roll("publicroll", event.shiftKey ? "PARRY" : "ATTACK") } } - _evaluateRoll(rolledDice, { - taw, - lowerThreshold = 1, - upperThreshold = 20, - countToMeisterlich = 3, - countToPatzer = 3, - werte = [] - }) { - let tap = taw; - let meisterlichCounter = 0; - let patzerCounter = 0; - let failCounter = 0; - - rolledDice.forEach((rolledDie, index) => { - if (tap < 0 && rolledDie.result > werte[index]) { - tap -= rolledDie.result - werte[index]; - if (tap < 0) { // konnte nicht vollständig ausgeglichen werden - failCounter++; - } - } else if (rolledDie.result > werte[index]) { // taw ist bereits aufgebraucht und wert kann nicht ausgeglichen werden - tap -= rolledDie.result - werte[index]; - failCounter++; - } - if (rolledDie.result <= lowerThreshold) meisterlichCounter++; - if (rolledDie.result > upperThreshold) patzerCounter++; - }) - - return { - tap, - meisterlich: meisterlichCounter === countToMeisterlich, - patzer: patzerCounter === countToPatzer, - } - } - - _onAttributeRoll(event) { - event.preventDefault(); - const dataset = event.currentTarget.dataset; + static #dieRoll(event) { + event.preventDefault() + const dataset = event.currentTarget.dataset if (dataset.roll) { - let label = dataset.label ? `[Attribut] ${dataset.label}` : ''; - let roll = new Roll(dataset.roll, this.actor.getRollData()); + let label = dataset.label ? `[Attribut] ${dataset.label}` : '' + let roll = new Roll(dataset.roll, this.actor.getRollData()) roll.toMessage({ speaker: ChatMessage.getSpeaker({actor: this.actor}), flavor: label, rollMode: game.settings.get('core', 'rollMode'), }); - return roll; + return roll } } - openEmbeddedDocument(documentId) { - this.object.items.get(documentId).sheet.render(true) + /** + * + * @param {MouseEvent} event + */ + static #openEmbeddedDocument(event) { + const dataset = event.target.dataset + const id = dataset.itemId ?? dataset.id + this.document.items.get(id).sheet.render(true) } - _onRoll(event) { - event.preventDefault(); - const dataset = event.currentTarget.dataset; - if (dataset.roll) { - let label = dataset.label ? `${dataset.label}` : ''; - let roll = new Roll(dataset.roll, this.actor.getRollData()); - roll.toMessage({ - speaker: ChatMessage.getSpeaker({actor: this.actor}), - flavor: label, - rollMode: game.settings.get('core', 'rollMode'), - }); - return roll; - } + static #openCultureDocument() { + this.document.itemTypes["Culture"]?.[0]?.sheet.render(true) } - #mapAllSets() { - const updateObject = {} - Array.from(this.object.system.heldenausruestung).forEach((equipmentSet, index) => { - updateObject[`system.heldenausruestung.${index}.links`] = equipmentSet.links; - updateObject[`system.heldenausruestung.${index}.rechts`] = equipmentSet.rechts; - updateObject[`system.heldenausruestung.${index}.brust`] = equipmentSet.brust; - updateObject[`system.heldenausruestung.${index}.bauch`] = equipmentSet.bauch; - updateObject[`system.heldenausruestung.${index}.ruecken`] = equipmentSet.ruecken; - updateObject[`system.heldenausruestung.${index}.kopf`] = equipmentSet.kopf; - updateObject[`system.heldenausruestung.${index}.fernkampf`] = equipmentSet.fernkampf; - updateObject[`system.heldenausruestung.${index}.munition`] = equipmentSet.munition; - updateObject[`system.heldenausruestung.${index}.armlinks`] = equipmentSet.armlinks; - updateObject[`system.heldenausruestung.${index}.armrechts`] = equipmentSet.armrechts; - updateObject[`system.heldenausruestung.${index}.beinlinks`] = equipmentSet.beinlinks; - updateObject[`system.heldenausruestung.${index}.beinrechts`] = equipmentSet.beinrechts; - - }) - return updateObject; + static #openSpeciesDocument() { + this.document.itemTypes["Species"]?.[0]?.sheet.render(true) } - showAdjustAttributeDialog(attributeName, attributeField, previousValue) { - const thisActor = this; - const myContent = ` - Value: - - `; + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() - function updateAttribute(html) { - const value = html.find("input#attributeValue").val(); - const attribute = {} - attribute[attributeField.toLowerCase()] = { - aktuell: value - } - thisActor.object.update({system: {attribute}}) + await this.document.update(formData.object) // Note: formData.object + } + + + _getTabsConfig(group) { + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + Meta._getTabConfig(tabs, this); + Social._getTabConfig(tabs, this); + Advsf._getTabConfig(tabs, this) + Combat._getTabConfig(tabs, this) + Equipment._getTabConfig(tabs, this) + Skills._getTabConfig(tabs, this) + Spells._getTabConfig(tabs, this) + Liturgies._getTabConfig(tabs, this) + Effects._getTabConfig(tabs, this) + return tabs } - new Dialog({ - title: `${attributeName} ändern auf`, - content: myContent, - buttons: { - button1: { - label: "Ändern", - callback: (html) => { - updateAttribute(html) - }, - icon: `` - } - } - }).render(true); + async _preparePartContext(partId, context) { + switch (partId) { + case "form": - } - - #addLiturgiesToContext(context) { - const actorData = context.data; - context.liturgies = []; - context.blessings = []; - - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Blessing") { - context.blessings.push({ - deity: item.system.gottheit, - value: item.system.wert - }) - } - }) - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Liturgy") { - - context.blessings.forEach(({deity, value}) => { - let insertObject = context.liturgies.find(p => p.deity === deity); - if (!insertObject) { - insertObject = { - deity: deity, - lkp: value, - O: [], - I: [], - II: [], - III: [], - IV: [], - V: [], - VI: [], - VII: [], - VIII: [], - "NA": [], - countO: 1, - countI: 1, - countII: 1, - countIII: 1, - countIV: 1, - countV: 1, - countVI: 1, - countVII: 1, - countVIII: 1, - countNA: 0, - total: 3, + const actorData = context.document + context.system = actorData.system + context.isOwner = actorData.isOwner + context.flags = actorData.flags + context.derived = context.document.system + context.professions = actorData.items.filter(p => p.type === 'Profession').map(p => { + // is tarnidentitaet revealed? + if (p.system.revealed) { + return { + id: p.id, + name: p.name, + alias: p.system.alias, + } + } else { + return { + id: p.id, + name: p.system.alias ?? p.name, + alias: p.name, } - context.liturgies.push(insertObject); } + }) - // sort by rank - const rankData = LiturgyData.getRankOfLiturgy(item.system, deity) - if (rankData) { - let {index, name, lkp, mod, costKaP} = rankData; + context.spezies = "" + if (actorData.itemTypes["Species"]?.[0]) { + const speciesData = actorData.itemTypes["Species"][0] + if (actorData.system.geschlecht === "männlich") { + context.spezies = speciesData.system.masculineDemonym + } else { + context.spezies = speciesData.system.feminineDemonym + } + } - insertObject["count" + name] = insertObject["count" + name] + 1; + context.kultur = "" + if (actorData.itemTypes["Culture"]?.[0]) { + const cultureData = actorData.itemTypes["Culture"][0] + if (actorData.system.geschlecht === "männlich") { + context.kultur = cultureData.system.masculineDemonym + } else { + context.kultur = cultureData.system.feminineDemonym + } + } - insertObject[name].push({ - id: item._id, - name: item.name, - lkpReq: lkp, - lkpMod: mod, - costKaP, - rank: index, // get effective liturgy rank based on deity - liturgiekenntnis: deity, + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.img = actorData.img + context.effects = actorData.effects ?? [] + + context.maxWounds = actorData.system.wunden.max ?? 3 + context.wounds = actorData.system.wunden.aktuell ?? 0 + context.woundsFilled = [] + for (let i = 1; i <= context.maxWounds; i++) { + context.woundsFilled[i] = i <= context.wounds + } + + context.zonenruestung = game.settings.get("DSA_4-1", "optional_ruestungzonen") + context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen") + context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") + context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice') + + + context.inidice = actorData.system.ini.wuerfel + context.inivalue = actorData.system.ini.aktuell + context.inimod = actorData.system.ini.mod + + context.aupper = Math.min((actorData.system.aup.aktuell / actorData.system.aup.max) * 100, 100) + context.lepper = Math.min((actorData.system.lep.aktuell / actorData.system.lep.max) * 100, 100) + context.keper = Math.min((actorData.system.kap.aktuell / actorData.system.kap.max) * 100, 100) + context.aspper = Math.min((actorData.system.asp.aktuell / actorData.system.asp.max) * 100, 100) + context.lepcurrent = actorData.system.lep.aktuell ?? 0 + + context.aupcurrent = actorData.system.aup.aktuell ?? 0 + + const fernkampf = actorData.findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData) + const links = actorData.findEquipmentOnSlot("links", actorData.system.setEquipped, actorData) + const rechts = actorData.findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData) + context.attacks = []; + + if (fernkampf) { + const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion)) + fkitems.forEach(async skill => { + const obj = await skill + context.attacks.push({ + name: obj.name, + using: fernkampf.name, + atroll: `1d20cs<${this.document.system.fk.aktuell + obj.system.at}`, + at: `${this.document.system.fk.aktuell + obj.system.at}`, + tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod + tp: `${fernkampf.system.rangedAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + }) + }) + } + if (links) { + const meitems = [] + links.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: links.name, + atroll: `1d20cs<${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M + at: `${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, + paroll: `1d20cs<${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M + pa: `${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, + tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${links.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + }) + }) + } + if (rechts) { + const meitems = [] + rechts.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: rechts.name, + atroll: `1d20cs<${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M + at: `${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, + paroll: `1d20cs<${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M + pa: `${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, + tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${rechts.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, }) - insertObject.total = insertObject.total + 2; - - } - }) - } - }) - - - // clean up counter - Object.values(context.liturgies).forEach((litObject) => { - - if (litObject.I.length === 0) litObject.countI = false; - if (litObject.II.length === 0) litObject.countII = false; - if (litObject.III.length === 0) litObject.countIII = false; - if (litObject.IV.length === 0) litObject.countIV = false; - if (litObject.V.length === 0) litObject.countV = false; - if (litObject.VI.length === 0) litObject.countVI = false; - if (litObject.VII.length === 0) litObject.countVII = false; - if (litObject.VIII.length === 0) litObject.countVIII = false; - if (litObject.NA.length === 0) litObject.countNA = false; - - - }) - - context.hasLiturgies = context.blessings.length > 0; - } - - #handleDroppedSkill(actor, skill) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === skill.name) { - return false; - } - } - } - - async #handleDroppedActiveEffect(actor, activeEffect) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === activeEffect.name) { - // replace active effect if its unique - - return true; - } - } - } - - #handleDroppedAdvantage(actor, advantage) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === advantage.name) { // TODO: adjust for uniqueness - return false; - } - } - } - - activateListeners(html) { - super.activateListeners(html); - - const tabs = new foundry.applications.ux.Tabs({ - navSelector: ".paperdoll-tabs.tabs", - contentSelector: ".sheet-body.paperdoll-sets", - initial: "set" + (this.object.system.setEquipped + 1) - }); - tabs.bind(html[0]); - - html.on('click', '.attribute.rollable', (evt) => { - this._onAttributeRoll(evt); - }); - - html.on('click', '[data-operation="switchSet"]', (evt) => { - const {id} = evt.currentTarget.dataset; - console.log(id); - this.object.update({"system.setEquipped": id}) - }) - - html.on('click', '[data-operation="removeEffect"]', (evt) => { - const {actorId, effectId} = evt.currentTarget.dataset; - if (game.user.isGM) { - this.object.items.get(effectId).delete(); - } - }) - - html.on('click', '.talent.rollable', (evt) => { - this._onTalentRoll(evt); - }); - - html.on('click', '.sidebar-element.rollable', (evt) => { - this._onRoll(evt); - }); - - // TODO: merge into click.clickable handler - html.on('click', '.talent .name', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - // TODO: merge into click.clickable handler - html.on('click', '.advantage .name', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - // TODO: merge into click.clickable handler - html.on('click', '.equipment', (evt) => { - this.openEmbeddedDocument(evt.target.parentElement.dataset.id); - evt.stopPropagation(); - }) - - html.on('click', '.clickable', async (evt) => { - const {id, operation} = evt.currentTarget.dataset; - if (operation === "openActorSheet") { - this.openEmbeddedDocument(id); - evt.stopPropagation(); - } - }) - - html.on('dragstart', '.equipment', (evt) => { - evt.originalEvent.dataTransfer.setData("application/json", JSON.stringify({ - documentId: evt.currentTarget.dataset.id - })); - }) - - html.on('drop', '.equipped', async (evt) => { - const {actor, target, setId} = evt.currentTarget.dataset; - try { - const {documentId} = JSON.parse(evt.originalEvent.dataTransfer.getData("application/json")); - - - if (actor === this.object._id && documentId) { // managing equipped items - //const slot = this.#isWorn(documentId, setId) - //const updateObject = await this.#getEquipmentset(Number(setId)) - const updateObject = this.#mapAllSets() - updateObject[`system.heldenausruestung.${setId}.${target}`] = documentId; - console.log(updateObject); - - await this.object.update(updateObject); - } - - evt.stopPropagation(); - } catch (e) { - } - }) - - new foundry.applications.ux.ContextMenu(html[0], '.talent.rollable', [ - { - name: "Entfernen", - icon: '', - callback: (event) => { - this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) - }, - condition: () => true - } - ], { - jQuery: false - }); - - - new foundry.applications.ux.ContextMenu(html[0], '.attribute.rollable', [ - { - name: "Anpassen", - icon: '', - callback: (event) => { - this.showAdjustAttributeDialog(event[0].dataset.name, event[0].dataset.label, event[0].dataset.value) - }, - condition: () => true - } - ], { - jQuery: false - }); - - let handler = evt => { - const talentId = evt.target.dataset.id - evt.dataTransfer.setData("application/json", JSON.stringify({ - talentId - })); - this._onDragStart(evt) - - } - - // Find all items on the character sheet. - html.find('.talent.rollable').each((i, li) => { - // Add draggable attribute and dragstart listener. - li.setAttribute("draggable", true); - li.addEventListener("dragstart", handler, false); - }); - - new foundry.applications.ux.ContextMenu(html[0], '.equipment', [ - { - name: "Aus dem Inventar entfernen", - icon: '', - callback: (event) => { - // TODO find id on heldenausruestung to remove the worn items as well - this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) - }, - condition: () => true - } - ], { - jQuery: false - }); - - new foundry.applications.ux.ContextMenu(html[0], '.equipped', [ - { - name: "Gegenstand vom Set entfernen", - callback: (event) => { - const {setId, target, actor} = event[0].dataset - - const updateObject = this.#mapAllSets() - updateObject[`system.heldenausruestung.${setId}.${target}`] = null; - - this.object.update(updateObject); - }, - condition: () => true - } - ], { - jQuery: false - }); - - html.on('click', '[data-operation="addWounds"]', async (evt) => { - const {value} = evt.currentTarget.dataset - this.object.update({"system.wunden.aktuell": value}) - }) - - html.on('click', '[data-operation="reduceWounds"]', async (evt) => { - const {value} = evt.currentTarget.dataset - this.object.update({"system.wunden.aktuell": value}) - }) - - html.on('click', '.liturgy.rollable', async (evt) => { - - evt.stopPropagation(); - - const {id, rank, lkp, deity} = evt.currentTarget.dataset; - const document = await this.object.items.get(id) - - const data = {}; - - data.rank = rank; - data.lkp = lkp; - data.deity = deity; - data.variations = []; - const ranks = LiturgyData.ranks - ranks.forEach(rank => { - if (document.system.auswirkung[rank]) { - data.variations.push({ - rank, - effect: document.system.auswirkung[rank] }) } - }) - data.mods = []; - const htmlContent = await renderTemplate('systems/DSA_4-1/templates/dialog/modify-liturgy.hbs', data); - - const dialogData = { - title: document.name, - content: htmlContent, - data: {}, - buttons: { - submit: { - label: "Wirken", - icon: '', - callback: (html) => { - }, + context.attributes = [ + { + eigenschaft: "mu", + name: "MU", + tooltip: "Mut", + wert: context.derived.attribute.mu.aktuell ?? 0, }, - }, - } - dialogData.render = new ModifyLiturgy(data).handleRender + { + eigenschaft: "kl", + name: "KL", + tooltip: "Klugheit", + wert: context.derived.attribute.kl.aktuell ?? 0, + }, + { + eigenschaft: "in", + name: "IN", + tooltip: "Intuition", + wert: context.derived.attribute.in.aktuell ?? 0, + }, + { + eigenschaft: "ch", + name: "CH", + tooltip: "Charisma", + wert: context.derived.attribute.ch.aktuell ?? 0, + }, + { + eigenschaft: "ff", + name: "FF", + tooltip: "Fingerfertigkeit", + wert: context.derived.attribute.ff.aktuell ?? 0, + }, + { + eigenschaft: "ge", + name: "GE", + tooltip: "Geschicklichkeit", + wert: context.derived.attribute.ge.aktuell ?? 0, + }, + { + eigenschaft: "ko", + name: "KO", + tooltip: "Konstitution", + wert: context.derived.attribute.ko.aktuell ?? 0, + }, + { + eigenschaft: "kk", + name: "KK", + tooltip: "Körperkraft", + wert: context.derived.attribute.kk.aktuell ?? 0, + }, + ] - const dialog = new Dialog(dialogData, { - classes: ['dsa41', 'dialog', 'liturgy'], - height: 480 - }) - - dialog.render(true); - - return false; - }) - - - } - - #handleDroppedEquipment(actor, equipment) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === equipment.name) { // TODO: adjust item quantity if item is the same - return false; - } + break; + case "meta": + await Meta._prepareContext(context, this.document) + break + case "social": + await Social._prepareContext(context, this.document) + break + case "advsf": + await Advsf._prepareContext(context, this.document) + break + case "combat": + await Combat._prepareContext(context, this.document) + break + case "equipment": + await Equipment._prepareContext(context, this.document) + break + case "skills": + await Skills._prepareContext(context, this.document) + break + case "spells": + await Spells._prepareContext(context, this.document) + break + case "liturgies": + await Liturgies._prepareContext(context, this.document) + break + case "effects": + await Effects._prepareContext(context, this.document) + break } + return context } - #handleDroppedLiturgy(actor, liturgy) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === liturgy.name) { // TODO: allow multiple miracles with the same name - return false; - } - } + _onRender(context, options) { + Meta._onRender(context, options, this.element) + Social._onRender(context, options, this.element) + Advsf._onRender(context, options, this) + Combat._onRender(context, options, this.element) + Effects._onRender(context, options, this.element) + Equipment._onRender(context, options, this) + Liturgies._onRender(context, options, this.element) + Skills._onRender(context, options, this.element) + Spells._onRender(context, options, this.element) } - #handleDroppedSpecialAbility(actor, specialAbility) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === specialAbility.name) { // TODO: allow multiple miracles with the same name - return false; + async _canDragDrop() { + return true + } + + + // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 + async _onDrop(event) { + const data = TextEditor.implementation.getDragEventData(event); + const actor = this.actor; + const allowed = Hooks.call("dropActorSheetData", actor, this, data); + if (allowed === false) return; + + // Dropped Documents + const documentClass = foundry.utils.getDocumentClass(data.type); + if (documentClass) { + const document = await documentClass.fromDropData(data); + + if (document.type === "Equipment" || document.type === "Advantage" || document.type === "Spell" || document.type === "Liturgy" || document.type === "ActiveEffect" || document.type === "SpecialAbility") { + // No duplication by moving items from one actor to another + if (document.parent && document.parent !== this.actor) { + document.parent.items.get(document._id).delete() + } + + await this._onDropDocument(event, document); } } } } + +export default CharacterSheet diff --git a/src/module/sheets/creatureSheet.mjs b/src/module/sheets/creatureSheet.mjs index 2c28134d..93d21402 100644 --- a/src/module/sheets/creatureSheet.mjs +++ b/src/module/sheets/creatureSheet.mjs @@ -1,32 +1,114 @@ -export class CreatureSheet extends foundry.appv1.sheets.ActorSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'actor', 'creature'], - width: 520, - height: 480, +const {HandlebarsApplicationMixin} = foundry.applications.api +const {ActorSheetV2} = foundry.applications.sheets + +export class CreatureSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'actor', 'creature'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: CreatureSheet.#onSubmitForm + }, + actions: { + removeAttack: CreatureSheet.#removeAttack, + addAttack: CreatureSheet.#addAttack, + roll: CreatureSheet.#dieRoll, + editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, + + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'meta', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'attacks', group: 'sheet', label: 'Attacken'}, + {id: 'description', group: 'sheet', label: 'Beschreibung'}, ], + initial: 'meta' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/creature/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/actor/creature/tab-meta.hbs` + }, + attacks: { + template: `systems/DSA_4-1/templates/actor/creature/tab-attacks.hbs` + }, + description: { + template: `systems/DSA_4-1/templates/actor/creature/tab-description.hbs` + } + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + static async #removeAttack(evt) { + const {index} = evt.srcElement.dataset; + let sans = Array.from(this.document.system.attacks); + sans.splice(index, 1); + await this.document.update({'system.attacks': sans}) + } + + static async #dieRoll(evt) { + const {rollType, rollName, roll} = evt.srcElement.dataset; + let r = new Roll(roll, this.document.getRollData()); + const label = `${rollType} (${rollName})` + await r.toMessage({ + speaker: ChatMessage.getSpeaker({actor: this.document}), + flavor: label, + rollMode: game.settings.get('core', 'rollMode'), }); } - /** @override */ - get template() { - return `systems/DSA_4-1/templates/actor/actor-creature-sheet.hbs`; + static async #addAttack() { + const name = this.element.querySelector('#attack_name').value + const at = this.element.querySelector('#attack_at').value + const pa = this.element.querySelector('#attack_pa').value + const tp = this.element.querySelector('#attack_tp').value + + const newAttack = { + name, + at, + pa, + tp + } + + await this.document.update({'system.attacks': [...this.document.system.attacks, newAttack]}) + + this.element.querySelector('#attack_name').value = "" + this.element.querySelector('#attack_at').value = "" + this.element.querySelector('#attack_pa').value = "" + this.element.querySelector('#attack_tp').value = "" } /** @override */ - getData() { + async _prepareContext(options) { - const context = super.getData(); - const actorData = context.data; + const context = await super._prepareContext(options); + const actorData = context.document; context.attacks = []; + context.actor = actorData; actorData.system.attacks.forEach((attack, index) => { context.attacks.push({ @@ -43,55 +125,7 @@ export class CreatureSheet extends foundry.appv1.sheets.ActorSheet { }) }) - return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - html.on('click', '.remove-attack', async (evt) => { - const {index} = evt.target.dataset; - let sans = Array.from(this.object.system.attacks); - sans.splice(index, 1); - await this.object.update({'system.attacks': sans}) - }) - - html.on('click', '.attacks-die.die', async (evt) => { - const {rollType, rollName, roll} = evt.currentTarget.dataset; - let r = new Roll(roll, this.actor.getRollData()); - const label = `${rollType} (${rollName})` - await r.toMessage({ - speaker: ChatMessage.getSpeaker({actor: this.object}), - flavor: label, - rollMode: game.settings.get('core', 'rollMode'), - }); - }) - - html.on('click', '.editor .add-attack', async (evt) => { - const name = html[0].querySelector('#attack_name').value - const at = html[0].querySelector('#attack_at').value - const pa = html[0].querySelector('#attack_pa').value - const tp = html[0].querySelector('#attack_tp').value - - const newAttack = { - name, - at, - pa, - tp - } - - await this.object.update({'system.attacks': [...this.object.system.attacks, newAttack]}) - - evt.target.parentElement.querySelector('#attack_name').value = "" - evt.target.parentElement.querySelector('#attack_at').value = "" - evt.target.parentElement.querySelector('#attack_pa').value = "" - evt.target.parentElement.querySelector('#attack_tp').value = "" - }) - - } - } diff --git a/src/module/sheets/equipmentSheet.mjs b/src/module/sheets/equipmentSheet.mjs index d3d769f8..d0fb20ac 100644 --- a/src/module/sheets/equipmentSheet.mjs +++ b/src/module/sheets/equipmentSheet.mjs @@ -1,42 +1,139 @@ -export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'equipment'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +/** + * @typedef ApplicationTab + * @property {string} id + * @property {string} group + * @property {boolean} active + * @property {string} cssClass + * @property {string} [label] + * @property {string} [icon] + * @property {string} [tooltip] + */ + +export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 640, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'equipment'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: EquipmentSheet.#onSubmitForm + }, + window: { + resizable: true, + }, + actions: { + editImage: + DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage + + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + // Additional Tabs are added based on the nature of this item + ], - }); + initial: 'meta' + } } - /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-equipment-sheet.hbs`; + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/equipment/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/item/equipment/tab-meta.hbs` + }, + melee: { + template: `systems/DSA_4-1/templates/item/equipment/tab-melee.hbs` + }, + ranged: { + template: `systems/DSA_4-1/templates/item/equipment/tab-ranged.hbs` + }, + ammunition: { + template: `systems/DSA_4-1/templates/item/equipment/tab-ammunition.hbs` + }, + armor: { + template: `systems/DSA_4-1/templates/item/equipment/tab-armor.hbs` + }, + settings: { + template: `systems/DSA_4-1/templates/item/equipment/tab-settings.hbs` + }, + } - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); + /** + * Handle form submission + * @this {EquipmentSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() - // Use a safe clone of the actor data for further operations. - const equipmentData = context.data; + let normalisedFormData = {} - // Add the actor's data to context.data for easier access, as well as flags. - context.system = equipmentData.system; - context.flags = equipmentData.flags; + Object.entries(formData.object).forEach(([key, value]) => { + if (Array.isArray(value)) { + normalisedFormData[key] = value[0] + } else { + normalisedFormData[key] = value + } + }) - context.quantity = context.system.quantity; - context.description = context.system.description; + // manage categories into array + normalisedFormData['system.category'] = [] + if (normalisedFormData.isMelee) normalisedFormData['system.category'].push("Nahkampfwaffe") + delete normalisedFormData.isMelee + if (normalisedFormData.isRanged) normalisedFormData['system.category'].push("Fernkampfwaffe") + delete normalisedFormData.isRanged + if (normalisedFormData.isAmmunition) normalisedFormData['system.category'].push("Munition") + delete normalisedFormData.isAmmunition + if (normalisedFormData.isArmor) normalisedFormData['system.category'].push("Rüstung") + delete normalisedFormData.isArmor + + await this.document.update(normalisedFormData) // Note: formData.object + } + + async _preparePartContext(partId, context) { + switch (partId) { + case 'meta': + this.#prepareMetaContext(context) + break; + case 'melee': + this.#prepareMeleeContext(context) + break; + case 'ranged': + this.#prepareRangedContext(context) + break; + case 'armor': + this.#prepareArmorContext(context) + break; + case 'settings': + this.#prepareSettingsContext(context) + break; + } + context.tab = context.tabs[partId] + return context + } + + #prepareMetaContext(context) { + const equipmentData = context.document.system + context.system = equipmentData + context.quantity = equipmentData.quantity + context.description = equipmentData.description + context.name = context.document.name + context.img = context.document.img context.categoryAndOptions = { options: { @@ -44,25 +141,23 @@ export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { Nahkampfwaffe: "Nahkampfwaffe", Fernkampfwaffe: "Fernkampfwaffe", Behälter: "Behälter", - Rüstung: "Rüstung", }, - entries: context.system.category, + entries: equipmentData.category, targetField: "category" }; - context.isMeleeWeapon = context.system.category.includes("Nahkampfwaffe"); - context.isRangedWeapon = context.system.category.includes("Fernkampfwaffe"); - context.isContainer = context.system.category.includes("Behälter"); - context.isArmor = context.system.category.includes("Rüstung"); - context.price = context.system.price; - context.weight = context.system.weight; + } + + #prepareMeleeContext(context) { + const equipmentData = context.document.system + context.system = equipmentData context.meleeSkillsAndOptions = { options: { "": "", Dolche: "Dolche", Fechtwaffen: "Fechtwaffen", - Säbel: "Säbel", + "Säbel": "Säbel", Schwerter: "Schwerter", - Anderthalbhänder: "Anderthalbhänder", + "Anderthalbhänder": "Anderthalbhänder", "Zweihandschwerter/-säbel": "Zweihandschwerter/-säbel", "Infanteriewaffen": "Infanteriewaffen", "Speere": "Speere", @@ -72,9 +167,13 @@ export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { "Kettenwaffen": "Kettenwaffen", "Raufen": "Raufen" }, - entries: context.system.meleeSkills, + entries: equipmentData.meleeSkills, targetField: "meleeSkills" } + } + + #prepareRangedContext(context) { + const equipmentData = context.document.system context.rangedSkillsAndOptions = { options: { "": "", @@ -84,24 +183,117 @@ export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { "Armbrust": "Armbrust", "Bogen": "Bogen", }, - entries: context.system.rangedSkills, + entries: equipmentData.rangedSkills, targetField: "rangedSkills" } - return context; } - activateListeners(html) { - super.activateListeners(html); + #prepareAmmunitionContext(context) { - html.on('change', '.array-editor select', (evt) => { - const addingValue = evt.currentTarget.value; - const fieldToTarget = evt.currentTarget.dataset.targetField; - const newSkills = [...this.object.system[fieldToTarget], addingValue]; + } - this.object.update({system: {[fieldToTarget]: newSkills}}); - evt.currentTarget.value = ""; + #prepareArmorContext(context) { + + } + + #prepareSettingsContext(context) { + context.isMelee = this.document.system.category.includes("Nahkampfwaffe") + context.isRanged = this.document.system.category.includes("Fernkampfwaffe") + context.isAmmunition = this.document.system.category.includes("Munition") + context.isArmor = this.document.system.category.includes("Rüstung") + } + + /** + * Adds Tabs based on the items nature + * + * @param {String} group + * @private + */ + _getTabsConfig(group) { + + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + + const category = this.document.system.category + /** + * + * @type {[{ApplicationTab}]} + */ + + if (category.includes("Nahkampfwaffe")) { + tabs.tabs.push({ + id: 'melee', group: group, label: 'Nahkampfwaffe' + }) + } + if (category.includes("Fernkampfwaffe")) { + tabs.tabs.push({ + id: 'ranged', group: group, label: 'Fernkampfwaffe' + }) + } + if (category.includes("Rüstung")) { + tabs.tabs.push({ + id: 'armor', group: group, label: 'Rüstung' + }) + } + + tabs.tabs.push({ + id: 'settings', group: group, label: 'Einstellungen' }) + return tabs + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.price = context.document.system.price + context.weight = context.document.system.weight + context.inventoryItems = [] + context.containerVolume = context.document.system.containerVolume + + return context + } + + /** + * Actions performed after any render of the Application. + * Post-render steps are not awaited by the render process. + * @param {ApplicationRenderContext} context Prepared context data + * @param {RenderOptions} options Provided render options + * @protected + */ + _onRender(context, options) { + + new foundry.applications.ux.DragDrop.implementation({ + dropSelector: ".inventory-table", + permissions: { + drop: this._canDragDrop.bind(this) + }, + callbacks: { + drop: this._onDrop.bind(this) + } + }).bind(this.element); + } + + _canDragDrop(event) { + console.log(event) + return true + } + + async _onDrop(event) { + const data = TextEditor.implementation.getDragEventData(event); + + // Dropped Documents + const documentClass = foundry.utils.getDocumentClass(data.type); + if (documentClass) { + + const document = await documentClass.fromDropData(data) + + console.log(document, document.parent) + + // Dropped Documents + + document.update({"parent": this.document}) + } } } diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 3edff152..1f64a1e5 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -1,85 +1,143 @@ -export class GroupSheet extends foundry.appv1.sheets.ActorSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'actor', 'group'], - width: 520, - height: 480, - tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, - ], - }); +const {HandlebarsApplicationMixin} = foundry.applications.api +const {ActorSheetV2} = foundry.applications.sheets +const {ContextMenu} = foundry.applications.ux + +export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'actor', 'group'], + tag: 'form', + dragDrop: [{ + dropSelector: '.tab.inventory.active' + }], + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: GroupSheet.#onSubmitForm + }, + window: { + resizable: true, + }, + actions: { + roll: GroupSheet.#dieRoll, + editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, + openEmbeddedDocument: GroupSheet.#openEmbeddedDocument, + openActorDocument: GroupSheet.#openActorDocument, + } } - static async onDroppedData(group, sheet, data) { - if (data.type === "Actor") { - const uuid = await foundry.utils.parseUuid(data.uuid); - const character = await (game.actors.get(uuid.id)) - - // check if character already is part of the group - if (group.system.characters.includes(character._id)) { - ui.notifications.warn(`${character.name} befindet sich bereits in der Heldengruppe ${group.name}`) - return false; - } - - - // update group - let settings = {...group.system.settings} - character.items.filter((i) => i.type === "Advantage").forEach((advantage) => { - if (!settings[sheet.#stringToKeyFieldName(advantage.name)]) { - settings[sheet.#stringToKeyFieldName(advantage.name)] = false - } - }) - character.items.filter((i) => i.type === "Skill").forEach((skill) => { - if (!settings[sheet.#stringToKeyFieldName(skill.name)]) { - settings[sheet.#stringToKeyFieldName(skill.name)] = false - } - }) - - await group.update({ - system: { - characters: [ - ...group.system.characters, - character._id - ], - settings: settings - } - }) - ui.notifications.info(`${character.name} ist der Heldengruppe ${group.name} beigetreten`) + static TABS = { + sheet: { + tabs: [ + {id: 'members', group: 'sheet', label: 'Gruppenmitglieder'}, + {id: 'inventory', group: 'sheet', label: 'Gruppeninventar'}, + ], + initial: 'members' } - if (data.type === "Equipment") { - const uuid = await foundry.utils.parseUuid(data.uuid); - const equipment = await (game.actors.get(uuid.id)) - ui.notifications.info(`${equipment.name} befindet sich nun im Inventar der Heldengruppe ${group.name}`) - return true; + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/group/main-sheet.hbs` + }, + members: { + template: `systems/DSA_4-1/templates/actor/group/tab-members.hbs` + }, + inventory: { + template: `systems/DSA_4-1/templates/actor/group/tab-inventory.hbs` + }, + settings: { + template: `systems/DSA_4-1/templates/actor/group/tab-settings.hbs` } } + constructor(options = {}) { + super(options); + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + if (formData.object.name) { + await (game.folders.get(this.document.system.groupId)).update({name: formData.object.name}) + } + + await this.document.update(formData.object) // Note: formData.object + } + #stringToKeyFieldName(s) { return s } - /** @override */ - get template() { - return `systems/DSA_4-1/templates/actor/group-sheet.hbs`; + + static #openEmbeddedDocument(event) { + const dataset = event.target.parentElement.dataset + const id = dataset.itemId ?? dataset.id + this.document.items.get(id).sheet.render(true) + } + + + static async #openActorDocument(event) { + const dataset = event.target.parentElement.dataset + const id = dataset.itemId ?? dataset.id + game.actors.get(id).sheet.render(true) + } + + static async #dieRoll(evt) { + console.log(evt) + } + + async #onUpdateCharacterSettings(data) { + if (data.type === "character") { + + // update group + let settings = {...this.document.system.settings} + data.items.filter((i) => i.type === "Advantage").forEach((advantage) => { + if (!settings[this.#stringToKeyFieldName(advantage.name)]) { + settings[this.#stringToKeyFieldName(advantage.name)] = false + } + }) + data.items.filter((i) => i.type === "Skill").forEach((skill) => { + if (!settings[this.#stringToKeyFieldName(skill.name)]) { + settings[this.#stringToKeyFieldName(skill.name)] = false + } + }) + + await this.document.update({"system.settings": settings}) + } + } + + _getTabsConfig(group) { + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + + // Modify tabs based on document properties + if (game.user.isGM) { + tabs.tabs.push({id: "settings", group: "sheet", label: "Einstellungen"}) + } + + return tabs } /** @override */ - async getData() { - const context = super.getData(); - - // Use a safe clone of the actor data for further operations. - const groupData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = groupData.system; - context.flags = groupData.flags; + async _prepareContext(options) { + const context = await super._prepareContext(options) + const groupData = context.document + context.system = groupData.system + context.flags = groupData.flags context.characters = [] - context.isGM = game.user.isGM; + context.isGM = game.user.isGM + context.name = groupData.name + context.img = groupData.img context.fields = []; @@ -101,8 +159,11 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { } } - for (const characterId of groupData.system.characters) { - const character = await game.actors.get(characterId) + // TODO hook on changes in the given folder + const characters = await game.folders.get(groupData.system.groupId).contents + console.log(characters) + + for (const character of characters) { character.items.filter((i) => i.type === "Advantage").filter((i) => hiddenFields.includes(this.#stringToKeyFieldName(i.name))).map((advantage) => { const n = this.#stringToKeyFieldName(advantage.name) @@ -117,15 +178,8 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { if (!context.fields[n]) { context.fields[n] = {} } - const eigenschaften = Object.values(skill.system.probe); context.fields[n][character.name] = { - taw: skill.system.taw, - eigenschaft1: eigenschaften[0], - eigenschaft2: eigenschaften[1], - eigenschaft3: eigenschaften[2], - rollEigenschaft1: character.system.attribute[eigenschaften[0].toLowerCase()].aktuell, - rollEigenschaft2: character.system.attribute[eigenschaften[1].toLowerCase()].aktuell, - rollEigenschaft3: character.system.attribute[eigenschaften[2].toLowerCase()].aktuell, + taw: skill.system.taw ?? "0", name: skill.name, actor: character._id, } @@ -153,11 +207,11 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { } } - context.equipments = []; - const actorData = context.data; - Object.values(actorData.items).forEach((item, index) => { + context.inventoryItems = []; + const actorData = context.document; + actorData.items.forEach((item, index) => { if (item.type === "Equipment") { - context.equipments.push({ + context.inventoryItems.push({ index: index, id: item._id, quantity: item.system.quantity, @@ -173,110 +227,8 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { return await context; } - openEmbeddedDocument(documentId) { - this.object.items.get(documentId).sheet.render(true) - } - - - _evaluateRoll(rolledDice, { - taw, - lowerThreshold = 1, - upperThreshold = 20, - countToMeisterlich = 3, - countToPatzer = 3, - werte = [] - }) { - let tap = taw; - let meisterlichCounter = 0; - let patzerCounter = 0; - let failCounter = 0; - - rolledDice.forEach((rolledDie, index) => { - if (tap < 0 && rolledDie.result > werte[index]) { - tap -= rolledDie.result - werte[index]; - if (tap < 0) { // konnte nicht vollständig ausgeglichen werden - failCounter++; - } - } else if (rolledDie.result > werte[index]) { // taw ist bereits aufgebraucht und wert kann nicht ausgeglichen werden - tap -= rolledDie.result - werte[index]; - failCounter++; - } - if (rolledDie.result <= lowerThreshold) meisterlichCounter++; - if (rolledDie.result > upperThreshold) patzerCounter++; - }) - - return { - tap, - meisterlich: meisterlichCounter === countToMeisterlich, - patzer: patzerCounter === countToPatzer, - } - } - - async _onTalentRoll(event) { - event.preventDefault(); - const dataset = event.currentTarget.dataset; - const actor = await game.actors.get(dataset.actorId); - console.log(dataset, actor) - if (dataset.rolleigenschaft1) { - let roll1 = new Roll("3d20", actor.getRollData()); - - let evaluated1 = (await roll1.evaluate()) - - const dsaDieRollEvaluated = this._evaluateRoll(evaluated1.terms[0].results, { - taw: dataset.taw, - werte: [dataset.rolleigenschaft1, dataset.rolleigenschaft2, dataset.rolleigenschaft3], - }) - - if (dsaDieRollEvaluated.tap >= 0) { // erfolg - evaluated1.toMessage({ - speaker: ChatMessage.getSpeaker({actor: actor}), - flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Meisterlich geschafft' : 'Geschafft'} mit ${dsaDieRollEvaluated.tap} Punkten übrig`, - }, {rollMode: "gmroll"}) - } else { // misserfolg - evaluated1.toMessage({ - speaker: ChatMessage.getSpeaker({actor: actor}), - flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Gepatzt' : ''} mit ${Math.abs(dsaDieRollEvaluated.tap)} Punkten daneben`, - }, {rollMode: "gmroll"}) - } - } - } - - activateListeners(html) { - super.activateListeners(html); - - html.on('click', '.owneroption.clickable', async (evt) => { - const dataset = evt.target.dataset; - const group = this.object; - switch (dataset.operation) { - case "removeFromParty": - const charactersWithoutMember = group.system.characters.filter(id => id !== dataset.id) - await group.update({ - system: { - characters: charactersWithoutMember - } - }) - } - }); - html.on('click', '.header.clickable', async (evt) => { - const {id, operation} = evt.currentTarget.dataset; - if (operation === "openActorSheet") { - evt.stopPropagation(); - (await game.actors.get(id)).sheet.render(true); - } - }) - - - html.on('click', '.equipment', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - html.on('click', ".rollable", (evt) => { - this._onTalentRoll(evt) - evt.stopPropagation() - }) - - new ContextMenu(html, '.equipment', [ + _onRender(context, options) { + /*ContextMenu.implementation.create(this, this.element, ".equipment", [ { name: "Aus dem Gruppeninventar entfernen", icon: '', @@ -285,6 +237,84 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { }, condition: () => true } - ]); + ], { + jQuery: false + });*/ + + // Drag-drop + new foundry.applications.ux.DragDrop.implementation({ + dragSelector: ".inventory-table .equipment", + dropSelector: ".inventory-table", + permissions: { + dragstart: this._canDragStart.bind(this), + drop: this._canDragDrop.bind(this) + }, + callbacks: { + dragstart: this._onDragStart.bind(this), + drop: this._onDrop.bind(this) + } + }).bind(this.element); + + // Update Group Members when either an Actor was moved into the linked Folder or removed from the linked Folder + Hooks.on('updateActor', (data) => { + if (data._id !== this.document._id) { // dont update yourself when you update yourself... baka! + if (data.type === "character" && data.folder?._id === this.document.system.groupId) { + this.#onUpdateCharacterSettings(data) + this.render() + } else if (data.type === "character") { + this.render() + } + } + }); + } + + /** + * An event that occurs when a drag workflow begins for a draggable item on the sheet. + * @param {DragEvent} event The initiating drag start event + * @returns {Promise} + * @protected + */ + async _onDragStart(event) { + const target = event.currentTarget; + if ("link" in event.target.dataset) return; + let dragData; + + // Owned Items + if (target.dataset.itemId) { + const item = this.actor.items.get(target.dataset.itemId); + dragData = item.toDragData(); + } + + // Active Effect + if (target.dataset.effectId) { + const effect = this.actor.effects.get(target.dataset.effectId); + dragData = effect.toDragData(); + } + + // Set data transfer + if (!dragData) return; + event.dataTransfer.setData("text/plain", JSON.stringify(dragData)); + } + + // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 + async _onDrop(event) { + const data = TextEditor.implementation.getDragEventData(event); + const actor = this.actor; + const allowed = Hooks.call("dropActorSheetData", actor, this, data); + if (allowed === false) return; + + // Dropped Documents + const documentClass = foundry.utils.getDocumentClass(data.type); + if (documentClass) { + const document = await documentClass.fromDropData(data); + await this._onDropDocument(event, document); + + // No duplication by moving items from one actor to another + if (document.parent) { + document.parent.items.get(document._id).delete() + } + } + } + } diff --git a/src/module/sheets/liturgySheet.mjs b/src/module/sheets/liturgySheet.mjs index 3bb34124..d2e0f14e 100644 --- a/src/module/sheets/liturgySheet.mjs +++ b/src/module/sheets/liturgySheet.mjs @@ -1,50 +1,62 @@ -export class LiturgySheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'liturgy'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class LiturgySheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'liturgy'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: LiturgySheet.#onSubmitForm + }, + } + + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'json', group: 'sheet', label: 'JSON'}, ], - }); + initial: 'json' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/liturgy/main-sheet.hbs` + }, + json: { + template: `systems/DSA_4-1/templates/item/liturgy/tab-json.hbs` + }, + } + + /** + * Handle form submission + * @this {EquipmentSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-liturgy-sheet.hbs`; - } + async _prepareContext(options) { + const context = await super._prepareContext(options); - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); + const liturgyData = context.document; - // Use a safe clone of the actor data for further operations. - const liturgyData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. context.system = liturgyData.system; context.flags = liturgyData.flags; context.json = JSON.stringify(liturgyData); return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (this.isEditable) { - - } - } - } diff --git a/src/module/sheets/skillSheet.mjs b/src/module/sheets/skillSheet.mjs index 6f72b3c3..3ea4f5d9 100644 --- a/src/module/sheets/skillSheet.mjs +++ b/src/module/sheets/skillSheet.mjs @@ -1,37 +1,61 @@ -export class SkillSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'skill'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'skill'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SkillSheet.#onSubmitForm + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'meta', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'description', group: 'sheet', label: 'Beschreibung'}, ], - }); + initial: 'meta' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/skill/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/item/skill/tab-meta.hbs` + }, + description: { + template: `systems/DSA_4-1/templates/item/skill/tab-description.hbs` + } + } + + /** + * Handle form submission + * @this {SkillSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-skill-sheet.hbs`; - } + async _prepareContext(options) { - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); + const context = await super._prepareContext(options) + const skillData = context.document; - // Use a safe clone of the actor data for further operations. - const skillData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. context.system = skillData.system; context.flags = skillData.flags; context.categoryOptions = { @@ -45,21 +69,11 @@ export class SkillSheet extends foundry.appv1.sheets.ItemSheet { Handwerk: "Handwerk" } - context.isCombat = context.system.gruppe === "Kampf" - context.isTalent = context.system.gruppe !== "Kampf" - context.isLanguage = context.system.gruppe === "Sprachen" || context.system.gruppe === "Schriften" - context.hasRequirement = context.system.voraussetzung.talent != null + context.isCombat = skillData.system.gruppe === "Kampf" + context.isTalent = skillData.system.gruppe !== "Kampf" + context.isLanguage = skillData.system.gruppe === "Sprachen" || skillData.system.gruppe === "Schriften" + context.hasRequirement = skillData.system.voraussetzung?.talent != null ?? false return context; } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) { - - } - } - } \ No newline at end of file diff --git a/src/module/sheets/specialAbilitySheet.mjs b/src/module/sheets/specialAbilitySheet.mjs index 533f1a8a..4828dbf2 100644 --- a/src/module/sheets/specialAbilitySheet.mjs +++ b/src/module/sheets/specialAbilitySheet.mjs @@ -1,51 +1,62 @@ -export class SpecialAbilitySheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'specialability'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'specialability'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SpecialAbilitySheet.#onSubmitForm + }, + } + + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'json', group: 'sheet', label: 'JSON'}, ], - }); - } - - /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-special-ability-sheet.hbs`; - } - - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); - - // Use a safe clone of the actor data for further operations. - const advantageData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = advantageData.system; - context.flags = advantageData.flags; - context.json = JSON.stringify(advantageData.system, null, 4); - - return context; - } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) { - + initial: 'json' } } + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/specialability/main-sheet.hbs` + }, + json: { + template: `systems/DSA_4-1/templates/item/specialability/tab-json.hbs` + }, + } + + /** + * Handle form submission + * @this {EquipmentSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + const context = await super._prepareContext(options); + + const specialabilityData = context.document; + + context.system = specialabilityData.system; + context.flags = specialabilityData.flags; + context.json = JSON.stringify(specialabilityData); + return context; + } + } diff --git a/src/module/sheets/spellSheet.mjs b/src/module/sheets/spellSheet.mjs index 3713a24b..2e793d9e 100644 --- a/src/module/sheets/spellSheet.mjs +++ b/src/module/sheets/spellSheet.mjs @@ -1,49 +1,69 @@ -export class SpellSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'spell'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SpellSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'spell'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SpellSheet.#onSubmitForm + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'meta', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'variants', group: 'sheet', label: 'Varianten'}, + {id: 'commonality', group: 'sheet', label: 'Verbreitung'}, ], - }); + initial: 'meta' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/spell/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/item/spell/tab-meta.hbs` + }, + variants: { + template: `systems/DSA_4-1/templates/item/spell/tab-variants.hbs` + }, + commonality: { + template: `systems/DSA_4-1/templates/item/spell/tab-commonality.hbs` + } + } + + /** + * Handle form submission + * @this {SpellSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-spell-sheet.hbs`; - } + async _prepareContext(options) { + const context = await super._prepareContext(options); + const spellData = context.document; - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); - - // Use a safe clone of the actor data for further operations. - const skillData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = skillData.system; - context.flags = skillData.flags; + context.system = spellData.system; + context.flags = spellData.flags; return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - } - } \ No newline at end of file diff --git a/src/module/sheets/vornachteilSheet.mjs b/src/module/sheets/vornachteilSheet.mjs deleted file mode 100644 index 6a9278c6..00000000 --- a/src/module/sheets/vornachteilSheet.mjs +++ /dev/null @@ -1,56 +0,0 @@ -export class VornachteilSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'advantage'], - width: 520, - height: 480, - tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, - ], - }); - } - - /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-advantage-sheet.hbs`; - } - - /** @override */ - getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. - const context = super.getData(); - - // Use a safe clone of the actor data for further operations. - const advantageData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = advantageData.system; - context.flags = advantageData.flags; - context.hasChoices = context.system.auswahl.length > 0; - context.choices = {} - context.system.auswahl.forEach(a => { - context.choices[a] = a - }) - context.hasModality = context.system.value != null - - return context; - } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) { - - } - } - -} diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs index 1e7eadce..3427a1d2 100644 --- a/src/module/xml-import/xml-import.mjs +++ b/src/module/xml-import/xml-import.mjs @@ -1,6 +1,8 @@ import {LiturgyData} from "../data/miracle/liturgydata.mjs"; -import {BlessingDataModel} from "../data/blessing.mjs"; import {Blessing} from "../documents/blessing.mjs"; +import {Profession} from "../documents/profession.mjs"; +import {Culture} from "../documents/culture.mjs"; +import {Species} from "../documents/species.mjs"; let months = [ "Praios", @@ -18,20 +20,48 @@ let months = [ "Namenloser Tag" ] +/** + * @typedef ImportOptions + * @property {Boolean} skipSpecies + * @property {Boolean} skipCulture + * @property {Boolean} skipProfessions + * @property {Boolean} skipAdvantages + * @property {Boolean} skipSpecialAbilities + * @property {Boolean} skipEquipment + * @property {Boolean} skipSpells + * @property {Boolean} skipLiturgies + * @property {Boolean} skipSkills + **/ /** * Imports a character from a file created in the tool Helden-Software * @param actorId the actor-id of the character * @param file the file from which the character should be imported + * @param {ImportOptions?} options the set of item types the import should skip */ -export async function importCharacter(actorId, file) { +export async function importCharacter(actorId, file, options = undefined) { let actor = game.actors.get(actorId) let xmlString = await parseFileToString(file) let domParser = new DOMParser() let dom = domParser.parseFromString(xmlString, 'application/xml') let rawJson = getJsonFromXML(dom) - let characterJson = mapRawJson(actor, rawJson) + + if (!options) { + options = { + skipSpecies: false, + skipCulture: false, + skipProfessions: false, + skipAdvantages: false, + skipSpecialAbilities: false, + skipEquipment: false, + skipSkills: false, + skipSpells: false, + skipLiturgies: false + } + } + + let characterJson = mapRawJson(actor, rawJson, options) actor.update(characterJson) } @@ -74,6 +104,38 @@ function getJsonFromXML(dom) { return jsonResult; } +/** + * gets the text content of a file + * @param file the file with the desired content + * @returns {Promise} a promise that returns the string contents of the file + */ +async function parseFileToString(file) { + return new Promise((resolve, reject) => { + let reader = new FileReader() + reader.readAsText(file, "utf-8") + reader.onload = event => { + resolve(event.target.result) + } + reader.onerror = event => { + reject(event) + } + }) +} + +/** + *Calculates a Birthdate String in the Calendar of Bosparans Fall + * @param json json with the day, the month and the year of the birthday + * @returns {string} a string in the format of "DD.MMMM.YYYY BF" + */ +function calculateBirthdate(json) { + let day = json.gbtag + let month = months[parseInt(json.gbmonat) - 1] + let year = json.gbjahr + + return `${day}. ${month} ${year} BF` +} + + async function addSkillFromCompendiumByNameToActor(talentName, taw, actor, combatStatistics, attributes) { const compendiumOfSkills = game.packs.get('DSA_4-1.talente'); const talentId = compendiumOfSkills.index.find(skill => skill.name === talentName) @@ -121,6 +183,7 @@ async function addAdvantageFromCompendiumByNameToActor(advantageName, advantageV } async function addSpellsFromCompendiumByNameToActor(spellName, zfw, representation, hauszauber, actor) { + const compendiumOfSpells = game.packs.get('DSA_4-1.spells'); const SCREAMING_NAME = spellName.toUpperCase() const spellId = compendiumOfSpells.index.find(spell => spell.name === SCREAMING_NAME) @@ -154,38 +217,17 @@ async function addLiturgiesFromCompendiumByNameToActor(liturgyName, actor) { } } -/** - * gets the text content of a file - * @param file the file with the desired content - * @returns {Promise} a promise that returns the string contents of the file - */ -async function parseFileToString(file) { - return new Promise((resolve, reject) => { - let reader = new FileReader() - reader.readAsText(file, "utf-8") - reader.onload = event => { - resolve(event.target.result) - } - reader.onerror = event => { - reject(event) - } - }) -} - -/** - *Calculates a Birthdate String in the Calendar of Bosparans Fall - * @param json json with the day, the month and the year of the birthday - * @returns {string} a string in the format of "DD.MMMM.YYYY BF" - */ -function calculateBirthdate(json) { - let day = json.gbtag - let month = months[parseInt(json.gbmonat) - 1] - let year = json.gbjahr - - return `${day}. ${month} ${year} BF` -} - function mapSkills(actor, held, kampfwerte) { + if (actor.itemTypes["Skill"].length > 0) { + actor.itemTypes["Skill"].forEach(s => { + actor.items.get(s._id).delete() + }) + } + if (actor.itemTypes["Blessing"].length > 0) { + actor.itemTypes["Blessing"].forEach(p => { + actor.items.get(p._id).delete() + }) + } for (let talent in held.talentliste.talent) { talent = held.talentliste.talent[talent] @@ -212,6 +254,11 @@ function mapSkills(actor, held, kampfwerte) { } function mapAdvantages(actor, held) { + if (actor.itemTypes["Advantage"].length > 0) { + actor.itemTypes["Advantage"].forEach(a => { + actor.items.get(a._id).delete() + }) + } for (let advantage in held.vt.vorteil) { advantage = held.vt.vorteil[advantage] addAdvantageFromCompendiumByNameToActor(advantage.name, advantage.value, actor) @@ -219,42 +266,134 @@ function mapAdvantages(actor, held) { } function mapSpells(actor, held) { + if (actor.itemTypes["Spell"].length > 0) { + actor.itemTypes["Spell"].forEach(s => { + actor.items.get(s._id).delete() + }) + } for (let spell in held.zauberliste.zauber) { spell = held.zauberliste.zauber[spell] addSpellsFromCompendiumByNameToActor(spell.name, spell.value, spell.repraesentation, spell.hauszauber === "true", actor) } } -function mapMiracles(actor, liturgies) { +function mapLiturgies(actor, liturgies) { + if (actor.itemTypes["Liturgy"].length > 0) { + actor.itemTypes["Liturgy"].forEach(l => { + actor.items.get(l._id).delete() + }) + } for (let liturgy in liturgies) { liturgy = liturgies[liturgy] addLiturgiesFromCompendiumByNameToActor(liturgy.name, actor) } } +async function mapProfessions(actor, professions) { + if (actor.itemTypes["Profession"].length > 0) { + actor.itemTypes["Profession"].forEach(p => { + actor.items.get(p._id).delete() + }) + } + if (professions.string) { + professions = {hauptprofession: professions} + } + Object.values(professions).forEach(profession => { + actor.createEmbeddedDocuments('Item', [ + new Profession({ + name: profession.string, + type: "Profession", + system: { + description: "", + alias: profession.tarnidentitaet ? profession.tarnidentitaet : profession.string, + revealed: !profession.tarnidentitaet + } + }) + ]) + }) + // actor.update({"system.meta.professions": professions}) +} + +async function mapSpezies(actor, spezies) { + if (actor.itemTypes["Species"].length > 0) { + actor.itemTypes["Species"].forEach(s => { + actor.items.get(s._id).delete() + }) + } + const compendiumOfSpecies = game.packs.get('DSA_4-1.spezien'); + const speciesId = compendiumOfSpecies?.index.find(species => species.name === spezies.name) + + if (speciesId) { + const species = + await compendiumOfSpecies.getDocument(speciesId); + try { + await actor.createEmbeddedDocuments('Item', [species]) + } catch (e) { + } + } else { + actor.createEmbeddedDocuments('Item', [ + new Species({ + name: spezies.name, + type: "Species", + system: { + feminineDemonym: spezies.string, + masculineDemonym: spezies.string, + description: "Importiert", + } + }) + ]) + } + +} + +async function mapKultur(actor, kultur) { + if (actor.itemTypes["Culture"].length > 0) { + actor.itemTypes["Culture"].forEach(c => { + actor.items.get(c._id).delete() + }) + } + const compendiumOfCultures = game.packs.get('DSA_4-1.kulturen'); + const cultureId = compendiumOfCultures?.index.find(culture => culture.name === kultur.name) + + if (cultureId) { + const culture = + await compendiumOfCultures.getDocument(cultureId); + try { + await actor.createEmbeddedDocuments('Item', [culture]) + } catch (e) { + } + } else { + actor.createEmbeddedDocuments('Item', [ + new Culture({ + name: kultur.name, + type: "Culture", + system: { + variant: kultur.variante.name ?? "", + feminineDemonym: kultur.string, + masculineDemonym: kultur.string, + description: "Importiert", + } + }) + ]) + } + +} + /** * parses a json into a fitting character-json + * @param {Character} actor * @param rawJson the json parsed from the Helden-Software XML + * @param {ImportOptions} options * @returns {{}} a json representation of the character */ -function mapRawJson(actor, rawJson) { +function mapRawJson(actor, rawJson, options) { let json = {} let held = rawJson.helden.held; json.name = held.name json.meta = {} - json.meta.spezies = held.basis.rasse.string - json.meta.kultur = held.basis.kultur.string - let professions = [] - for (let profession in held.basis.ausbildungen.ausbildung) { - profession = held.basis.ausbildungen.ausbildung[profession] - if (profession.tarnidentitaet) { - professions = [profession.tarnidentitaet] - break; - } - let professionString = profession.string - professions.push(professionString) - } - json.meta.professions = professions + if (!options.skipSpecies) mapSpezies(actor, held.basis.rasse) // as string includes the demonymized form + if (!options.skipCulture) mapKultur(actor, held.basis.kultur) // as string includes the demonymized form + if (!options.skipProfessions) mapProfessions(actor, held.basis.ausbildungen.ausbildung) json.meta.geschlecht = held.basis.geschlecht.name json.meta.haarfarbe = held.basis.rasse.aussehen.haarfarbe json.meta.groesse = held.basis.rasse.groesse.value @@ -311,7 +450,7 @@ function mapRawJson(actor, rawJson) { aktuell: attribute.value } json.attribute.so = getAttributeJson(attributes, "Sozialstatus") - mapAdvantages(actor, held) + if (!options.skipAdvantages) mapAdvantages(actor, held) let specialAbilities = [] let liturgies = [] for (let specialAbility in held.sf.sonderfertigkeit) { @@ -359,9 +498,9 @@ function mapRawJson(actor, rawJson) { } json.kampfwerte = combatValues - mapSkills(actor, held, combatValues) - mapSpells(actor, held) - mapMiracles(actor, liturgies) + if (!options.skipSkills) mapSkills(actor, held, combatValues) + if (!options.skipSpells) mapSpells(actor, held) + if (!options.skipLiturgies) mapLiturgies(actor, liturgies) let notes = [] for (let note in held.kommentare) { diff --git a/src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json b/src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json new file mode 100644 index 00000000..f8c00cc0 --- /dev/null +++ b/src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json @@ -0,0 +1,6 @@ +{ + "name": "helden.model.kultur.Mittelreich", + "masculineDemonym": "Mittelländische Landbevölkerung", + "feminineDemonym": "Mittelländische Landbevölkerung", + "description": "" +} \ No newline at end of file diff --git a/src/packs/_source/munition/balläster-m.json b/src/packs/_source/munition/balläster-m.json index 27ef87dc..14817e5e 100644 --- a/src/packs/_source/munition/balläster-m.json +++ b/src/packs/_source/munition/balläster-m.json @@ -2,24 +2,14 @@ "name": "Munition (Balläster)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.125, "price": 0.6, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/eisenwalder-m.json b/src/packs/_source/munition/eisenwalder-m.json index 008ca7b9..3d9780ac 100644 --- a/src/packs/_source/munition/eisenwalder-m.json +++ b/src/packs/_source/munition/eisenwalder-m.json @@ -2,24 +2,14 @@ "name": "Munition (Eisenwalder)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0, "price": 1.5, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 10, + "count": 10 + } } diff --git a/src/packs/_source/munition/elfenbogen-m.json b/src/packs/_source/munition/elfenbogen-m.json index 64c590fb..2aef5eaa 100644 --- a/src/packs/_source/munition/elfenbogen-m.json +++ b/src/packs/_source/munition/elfenbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Elfenbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow2.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.075, "price": 0.4, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/kompositbogen-m.json b/src/packs/_source/munition/kompositbogen-m.json index cd73f87a..055aae0c 100644 --- a/src/packs/_source/munition/kompositbogen-m.json +++ b/src/packs/_source/munition/kompositbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Kompositbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.05, "price": 0.25, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/kriegsbogen-m.json b/src/packs/_source/munition/kriegsbogen-m.json index 08ddb371..66e7a9ac 100644 --- a/src/packs/_source/munition/kriegsbogen-m.json +++ b/src/packs/_source/munition/kriegsbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Kriegsbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.1, "price": 0.6, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/kurzbogen-m.json b/src/packs/_source/munition/kurzbogen-m.json index 2e174c37..5ac2fc28 100644 --- a/src/packs/_source/munition/kurzbogen-m.json +++ b/src/packs/_source/munition/kurzbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Kurzbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.05, "price": 0.25, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/langbogen-m.json b/src/packs/_source/munition/langbogen-m.json index 5d8978a7..fc89dfbf 100644 --- a/src/packs/_source/munition/langbogen-m.json +++ b/src/packs/_source/munition/langbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Langbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.075, "price": 0.4, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/leichte-armbrust-m.json b/src/packs/_source/munition/leichte-armbrust-m.json index e61e3b5f..fc700dfa 100644 --- a/src/packs/_source/munition/leichte-armbrust-m.json +++ b/src/packs/_source/munition/leichte-armbrust-m.json @@ -2,24 +2,14 @@ "name": "Munition (Leichte Armbrust)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.075, "price": 1.5, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/windenarmbrust-m.json b/src/packs/_source/munition/windenarmbrust-m.json index 3086a929..5cf359bd 100644 --- a/src/packs/_source/munition/windenarmbrust-m.json +++ b/src/packs/_source/munition/windenarmbrust-m.json @@ -2,24 +2,14 @@ "name": "Munition (Windenarmbrust)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.1, "price": 2, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/ruestzeug/buckler.json b/src/packs/_source/ruestzeug/buckler.json index 8915102f..c7ea362d 100644 --- a/src/packs/_source/ruestzeug/buckler.json +++ b/src/packs/_source/ruestzeug/buckler.json @@ -8,21 +8,13 @@ "weight": 1, "price": 40, "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 1, + "iniModifier": -1, + "attackModifier": -2, + "parryModifier": -1, "meleeAttackModifier": 0, "meleeAttackModifierIncrement": 0, "meleeSkills": [ "Schilde" ], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 1, - "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/dicke-kleidung.json b/src/packs/_source/ruestzeug/dicke-kleidung.json index e0a41a1a..b6eb7922 100644 --- a/src/packs/_source/ruestzeug/dicke-kleidung.json +++ b/src/packs/_source/ruestzeug/dicke-kleidung.json @@ -7,20 +7,17 @@ ], "weight": 3, "price": 0, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 1, + "armorValue": { + "total": 1, + "kopf": 0, + "brust": 1, + "ruecken": 1, + "bauch": 1, + "armlinks": 1, + "beinlinks": 1, + "armrechts": 1, + "beinrechts": 1 + }, "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/garether-platte.json b/src/packs/_source/ruestzeug/garether-platte.json index e4dcc56d..084cac96 100644 --- a/src/packs/_source/ruestzeug/garether-platte.json +++ b/src/packs/_source/ruestzeug/garether-platte.json @@ -7,20 +7,17 @@ ], "weight": 14, "price": 750, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 6, + "armorValue": { + "total": 5, + "kopf": 0, + "brust": 6, + "ruecken": 5, + "bauch": 6, + "armlinks": 5, + "armrechts": 5, + "beinlinks": 4, + "beinrechts": 4 + }, "armorHandicap": 4, "description": "" } diff --git a/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json b/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json index 478b77b7..0c9d9ad8 100644 --- a/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json +++ b/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json @@ -7,20 +7,17 @@ ], "weight": 17, "price": 1000, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 8, - "armorHandicap": 5, + "armorValue": { + "total": 6, + "kopf": 3, + "brust": 7, + "ruecken": 5, + "bauch": 7, + "armlinks": 5, + "beinlinks": 5, + "armrechts": 5, + "beinrechts": 5 + }, + "armorHandicap": 4, "description": "" } diff --git a/src/packs/_source/ruestzeug/kettenhemd-halbarm.json b/src/packs/_source/ruestzeug/kettenhemd-halbarm.json index 7f18342b..87b805d7 100644 --- a/src/packs/_source/ruestzeug/kettenhemd-halbarm.json +++ b/src/packs/_source/ruestzeug/kettenhemd-halbarm.json @@ -7,20 +7,17 @@ ], "weight": 6.5, "price": 150, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, - "armorHandicap": 3, + "armorValue": { + "total": 3, + "kopf": 0, + "brust": 4, + "ruecken": 4, + "bauch": 4, + "armlinks": 2, + "armrechts": 2, + "beinlinks": 1, + "beinrechts": 1 + }, + "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/komplette-gestechruestung.json b/src/packs/_source/ruestzeug/komplette-gestechruestung.json index 77e2e1d3..aec4ce3c 100644 --- a/src/packs/_source/ruestzeug/komplette-gestechruestung.json +++ b/src/packs/_source/ruestzeug/komplette-gestechruestung.json @@ -7,20 +7,17 @@ ], "weight": 30, "price": 2500, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 12, - "armorHandicap": 10, + "armorValue": { + "total": 8, + "kopf": 8, + "brust": 8, + "ruecken": 7, + "bauch": 8, + "armlinks": 7, + "beinlinks": 7, + "armrechts": 7, + "beinrechts": 7 + }, + "armorHandicap": 8, "description": "" } diff --git a/src/packs/_source/ruestzeug/kroetenhaut.json b/src/packs/_source/ruestzeug/kroetenhaut.json index c32534f9..6c6a54a8 100644 --- a/src/packs/_source/ruestzeug/kroetenhaut.json +++ b/src/packs/_source/ruestzeug/kroetenhaut.json @@ -7,20 +7,17 @@ ], "weight": 4, "price": 60, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 3, + "ruecken": 2, + "bauch": 2, + "armlinks": 1, + "beinlinks": 0, + "armrechts": 1, + "beinrechts": 0 + }, "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/kuerass.json b/src/packs/_source/ruestzeug/kuerass.json index 36cd7334..0570b973 100644 --- a/src/packs/_source/ruestzeug/kuerass.json +++ b/src/packs/_source/ruestzeug/kuerass.json @@ -7,20 +7,17 @@ ], "weight": 4, "price": 110, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, - "armorHandicap": 2, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 5, + "ruecken": 1, + "bauch": 2, + "armlinks": 0, + "beinlinks": 0, + "armrechts": 0, + "beinrechts": 0 + }, + "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/langes-kettenhemd.json b/src/packs/_source/ruestzeug/langes-kettenhemd.json index fe571b4c..28e952c5 100644 --- a/src/packs/_source/ruestzeug/langes-kettenhemd.json +++ b/src/packs/_source/ruestzeug/langes-kettenhemd.json @@ -7,20 +7,17 @@ ], "weight": 10, "price": 180, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 4, - "armorHandicap": 4, + "armorValue": { + "total": 3, + "kopf": 0, + "brust": 4, + "ruecken": 4, + "bauch": 4, + "armlinks": 3, + "armrechts": 3, + "beinlinks": 2, + "beinrechts": 2 + }, + "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/lederharnisch.json b/src/packs/_source/ruestzeug/lederharnisch.json index a6e06681..c9d37a51 100644 --- a/src/packs/_source/ruestzeug/lederharnisch.json +++ b/src/packs/_source/ruestzeug/lederharnisch.json @@ -7,20 +7,17 @@ ], "weight": 4.5, "price": 80, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, - "armorHandicap": 3, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 3, + "ruecken": 3, + "bauch": 3, + "armlinks": 0, + "beinlinks": 0, + "armrechts": 0, + "beinrechts": 0 + }, + "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/leichte-platte.json b/src/packs/_source/ruestzeug/leichte-platte.json index b3312630..b75a8472 100644 --- a/src/packs/_source/ruestzeug/leichte-platte.json +++ b/src/packs/_source/ruestzeug/leichte-platte.json @@ -7,20 +7,17 @@ ], "weight": 7.5, "price": 250, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 4, - "armorHandicap": 3, + "armorValue": { + "total": 3, + "kopf": 0, + "brust": 5, + "ruecken": 4, + "bauch": 5, + "armlinks": 0, + "armrechts": 0, + "beinlinks": 2, + "beinrechts": 2 + }, + "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/schuppenpanzer.json b/src/packs/_source/ruestzeug/schuppenpanzer.json index 508c6f19..f1969f89 100644 --- a/src/packs/_source/ruestzeug/schuppenpanzer.json +++ b/src/packs/_source/ruestzeug/schuppenpanzer.json @@ -7,20 +7,17 @@ ], "weight": 12, "price": 1000, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 5, - "armorHandicap": 5, + "armorValue": { + "total": 4, + "kopf": 0, + "brust": 5, + "ruecken": 5, + "bauch": 5, + "armlinks": 3, + "beinlinks": 3, + "armrechts": 3, + "beinrechts": 3 + }, + "armorHandicap": 4, "description": "" } diff --git a/src/packs/_source/ruestzeug/spiegelpanzer.json b/src/packs/_source/ruestzeug/spiegelpanzer.json index 9a04ba63..8887fc45 100644 --- a/src/packs/_source/ruestzeug/spiegelpanzer.json +++ b/src/packs/_source/ruestzeug/spiegelpanzer.json @@ -7,20 +7,17 @@ ], "weight": 10, "price": 1000, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 5, - "armorHandicap": 4, + "armorValue": { + "total": 4, + "kopf": 0, + "brust": 5, + "ruecken": 5, + "bauch": 5, + "armlinks": 3, + "armrechts": 3, + "beinlinks": 2, + "beinrechts": 2 + }, + "armorHandicap": 3, "description": "" } diff --git a/src/packs/_source/ruestzeug/wattierte-unterkleidung.json b/src/packs/_source/ruestzeug/wattierte-unterkleidung.json index defd8026..6bf993eb 100644 --- a/src/packs/_source/ruestzeug/wattierte-unterkleidung.json +++ b/src/packs/_source/ruestzeug/wattierte-unterkleidung.json @@ -20,7 +20,17 @@ "rangedRangeDamageModifier": "", "rangedAttackDamage": "", "rangedReloadTime": 0, - "armorValue": 1, + "armorValue": { + "total": 1.5, + "kopf": 0, + "brust": 1, + "ruecken": 1, + "bauch": 1, + "armlinks": 1, + "beinlinks": 1, + "armrechts": 1, + "beinrechts": 1 + }, "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/wattierter-waffenrock.json b/src/packs/_source/ruestzeug/wattierter-waffenrock.json index c2aeb7a4..922862e6 100644 --- a/src/packs/_source/ruestzeug/wattierter-waffenrock.json +++ b/src/packs/_source/ruestzeug/wattierter-waffenrock.json @@ -7,20 +7,17 @@ ], "weight": 3, "price": 40, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 2, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 2, + "ruecken": 2, + "bauch": 2, + "armlinks": 1, + "beinlinks": 1, + "armrechts": 1, + "beinrechts": 1 + }, "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/spezien/helden.model.rasse.Mittellaender.json b/src/packs/_source/spezien/helden.model.rasse.Mittellaender.json new file mode 100644 index 00000000..88b9b572 --- /dev/null +++ b/src/packs/_source/spezien/helden.model.rasse.Mittellaender.json @@ -0,0 +1,7 @@ +{ + "name": "helden.model.rasse.Mittellaender", + "masculineDemonym": "Mittelländer", + "feminineDemonym": "Mittelländerin", + "description": "", + "baseSpeed": 6 +} \ No newline at end of file diff --git a/src/packs/_source/zauber/Windstille.json b/src/packs/_source/zauber/Windstille.json index 9fc527fd..09e50f5e 100644 --- a/src/packs/_source/zauber/Windstille.json +++ b/src/packs/_source/zauber/Windstille.json @@ -1,7 +1,11 @@ { "seite": "287", "name": "WINDSTILLE", - "probe": ["KL", "CH", "KK"], + "probe": [ + "KL", + "CH", + "KK" + ], "technik": "Der Elf formt die Hände über seinem Kopf zu einem Dach, spricht 'rongra sala bian'dao' und breitet die Arme aus.", "zauberdauer": "30 Aktionen", "wirkung": "Der Zauber erschafft eine Zone völliger Windstille, unabhängig von der Windstärke außerhalb. Diese Zone bewegt sich mit dem Elfen. Innerhalb dieser Zone steht die Luft still – selbst Blätter und Rauch verharren. Geräusche tragen schlechter, Pfeile und Geschosse verlieren an Reichweite, und fliegende Wesen haben Mühe, sich zu bewegen. Die Zauberprobe ist um die aktuelle Windstärke (nach Beaufort-Skala) erschwert. Der Effekt wirkt bis zur Windstärke 12 (Orkan).", @@ -29,7 +33,10 @@ }, "reversalis": "Jede Luftbewegung innerhalb der Zone wird um ZfP*/2 Windstärken verstärkt, sodass schon ein leichtes Blasen einen kräftigen Wind erzeugen kann. Diese Variante kostet 10 AsP pro Spielrunde.", "antimagie": "VERÄNDERUNG AUFHEBEN oder LUFTBANN können den Zauber schwächen oder beenden. Befindet sich die Zone in einem Sturm, kann dieser abgeschwächt, aber nicht aufgehoben werden.", - "merkmal": ["Elementar (Luft)", "Umwelt"], + "merkmal": [ + "Elementar (Luft)", + "Umwelt" + ], "komplexität": "C", "repräsentation": "Elf 6, Mag, Dru (Mag) je 2", "info": "WINDSTILLE gilt als Teil einer Hexalogie des Banns elementarer Gewalten, die vermutlich von el" diff --git a/src/style/_attributes.scss b/src/style/_attributes.scss deleted file mode 100644 index 1b3fd95a..00000000 --- a/src/style/_attributes.scss +++ /dev/null @@ -1,95 +0,0 @@ -@use "./_colours"; -@use "./_numbers"; -@use "./_assets"; -@use "sass:color"; - -.dsa41.sheet.actor.character { - - .sheet-header { - position: relative; - - .attributes { - position: absolute; - top: 8px; - right: 4px; - height: 48px; - display: flex; - - .attribute.rollable { - width: 48px; - height: 48px; - position: relative; - box-shadow: inset numbers.$dice-box-inset numbers.$dice-box-inset numbers.$dice-box-blur-radius colours.$dice-box-shadow; - background: assets.$dice-box-background; - margin-left: 2px; - border: numbers.$dice-box-border-width inset colours.$dice-box-border-color; - - .die { - stroke-width: 0.5; - - svg { - position: absolute; - left: 4px; - top: 4px; - bottom: 4px; - right: 4px; - } - - .border { - fill: rgba(0, 0, 0, 0); - stroke: colours.$attribute-die-border-color; - } - - .center { - fill: colours.$attribute-die-color; - stroke: colours.$attribute-die-border-color; - } - - .topleft { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$lighter_factor); - stroke: colours.$attribute-die-border-color; - } - - .bottomleft { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$lightest_factor); - stroke: colours.$attribute-die-border-color; - } - - .topright { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$darken_factor); - stroke: colours.$attribute-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$darkest_factor); - stroke: colours.$attribute-die-border-color; - } - } - - .wert { - font-weight: bold; - position: absolute; - left: 0; - width: 48px; - top: 0; - line-height: 48px; - vertical-align: middle; - text-align: center; - color: colours.$attribute-die-label-color; - } - - .name { - position: absolute; - left: 0; - right: 0; - bottom: 0; - line-height: 12px; - vertical-align: middle; - text-align: center; - color: colours.$attribute-label-color; - background-color: colours.$attribute-label-background-color; - } - } - } - } -} diff --git a/src/style/_character-sheet.scss b/src/style/_character-sheet.scss deleted file mode 100644 index 6c88c78b..00000000 --- a/src/style/_character-sheet.scss +++ /dev/null @@ -1,651 +0,0 @@ -@use "sass:color"; -@use "_numbers"; -@use "_colours" as colour; - - -.dsa41.sheet.actor.character { - - .window-header.flexrow.draggable.resizable { - } - - $sidebar-width: 224px; - $attribute-height: 60px; - $tabs-spacing: 14px; - $tabs-height: 26px; - - .window-content { - display: unset; /* we are on our own */ - position: relative; - - header.sheet-header { - position: absolute; - top: 0; - left: 0; - height: $attribute-height; - right: 0; - } - - div.head-data { - position: absolute; - left: 0; - top: $attribute-height; - width: $sidebar-width; - bottom: 0; - padding: 8px; - - - .profile-img { - width: $sidebar-width - 16px; - } - } - - nav.sheet-tabs.tabs { - position: absolute; - left: $sidebar-width; - top: $attribute-height+$tabs-spacing; - right: 0; - height: $tabs-height; - } - - section.sheet-body { - position: absolute; - top: $attribute-height+$tabs-height+$tabs-spacing+4px; - left: $sidebar-width; - right: 4px; - bottom: 4px; - padding: 8px; - overflow: auto; - } - - .tab.overview.active { - - display: flex; - flex-direction: column; - height: 100%; - - .meta-data { - flex: 0; - - columns: 2; - gap: 0 16px; - - - div { - break-inside: avoid; - padding: 4px 0; - } - - .double { - display: grid; - grid-template-columns: 1fr 1fr; - grid-template-areas: 'label label' 'left right'; - gap: 0 8px; - - label { - grid-area: label; - } - } - - .editor { - background-color: rgba(0, 0, 0, 0.2) - } - - & + .meta-data { - flex: 1; - } - } - - .meta-data.html { - - & > div { - display: flex; - flex-direction: column; - height: 100%; - - label { - flex: 0; - } - - .editor { - flex: 1; - } - } - - } - - } - - .tab.attributes.active { - height: 100%; - - .attribute { - padding: 8px 0; - display: flex; - gap: 0 8px; - - label { - width: 120px; - text-align: right; - vertical-align: middle; - line-height: 24px; - } - - input { - max-width: 80px; - text-align: right; - } - - .mod { - color: grey; - text-shadow: 0 -1px 0 #ccc; - box-Shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); - border-radius: 4px; - height: 24px; - width: 24px; - background: linear-gradient(0deg, rgba(24, 24, 24, 1) 0%, rgba(80, 80, 80, 1) 100%);; - display: inline-block; - text-align: center; - vertical-align: middle; - line-height: 24px; - margin-left: 4px; - } - - } - - .attributes-overview { - - columns: 2; - gap: 0 16px; - - } - - .resource-overview { - - .attribute { - - } - - } - - .advantages, .special-abilities { - margin-bottom: 16px; - - ul { - list-style-type: none; - padding: 0; - margin: 0; - text-indent: 0; - - li { - display: inline-block; - } - - .advantage, .special-ability { - position: relative; - border: 1px solid gold; - box-shadow: 2px 2px 4px #000; - border-radius: 8px; - height: 24px; - color: gold; - text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); - display: inline-block; - padding: 0 8px; - margin-left: 0; - margin-bottom: 4px; - background-image: url("../assets/velvet_button.png"); - background-repeat: repeat-y; - background-size: cover; - - span { - position: relative; - z-index: 2; - line-height: 24px; - vertical-align: middle; - } - - &.special-ability { - &::after { - background: rgba(128, 0, 96, 0.5); - } - } - - &::after { - content: ""; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - border-radius: 8px; - background: rgba(0, 128, 0, 0.5); - } - - & + .advantage, & + .special-ability { - margin-left: 8px; - } - - &.disadvantage { - font-style: italic; - - &::after { - background: rgba(128, 0, 0, 0.5); - } - } - } - } - - } - - - } - - .backpack.active { - display: grid; - grid-template-columns: 1fr 320px; - grid-template-rows: 74px 1fr; - gap: 10px; - height: 100%; - grid-template-areas: - "capacity capacity" - "inventory equipment"; - - .capacity { - - grid-area: capacity; - - .resource { - - position: relative; - border: 1px inset #ccc; - background-color: rgba(0, 0, 0, 0.2); - height: 8px; - - span.fill { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%); - } - - } - } - - .inventory { - grid-area: inventory; - - .equipment:hover { - .item-name { - text-shadow: 0 0 10px rgb(255 0 0); - } - } - } - } - - - .tab.combat.active { - - display: grid; - - grid-template-columns: 1fr 320px; - grid-template-rows: 32px 32px 1fr; - grid-template-areas: "res res" "wounds wounds" "actions actions"; - gap: 10px; - - .tab-resources { - grid-area: res; - } - - .wounds { - position: relative; - height: 24px; - display: flex; - margin-bottom: 8px; - padding-left: 130px; - grid-area: wounds; - - label { - position: absolute; - left: 0; - top: 0; - line-height: 24px; - width: 120px; - bottom: 0; - vertical-align: middle; - text-align: right; - height: 24px; - display: inline-block; - z-index: 2; - } - - .filled-segment { - border: 1px solid black; - background-image: url('../assets/gradient.png'); - background-size: 24px 100%; - position: relative; - flex: 1; - text-align: center; - vertical-align: middle; - line-height: 24px; - color: white; - text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); - background-color: rgba(255, 0, 0, 0.8); - background-blend-mode: multiply; - - } - - .empty-segment { - border: 1px solid black; - background-image: url('../assets/gradient.png'); - background-size: 32px 100%; - position: relative; - flex: 1; - text-align: center; - vertical-align: middle; - line-height: 24px; - color: gold; - text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); - background-color: rgba(0, 0, 0, 0.8); - background-blend-mode: multiply; - - } - - } - - .actions { - grid-area: actions; - } - - &.zones { - grid-template-areas: "res res" "wounds wounds" "actions paperdoll"; - - .paperdoll { - grid-area: paperdoll; - - div { - position: relative; - margin-left: 9px; - margin-top: 42px; - - .wound { - position: absolute; - width: 32px; - height: 32px; - border-radius: 16px; - border: 1px solid black; - background-color: rgba(0, 0, 0, 0.5); - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); - line-height: 32px; - vertical-align: middle; - text-align: center; - color: red; - - - &.armlinks { - top: 146px; - left: 210px; - } - - &.armrechts { - top: 146px; - left: 60px; - } - - &.beinlinks { - top: 346px; - left: 210px; - } - - &.beinrechts { - top: 346px; - left: 60px; - } - - &.bauch { - top: 166px; - left: 136px; - } - - &.kopf { - top: 6px; - left: 136px - } - - &.brust { - top: 86px; - left: 110px; - } - - } - - .armor { - position: absolute; - width: 32px; - height: 32px; - border-radius: 0 0 16px 16px; - line-height: 32px; - vertical-align: middle; - text-align: center; - border: 1px solid silver; - background-color: rgba(0, 0, 0, 0.5); - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); - color: silver; - - &.armlinks { - top: 180px; - left: 210px; - } - - &.armrechts { - top: 180px; - left: 60px; - } - - &.beinlinks { - top: 380px; - left: 210px; - } - - &.beinrechts { - top: 380px; - left: 60px; - } - - &.bauch { - top: 200px; - left: 136px; - } - - &.kopf { - top: 40px; - left: 136px - } - - &.brust { - top: 120px; - left: 110px; - } - } - } - - } - - } - - - } - - .tab.spells { - - tr { - height: 24px; - margin: 0; - padding: 0; - } - - td { - margin: 0; - padding: 0; - height: 24px; - } - - $color: #05f; - - .spell.rollable svg { - width: 24px; - height: 24px; - top: 1px; - z-index: 1; - position: relative; - - .border { - fill: #0000; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } - } - - .die-column { - width: 24px; - } - - .clickable { - span { - position: relative; - z-index: 1; - } - } - - tbody { - - tr { - - position: relative; - - &::after { - content: ''; - background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$end_2_gradient)); - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - position: absolute; - top: 2px; - left: 12px; - bottom: 2px; - right: 33%; - z-index: 0; - pointer-events: none; - } - - &:nth-child(odd) { - &::after { - background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$end_2_gradient)); - } - } - } - - } - - .merkmal-list { - list-style: none; - margin: 0; - padding: 0; - text-indent: 0; - - li { - display: inline-block; - padding: 0 4px; - } - } - - } - - .tab.liturgies { - - table { - border-top: unset; - border-bottom: unset; - position: relative; - } - - .liturgy-header { - background: unset; - border: unset; - - tr { - height: 90px; - - th { - vertical-align: middle; - color: black; - text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.2); - } - } - } - - td, th { - padding-left: 8px; - } - } - - .tab-resources { - display: flex; - justify-content: center; - gap: 0 16px; - padding-bottom: 8px; - - & > div { - - - height: 32px; - position: relative; - - label { - width: 80px; - line-height: 32px; - vertical-align: middle; - } - - input { - display: inline-block; - width: 40px; - height: 32px; - } - - span.inline { - line-height: 32px; - vertical-align: middle; - width: 40px; - text-align: center; - } - - - } - - } - - } - -} diff --git a/src/style/_creature-sheet.scss b/src/style/_creature-sheet.scss deleted file mode 100644 index 6c222a63..00000000 --- a/src/style/_creature-sheet.scss +++ /dev/null @@ -1,174 +0,0 @@ -@use "_colours" as colour; -@use 'sass:color'; -@use "_numbers"; - -.dsa41.sheet.actor.creature { - - .window-content { - - form { - - display: grid; - grid-template-columns: 1fr; - grid-template-rows: 74px 30px 1fr; - - .sheet-header { - - height: 64px; - display: grid; - grid-template-columns: 64px max-content; - grid-template-rows: 1fr; - gap: 0 8px; - - img { - width: 64px; - height: 64px; - } - - input { - line-height: 64px; - height: 64px; - font-size: 2rem; - - } - - } - - .sheet-body { - .tab { - margin: 8px; - - height: 100%; - - div.input { - - height: 32px; - display: grid; - grid-template-columns: 120px 1fr; - - &.compound { - - grid-template-columns: 120px 140px 1fr; - - span { - width: 120px; - } - - - input { - width: 100px; - } - - } - - label { - height: 32px; - width: 100%; - - span { - width: 120px; - text-align: left; - line-height: 32px; - vertical-align: middle; - display: inline-block; - } - - input { - text-align: right; - line-height: 32px; - vertical-align: middle; - padding-left: 120px; - display: inline-block; - } - - } - - } - - table.attacks-table { - - td { - padding: 2px 4px; - } - } - - .rollable.tablecell { - position: relative; - - - .attacks-die { - width: 24px; - height: 24px; - position: absolute; - left: 4px; - top: 4px; - bottom: 2px; - z-index: 1; - - - svg { - stroke-width: 0.5; - - $color: #f30; - - .border { - fill: #0000; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } - } - - - } - - input { - position: absolute; - left: 16px; - top: 4px; - bottom: 2px; - right: 4px; - width: unset; - text-indent: 12px; - } - } - - .button-inline { - border: unset; - background: unset; - } - - .editor { - height: 100%; - } - - } - } - - } - } - -} - diff --git a/src/style/_lists.scss b/src/style/_lists.scss deleted file mode 100644 index 7372c8d6..00000000 --- a/src/style/_lists.scss +++ /dev/null @@ -1,18 +0,0 @@ - -.dsa41.sheet.actor.character { - .tab.skills { - - columns: 2; - column-gap: 20px; - - .talent-group { - break-inside: avoid-column; - } - - ul { - list-style-type: none; - padding-left: 0; - } - - } -} diff --git a/src/style/_liturgy-banner.scss b/src/style/_liturgy-banner.scss deleted file mode 100644 index a6d30efb..00000000 --- a/src/style/_liturgy-banner.scss +++ /dev/null @@ -1,247 +0,0 @@ -@use "sass:map"; -@use "sass:color"; -@use "colours" as colour; -@use "numbers"; - -$deity_colours_border: ( - "Praios": orange, - "Rondra": red, - "Efferd": #74d0ec, - "Travia": #c6491a, - "Boron": #515151, - "Hesinde": #089e08, - "Firun": #8fdeff, - "Tsa": #6a24d8, - "Phex": #1569da, - "Peraine": #56a116, - "Ingerimm": #a53d19, - "Rahja": #ed70c2, -); -$deity_colours_tint: ( - "Praios": rgba(orange, 0.5), - "Rondra": rgba(red, 0.5), - "Efferd": rgba(#74d0ec, 0.5), - "Travia": rgba(#c6491a, 0.5), - "Boron": rgba(#515151, 0.5), - "Hesinde": rgba(#089e08, 0.5), - "Firun": rgba(#8fdeff, 0.5), - "Tsa": linear-gradient( - -45deg, - rgba(255, 0, 0, 0.5) 0%, - rgba(255, 154, 0, 0.5) 10%, - rgba(208, 222, 33, 0.5) 20%, - rgba(79, 220, 74, 0.5) 30%, - rgba(63, 218, 216, 0.5) 40%, - rgba(47, 201, 226, 0.5) 50%, - rgba(28, 127, 238, 0.5) 60%, - rgba(95, 21, 242, 0.5) 70%, - rgba(186, 12, 248, 0.5) 80%, - rgba(251, 7, 217, 0.5) 90%, - rgba(255, 0, 0, 0.5) 100% - ), - "Phex": rgba(#1569da, 0.5), - "Peraine": rgba(#56a116, 0.5), - "Ingerimm": rgba(#a53d19, 0.5), - "Rahja": rgba(#ed70c2, 0.5), -); - -@mixin coloring($name) { - $color: map.get($deity_colours_border, $name); - $color-tint: map.get($deity_colours_tint, $name); - &.#{$name} { - - th.background { - &::after { - background: $color-tint; - } - } - - .banner-bot { - border-color: $color; - } - - .banner-mid { - border-color: $color; - } - - .banner-top { - &::before, &::after { - border-color: $color; - } - } - } -} - -.tab.liturgies { - table { - - @include coloring('Praios'); - @include coloring('Rondra'); - @include coloring('Efferd'); - @include coloring('Travia'); - @include coloring('Boron'); - @include coloring('Hesinde'); - @include coloring('Firun'); - @include coloring('Tsa'); - @include coloring('Phex'); - @include coloring('Peraine'); - @include coloring('Ingerimm'); - @include coloring('Rahja'); - - tr { - th.background { - - &::before { - position: absolute; - content: ''; - background-image: url("../assets/velvet_strip.png"); - background-repeat: repeat-y; - background-size: cover; - width: 86px; - height: 100%; - - top: 45px; - left: 12px; - } - - &::after { /* for tinting the texture */ - content: ""; - position: absolute; - width: 86px; - height: 100%; - - top: 45px; - left: 12px; - } - } - } - - .banner-top { - position: relative; - - width: 90px; - - img { - position: absolute; - top: 2px; - left: 1px; - width: 90px; - height: 90px; - border: 0; - z-index: 1; - } - - &::after { - z-index: 0; - border-width: 0 4px 0 4px; - //background-color: #64b; - border-style: solid; - position: absolute; - content: ""; - left: -2px; - top: 45px; - bottom: 0; - width: 94px; - } - - &::before { - position: absolute; - border-radius: 45px; - height: 94px; - width: 94px; - content: ''; - left: -2px; - right: -2px; - top: 0; - border-width: 4px; - border-style: solid; - z-index: 2; - } - } - - .banner-mid { - position: relative; - border-width: 0 4px 0 4px; - //background-color: #64b; - border-style: solid; - width: 90px; - - div { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - display: flex; - justify-content: center; - align-items: center; - - div.rank-label { - position: absolute; - left: 2px; - right: 2px; - top: 0; - bottom: 0; - border-bottom: 2px solid black; - color: gold; - text-shadow: 2px 2px 1px black; - } - } - } - - .banner-bot { - position: relative; - border-width: 4px; - border-style: solid; - width: 90px; - height: 12px; - } - } - - .liturgy.rollable { - width: 24px; - - svg { - $color: #e4de61; - width: 24px; - height: 24px; - top: 1px; - z-index: 1; - position: relative; - - .border { - fill: #0000; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } - } - } - - .clickable:hover { - text-shadow: 0 0 10px rgb(255 0 0); - } - -} diff --git a/src/style/_player-action.scss b/src/style/_player-action.scss deleted file mode 100644 index a56b7b59..00000000 --- a/src/style/_player-action.scss +++ /dev/null @@ -1,26 +0,0 @@ -@use "./_colours"; -@use "./_numbers"; -@use "sass:color"; - -.player-action { - - display: inline-block; - width: 120px; - height: 80px; - float: left; - margin: 0 8px 8px 0; - - border: 1px solid #333; - background-color: color.scale(colours.$default-action, $alpha: 20%); - color: colours.$default-action-color; - border-radius: 4px; - box-shadow: numbers.$pill-box-inset numbers.$pill-box-inset numbers.$pill-box-blur-radius colours.$pill-box-shadow; - - - &.special-ability { - background-color: color.scale(colours.$special-action, $alpha: 20%); - color: colours.$special-action-color; - - } - -} diff --git a/src/style/_tabs.scss b/src/style/_tabs.scss deleted file mode 100644 index 7f872530..00000000 --- a/src/style/_tabs.scss +++ /dev/null @@ -1,48 +0,0 @@ -@use "./numbers"; -@use "./colours"; -@use "./assets"; - -.dsa41.sheet { - - nav.sheet-tabs.tabs { - - position: relative; - display: flow; - border-top: unset; - border-bottom: unset; - margin-bottom: 9px; - - a.item[data-tab] { - - background-color: colours.$tab-inactive-background-color; - - &.active { - border-left: numbers.$tab-border-width solid colours.$tab-border-color; - border-top: numbers.$tab-border-width solid colours.$tab-border-color; - border-right: numbers.$tab-border-width solid colours.$tab-border-color; - border-bottom: 0; - top: numbers.$tab-border-width*2; - background: assets.$tab-background; - position: relative; - z-index: 2; - - } - - } - - } - - section.sheet-body { - - border: numbers.$tab-border-width solid colours.$tab-border-color; - background: assets.$tab-pane-background; - - div.tab { - - overflow: auto; - - } - - } - -} diff --git a/src/style/_assets.scss b/src/style/atoms/_assets.scss similarity index 100% rename from src/style/_assets.scss rename to src/style/atoms/_assets.scss diff --git a/src/style/_colours.scss b/src/style/atoms/_colours.scss similarity index 60% rename from src/style/_colours.scss rename to src/style/atoms/_colours.scss index 4fc2e42f..26d0d225 100644 --- a/src/style/_colours.scss +++ b/src/style/atoms/_colours.scss @@ -34,9 +34,35 @@ $tab-background-color: #fff8; $dice-box-shadow: rgba(0, 0, 0, 0.25); $pill-box-shadow: rgba(0, 0, 0, 0.3); +$tab-shadow: rgba(0, 0, 0, 0.3); +$tab-pane-shadow: rgba(0, 0, 0, 0.3); + $attribute-die-border-color: #000; + $attribute-die-color: #F00; $attribute-die-label-color: #FFF; + +$attribute-die-co-color: #b3241a; +$attribute-die-sm-color: #8259a3; +$attribute-die-in-color: #388834; +$attribute-die-ch-color: #0d0d0d; + +$attribute-die-dx-color: #688ec4; +$attribute-die-ag-color: #d5b467; +$attribute-die-bd-color: #a3a3a3; +$attribute-die-st-color: #d6a878; + +$attribute-die-co-text-color: #fff; +$attribute-die-sm-text-color: #fff; +$attribute-die-in-text-color: #fff; +$attribute-die-ch-text-color: #fff; + +$attribute-die-dx-text-color: #000; +$attribute-die-ag-text-color: #000; +$attribute-die-bd-text-color: #000; +$attribute-die-st-text-color: #000; + + $attribute-label-color: #FFF; $attribute-label-background-color: #0008; @@ -44,9 +70,9 @@ $rollable-die-border-color: #000; $dice-box-border-color: #333; -$default-action: #c41; -$default-action-color: #FFF; +$default-action: rgba(204, 68, 17, 0.8); +$default-action-color: #000; -$special-action: #42c; +$special-action: rgba(68, 34, 204, 0.8); -$special-action-color: #FFF; +$special-action-color: #000; diff --git a/src/style/atoms/_fonts.scss b/src/style/atoms/_fonts.scss new file mode 100644 index 00000000..05608815 --- /dev/null +++ b/src/style/atoms/_fonts.scss @@ -0,0 +1,21 @@ +@font-face { + font-family: "Andalus"; + src: url("/systems/DSA_4-1/assets/fonts/andlso.ttf"); +} + +@font-face { + font-family: "Gentium"; + src: url("/systems/DSA_4-1/assets/fonts/GenBasR.ttf"); +} + +@font-face { + font-family: "Gentium"; + src: url("/systems/DSA_4-1/assets/fonts/GenBasI.ttf"); + font-style: italic; +} + +@font-face { + font-family: "Gentium"; + src: url("/systems/DSA_4-1/assets/fonts/GenBasB.ttf"); + font-weight: bold; +} \ No newline at end of file diff --git a/src/style/_numbers.scss b/src/style/atoms/_numbers.scss similarity index 71% rename from src/style/_numbers.scss rename to src/style/atoms/_numbers.scss index e79d87d1..7b8faefa 100644 --- a/src/style/_numbers.scss +++ b/src/style/atoms/_numbers.scss @@ -16,6 +16,14 @@ $dice-box-inset: 4px; $dice-box-blur-radius: 4px; $dice-box-border-width: 1px; +$tab-shadow-right: 1px; +$tab-shadow-bottom: 0; +$tab-shadow-blur-radius: 0; + +$tab-pane-shadow-right: 1px; +$tab-pane-shadow-bottom: 1px; +$tab-pane-shadow-blur-radius: 0; + $pill-box-inset: 2px; $pill-box-blur-radius: 4px; diff --git a/src/style/atoms/_svg.scss b/src/style/atoms/_svg.scss new file mode 100644 index 00000000..2092062b --- /dev/null +++ b/src/style/atoms/_svg.scss @@ -0,0 +1,3 @@ +svg { + pointer-events: none; +} \ No newline at end of file diff --git a/src/style/atoms/_typography.scss b/src/style/atoms/_typography.scss new file mode 100644 index 00000000..e3cb3ab3 --- /dev/null +++ b/src/style/atoms/_typography.scss @@ -0,0 +1,36 @@ +.application.sheet.dsa41 { + + --font-body: Gentium, sans-serif; + + label, + .sheet-tabs.tabs a, + h2, h3 { + font-family: Gentium, sans-serif; + font-weight: bold; + font-size: 12pt; + } + + h2 { + height: 32px; + line-height: 32px; + padding: 0; + margin: 0; + } + + ul { + li { + margin-bottom: 16px; + } + } + + input, + .rkp .pill { + font-family: Andalus, sans-serif; + } + + .editor.prosemirror.active, .editor.prosemirror.inactive { + font-family: Gentium, sans-serif; + } + +} + diff --git a/src/style/molecules/_attributes.scss b/src/style/molecules/_attributes.scss new file mode 100644 index 00000000..3c8ef194 --- /dev/null +++ b/src/style/molecules/_attributes.scss @@ -0,0 +1,159 @@ +@use "../atoms/colours"; +@use "../atoms/numbers"; +@use "../atoms/assets"; +@use "sass:color"; + +.dsa41.sheet.actor.character { + + .sheet-header { + position: relative; + + .attributes { + display: flex; + + .attribute.rollable { + width: 48px; + height: 48px; + position: relative; + box-shadow: inset numbers.$dice-box-inset numbers.$dice-box-inset numbers.$dice-box-blur-radius colours.$dice-box-shadow; + background: assets.$dice-box-background; + margin-left: 2px; + border: numbers.$dice-box-border-width inset colours.$dice-box-border-color; + + .die { + stroke-width: 0.5; + + svg { + position: absolute; + left: -6px; + top: -6px; + bottom: -6px; + right: -6px; + + path { + fill: colours.$attribute-die-color; + } + } + } + + .wert { + font-weight: bold; + position: absolute; + left: -2px; + width: 48px; + top: -2px; + font-size: smaller; + line-height: 48px; + vertical-align: middle; + text-align: center; + color: colours.$attribute-die-label-color; + } + + .name { + position: absolute; + left: 0; + right: 0; + bottom: 0; + line-height: 12px; + vertical-align: middle; + text-align: center; + color: colours.$attribute-label-color; + background-color: colours.$attribute-label-background-color; + } + } + + &.colorfulDice { + + &.Mut { + + .die svg path { + fill: colours.$attribute-die-co-color; + } + + .wert { + color: colours.$attribute-die-co-text-color; + } + } + + .Klugheit { + + .die svg path { + fill: colours.$attribute-die-sm-color; + } + + .wert { + color: colours.$attribute-die-sm-text-color; + } + } + + .Intuition { + + .die svg path { + fill: colours.$attribute-die-in-color; + } + + .wert { + color: colours.$attribute-die-in-text-color; + } + } + + .Charisma { + + .die svg path { + fill: colours.$attribute-die-ch-color; + } + + .wert { + color: colours.$attribute-die-ch-text-color; + } + } + + .Geschicklichkeit { + + .die svg path { + fill: colours.$attribute-die-dx-color; + } + + .wert { + color: colours.$attribute-die-dx-text-color; + } + } + + .Fingerfertigkeit { + + .die svg path { + fill: colours.$attribute-die-ag-color; + } + + .wert { + color: colours.$attribute-die-ag-text-color; + } + } + + .Konstitution { + + .die svg path { + fill: colours.$attribute-die-bd-color; + } + + .wert { + color: colours.$attribute-die-bd-text-color; + } + } + + .Körperkraft { + + .die svg path { + fill: colours.$attribute-die-st-color; + } + + .wert { + color: colours.$attribute-die-st-text-color; + } + } + + } + + } + } +} diff --git a/src/style/molecules/_droppables.scss b/src/style/molecules/_droppables.scss new file mode 100644 index 00000000..a3eabd6a --- /dev/null +++ b/src/style/molecules/_droppables.scss @@ -0,0 +1,27 @@ +.droppable { + + .inventory-table { + position: relative; + } + + .inventory-table::after { + + content: 'Gegenstände hier fallen lassen'; + pointer-events: none; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + border-radius: 8px; + border-style: dashed; + border-color: gray; + line-height: 34px; + height: 34px; + vertical-align: middle; + text-align: center; + background-color: rgba(0, 0, 0, 0.4); + color: gray; + } + +} \ No newline at end of file diff --git a/src/style/molecules/_lists.scss b/src/style/molecules/_lists.scss new file mode 100644 index 00000000..790b51ca --- /dev/null +++ b/src/style/molecules/_lists.scss @@ -0,0 +1,4 @@ + +.dsa41.sheet.actor.character { + +} diff --git a/src/style/molecules/_liturgy-banner.scss b/src/style/molecules/_liturgy-banner.scss new file mode 100644 index 00000000..c79f60cb --- /dev/null +++ b/src/style/molecules/_liturgy-banner.scss @@ -0,0 +1,251 @@ +@use "sass:map"; +@use "sass:color"; +@use "../atoms/colours" as colour; +@use "../atoms/numbers"; + +$deity_colours_border: ( + "Praios": orange, + "Rondra": red, + "Efferd": #74d0ec, + "Travia": #c6491a, + "Boron": #515151, + "Hesinde": #089e08, + "Firun": #8fdeff, + "Tsa": #6a24d8, + "Phex": #1569da, + "Peraine": #56a116, + "Ingerimm": #a53d19, + "Rahja": #ed70c2, +); +$deity_colours_tint: ( + "Praios": rgba(orange, 0.5), + "Rondra": rgba(red, 0.5), + "Efferd": rgba(#74d0ec, 0.5), + "Travia": rgba(#c6491a, 0.5), + "Boron": rgba(#515151, 0.5), + "Hesinde": rgba(#089e08, 0.5), + "Firun": rgba(#8fdeff, 0.5), + "Tsa": linear-gradient( + -45deg, + rgba(255, 0, 0, 0.5) 0%, + rgba(255, 154, 0, 0.5) 10%, + rgba(208, 222, 33, 0.5) 20%, + rgba(79, 220, 74, 0.5) 30%, + rgba(63, 218, 216, 0.5) 40%, + rgba(47, 201, 226, 0.5) 50%, + rgba(28, 127, 238, 0.5) 60%, + rgba(95, 21, 242, 0.5) 70%, + rgba(186, 12, 248, 0.5) 80%, + rgba(251, 7, 217, 0.5) 90%, + rgba(255, 0, 0, 0.5) 100% + ), + "Phex": rgba(#1569da, 0.5), + "Peraine": rgba(#56a116, 0.5), + "Ingerimm": rgba(#a53d19, 0.5), + "Rahja": rgba(#ed70c2, 0.5), +); + +@mixin coloring($name) { + $color: map.get($deity_colours_border, $name); + $color-tint: map.get($deity_colours_tint, $name); + &.#{$name} { + + th.background { + &::after { + background: $color-tint; + } + } + + .banner-bot { + border-color: $color; + } + + .banner-mid { + border-color: $color; + } + + .banner-top { + &::before, &::after { + border-color: $color; + } + } + } +} + +.dsa41.sheet { + + .tab.liturgies { + table { + + @include coloring('Praios'); + @include coloring('Rondra'); + @include coloring('Efferd'); + @include coloring('Travia'); + @include coloring('Boron'); + @include coloring('Hesinde'); + @include coloring('Firun'); + @include coloring('Tsa'); + @include coloring('Phex'); + @include coloring('Peraine'); + @include coloring('Ingerimm'); + @include coloring('Rahja'); + + tr { + th.background { + + &::before { + position: absolute; + content: ''; + background-image: url("/systems/DSA_4-1/assets/velvet_strip.png"); + background-repeat: repeat-y; + background-size: cover; + width: 86px; + height: 100%; + + top: 45px; + left: 28px; + } + + &::after { /* for tinting the texture */ + content: ""; + position: absolute; + width: 86px; + height: 100%; + + top: 45px; + left: 28px; + } + } + } + + .banner-top { + position: relative; + + width: 90px; + + img { + position: absolute; + top: 2px; + left: 1px; + width: 90px; + height: 90px; + border: 0; + z-index: 1; + } + + &::after { + z-index: 0; + border-width: 0 4px 0 4px; + //background-color: #64b; + border-style: solid; + position: absolute; + content: ""; + left: -2px; + top: 45px; + bottom: 0; + width: 94px; + } + + &::before { + position: absolute; + border-radius: 45px; + height: 94px; + width: 94px; + content: ''; + left: -2px; + right: -2px; + top: 0; + border-width: 4px; + border-style: solid; + z-index: 2; + } + } + + .banner-mid { + position: relative; + border-width: 0 4px 0 4px; + //background-color: #64b; + border-style: solid; + width: 90px; + + div { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + display: flex; + justify-content: center; + align-items: center; + + div.rank-label { + position: absolute; + left: 2px; + right: 2px; + top: 0; + bottom: 0; + border-bottom: 2px solid black; + color: gold; + text-shadow: 2px 2px 1px black; + } + } + } + + .banner-bot { + position: relative; + border-width: 4px; + border-style: solid; + width: 90px; + height: 12px; + } + } + + .liturgy.rollable { + width: 24px; + + svg { + $color: #e4de61; + width: 24px; + height: 24px; + top: 1px; + z-index: 1; + position: relative; + + .border { + fill: #0000; + } + + .center { + fill: $color; + stroke: colour.$rollable-die-border-color; + } + + .topleft { + fill: color.adjust($color, $lightness: numbers.$lighter_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomleft { + fill: color.adjust($color, $lightness: numbers.$lightest_factor); + stroke: colour.$rollable-die-border-color; + } + + .topright { + fill: color.adjust($color, $lightness: numbers.$darken_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomright, .bottom { + fill: color.adjust($color, $lightness: numbers.$darkest_factor); + stroke: colour.$rollable-die-border-color; + } + } + } + + .clickable:hover { + text-shadow: 0 0 10px rgb(255 0 0); + } + + } + +} \ No newline at end of file diff --git a/src/style/_paperdoll.scss b/src/style/molecules/_paperdoll.scss similarity index 100% rename from src/style/_paperdoll.scss rename to src/style/molecules/_paperdoll.scss diff --git a/src/style/molecules/_pill.scss b/src/style/molecules/_pill.scss new file mode 100644 index 00000000..3c8ba82c --- /dev/null +++ b/src/style/molecules/_pill.scss @@ -0,0 +1,19 @@ +.application.sheet.dsa41 { + + .pill { + + height: 24px; + line-height: 24px; + font-size: 14px; + vertical-align: middle; + padding: 1px 4px; + margin-right: 4px; + border-radius: 8px; + border: 1px solid orange; + color: orange; + background-color: rgba(0, 0, 0, 0.6); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), inset -1px -1px 0 rgba(0, 0, 0, 0.1); + display: inline-block; + } + +} \ No newline at end of file diff --git a/src/style/molecules/_player-action.scss b/src/style/molecules/_player-action.scss new file mode 100644 index 00000000..f2cd4931 --- /dev/null +++ b/src/style/molecules/_player-action.scss @@ -0,0 +1,47 @@ +@use "../atoms/colours"; +@use "../atoms/numbers"; +@use "sass:color"; + +.dsa41.sheet { + .player-action { + + display: inline-block; + width: 120px; + height: 80px; + float: left; + margin: 0 8px 8px 0; + position: relative; + + border: 1px solid #333; + color: colours.$default-action-color; + background: url('../../../ui/parchment.jpg'); + background-size: 128px 100%; + border-radius: 4px; + box-shadow: numbers.$pill-box-inset numbers.$pill-box-inset numbers.$pill-box-blur-radius colours.$pill-box-shadow; + + span { + position: relative; + z-index: 2; + } + + &::after { /* for tinting the texture */ + content: ""; + position: absolute; + background-color: colours.$default-action; + background-blend-mode: multiply; + + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1; + } + + &.special-ability::after { + background-color: colours.$special-action; + color: colours.$special-action-color; + + } + + } +} diff --git a/src/style/molecules/_richtext-editor.scss b/src/style/molecules/_richtext-editor.scss new file mode 100644 index 00000000..ffe51fae --- /dev/null +++ b/src/style/molecules/_richtext-editor.scss @@ -0,0 +1,13 @@ +.application.sheet.dsa41 { + + .editor.prosemirror { + flex: 1; + background-color: rgba(0, 0, 0, 0.1); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); + border: 1px solid #666; + outline: 1px solid transparent; + border-radius: 4px; + + } + +} \ No newline at end of file diff --git a/src/style/_rollable.scss b/src/style/molecules/_rollable.scss similarity index 82% rename from src/style/_rollable.scss rename to src/style/molecules/_rollable.scss index 5a294533..a1c7cb5b 100644 --- a/src/style/_rollable.scss +++ b/src/style/molecules/_rollable.scss @@ -1,7 +1,7 @@ @use 'sass:color'; @use 'sass:map'; -@use "_colours" as colour; -@use "_numbers" as numbers; +@use "../atoms/colours" as colour; +@use "../atoms/numbers" as numbers; $rollable_colours: ( "nachteil": colour.$nachteil-color, @@ -146,9 +146,8 @@ $rollable_colours_font: ( .value { width: 28px; height: 28px; - left: 0; + left: -1px; top: -2px; - scale: 0.8; img { position: absolute; @@ -171,39 +170,22 @@ $rollable_colours_font: ( .die { stroke-width: 0.5; + svg { + + margin: -4px; + + path { + fill: $color; + stroke: colour.$rollable-die-border-color; + stroke-width: 5px; + } + } + span.value { color: $font_color; + } - .border { - fill: colour.$rollable-die-border-color; - stroke: colour.$rollable-die-border-color; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } } .container { diff --git a/src/style/_sidebar-elements.scss b/src/style/molecules/_sidebar-elements.scss similarity index 96% rename from src/style/_sidebar-elements.scss rename to src/style/molecules/_sidebar-elements.scss index f774031b..2e69c5e3 100644 --- a/src/style/_sidebar-elements.scss +++ b/src/style/molecules/_sidebar-elements.scss @@ -60,7 +60,7 @@ left: 0; top: 0; bottom: 0; - background: url('../assets/gradient.png'); + background: url('/systems/DSA_4-1/assets/gradient.png'); background-size: 32px 100%; &::after { diff --git a/src/style/molecules/_tabs.scss b/src/style/molecules/_tabs.scss new file mode 100644 index 00000000..9a42f929 --- /dev/null +++ b/src/style/molecules/_tabs.scss @@ -0,0 +1,109 @@ +@use "../atoms/numbers"; +@use "../atoms/colours"; +@use "../atoms/assets"; + +.dsa41.sheet { + + nav.sheet-tabs.tabs { + + position: relative; + display: flow; + border-top: unset; + border-bottom: unset; + margin-bottom: 0; + + a.item[data-tab] { + + background-color: colours.$tab-inactive-background-color; + + &.active { + border-left: numbers.$tab-border-width solid colours.$tab-border-color; + border-top: numbers.$tab-border-width solid colours.$tab-border-color; + border-right: numbers.$tab-border-width solid colours.$tab-border-color; + border-bottom: 0; + top: numbers.$tab-border-width*2; + background: assets.$tab-background; + position: relative; + z-index: 2; + } + + } + + } + + section.sheet-body { + + border: numbers.$tab-border-width solid colours.$tab-border-color; + background: assets.$tab-pane-background; + + div.tab { + + overflow: auto; + + } + + } + + + // Tabs v2 + + .sheet-tabs { + + position: relative; + display: flow; + border-top: unset; + border-bottom: unset; + margin-bottom: 0; + + a[data-action="tab"] { + + background-color: colours.$tab-inactive-background-color; + display: inline-block; + height: 32px; + line-height: 32px; + vertical-align: middle; + padding: 0 16px; + + span { + + } + + &.active { + + border-left: numbers.$tab-border-width solid colours.$tab-border-color; + border-top: numbers.$tab-border-width solid colours.$tab-border-color; + border-right: numbers.$tab-border-width solid colours.$tab-border-color; + border-bottom: 0; + top: numbers.$tab-border-width; + background: assets.$tab-background; + position: relative; + z-index: 2; + + box-shadow: numbers.$tab-shadow-right numbers.$tab-shadow-bottom numbers.$tab-shadow-blur-radius colours.$tab-shadow; + + span { + + } + + } + + } + } + + section.tab { + border: numbers.$tab-border-width solid colours.$tab-border-color; + background: assets.$tab-pane-background; + box-shadow: numbers.$tab-pane-shadow-right numbers.$tab-pane-shadow-bottom numbers.$tab-pane-shadow-blur-radius colours.$tab-pane-shadow; + + flex: 1; + + & > div { + display: flex; + flex-direction: column; + height: 100%; + gap: 8px; + padding: 8px; + } + } + +} diff --git a/src/style/_active-effect-sheet.scss b/src/style/organisms/_active-effect-sheet.scss similarity index 89% rename from src/style/_active-effect-sheet.scss rename to src/style/organisms/_active-effect-sheet.scss index dd1dddb0..18c57971 100644 --- a/src/style/_active-effect-sheet.scss +++ b/src/style/organisms/_active-effect-sheet.scss @@ -14,6 +14,11 @@ height: 48px; line-height: 48px; } + + button { + height: 48px; + width: 48px; + } } .meta { diff --git a/src/style/_advantage-sheet.scss b/src/style/organisms/_advantage-sheet.scss similarity index 100% rename from src/style/_advantage-sheet.scss rename to src/style/organisms/_advantage-sheet.scss diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss new file mode 100644 index 00000000..f04ae439 --- /dev/null +++ b/src/style/organisms/_character-sheet.scss @@ -0,0 +1,107 @@ +@use "sass:color"; +@use "../atoms/numbers"; +@use "../atoms/colours" as colour; +@use "./character-tabs/meta"; +@use "./character-tabs/social"; +@use "./character-tabs/attributes"; +@use "./character-tabs/inventory"; +@use "./character-tabs/combat"; +@use "./character-tabs/spells"; +@use "./character-tabs/liturgies"; +@use "./character-tabs/skills"; + +.application.sheet.dsa41.actor.character { + + $sidebar-width: 224px; + $attribute-height: 60px; + $tabs-spacing: 14px; + $tabs-height: 26px; + + .window-content { + display: unset; /* we are on our own */ + position: relative; + + .header-fields { + position: absolute; + top: 0; + left: 0; + height: $attribute-height; + right: 0; + display: grid; + grid-template-columns: 1fr max-content; + gap: 0 8px; + + .name { + border: unset; + font-size: large; + } + + } + + div.head-data { + position: absolute; + left: 16px; + top: $attribute-height+30px; + width: $sidebar-width - 16px; + bottom: 16px; + padding: 0; + + + .profile-img { + width: $sidebar-width - 16px; + } + } + + nav.sheet-tabs.tabs { + position: absolute; + left: $sidebar-width+16px; + top: $attribute-height+$tabs-spacing+13px; + right: 16px; + height: $tabs-height; + } + + section.tab { + position: absolute; + top: $attribute-height+$tabs-height+$tabs-spacing+21px; + left: $sidebar-width+16px; + right: 16px; + bottom: 16px; + padding: 0; + overflow: auto; + } + + .tab.meta.active { + @include meta.tab; + } + + .tab.social.active { + @include social.tab; + } + + .tab.attributes.active { + @include attributes.tab; + } + + .tab.equipment.active { + @include inventory.tab; + } + + .tab.combat.active { + @include combat.tab; + } + + .tab.skills.active { + @include skills.tab; + } + + .tab.spells { + @include spells.tab; + } + + .tab.liturgies { + @include liturgies.tab; + } + + } + +} diff --git a/src/style/organisms/_creature-sheet.scss b/src/style/organisms/_creature-sheet.scss new file mode 100644 index 00000000..707971cd --- /dev/null +++ b/src/style/organisms/_creature-sheet.scss @@ -0,0 +1,168 @@ +@use "../atoms/colours" as colour; +@use 'sass:color'; +@use "../atoms/numbers"; + +.dsa41.sheet.actor.creature { + + .window-content { + + .sheet-header { + + height: 64px; + display: grid; + grid-template-columns: 64px 1fr; + grid-template-rows: 1fr; + gap: 0 8px; + margin-bottom: 8px; + + img { + width: 64px; + height: 64px; + } + + input { + line-height: 64px; + height: 64px; + font-size: 2rem; + + } + + } + + div.input { + + height: 32px; + display: grid; + grid-template-columns: 120px 1fr; + + &.compound { + + grid-template-columns: 120px 140px 1fr; + + span { + width: 120px; + } + + + input { + width: 100px; + } + + } + + label { + height: 32px; + width: 100%; + + span { + width: 120px; + text-align: left; + line-height: 32px; + vertical-align: middle; + display: inline-block; + } + + input { + text-align: right; + line-height: 32px; + vertical-align: middle; + padding-left: 120px; + display: inline-block; + } + + } + + } + + table.attacks-table { + + margin: 0; + + td { + padding: 2px 4px; + } + } + + .rollable.tablecell { + position: relative; + + + .attacks-die { + width: 24px; + height: 24px; + position: absolute; + left: 4px; + top: 4px; + bottom: 2px; + z-index: 1; + + + svg { + stroke-width: 0.5; + + $color: #f30; + + .border { + fill: #0000; + } + + .center { + fill: $color; + stroke: colour.$rollable-die-border-color; + } + + .topleft { + fill: color.adjust($color, $lightness: numbers.$lighter_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomleft { + fill: color.adjust($color, $lightness: numbers.$lightest_factor); + stroke: colour.$rollable-die-border-color; + } + + .topright { + fill: color.adjust($color, $lightness: numbers.$darken_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomright, .bottom { + fill: color.adjust($color, $lightness: numbers.$darkest_factor); + stroke: colour.$rollable-die-border-color; + } + } + + + } + + input { + position: absolute; + left: 16px; + top: 4px; + bottom: 2px; + right: 4px; + width: unset; + text-indent: 12px; + } + } + + .button-inline { + border: unset; + background: unset; + } + + .editor { + height: 100%; + } + + .tab.active { + padding: 8px; + } + + .tab.attacks.active { + padding: 16px; + } + + } +} + diff --git a/src/style/organisms/_culture-sheet.scss b/src/style/organisms/_culture-sheet.scss new file mode 100644 index 00000000..034e17b6 --- /dev/null +++ b/src/style/organisms/_culture-sheet.scss @@ -0,0 +1,26 @@ +.application.sheet.dsa41.item.culture { + + section.culture { + + display: flex; + flex-direction: column; + flex: 1; + + div { + flex: 0; + } + + div.editor { + flex: 1; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/_equipment-sheet.scss b/src/style/organisms/_equipment-sheet.scss similarity index 87% rename from src/style/_equipment-sheet.scss rename to src/style/organisms/_equipment-sheet.scss index 80f041f0..a565df70 100644 --- a/src/style/_equipment-sheet.scss +++ b/src/style/organisms/_equipment-sheet.scss @@ -1,28 +1,15 @@ -@use "./_colours"; -@use "./_numbers"; +@use "../atoms/colours"; +@use "../atoms/numbers"; -.app.window-app.dsa41.sheet.item.equipment { +.application.sheet.dsa41.item.equipment { - .sheet-body { + .tab.meta.active > div { - position: relative; - - .tab.active { - padding: 4px; - top: 0; - bottom: 0; - left: 0; - right: 0; - } - - .tab.meta.active { - - position: absolute; display: grid; grid-auto-columns: 1fr 1fr; grid-template-columns: 80px auto; - grid-template-rows: 24px 48px auto 48px; - gap: 0 0; + grid-template-rows: 32px 48px auto 48px; + gap: 8px; grid-template-areas: "category category" "quantity name" @@ -57,6 +44,7 @@ grid-area: bottomline; display: grid; grid-template-columns: repeat(2, 1fr); + gap: 8px; .named-value { position: relative; @@ -104,7 +92,7 @@ ul { list-style-type: none; - padding: 0; + padding: 0 32px 0 0; margin: 0; text-indent: 0; @@ -124,6 +112,7 @@ position: absolute; right: 0; top: 0; + width: 24px; } } @@ -153,7 +142,4 @@ } - - } - } diff --git a/src/style/_group-sheet.scss b/src/style/organisms/_group-sheet.scss similarity index 84% rename from src/style/_group-sheet.scss rename to src/style/organisms/_group-sheet.scss index 0f61f602..e246ff98 100644 --- a/src/style/_group-sheet.scss +++ b/src/style/organisms/_group-sheet.scss @@ -1,40 +1,14 @@ -.dsa41.sheet.actor.group { - - - .window-content { - display: unset; - position: relative; - } +.application.sheet.dsa41.actor.group { .sheet-header { - .sheet-name { - font-size: 24pt; - height: 48px; - } - } + display: grid; + grid-template-columns: 32px 1fr; + gap: 8px; - .sheet-tabs { - position: absolute; - left: 0; - right: 0; - top: 76px; - height: 32px; - padding: 0 16px; - } - - .sheet-body { - position: absolute; - top: 98px; - left: 0; - bottom: 0; - right: 0; - padding: 8px; - margin: 8px; - - div.tab { - height: 100%; - position: relative; + img { + height: 32px; + width: 32px; } } diff --git a/src/style/_modify-liturgy.scss b/src/style/organisms/_modify-liturgy.scss similarity index 100% rename from src/style/_modify-liturgy.scss rename to src/style/organisms/_modify-liturgy.scss diff --git a/src/style/organisms/_profession-sheet.scss b/src/style/organisms/_profession-sheet.scss new file mode 100644 index 00000000..5c9a5023 --- /dev/null +++ b/src/style/organisms/_profession-sheet.scss @@ -0,0 +1,26 @@ +.application.sheet.dsa41.item.profession { + + section.profession { + + display: flex; + flex-direction: column; + flex: 1; + + div { + flex: 0; + } + + div.editor { + flex: 1; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/_talent-sheet.scss b/src/style/organisms/_skill-sheet.scss similarity index 86% rename from src/style/_talent-sheet.scss rename to src/style/organisms/_skill-sheet.scss index 0cfc8857..805d6b62 100644 --- a/src/style/_talent-sheet.scss +++ b/src/style/organisms/_skill-sheet.scss @@ -1,6 +1,6 @@ -.sheet.item.skill { +.dsa41.sheet.item.skill { - .tab.meta.active { + .meta-details { display: grid; grid-template-areas: @@ -8,9 +8,7 @@ "taw statistics ebe" "language language language" "attack attack attack"; - - gap: 8px; - margin: 8px; + height: unset; .category { grid-area: category; @@ -44,8 +42,13 @@ grid-area: attack; display: flex; flex-direction: row; + gap: 16px; } } + .description-details { + + } + } diff --git a/src/style/organisms/_species-sheet.scss b/src/style/organisms/_species-sheet.scss new file mode 100644 index 00000000..dc0c31c6 --- /dev/null +++ b/src/style/organisms/_species-sheet.scss @@ -0,0 +1,26 @@ +.application.sheet.dsa41.item.species { + + section.species { + + display: flex; + flex-direction: column; + flex: 1; + + div { + flex: 0; + } + + div.editor { + flex: 1; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_attributes.scss b/src/style/organisms/character-tabs/_attributes.scss new file mode 100644 index 00000000..f64cafe8 --- /dev/null +++ b/src/style/organisms/character-tabs/_attributes.scss @@ -0,0 +1,80 @@ +@mixin tab { + height: 100%; + + .advantages-and-specialabilities { + + height: unset; + display: unset; + gap: 0; + padding: unset; + + .advantages, .special-abilities { + margin-bottom: 16px; + + ul { + list-style-type: none; + padding: 0; + margin: 0; + text-indent: 0; + + li { + display: inline-block; + } + + .advantage, .special-ability { + position: relative; + border: 1px solid gold; + box-shadow: 2px 2px 4px #000; + border-radius: 8px; + height: 24px; + color: gold; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); + display: inline-block; + padding: 0 8px; + margin-left: 0; + margin-bottom: 4px; + background-image: url("../../assets/velvet_button.png"); + background-repeat: repeat-y; + background-size: cover; + + span { + position: relative; + z-index: 2; + line-height: 24px; + vertical-align: middle; + } + + &.special-ability { + &::after { + background: rgba(128, 0, 96, 0.5); + } + } + + &::after { + content: ""; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + border-radius: 8px; + background: rgba(0, 128, 0, 0.5); + } + + & + .advantage, & + .special-ability { + margin-left: 8px; + } + + &.disadvantage { + font-style: italic; + + &::after { + background: rgba(128, 0, 0, 0.5); + } + } + } + } + + } + } +} diff --git a/src/style/organisms/character-tabs/_combat.scss b/src/style/organisms/character-tabs/_combat.scss new file mode 100644 index 00000000..d8c667b2 --- /dev/null +++ b/src/style/organisms/character-tabs/_combat.scss @@ -0,0 +1,229 @@ +@mixin tab { + + display: grid; + + grid-template-columns: 1fr 320px; + grid-template-rows: 32px 32px 1fr; + grid-template-areas: "res res" "wounds wounds" "actions actions"; + padding: 8px; + gap: 8px; + + div.combatline { + grid-area: res; + display: flex; + flex-direction: row; + justify-self: center; + height: unset; + padding: 0; + gap: 0 8px; + + + input { + width: 48px; + height: 32px; + } + + span, label { + line-height: 32px; + height: 32px; + vertical-align: middle; + } + + } + + .wounds { + position: relative; + height: 24px; + display: flex; + flex-direction: unset; + gap: unset; + padding: unset; + margin-bottom: 8px; + padding-left: 130px; + grid-area: wounds; + + label { + position: absolute; + left: 0; + top: 0; + line-height: 24px; + width: 120px; + bottom: 0; + vertical-align: middle; + text-align: left; + height: 24px; + display: inline-block; + z-index: 2; + } + + .filled-segment { + border: 1px solid black; + background-image: url('/systems/DSA_4-1/assets/gradient.png'); + background-size: 24px 100%; + position: relative; + flex: 1; + text-align: center; + vertical-align: middle; + line-height: 24px; + color: white; + text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); + background-color: rgba(255, 0, 0, 0.8); + background-blend-mode: multiply; + + } + + .empty-segment { + border: 1px solid black; + background-image: url('/systems/DSA_4-1/assets/gradient.png'); + background-size: 32px 100%; + position: relative; + flex: 1; + text-align: center; + vertical-align: middle; + line-height: 24px; + color: gold; + text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, 0.8); + background-blend-mode: multiply; + + } + + } + + .actions { + grid-area: actions; + padding: 0; + + .grid-of-actions { + display: unset; + } + } + + + &.zones { + grid-template-areas: "res res" "wounds wounds" "actions paperdoll"; + + .paperdoll { + grid-area: paperdoll; + + div { + position: relative; + margin-left: 9px; + margin-top: 42px; + + .wound { + position: absolute; + width: 32px; + height: 32px; + border-radius: 16px; + border: 1px solid black; + background-color: rgba(0, 0, 0, 0.5); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); + line-height: 32px; + vertical-align: middle; + text-align: center; + color: red; + + + &.armlinks { + top: 146px; + left: 210px; + } + + &.armrechts { + top: 146px; + left: 60px; + } + + &.beinlinks { + top: 346px; + left: 210px; + } + + &.beinrechts { + top: 346px; + left: 60px; + } + + &.bauch { + top: 166px; + left: 136px; + } + + &.kopf { + top: 6px; + left: 136px + } + + &.brust { + top: 86px; + left: 110px; + } + + &.ruecken { + top: 86px; + left: 160px; + } + + } + + .armor { + position: absolute; + width: 32px; + height: 32px; + border-radius: 0 0 16px 16px; + line-height: 32px; + vertical-align: middle; + text-align: center; + border: 1px solid silver; + background-color: rgba(0, 0, 0, 0.5); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); + color: silver; + + &.armlinks { + top: 180px; + left: 210px; + } + + &.armrechts { + top: 180px; + left: 60px; + } + + &.beinlinks { + top: 380px; + left: 210px; + } + + &.beinrechts { + top: 380px; + left: 60px; + } + + &.bauch { + top: 200px; + left: 136px; + } + + &.kopf { + top: 40px; + left: 136px + } + + &.ruecken { + top: 120px; + left: 160px; + } + + &.brust { + top: 120px; + left: 110px; + } + } + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_inventory.scss b/src/style/organisms/character-tabs/_inventory.scss new file mode 100644 index 00000000..62d8f8c2 --- /dev/null +++ b/src/style/organisms/character-tabs/_inventory.scss @@ -0,0 +1,59 @@ +@mixin tab { + + & > div { + display: grid; + grid-template-columns: 1fr 320px; + grid-template-rows: 74px 1fr; + gap: 10px; + height: 100%; + grid-template-areas: +"capacity capacity" +"inventory equipment"; + + .capacity { + + grid-area: capacity; + + .resource { + + position: relative; + border: 1px inset #ccc; + background-color: rgba(0, 0, 0, 0.2); + height: 8px; + + span.fill { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%); + } + + } + } + + .inventory { + grid-area: inventory; + display: flex; + flex-direction: column; + + h3 { + flex: 0; + } + + .inventory-table { + flex: 1; + + .equipment { + height: 32px; + } + } + + .equipment:hover { + .item-name { + text-shadow: 0 0 10px rgb(255 0 0); + } + } + } + } +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_liturgies.scss b/src/style/organisms/character-tabs/_liturgies.scss new file mode 100644 index 00000000..197464df --- /dev/null +++ b/src/style/organisms/character-tabs/_liturgies.scss @@ -0,0 +1,68 @@ +@mixin tab { + + + > div { + height: unset; + } + + table { + border-top: unset; + border-bottom: unset; + position: relative; + } + + .liturgy-header { + background: unset; + border: unset; + + tr { + height: 90px; + + th { + vertical-align: middle; + color: black; + text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.2); + } + } + } + + td, th { + padding-left: 8px; + } +} + +.tab-resources { + display: flex; + justify-content: center; + gap: 0 16px; + padding-bottom: 8px; + + & > div { + + + height: 32px; + position: relative; + + label { + width: 80px; + line-height: 32px; + vertical-align: middle; + } + + input { + display: inline-block; + width: 40px; + height: 32px; + } + + span.inline { + line-height: 32px; + vertical-align: middle; + width: 40px; + text-align: center; + } + + + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_meta.scss b/src/style/organisms/character-tabs/_meta.scss new file mode 100644 index 00000000..62876997 --- /dev/null +++ b/src/style/organisms/character-tabs/_meta.scss @@ -0,0 +1,64 @@ +@mixin tab { + + display: flex; + flex-direction: column; + + .meta-data { + flex: 0; + height: unset; + columns: 2; + gap: 0 16px; + + + div { + break-inside: avoid; + } + + .meta-line { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 0 8px; + padding-bottom: 8px; + } + + .double { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-areas: 'label label' 'left right'; + gap: 0 8px; + + label { + grid-area: label; + } + } + + & + .meta-data { + flex: 1; + } + } + + .meta-data.html { + height: unset; + display: flex; + flex-direction: row; + gap: 0 8px; + flex: 1; + + & > div { + flex: 1; + display: flex; + flex-direction: column; + height: 100%; + + label { + flex: 0; + } + + .editor { + flex: 1; + } + } + + } + +} diff --git a/src/style/organisms/character-tabs/_skills.scss b/src/style/organisms/character-tabs/_skills.scss new file mode 100644 index 00000000..ae8552b8 --- /dev/null +++ b/src/style/organisms/character-tabs/_skills.scss @@ -0,0 +1,41 @@ +@mixin tab { + + container: thisTab / inline-size; + + .collapsible { + + columns: 2; + column-gap: 20px; + padding: 8px; + display: block; + height: unset; + + .talent-group { + break-inside: avoid-column; + display: unset; + height: unset; + gap: unset; + padding: unset; + + } + + ul { + list-style-type: none; + padding-left: 0; + } + } + + + @container thisTab (inline-size <= 740px ) { + .collapsible { + columns: 1; + } + } + + @container thisTab (inline-size > 740px ) { + .collapsible { + columns: 2; + } + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_social.scss b/src/style/organisms/character-tabs/_social.scss new file mode 100644 index 00000000..bbfc49e7 --- /dev/null +++ b/src/style/organisms/character-tabs/_social.scss @@ -0,0 +1,38 @@ +@mixin tab { + + display: flex; + flex-direction: column; + + .social-line { + flex: 0; + height: unset; + display: grid; + grid-template-columns: 1fr 1fr 80px; + } + + .meta-data.html { + + height: unset; + display: flex; + flex-direction: row; + gap: 0 8px; + flex: 1; + + & > div { + display: flex; + flex-direction: column; + height: 100%; + flex: 1; + + label { + flex: 0; + } + + .editor { + flex: 1; + } + } + + } + +} diff --git a/src/style/organisms/character-tabs/_spells.scss b/src/style/organisms/character-tabs/_spells.scss new file mode 100644 index 00000000..433d556d --- /dev/null +++ b/src/style/organisms/character-tabs/_spells.scss @@ -0,0 +1,108 @@ +@use "sass:color"; +@use "../../atoms/numbers"; +@use "../../atoms/colours" as colour; + +@mixin tab { + tr { + height: 24px; + margin: 0; + padding: 0; + } + + td { + margin: 0; + padding: 0; + height: 24px; + } + + $color: #05f; + + .spell.rollable svg { + width: 24px; + height: 24px; + top: 1px; + z-index: 1; + position: relative; + + .border { + fill: #0000; + } + + .center { + fill: $color; + stroke: colour.$rollable-die-border-color; + } + + .topleft { + fill: color.adjust($color, $lightness: numbers.$lighter_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomleft { + fill: color.adjust($color, $lightness: numbers.$lightest_factor); + stroke: colour.$rollable-die-border-color; + } + + .topright { + fill: color.adjust($color, $lightness: numbers.$darken_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomright, .bottom { + fill: color.adjust($color, $lightness: numbers.$darkest_factor); + stroke: colour.$rollable-die-border-color; + } + } + + .die-column { + width: 24px; + } + + .clickable { + span { + position: relative; + z-index: 1; + } + } + + tbody { + + tr { + + position: relative; + + &::after { + content: ''; + background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$end_2_gradient)); + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + position: absolute; + top: 2px; + left: 12px; + bottom: 2px; + right: 33%; + z-index: 0; + pointer-events: none; + } + + &:nth-child(odd) { + &::after { + background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$end_2_gradient)); + } + } + } + + } + + .merkmal-list { + list-style: none; + margin: 0; + padding: 0; + text-indent: 0; + + li { + display: inline-block; + padding: 0 4px; + } + } +} \ No newline at end of file diff --git a/src/style/styles.scss b/src/style/styles.scss index e30542c1..32e2a996 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -1,16 +1,26 @@ -@use "_rollable"; -@use "_lists"; -@use "_attributes"; -@use "_sidebar-elements"; -@use "_character-sheet"; -@use "_group-sheet"; -@use "_tabs"; -@use "_equipment-sheet"; -@use "_paperdoll"; -@use "_creature-sheet"; -@use "_player-action"; -@use "_modify-liturgy"; -@use "_liturgy-banner"; -@use "_talent-sheet"; -@use "_active-effect-sheet"; -@use "_advantage-sheet"; +@use "atoms/fonts"; +@use "atoms/typography"; +@use "atoms/svg"; +@use "molecules/pill"; +@use "molecules/rollable"; +@use "molecules/lists"; +@use "molecules/attributes"; +@use "molecules/sidebar-elements"; + +@use "molecules/tabs"; +@use "molecules/paperdoll"; +@use "molecules/player-action"; +@use "molecules/liturgy-banner"; +@use "molecules/richtext-editor"; +@use "organisms/character-sheet"; +@use "organisms/group-sheet"; +@use "organisms/equipment-sheet"; +@use "organisms/creature-sheet"; +@use "organisms/modify-liturgy"; +@use "organisms/skill-sheet"; +@use "organisms/active-effect-sheet"; +@use "organisms/advantage-sheet"; +@use "organisms/culture-sheet"; +@use "organisms/species-sheet"; +@use "organisms/profession-sheet"; + diff --git a/src/system.json b/src/system.json index 64166527..378e2ba9 100644 --- a/src/system.json +++ b/src/system.json @@ -92,6 +92,30 @@ "type": "Item", "path": "packs/wunden", "private": false + }, + { + "name": "Professions", + "label": "Professionen", + "system": "DSA_4-1", + "type": "Item", + "path": "packs/professionen", + "private": false + }, + { + "name": "Species", + "label": "Rassen", + "system": "DSA_4-1", + "type": "Item", + "path": "packs/spezien", + "private": false + }, + { + "name": "Cultures", + "label": "Kulturen", + "system": "DSA_4-1", + "type": "Item", + "path": "packs/kulturen", + "private": false } ], "languages": [ @@ -127,6 +151,27 @@ } }, "Item": { + "Culture": { + "htmlFields": [ + "description" + ] + }, + "Species": { + "htmlFields": [ + "description" + ], + "numberFields": [ + "baseSpeed" + ] + }, + "Profession": { + "htmlFields": [ + "description" + ], + "booleanFields": [ + "revealed" + ] + }, "Equipment": { "stringFields": [ "name", diff --git a/src/templates/actor/actor-character-sheet.hbs b/src/templates/actor/actor-character-sheet.hbs deleted file mode 100644 index f499c11b..00000000 --- a/src/templates/actor/actor-character-sheet.hbs +++ /dev/null @@ -1,814 +0,0 @@ -
- - {{!-- Sheet Header --}} -
- {{!-- Header stuff goes here --}} -
-
- {{#each attributes}} - {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} - {{/each}} -
-
-
- -
-

- - - - - - {{#if ausdauer}} - - {{/if}} - - {{#if this.hasLiturgies}} - - {{/if}} - - {{#if this.hasSpells}} - - {{/if}} - - {{#each attacks}} -
-

{{this.using}} ({{this.name}})

-
- {{#if this.at}} - - {{/if}} - {{#if this.pa}} - - {{/if}} -
- {{#if this.at}} - - {{/if}} - {{#if this.ini}} - - {{/if}} -
- {{/each}} - - - -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
- - - - -
-
-
-
- - -
- {{#each this.mods.mu}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.kl}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.in}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ch}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ff}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ge}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ko}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.kk}} - {{this.value}} - {{/each}} -
- -
-
- - -
-
- - -
- {{#each this.mods.at}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.pa}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.fk}} - {{this.value}} - {{/each}} -
-
-
-
-
- - - -
- {{#if ausdauer}} -
- - - -
- {{/if}} - {{#if hasSpells}} -
- - - -
- {{/if}} - {{#if hasLiturgies}} -
- - - -
- {{/if}} -
-
-

Vor- und Nachteile

-
    - {{#each this.advantages}} -
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • - {{/each}} -
-
-
-

Sonderfertigkeiten

-
    - {{#each this.specialAbilities}} -
  • {{> "systems/DSA_4-1/templates/ui/partial-sf-button.hbs" this}}
  • - {{/each}} -
-
-
- -
- -
- -
- - - w6 - -
-
- - - von - -
- {{#if ausdauer}} -
- - - von - -
- {{/if}} - {{#if (not zonenruestung)}} -
- - {{derived.rs}} -
- {{/if}} -
- - {{derived.be}} -
- - -
- {{#if (not trefferzonen)}} -
- - {{#each this.woundsFilled}} - {{#if this}} -
{{@index}}
- {{else}} -
{{@index}}
- {{/if}} - {{/each}} -
- {{/if}} - - -
-

Aktionen im Kampf

- {{#each this.actions}} - {{> "systems/DSA_4-1/templates/ui/partial-action-button.hbs" this}} - {{/each}} -
- - {{#if (or trefferzonen zonenruestung)}} -
-

{{#if (and trefferzonen zonenruestung)}}Trefferzonen{{/if}}{{#if - (and trefferzonen (not zonenruestung))}}Wunden{{/if}}{{#if - (and (not trefferzonen) zonenruestung)}}Rüstung{{/if}}

-
- - - - {{#if trefferzonen}} - {{derived.wunden.kopf}} - {{derived.wunden.brust}} - {{derived.wunden.armlinks}} - {{derived.wunden.armrechts}} - {{derived.wunden.bauch}} - {{derived.wunden.beinlinks}} - {{derived.wunden.beinrechts}} - {{/if}} - {{#if zonenruestung}} - {{derived.rs.kopf}} - {{derived.rs.brust}} - {{derived.rs.armlinks}} - {{derived.rs.armrechts}} - {{derived.rs.bauch}} - {{derived.rs.beinlinks}} - {{derived.rs.beinrechts}} - {{/if}} -
-
- {{/if}} - -
-
-
-

Kampftalente

-
    - {{#each skills.Kampf}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Körperliche Talente

-
    -
  • - {{#each skills.Körperlich}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Gesellschaftliche Talente

-
    -
  • - {{#each skills.Gesellschaft}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Natur Talente

-
    -
  • - {{#each skills.Natur}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Wissenstalente

-
    -
  • - {{#each skills.Wissen}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Schriften & Sprachen

-
    -
  • - {{#each skills.Schriften}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} -
  • - {{/each}} - {{#each skills.Sprachen}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Handwerkliche Talente

-
    -
  • - {{#each skills.Handwerk}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
- -
-
- -
- -
- -
-
- - -
-

Inventar

- - {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" equipments}} - -
- -
-

Ausrüstung

- {{!-- Set Tab Navigation --}} - - {{!-- Set Body --}} -
- {{#each this.sets}} -
- -
- - - - - {{#each this.slots}} -
- {{/each}} - {{#if (eq ../actor.system.setEquipped @index)}} - - {{else}} - - {{/if}} - -
-
- {{/each}} - -
-
- -
- {{#if this.hasSpells}} -
- -
- -
- - - von - -
-
- - -
-
- - - - - - - - - - - - - {{#each this.spells}} - - - - - - - - - - {{/each}} - -
ZaubernameProbeZfWMerkmale
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - - {{this.name}}{{this.eigenschaft1}}{{this.eigenschaft2}}{{this.eigenschaft3}}{{this.zfw}} -
    {{#each this.merkmal}} -
  • {{this}}
  • {{/each}}
-
- -
- {{/if}} - {{#if this.hasLiturgies}} -
- -
- -
- - - von - -
-
- - {{#each this.liturgies}} - - - - - - - - - - {{#if this.countO}} - - - - - {{#each this.O}} - - - - - - {{/each}} - {{/if}} - {{#if this.countI}} - - - - {{#each this.I}} - - - - - - {{/each}} - {{/if}} - {{#if this.countII}} - - - - {{#each this.II}} - - - - - {{/each}} - {{/if}} - {{#if this.countIII}} - - - - {{#each this.III}} - - - - - {{/each}} - {{/if}} - {{#if this.countIV}} - - - - {{#each this.IV}} - - - - - {{/each}}{{/if}} - {{#if this.countV}} - - - - {{#each this.V}} - - - - - {{/each}} - {{/if}} - {{#if this.countVI}} - - - - {{#each this.VI}} - - - - - {{/each}} - {{/if}}{{#if this.countVII}} - - - - {{#each this.VII}} - - - - - {{/each}} - {{/if}}{{#if this.countVIII}} - - - - {{#each this.VIII}} - - - - - {{/each}} - {{/if}} - -
Liturgiekenntnis: {{this.lkp}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{/each}} - -
- {{/if}} - -
- - - - - - - - {{#each this.effects}} - - - - - - {{/each}} - -
EffektVeränderungen
- {{this.name}} - {{this.conditions}}{{#if ../isGM}} - {{/if}}
-
- -
-
diff --git a/src/templates/actor/actor-creature-sheet.hbs b/src/templates/actor/actor-creature-sheet.hbs deleted file mode 100644 index 221b9a79..00000000 --- a/src/templates/actor/actor-creature-sheet.hbs +++ /dev/null @@ -1,137 +0,0 @@ -
- - {{!-- Sheet Header --}} -
- {{!-- Header stuff goes here --}} - - - - -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
-
- - -
-
- - -
-
- - - -
-
- -
- - w6 + -
- - -
-
-
-
- - - - - - - - - - - - - {{#each this.attacks}} - - - - - - - - {{/each}} - - - - - - - - - - - - - - - - -
NameAttackeParadeSchaden
- - -
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} -
- -
-
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} -
- -
-
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} -
- -
- -
Attacke hinzufügen
- - - - - - - - - - -
- -
-
- {{editor system.description target="system.description" button=true owner=owner editable=editable}} - -
-
-
diff --git a/src/templates/actor/character/main-sheet.hbs b/src/templates/actor/character/main-sheet.hbs new file mode 100644 index 00000000..ec7e1e6a --- /dev/null +++ b/src/templates/actor/character/main-sheet.hbs @@ -0,0 +1,99 @@ +
+ + {{!-- Sheet Header --}} +
+ {{!-- Header stuff goes here --}} + +
+
+ +
+ {{spezies}} + {{kultur}} + {{#each professions}} + {{this.name}} + {{/each}} +
+
+
+ {{#each attributes}} + {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} + {{/each}} +
+
+
+ +
+ + + + + + {{#if ausdauer}} + + {{/if}} + + {{#if this.hasLiturgies}} + + {{/if}} + + {{#if this.hasSpells}} + + {{/if}} + + {{#each attacks}} +
+

{{this.using}} ({{this.name}})

+
+ {{#if this.at}} + + {{/if}} + {{#if this.pa}} + + {{/if}} +
+ {{#if this.at}} + + {{/if}} + {{#if this.ini}} + + {{/if}} +
+ {{/each}} + +
+ + {{!-- Sheet Tab Navigation --}} + + +
diff --git a/src/templates/actor/character/tab-advsf.hbs b/src/templates/actor/character/tab-advsf.hbs new file mode 100644 index 00000000..346a6ba4 --- /dev/null +++ b/src/templates/actor/character/tab-advsf.hbs @@ -0,0 +1,22 @@ +
+
+
+

Vor- und Nachteile

+
    + {{#each this.advantages}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • + {{/each}} +
+
+
+

Sonderfertigkeiten

+
    + {{#each this.specialAbilities}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-sf-button.hbs" this}}
  • + {{/each}} +
+
+
+
diff --git a/src/templates/actor/character/tab-combat.hbs b/src/templates/actor/character/tab-combat.hbs new file mode 100644 index 00000000..1dbe9569 --- /dev/null +++ b/src/templates/actor/character/tab-combat.hbs @@ -0,0 +1,102 @@ +
+ +
+ +
+ + + w6 + +
+
+ + + von + +
+ {{#if ausdauer}} +
+ + + von + +
+ {{/if}} + {{#if (not zonenruestung)}} +
+ + {{derived.rs}} +
+ {{/if}} +
+ + {{derived.be}} +
+ + +
+ {{#if (not trefferzonen)}} +
+ + {{#each this.woundsFilled}} + {{#if this}} +
{{@index}}
+ {{else}} +
{{@index}}
+ {{/if}} + {{/each}} +
+ {{/if}} + + +
+

Aktionen im Kampf

+
+ {{#each this.actions}} + {{> "systems/DSA_4-1/templates/ui/partial-action-button.hbs" this}} + {{/each}} +
+
+ + {{#if (or trefferzonen zonenruestung)}} +
+

{{#if (and trefferzonen zonenruestung)}}Trefferzonen{{/if}}{{#if + (and trefferzonen (not zonenruestung))}}Wunden{{/if}}{{#if + (and (not trefferzonen) zonenruestung)}}Rüstung{{/if}}

+
+ + + + {{#if trefferzonen}} + {{derived.wunden.kopf}} + {{derived.wunden.brust}} + {{derived.wunden.armlinks}} + {{derived.wunden.armrechts}} + {{derived.wunden.ruecken}} + {{derived.wunden.bauch}} + {{derived.wunden.beinlinks}} + {{derived.wunden.beinrechts}} + {{/if}} + {{#if zonenruestung}} + {{derived.rs.kopf}} + {{derived.rs.brust}} + {{derived.rs.armlinks}} + {{derived.rs.armrechts}} + {{derived.rs.ruecken}} + {{derived.rs.bauch}} + {{derived.rs.beinlinks}} + {{derived.rs.beinrechts}} + {{/if}} +
+
+ {{/if}} + +
diff --git a/src/templates/actor/character/tab-effects.hbs b/src/templates/actor/character/tab-effects.hbs new file mode 100644 index 00000000..b131f219 --- /dev/null +++ b/src/templates/actor/character/tab-effects.hbs @@ -0,0 +1,28 @@ +
+ + + + + + + + + + + {{#each this.effects}} + + + + + + {{/each}} + +
EffektVeränderungen
+ {{this.name}} + {{this.conditions}}{{#if ../isGM}} + {{/if}}
+ +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-equipment.hbs b/src/templates/actor/character/tab-equipment.hbs new file mode 100644 index 00000000..8b6a83e4 --- /dev/null +++ b/src/templates/actor/character/tab-equipment.hbs @@ -0,0 +1,40 @@ +
+
+
+ +
+ +
+
+ + +
+

Inventar

+ + {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" equipments}} + +
+ +
+
\ No newline at end of file diff --git a/src/templates/actor/character/tab-liturgies.hbs b/src/templates/actor/character/tab-liturgies.hbs new file mode 100644 index 00000000..6bc342d8 --- /dev/null +++ b/src/templates/actor/character/tab-liturgies.hbs @@ -0,0 +1,200 @@ +
+
+
+ +
+ + + von + +
+
+ + {{#each this.liturgies}} + + + + + + + + + + + + + + {{#each this.O}} + + + + + + {{/each}} + {{#if this.countI}} + + + + {{#each this.I}} + + + + + + {{/each}} + {{/if}} + {{#if this.countII}} + + + + {{#each this.II}} + + + + + {{/each}} + {{/if}} + {{#if this.countIII}} + + + + {{#each this.III}} + + + + + {{/each}} + {{/if}} + {{#if this.countIV}} + + + + {{#each this.IV}} + + + + + {{/each}}{{/if}} + {{#if this.countV}} + + + + {{#each this.V}} + + + + + {{/each}} + {{/if}} + {{#if this.countVI}} + + + + {{#each this.VI}} + + + + + {{/each}} + {{/if}}{{#if this.countVII}} + + + + {{#each this.VII}} + + + + + {{/each}} + {{/if}}{{#if this.countVIII}} + + + + {{#each this.VIII}} + + + + + {{/each}} + {{/if}} + +
Liturgiekenntnis: {{this.lkp}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{/each}} +
+ +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-meta.hbs b/src/templates/actor/character/tab-meta.hbs new file mode 100644 index 00000000..71fa322e --- /dev/null +++ b/src/templates/actor/character/tab-meta.hbs @@ -0,0 +1,47 @@ +
+ + + +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-set.hbs b/src/templates/actor/character/tab-set.hbs new file mode 100644 index 00000000..43b5bb2c --- /dev/null +++ b/src/templates/actor/character/tab-set.hbs @@ -0,0 +1,29 @@ +
+ + +
+ + + + + {{#each this.slots}} +
+ {{/each}} + {{#if (eq ../actor.system.setEquipped @index)}} + + {{else}} + + {{/if}} + +
+ +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-skills.hbs b/src/templates/actor/character/tab-skills.hbs new file mode 100644 index 00000000..26c619c2 --- /dev/null +++ b/src/templates/actor/character/tab-skills.hbs @@ -0,0 +1,87 @@ +
+
+
+

Kampftalente

+
    + {{#each skills.Kampf}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Körperliche Talente

+
    +
  • + {{#each skills.Körperlich}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Gesellschaftliche Talente

+
    +
  • + {{#each skills.Gesellschaft}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Natur Talente

+
    +
  • + {{#each skills.Natur}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Wissenstalente

+
    +
  • + {{#each skills.Wissen}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Schriften & Sprachen

+
    +
  • + {{#each skills.Schriften}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} +
  • + {{/each}} + {{#each skills.Sprachen}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Handwerkliche Talente

+
    +
  • + {{#each skills.Handwerk}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+
\ No newline at end of file diff --git a/src/templates/actor/character/tab-social.hbs b/src/templates/actor/character/tab-social.hbs new file mode 100644 index 00000000..d4a5256c --- /dev/null +++ b/src/templates/actor/character/tab-social.hbs @@ -0,0 +1,40 @@ +
+ + + +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-spells.hbs b/src/templates/actor/character/tab-spells.hbs new file mode 100644 index 00000000..b8ea3278 --- /dev/null +++ b/src/templates/actor/character/tab-spells.hbs @@ -0,0 +1,49 @@ +
+ +
+ +
+ + + von + +
+
+ + +
+
+ + + + + + + + + + + + + {{#each this.spells}} + + + + + + + + + + {{/each}} + +
ZaubernameProbeZfWMerkmale
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + + {{this.name}}{{this.eigenschaft1}}{{this.eigenschaft2}}{{this.eigenschaft3}}{{this.zfw}} +
    {{#each this.merkmal}} +
  • {{this}}
  • {{/each}}
+
+
\ No newline at end of file diff --git a/src/templates/actor/creature/main-sheet.hbs b/src/templates/actor/creature/main-sheet.hbs new file mode 100644 index 00000000..a59c040d --- /dev/null +++ b/src/templates/actor/creature/main-sheet.hbs @@ -0,0 +1,22 @@ +
+
+ {{!-- Header stuff goes here --}} + + {{actor.name}} + + +
+ + +
\ No newline at end of file diff --git a/src/templates/actor/creature/tab-attacks.hbs b/src/templates/actor/creature/tab-attacks.hbs new file mode 100644 index 00000000..b1020e5a --- /dev/null +++ b/src/templates/actor/creature/tab-attacks.hbs @@ -0,0 +1,83 @@ +
+ + + + + + + + + + + + {{#each this.attacks}} + + + + + + + + {{/each}} + + + + + + + + + + + + + + + + +
NameAttackeParadeSchaden
+ + +
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} +
+ +
+
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} +
+ +
+
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} +
+ +
+ +
Attacke hinzufügen
+ + + + + + + + + + +
+
\ No newline at end of file diff --git a/src/templates/actor/creature/tab-description.hbs b/src/templates/actor/creature/tab-description.hbs new file mode 100644 index 00000000..7d97f68c --- /dev/null +++ b/src/templates/actor/creature/tab-description.hbs @@ -0,0 +1,12 @@ +
+ + {{{system.description}}} + +
\ No newline at end of file diff --git a/src/templates/actor/creature/tab-meta.hbs b/src/templates/actor/creature/tab-meta.hbs new file mode 100644 index 00000000..8434981b --- /dev/null +++ b/src/templates/actor/creature/tab-meta.hbs @@ -0,0 +1,33 @@ +
+
+
+ + +
+
+ + +
+
+ + + +
+
+ +
+ + w6 + +
+ + +
+
+
\ No newline at end of file diff --git a/src/templates/actor/group-sheet.hbs b/src/templates/actor/group-sheet.hbs deleted file mode 100644 index 776e34e7..00000000 --- a/src/templates/actor/group-sheet.hbs +++ /dev/null @@ -1,121 +0,0 @@ -
- - {{!-- Sheet Header --}} -
- - - -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
- {{#unless isGM}} -
- {{#each characters}} - {{#if this.isVisible}} -
-
- {{this.name}} - {{this.name}} -
-
- {{/if}} - {{/each}} -
- {{else}} -
- - - - - {{#each this.fields.head}} - - {{/each}} - - - - {{#each this.fields}} - {{#unless (eq @key "head")}} - - - - {{#each this}} - - {{/each}} - - - {{/unless}} - {{/each}} - -
-
-
- {{this.name}} - {{this.name}} -
- {{#if this.isLimited}} -
- {{#each this.attributes}} -
- {{this.value}} - {{this.name}} -
- {{/each}} -
- {{/if}} -
-
- {{ @key}} - - {{#if (eq this "-")}} - - {{else}} - {{#if this.taw}} -
- {{this.taw}} ({{this.eigenschaft1}}, {{this.eigenschaft2}} - , {{this.eigenschaft3}}) -
- {{else}} - Ja - {{/if}} - {{/if}} -
-
- {{/unless}} -
-
- {{> 'systems/DSA_4-1/templates/ui/partial-equipment-group-button.hbs' equipments}} -
- {{#if owner}} -
- {{#each settings}} -
- -
- {{/each}} -
- {{/if}} - -
- -
diff --git a/src/templates/actor/group/main-sheet.hbs b/src/templates/actor/group/main-sheet.hbs new file mode 100644 index 00000000..38ccb4bf --- /dev/null +++ b/src/templates/actor/group/main-sheet.hbs @@ -0,0 +1,22 @@ +
+
+ + {{name}} + + +
+ + {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/actor/group/tab-inventory.hbs b/src/templates/actor/group/tab-inventory.hbs new file mode 100644 index 00000000..e3a6eae2 --- /dev/null +++ b/src/templates/actor/group/tab-inventory.hbs @@ -0,0 +1,7 @@ +
+ + {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" inventoryItems}} + +
diff --git a/src/templates/actor/group/tab-members.hbs b/src/templates/actor/group/tab-members.hbs new file mode 100644 index 00000000..a89491c3 --- /dev/null +++ b/src/templates/actor/group/tab-members.hbs @@ -0,0 +1,81 @@ +
+ {{#unless isGM}} +
+ {{#each this.characters}} + {{#if this.isVisible}} +
+
+ {{this.name}} + {{this.name}} +
+
+ {{/if}} + {{/each}} +
+ {{else}} +
+ + + + + {{#each this.fields.head}} + + {{/each}} + + + + {{#each this.fields}} + {{#unless (eq @key "head")}} + + + + {{#each this}} + + {{/each}} + + + {{/unless}} + {{/each}} + +
+
+
+ {{this.name}} + {{this.name}} +
+ {{#if this.isLimited}} +
+ {{#each this.attributes}} +
+ {{this.value}} + {{this.name}} +
+ {{/each}} +
+ {{/if}} +
+
+ {{ @key}} + + {{#if (eq this "-")}} + + {{else}} + {{#if (lt this.taw 0)}} +
+ {{this.taw}} +
+ {{else}} + Ja + {{/if}} + {{/if}} +
+
+ {{/unless}} +
\ No newline at end of file diff --git a/src/templates/actor/group/tab-settings.hbs b/src/templates/actor/group/tab-settings.hbs new file mode 100644 index 00000000..d87adfa5 --- /dev/null +++ b/src/templates/actor/group/tab-settings.hbs @@ -0,0 +1,12 @@ +
+ +
    + {{#each system.settings}} +
    + +
    + {{/each}} +
+
\ No newline at end of file diff --git a/src/templates/item/activeeffect/main-sheet.hbs b/src/templates/item/activeeffect/main-sheet.hbs new file mode 100644 index 00000000..ce7a83a5 --- /dev/null +++ b/src/templates/item/activeeffect/main-sheet.hbs @@ -0,0 +1,24 @@ +
+ +
+ {{name}} + + + +
+ +
+ + + {{{notes}}} + +
+ +
diff --git a/src/templates/item/advantage/main-sheet.hbs b/src/templates/item/advantage/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/advantage/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/advantage/tab-advantage.hbs b/src/templates/item/advantage/tab-advantage.hbs new file mode 100644 index 00000000..2b11c313 --- /dev/null +++ b/src/templates/item/advantage/tab-advantage.hbs @@ -0,0 +1,33 @@ +
+
+ + + +
+ {{#if hasModality}} +
+ + {{#if hasChoices}} + + {{else}} + + {{/if}} +
+ {{/if}} +
+ + + {{{ system.description}}} + +
+ +
\ No newline at end of file diff --git a/src/templates/item/culture-sheet.hbs b/src/templates/item/culture-sheet.hbs new file mode 100644 index 00000000..b3b864ea --- /dev/null +++ b/src/templates/item/culture-sheet.hbs @@ -0,0 +1,21 @@ +
+
+ + +
+
+ + +
+
+ + + {{{description}}} + +
+
\ No newline at end of file diff --git a/src/templates/item/equipment/main-sheet.hbs b/src/templates/item/equipment/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/equipment/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-ammunition.hbs b/src/templates/item/equipment/tab-ammunition.hbs new file mode 100644 index 00000000..bc18aed5 --- /dev/null +++ b/src/templates/item/equipment/tab-ammunition.hbs @@ -0,0 +1,15 @@ +
+
+
+ + +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-armor.hbs b/src/templates/item/equipment/tab-armor.hbs new file mode 100644 index 00000000..69f49f1f --- /dev/null +++ b/src/templates/item/equipment/tab-armor.hbs @@ -0,0 +1,84 @@ +
+
+ +
+ Rüstungswerte + +
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-melee.hbs b/src/templates/item/equipment/tab-melee.hbs new file mode 100644 index 00000000..fcd7a83d --- /dev/null +++ b/src/templates/item/equipment/tab-melee.hbs @@ -0,0 +1,43 @@ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-meta.hbs b/src/templates/item/equipment/tab-meta.hbs new file mode 100644 index 00000000..8bbcf645 --- /dev/null +++ b/src/templates/item/equipment/tab-meta.hbs @@ -0,0 +1,38 @@ +
+
+
+ {{name}} + +
+
+ +
+ {{!-- categories are now in their on tab --}} +
+ + + {{{system.description}}} + +
+
+ + +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-ranged.hbs b/src/templates/item/equipment/tab-ranged.hbs new file mode 100644 index 00000000..4eb4f520 --- /dev/null +++ b/src/templates/item/equipment/tab-ranged.hbs @@ -0,0 +1,32 @@ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-settings.hbs b/src/templates/item/equipment/tab-settings.hbs new file mode 100644 index 00000000..044a0a40 --- /dev/null +++ b/src/templates/item/equipment/tab-settings.hbs @@ -0,0 +1,25 @@ +
+
+
+ Art des Gegenstands + + + + +
+
+
\ No newline at end of file diff --git a/src/templates/item/item-activeeffect-sheet.hbs b/src/templates/item/item-activeeffect-sheet.hbs deleted file mode 100644 index e7c02a70..00000000 --- a/src/templates/item/item-activeeffect-sheet.hbs +++ /dev/null @@ -1,20 +0,0 @@ -
-
- -
- - - - -
- -
- - {{editor item.system.notes target="system.notes" button=true owner=owner editable=editable}} -
- - -
-
diff --git a/src/templates/item/item-advantage-sheet.hbs b/src/templates/item/item-advantage-sheet.hbs deleted file mode 100644 index cf02f991..00000000 --- a/src/templates/item/item-advantage-sheet.hbs +++ /dev/null @@ -1,35 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
-
- - - -
- {{#if hasModality}} -
- - {{#if hasChoices}} - - {{else}} - - {{/if}} -
- {{/if}} -
- - {{editor system.description target="system.description" button=true owner=owner editable=editable}} -
- -
-
-
diff --git a/src/templates/item/item-equipment-sheet.hbs b/src/templates/item/item-equipment-sheet.hbs deleted file mode 100644 index c8334090..00000000 --- a/src/templates/item/item-equipment-sheet.hbs +++ /dev/null @@ -1,164 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
- - -
-
- -
-
-
- - {{editor system.description target="system.description" button=true owner=owner editable=editable}} -
-
- - -
-
- - {{#if isMeleeWeapon}} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {{/if}} - {{#if isRangedWeapon}} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {{/if}} - {{#if isContainer}} -
- Behälter Specs -
- {{/if}} - {{#if isArmor}} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {{/if}} -
-
diff --git a/src/templates/item/item-liturgy-sheet.hbs b/src/templates/item/item-liturgy-sheet.hbs deleted file mode 100644 index d50d00ce..00000000 --- a/src/templates/item/item-liturgy-sheet.hbs +++ /dev/null @@ -1,14 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
-
{{json}}
-
-
-
diff --git a/src/templates/item/item-skill-sheet.hbs b/src/templates/item/item-skill-sheet.hbs deleted file mode 100644 index 72ad0f8a..00000000 --- a/src/templates/item/item-skill-sheet.hbs +++ /dev/null @@ -1,97 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
- -
-
- -
- {{#if isTalent}} -
- -
- -
-
-
- -
-
- {{/if}} -
- -
- {{#if isLanguage}} -
- -
- {{/if}} - {{#if isCombat}} -
-
- -
-
- -
-
- {{/if}} - -
-
-
- - {{editor system.talent target="system.talent" button=true owner=owner editable=editable}} -
- {{#if hasRequirement}} -
- -
    - {{#each system.voraussetzung}} -
  • - - -
  • - {{/each}} -
-
- {{/if}} -
- - -
-
diff --git a/src/templates/item/item-spell-sheet.hbs b/src/templates/item/item-spell-sheet.hbs deleted file mode 100644 index f2471a68..00000000 --- a/src/templates/item/item-spell-sheet.hbs +++ /dev/null @@ -1,98 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
- -
-
- -
-
-
- -
-
- -
-
- -
-
- -
- -
-
-
- -
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
diff --git a/src/templates/item/liturgy/main-sheet.hbs b/src/templates/item/liturgy/main-sheet.hbs new file mode 100644 index 00000000..38015a2f --- /dev/null +++ b/src/templates/item/liturgy/main-sheet.hbs @@ -0,0 +1,4 @@ +
+ + Alveranische Baustelle, bitte gehen Sie weiter, hier gibt es nichts zu sehen. +
\ No newline at end of file diff --git a/src/templates/item/liturgy/tab-json.hbs b/src/templates/item/liturgy/tab-json.hbs new file mode 100644 index 00000000..a4db94c6 --- /dev/null +++ b/src/templates/item/liturgy/tab-json.hbs @@ -0,0 +1,8 @@ +
+ +
{{json}}
+ +
+ diff --git a/src/templates/item/profession-sheet.hbs b/src/templates/item/profession-sheet.hbs new file mode 100644 index 00000000..dabd4e73 --- /dev/null +++ b/src/templates/item/profession-sheet.hbs @@ -0,0 +1,21 @@ +
+
+ + + {{#if isOwner}} + {{/if}} + +
+
+ + + {{{system.description}}} + +
+
\ No newline at end of file diff --git a/src/templates/item/skill/main-sheet.hbs b/src/templates/item/skill/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/skill/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/skill/tab-description.hbs b/src/templates/item/skill/tab-description.hbs new file mode 100644 index 00000000..321866d1 --- /dev/null +++ b/src/templates/item/skill/tab-description.hbs @@ -0,0 +1,30 @@ +{{!-- Individual Tab Template --}} +
+ {{!-- Tab content here --}} +
+ + {{{system.talent}}} + + + {{#if hasRequirement}} +
+ +
    + {{#each system.voraussetzung}} +
  • + + +
  • + {{/each}} +
+
+ {{/if}} +
+
diff --git a/src/templates/item/skill/tab-meta.hbs b/src/templates/item/skill/tab-meta.hbs new file mode 100644 index 00000000..ebc0cf24 --- /dev/null +++ b/src/templates/item/skill/tab-meta.hbs @@ -0,0 +1,68 @@ +{{!-- Individual Tab Template --}} +
+ {{!-- Tab content here --}} +
+
+ +
+
+ +
+ {{#if isTalent}} +
+ +
+ +
+
+
+ +
+
+ {{/if}} +
+ +
+ {{#if isLanguage}} +
+ +
+ {{/if}} + {{#if isCombat}} +
+
+ +
+
+ +
+
+ {{/if}} +
+
\ No newline at end of file diff --git a/src/templates/item/specialability/main-sheet.hbs b/src/templates/item/specialability/main-sheet.hbs new file mode 100644 index 00000000..fb0530ff --- /dev/null +++ b/src/templates/item/specialability/main-sheet.hbs @@ -0,0 +1,4 @@ +
+ + Sonderfertigkeiten bitte sei Besonders und Fertig +
\ No newline at end of file diff --git a/src/templates/item/specialability/tab-json.hbs b/src/templates/item/specialability/tab-json.hbs new file mode 100644 index 00000000..d9c5d89c --- /dev/null +++ b/src/templates/item/specialability/tab-json.hbs @@ -0,0 +1,8 @@ +
+ +
{{json}}
+ +
+ diff --git a/src/templates/item/species-sheet.hbs b/src/templates/item/species-sheet.hbs new file mode 100644 index 00000000..7f45c5d9 --- /dev/null +++ b/src/templates/item/species-sheet.hbs @@ -0,0 +1,25 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + {{{description}}} + +
+
\ No newline at end of file diff --git a/src/templates/item/spell/main-sheet.hbs b/src/templates/item/spell/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/spell/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/spell/tab-commonality.hbs b/src/templates/item/spell/tab-commonality.hbs new file mode 100644 index 00000000..351998d0 --- /dev/null +++ b/src/templates/item/spell/tab-commonality.hbs @@ -0,0 +1,21 @@ +
+ +
+ +
+
+ +
+
+ +
+ +
\ No newline at end of file diff --git a/src/templates/item/spell/tab-meta.hbs b/src/templates/item/spell/tab-meta.hbs new file mode 100644 index 00000000..7dc4079b --- /dev/null +++ b/src/templates/item/spell/tab-meta.hbs @@ -0,0 +1,48 @@ +
+ +
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
\ No newline at end of file diff --git a/src/templates/item/spell/tab-variants.hbs b/src/templates/item/spell/tab-variants.hbs new file mode 100644 index 00000000..334d3786 --- /dev/null +++ b/src/templates/item/spell/tab-variants.hbs @@ -0,0 +1,26 @@ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+ +
\ No newline at end of file diff --git a/src/templates/ui/partial-attribute-button.hbs b/src/templates/ui/partial-attribute-button.hbs index ae542d07..2fce6caa 100644 --- a/src/templates/ui/partial-attribute-button.hbs +++ b/src/templates/ui/partial-attribute-button.hbs @@ -1,4 +1,5 @@ -
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} diff --git a/src/templates/ui/partial-die.hbs b/src/templates/ui/partial-die.hbs index dfb408fc..8b86f709 100644 --- a/src/templates/ui/partial-die.hbs +++ b/src/templates/ui/partial-die.hbs @@ -1,43 +1,8 @@ - - + + + - - - - - - + fill="#000000" + d="m 379.93,375.668 c -0.57,0.019 -1.226,0.228 -1.585,0.731 l -80.673,96.527 c -1.342,1.681 -1.433,2.056 0.366,2.073 l 161.59,-0.427 c 2.221,-0.182 2.23,-0.07 0.792,-1.951 l -79.27,-96.527 c -0.164,-0.254 -0.649,-0.44 -1.22,-0.426 z m 15.489,8.598 72.746,88.478 c 0.974,1.182 1.212,1.249 2.927,0.427 l 38.354,-17.562 c 2.513,-1.134 2.165,-1.366 0.487,-2.5 z m -33.965,3.232 c -0.034,-0.072 -0.625,0.37 -1.952,1.281 l -105.612,69.513 33.05,15.001 c 1.724,0.568 2.239,0.599 3.354,-0.793 l 69.698,-83.234 c 0.981,-1.137 1.495,-1.696 1.462,-1.768 z m 153.602,72.258 c -0.328,0.023 -0.846,0.212 -1.646,0.548 l -39.392,17.989 c -1.398,0.635 -1.311,1.49 -0.792,2.561 l 45.793,116.162 -3.292,-135.309 c -0.101,-1.479 -0.123,-1.99 -0.671,-1.951 z m -264.154,3.598 -4.208,131.651 38.782,-113.907 c 0.573,-1.682 0.559,-1.767 -0.61,-2.317 z m 210.859,17.073 -165.249,0.427 c -2.361,-0.035 -2.264,-0.033 -1.098,1.89 l 83.905,141.529 c 1.417,2.159 1.265,2.092 2.744,-0.121 L 462.675,482.38 c 0.708,-1.127 1.212,-1.914 -0.914,-1.953 z m 6.586,3.72 c -0.152,0.064 -0.318,0.639 -0.793,1.524 l -81.16,142.809 c -0.887,1.508 -1.097,2.048 1.036,1.708 l 128.845,-17.744 c 2.044,-0.467 1.982,-1.197 1.281,-3.232 l -48.6,-123.479 c -0.321,-1.183 -0.456,-1.65 -0.609,-1.586 z m -178.176,1.342 c -0.158,0.113 -0.3,0.715 -0.609,1.585 l -41.16,121.162 c -0.701,2.573 -0.78,3.541 1.829,4.024 l 123.113,17.805 c 2.328,0.351 2.03,-0.822 1.463,-1.951 L 291.024,486.769 c -0.526,-1.067 -0.695,-1.394 -0.853,-1.28 z m -32.013,133.845 120.796,68.538 c 1.564,0.949 1.929,0.604 1.707,-1.036 l -2.561,-48.05 c -0.07,-1.551 -0.28,-2.183 -1.89,-2.439 z m 249.764,0.121 -122.625,16.952 c -1.618,0.238 -1.326,1.032 -1.342,2.195 l 2.622,48.903 c 0.135,1.483 0.091,2.017 1.89,1.098 z"/> - + \ No newline at end of file diff --git a/src/templates/ui/partial-equipment-button.hbs b/src/templates/ui/partial-equipment-button.hbs index f6503019..63c733a8 100644 --- a/src/templates/ui/partial-equipment-button.hbs +++ b/src/templates/ui/partial-equipment-button.hbs @@ -11,8 +11,8 @@ {{#each this}} - - + + {{this.name}} {{this.quantity}} {{#if this.worn}}({{/if}}{{this.weight}}{{#if this.worn}}){{/if}} diff --git a/src/templates/ui/partial-equipment-group-button.hbs b/src/templates/ui/partial-equipment-group-button.hbs deleted file mode 100644 index 37e310b6..00000000 --- a/src/templates/ui/partial-equipment-group-button.hbs +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - {{#each this}} - - - - - - - {{/each}} - -
AnzahlGewicht
{{this.name}}{{this.quantity}}{{this.weight}}
diff --git a/src/templates/ui/partial-rollable-button.hbs b/src/templates/ui/partial-rollable-button.hbs index 535886b1..7007661b 100644 --- a/src/templates/ui/partial-rollable-button.hbs +++ b/src/templates/ui/partial-rollable-button.hbs @@ -1,12 +1,13 @@ -
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{#if this.taw}} + {{#if this.taw}} {{this.taw}} {{else}} {{#if this.liturgiekenntnis}} diff --git a/src/templates/ui/partial-rollable-weaponskill-button.hbs b/src/templates/ui/partial-rollable-weaponskill-button.hbs index e1d68f60..552ea31f 100644 --- a/src/templates/ui/partial-rollable-weaponskill-button.hbs +++ b/src/templates/ui/partial-rollable-weaponskill-button.hbs @@ -5,7 +5,8 @@
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{#if this.taw}} + {{#if this.taw}} {{this.taw}} {{else}} {{#if this.liturgiekenntnis}}