diff --git a/src/main.mjs b/src/main.mjs index 22e9aef3..170e8dc9 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -9,6 +9,8 @@ import { CharacterSheet } from "./module/sheets/characterSheet.mjs"; import { VornachteilSheet } from "./module/sheets/vornachteilSheet.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"; async function preloadHandlebarsTemplates() { return loadTemplates([ @@ -17,7 +19,8 @@ async function preloadHandlebarsTemplates() { 'systems/DSA_4-1/templates/ui/partial-attribute-button.hbs', 'systems/DSA_4-1/templates/ui/partial-talent-editable.hbs', 'systems/DSA_4-1/templates/ui/partial-die.hbs', - 'systems/DSA_4-1/templates/ui/partial-advantage-button.hbs' + 'systems/DSA_4-1/templates/ui/partial-advantage-button.hbs', + 'systems/DSA_4-1/templates/ui/partial-array-editor.hbs' ]); } @@ -39,7 +42,8 @@ Hooks.once("init", () => { CONFIG.Item.dataModels = { Skill: SkillDataModel, Spell: SpellDataModel, - Advantage: VornachteileDataModel + Advantage: VornachteileDataModel, + Equipment: EquipmentDataModel, } CONFIG.Combat.initiative = { @@ -76,7 +80,11 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.VornachteilLabels.Item' }) - + Items.registerSheet('dsa41.equipment', AusruestungSheet, { + types: ["Equipment"], + makeDefault: true, + label: 'DSA41.AusruestungLabels.Item' + }) return preloadHandlebarsTemplates(); }) diff --git a/src/module/data/equipment.mjs b/src/module/data/equipment.mjs new file mode 100644 index 00000000..f8768127 --- /dev/null +++ b/src/module/data/equipment.mjs @@ -0,0 +1,41 @@ +import BaseItem from "./base-item.mjs"; +const { + ArrayField, NumberField, StringField, HTMLField +} = foundry.data.fields; + +export class EquipmentDataModel extends BaseItem { + + static defineSchema() { + return { + quantity: new NumberField({ required: true, integer: true, initial: 1}), + category: new ArrayField(new StringField({ required: true })), + description: new HTMLField(), + weight: new NumberField({ required: true }), + price: new StringField(), + + breakFactor: new NumberField({ required: false }), + iniModifier: new NumberField({ required: false }), + attackModifier: new NumberField({ required: false }), + parryModifier: new NumberField({ required: false }), + + meleeAttackModifier: new NumberField({ integer: true }), + meleeAttackModifierIncrement: new NumberField({ integer: true }), + meleeSkills: new ArrayField( + new StringField({ required: true }), + ), + meleeAttackDamage: new StringField(), + + rangedSkills: new ArrayField( + new StringField({ required: true }), + ), + rangedRangeModifier: new StringField({ required: false }), + rangeRangeDamageModifier: new StringField({ required: false }), + rangedAttackDamage: new StringField(), + rangedReloadTime: new NumberField({ required: false }), + + armorValue: new NumberField({ required: false }), + armorHandicap: new NumberField({ required: false }), + } + } + +} diff --git a/src/module/documents/equipment.mjs b/src/module/documents/equipment.mjs new file mode 100644 index 00000000..7dcf1bfd --- /dev/null +++ b/src/module/documents/equipment.mjs @@ -0,0 +1,10 @@ + +export class Equipment extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 66b453fd..96b1955e 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -34,6 +34,7 @@ export class CharacterSheet extends ActorSheet { this.#addSkillsToContext(context) this.#addAdvantagesToContext(context) this.#addAttributesToContext(context) + this.#addEquipmentsToContext(context) return context; } @@ -152,6 +153,21 @@ export class CharacterSheet extends ActorSheet { } + #addEquipmentsToContext(context) { + context.equipments = []; + const actorData = context.data; + Object.values(actorData.items).forEach( (item, index) => { + if (item.type === "Equipment") { + context.equipments.push({ + index: index, + id: item._id, + quantity: item.system.quantity, + name: item.name, + }) + } + }) + } + prepareEigenschaftRoll(actorData, name) { return actorData.system.attribute[name.toLowerCase()].aktuell } @@ -306,6 +322,11 @@ export class CharacterSheet extends ActorSheet { evt.stopPropagation(); }) + html.on('click', '.equipment .name', (evt) => { + this.openEmbeddedDocument(evt.target.dataset.id); + evt.stopPropagation(); + }) + new ContextMenu(html, '.talent.rollable', [ { name: "Entfernen", @@ -357,6 +378,16 @@ export class CharacterSheet extends ActorSheet { } } + #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 + console.log(equipment); + return false; + } + } + } + static getElementByName(collection, id) { const array = Array.from(collection); for (const element of array) { @@ -380,6 +411,9 @@ export class CharacterSheet extends ActorSheet { return characterSheet.#handleDroppedSkill(actor, document); // on false cancel this whole operation case "Advantage": return characterSheet.#handleDroppedAdvantage(actor, document); + case "Equipment": + return characterSheet.#handleDroppedEquipment(actor, document); + default: return false; } diff --git a/src/module/sheets/equipmentSheet.mjs b/src/module/sheets/equipmentSheet.mjs new file mode 100644 index 00000000..49e909d0 --- /dev/null +++ b/src/module/sheets/equipmentSheet.mjs @@ -0,0 +1,109 @@ +export class AusruestungSheet extends ItemSheet { + /**@override */ + static get defaultOptions() { + return foundry.utils.mergeObject(super.defaultOptions, { + classes: ['dsa41', 'sheet', 'item', 'equipment'], + width: 520, + height: 480, + tabs: [ + { + navSelector: '.sheet-tabs', + contentSelector: '.sheet-body', + initial: 'description', + }, + ], + }); + } + + /** @override */ + get template() { + return `systems/DSA_4-1/templates/item/item-equipment-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 equipmentData = context.data; + + // Add the actor's data to context.data for easier access, as well as flags. + context.system = equipmentData.system; + context.flags = equipmentData.flags; + + context.quantity = context.system.quantity; + context.description = context.system.description; + + context.categoryAndOptions = { + options: { + Gegenstand: "Gegenstand", + Nahkampfwaffe: "Nahkampfwaffe", + Fernkampfwaffe: "Fernkampfwaffe", + Behälter: "Behälter", + Rüstung: "Rüstung", + }, + entries: context.system.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; + context.meleeSkillsAndOptions = { + options: { + "": "", + Dolche: "Dolche", + Fechtwaffen: "Fechtwaffen", + Säbel: "Säbel", + Schwerter: "Schwerter", + Anderthalbhänder: "Anderthalbhänder", + "Zweihandschwerter/-säbel": "Zweihandschwerter/-säbel", + "Infanteriewaffen": "Infanteriewaffen", + "Speere": "Speere", + "Stäbe": "Stäbe", + "Hiebwaffen": "Hiebwaffen", + "Zweihand-Hiebwaffen": "Zweihand-Hiebwaffen", + "Kettenwaffen": "Kettenwaffen", + "Raufen": "Raufen" + }, + entries: context.system.meleeSkills, + targetField: "meleeSkills" + } + context.rangedSkillsAndOptions = { + options: { + "": "", + "Wurfmesser": "Wurfmesser", + "Wurfspeer": "Wurfspeer", + "Wurfbeil": "Wurfbeil", + "Armbrust": "Armbrust", + "Bogen": "Bogen", + }, + entries: context.system.rangedSkills, + targetField: "rangedSkills" + } + return context; + } + + activateListeners(html) { + super.activateListeners(html); + + 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 = ""; + }) + + // Everything below here is only needed if the sheet is editable + if (!this.isEditable) return; + } + +} diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 5d77b33a..dd53d5c4 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -20,49 +20,52 @@ export class GroupSheet extends ActorSheet { const context = super.getData(); // Use a safe clone of the actor data for further operations. - const skillData = context.data; + const groupData = 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 = groupData.system; + context.flags = groupData.flags; context.characters = []; - for (const characterId of skillData.system.characters) { + for (const characterId of groupData.system.characters) { const character = await game.actors.get(characterId) context.characters.push( { img: character.img, name: character.name, + id: character._id, attributes: [ - { name: "MU", value: character.system.attribute.mu.aktuell }, - { name: "KL", value: character.system.attribute.kl.aktuell }, - { name: "IN", value: character.system.attribute.in.aktuell }, - { name: "CH", value: character.system.attribute.ch.aktuell }, - { name: "FF", value: character.system.attribute.ff.aktuell }, - { name: "GE", value: character.system.attribute.ge.aktuell }, - { name: "KO", value: character.system.attribute.ko.aktuell }, - { name: "KK", value: character.system.attribute.kk.aktuell }, + {name: "MU", value: character.system.attribute.mu.aktuell}, + {name: "KL", value: character.system.attribute.kl.aktuell}, + {name: "IN", value: character.system.attribute.in.aktuell}, + {name: "CH", value: character.system.attribute.ch.aktuell}, + {name: "FF", value: character.system.attribute.ff.aktuell}, + {name: "GE", value: character.system.attribute.ge.aktuell}, + {name: "KO", value: character.system.attribute.ko.aktuell}, + {name: "KK", value: character.system.attribute.kk.aktuell}, ], - advantages: character.items.filter( (i) => i.type === "Advantage").map( (advantage) => { + advantages: character.items.filter((i) => i.type === "Advantage").map((advantage) => { return { name: advantage.name, id: advantage._id, value: advantage.system.value, } }), - skills: character.items.filter( (i) => i.type === "Skill").map( (skill) => { + skills: character.items.filter((i) => i.type === "Skill").map((skill) => { return { name: skill.name, taw: skill.system.taw, id: skill._id } }), + isLimited: character.isOwner || !character.limited, + isVisible: character.isOwner || character.visible, isOwner: character.isOwner } ) } - console.log(context.characters) + console.log(groupData, context.characters) return await context; } @@ -76,15 +79,48 @@ export class GroupSheet extends ActorSheet { 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 await group.update({ system: { characters: [ - ...group.system.characters, - character._id + ...group.system.characters, + character._id ] } }) ui.notifications.info(`${character.name} ist der Heldengruppe ${group.name} beigetreten`) } } + + 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); + } + }) + } } diff --git a/src/style/_equipment-sheet.scss b/src/style/_equipment-sheet.scss new file mode 100644 index 00000000..910033d5 --- /dev/null +++ b/src/style/_equipment-sheet.scss @@ -0,0 +1,133 @@ +.app.window-app.dsa41.sheet.item.equipment { + + .sheet-body { + + position: relative; + top: 5px; + + .tab.meta.active { + + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 4px; + display: grid; + grid-auto-columns: 1fr 1fr; + grid-template-columns: 80px auto; + grid-template-rows: 24px 48px auto 48px; + gap: 0px 0px; + grid-template-areas: + "category category" + "quantity name" + "description description" + "bottomline bottomline"; + + .name { + grid-area: name; + } + + .bottomline { + grid-area: bottomline; + display: grid; + grid-template-columns: repeat(2, 1fr); + + .named-value { + position: relative; + height: 48px; + + label { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 80px; + line-height: 24px; + vertical-align: middle; + + input { + position: absolute; + left: 80px; + top: 0; + bottom: 0; + right: 0; + } + } + } + + + } + + .category { + grid-area: category; + position: relative; + + label { + line-height: 24px; + vertical-align: middle; + + + } + + .array-editor { + position: absolute; + right: 0; + left: 80px; + top: 0; + bottom: 0; + + ul { + list-style-type: none; + padding: 0; + margin: 0; + text-indent: 0; + + li { + display: inline-block; + border: 1px solid #333; + background-color: rgba(255, 255, 255, 0.2); + border-radius: 12px; + line-height: 24px; + vertical-align: middle; + padding: 0 8px; + box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); + } + } + + select { + position: absolute; + right: 0; + top: 0; + } + } + + } + + .quantity { + grid-area: quantity; + } + + .description { + grid-area: description; + position: relative; + label { + height: 14px; + } + .editor { + position: absolute; + top: 14px; + left: 0; + right: 0; + bottom: 0; + border-bottom: 1px inset #333; + } + } + + } + + + + } + +} diff --git a/src/style/_group-sheet.scss b/src/style/_group-sheet.scss index 5101d62c..a39b8874 100644 --- a/src/style/_group-sheet.scss +++ b/src/style/_group-sheet.scss @@ -42,6 +42,16 @@ height: 100%; width: 100%; + &.minimal { + display: unset!important; + + .character { + display: inline-block; + margin: 4px; + box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); + } + } + .character { width: 192px; diff --git a/src/style/_tabs.scss b/src/style/_tabs.scss index d2e66b98..a044082a 100644 --- a/src/style/_tabs.scss +++ b/src/style/_tabs.scss @@ -2,7 +2,7 @@ @use "./colours"; @use "./assets"; -.dsa41.sheet.actor { +.dsa41.sheet { nav.sheet-tabs.tabs { diff --git a/src/style/styles.scss b/src/style/styles.scss index 9df419d2..ce171464 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -5,4 +5,4 @@ @use "_character-sheet"; @use "_group-sheet"; @use "_tabs"; - +@use "_equipment-sheet"; diff --git a/src/system.json b/src/system.json index 1a6511c7..2e5d0f5d 100644 --- a/src/system.json +++ b/src/system.json @@ -101,6 +101,17 @@ } }, "Item": { + "Equipment": { + "stringFields": [ + "name", "category" + ], + "htmlFields": [ + "description" + ], + "numberFields": [ + "quantity" + ] + }, "Advantage": { "stringFields": [ "name" diff --git a/src/templates/actor/actor-character-sheet.hbs b/src/templates/actor/actor-character-sheet.hbs index a6852343..338afbb6 100644 --- a/src/templates/actor/actor-character-sheet.hbs +++ b/src/templates/actor/actor-character-sheet.hbs @@ -67,10 +67,6 @@ -
- -
-
@@ -150,6 +146,15 @@
+ +
diff --git a/src/templates/actor/group-sheet.hbs b/src/templates/actor/group-sheet.hbs index 69bbe95a..26d3b79e 100644 --- a/src/templates/actor/group-sheet.hbs +++ b/src/templates/actor/group-sheet.hbs @@ -16,16 +16,32 @@ {{!-- Sheet Body --}}
+ {{#if actor.limited}} +
+ {{#each characters}} + {{#if this.isVisible}} +
+
+ {{this.name}} + {{this.name}} +
+
+ {{/if}} + {{/each}} +
+ {{else}}
{{#each characters}} + {{#if this.isVisible}}
-
+
{{this.name}} {{this.name}}
+ {{#if this.isLimited}}
{{#each this.attributes}} -
+
{{this.value}} {{this.name}}
@@ -33,20 +49,23 @@
    - {{#each skills}}
  • {{this.name}}: {{this.taw}}
  • {{/each}} + {{#each skills}}
  • {{this.name}}: {{this.taw}}
  • {{/each}}
    - {{#each advantages}}
  • {{this.name}} {{#if this.value}}[{{this.value}}]{{/if}}
  • {{/each}} + {{#each advantages}}
  • {{this.name}} {{#if this.value}}[{{this.value}}]{{/if}}
  • {{/each}}
+ {{/if}} {{#if this.isOwner}}
- +
{{/if}}
+ {{/if}} {{/each}}
+ {{/if}}
diff --git a/src/templates/item/item-equipment-sheet.hbs b/src/templates/item/item-equipment-sheet.hbs new file mode 100644 index 00000000..ed248076 --- /dev/null +++ b/src/templates/item/item-equipment-sheet.hbs @@ -0,0 +1,160 @@ +
+ + {{!-- 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-skill-sheet.hbs b/src/templates/item/item-skill-sheet.hbs index 22cd7fd3..60cb9eb9 100644 --- a/src/templates/item/item-skill-sheet.hbs +++ b/src/templates/item/item-skill-sheet.hbs @@ -53,9 +53,8 @@
- + + {{editor system.talent target="system.talent" button=true owner=owner editable=editable}}
diff --git a/src/templates/ui/partial-array-editor.hbs b/src/templates/ui/partial-array-editor.hbs new file mode 100644 index 00000000..9831acd8 --- /dev/null +++ b/src/templates/ui/partial-array-editor.hbs @@ -0,0 +1,11 @@ +
+ +
    +{{#each entries}} +
  • {{this}}
  • +{{/each}} +
+ +