diff --git a/README.md b/README.md index 68f1b03f..e8d0abac 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,26 @@ API: https://foundryvtt.com/api/classes/foundry.abstract.Document.html Demo: https://github.com/foundryvtt/dnd5e -Flim Flam +# Features + +## Spieler Tools + +## GM Tools + +### Gruppenmanagement + +Um die Übersicht zu wahren, gibt es mit Gruppen das Werkzeug in die Hände der Spielleitung um wichtige Infos wie +Eigenschaften, Vor und Nachteile und andere Statistiken eines Charakters innerhalb einer Gruppe zu haben und diese +gleichzeitigt mit denen anderer vergleichen zu können. + +### Kreaturen + +Da die Erstellung eines Charakters sehr komplex ist, gibt es mit Kreaturen eine stark abgespeckte Variante, die leicht +während der Sitzung oder in Vorbereitung angelegt werden können. Nur die für kämpfischer Begegnungen relevanten +Informationen sind verfügbar. + +### Händler + +Um die Vorbereitung einer Sitzung so komfortabel wie möglich zu gestalten, gibt es mit Händler die Möglichkeit Gebäude +oder NSCs vorzubereiten welche Waren und oder (ggf. in Anzahl beschränkte) Dienstleistungen bereitstellen, gegen einen +Preis natürlich. \ No newline at end of file diff --git a/src/assets/Aves.png b/src/assets/Aves.png deleted file mode 100644 index 412161f4..00000000 Binary files a/src/assets/Aves.png and /dev/null differ diff --git a/src/assets/Boron.png b/src/assets/Boron.png deleted file mode 100644 index bcd55539..00000000 Binary files a/src/assets/Boron.png and /dev/null differ diff --git a/src/assets/Efferd.png b/src/assets/Efferd.png deleted file mode 100644 index 54a78bbe..00000000 Binary files a/src/assets/Efferd.png and /dev/null differ diff --git a/src/assets/Firun.png b/src/assets/Firun.png deleted file mode 100644 index 23568f5f..00000000 Binary files a/src/assets/Firun.png and /dev/null differ diff --git a/src/assets/Hesinde.png b/src/assets/Hesinde.png deleted file mode 100644 index bdb07e46..00000000 Binary files a/src/assets/Hesinde.png and /dev/null differ diff --git a/src/assets/Ifirn.png b/src/assets/Ifirn.png deleted file mode 100644 index a93d0406..00000000 Binary files a/src/assets/Ifirn.png and /dev/null differ diff --git a/src/assets/Ingerimm.png b/src/assets/Ingerimm.png deleted file mode 100644 index ef2dc864..00000000 Binary files a/src/assets/Ingerimm.png and /dev/null differ diff --git a/src/assets/Kor.png b/src/assets/Kor.png deleted file mode 100644 index 7b3a2abb..00000000 Binary files a/src/assets/Kor.png and /dev/null differ diff --git a/src/assets/Marbo.png b/src/assets/Marbo.png deleted file mode 100644 index 24baebca..00000000 Binary files a/src/assets/Marbo.png and /dev/null differ diff --git a/src/assets/Namenlos.png b/src/assets/Namenlos.png deleted file mode 100644 index aa70fb5d..00000000 Binary files a/src/assets/Namenlos.png and /dev/null differ diff --git a/src/assets/Nandus.png b/src/assets/Nandus.png deleted file mode 100644 index 8b7a3493..00000000 Binary files a/src/assets/Nandus.png and /dev/null differ diff --git a/src/assets/Peraine.png b/src/assets/Peraine.png deleted file mode 100644 index 8572c7cf..00000000 Binary files a/src/assets/Peraine.png and /dev/null differ diff --git a/src/assets/Phex.png b/src/assets/Phex.png deleted file mode 100644 index 7de13f2c..00000000 Binary files a/src/assets/Phex.png and /dev/null differ diff --git a/src/assets/Praios.png b/src/assets/Praios.png deleted file mode 100644 index e5e62963..00000000 Binary files a/src/assets/Praios.png and /dev/null differ diff --git a/src/assets/Rahja.png b/src/assets/Rahja.png deleted file mode 100644 index c4ad56cf..00000000 Binary files a/src/assets/Rahja.png and /dev/null differ diff --git a/src/assets/Rondra.png b/src/assets/Rondra.png deleted file mode 100644 index 619ad98a..00000000 Binary files a/src/assets/Rondra.png and /dev/null differ diff --git a/src/assets/Satuaria.png b/src/assets/Satuaria.png deleted file mode 100644 index 5c90ab28..00000000 Binary files a/src/assets/Satuaria.png and /dev/null differ diff --git a/src/assets/Simia.png b/src/assets/Simia.png deleted file mode 100644 index d6fc5214..00000000 Binary files a/src/assets/Simia.png and /dev/null differ diff --git a/src/assets/Tairach.png b/src/assets/Tairach.png deleted file mode 100644 index 8b156577..00000000 Binary files a/src/assets/Tairach.png and /dev/null differ diff --git a/src/assets/Travia.png b/src/assets/Travia.png deleted file mode 100644 index 548c7de2..00000000 Binary files a/src/assets/Travia.png and /dev/null differ diff --git a/src/assets/Tsa.png b/src/assets/Tsa.png deleted file mode 100644 index 10a2f1fb..00000000 Binary files a/src/assets/Tsa.png and /dev/null differ diff --git a/src/assets/Ucuri.png b/src/assets/Ucuri.png deleted file mode 100644 index d5897df3..00000000 Binary files a/src/assets/Ucuri.png and /dev/null differ diff --git a/src/assets/circle.svg b/src/assets/circle.svg deleted file mode 100644 index b4ec7a2e..00000000 --- a/src/assets/circle.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/src/assets/die.svg b/src/assets/die.svg deleted file mode 100644 index df29e2dc..00000000 --- a/src/assets/die.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/assets/example-character.xml b/src/assets/example-character.xml deleted file mode 100644 index f636eace..00000000 --- a/src/assets/example-character.xml +++ /dev/null @@ -1,637 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a1RMsniSGUvFk5vUM6faRb5HF7M= - - - IoH2tMVRNhVL5zF5VrhsiYRdosA0GopNsJMf4tFpYVi5yPW6RhGqNQ== - - - -

/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9 - xD7nN1kuFw== -

- li7dzDacuo67Jg7mtqEm2TRuOMU= - Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOHCBiNU0Nogps - QW5QvnlMpA== - - uVrvWkzIbUdL7E80AiD0PJDX3Ck0beY5StXp1wDAA1/ePpemd6rTBNd8YoCzOovNrX016YMcTSiO - iExM4RWtJA== - -
-
-
-
-
\ No newline at end of file diff --git a/src/assets/kampftalent.svg b/src/assets/kampftalent.svg deleted file mode 100644 index ba60a679..00000000 --- a/src/assets/kampftalent.svg +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - - - - - PA - - - - - - AT - 23 - - Bogen - - - - - - 16 diff --git a/src/assets/liturgie.svg b/src/assets/liturgie.svg deleted file mode 100644 index 31667cdc..00000000 --- a/src/assets/liturgie.svg +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - - - - - CH - 14 - - - IN - 14 - - - MU - 13 - - Ruf zur Ruhe - - - - - diff --git a/src/assets/nachteil.svg b/src/assets/nachteil.svg deleted file mode 100644 index d0f96c97..00000000 --- a/src/assets/nachteil.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - Arroganz - - - - - - 8 diff --git a/src/assets/rollable.svg b/src/assets/rollable.svg deleted file mode 100644 index 3f671c00..00000000 --- a/src/assets/rollable.svg +++ /dev/null @@ -1,335 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - KK - 8 - - - - - - GE - 13 - - - - - - MU - 13 - - - Klettern - - - - - - - - - - 13 - - diff --git a/src/assets/zauber.svg b/src/assets/zauber.svg deleted file mode 100644 index b8527c1b..00000000 --- a/src/assets/zauber.svg +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - KO - 8 - - - - - GE - 13 - - - - - - IN - 14 - - - Armatrutz - - - - - - - - - - 3 - - diff --git a/src/main.mjs b/src/main.mjs index 6b60f8bf..eee9babc 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -28,6 +28,8 @@ import {CultureSheet} from "./module/sheets/CultureSheet.mjs"; import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs"; import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs"; import {XmlImportDialog} from "./module/dialog/xmlImportDialog.mjs"; +import {MerchantDataModel} from "./module/data/merchant.mjs"; +import {MerchantSheet} from "./module/sheets/merchantSheet.mjs"; async function preloadHandlebarsTemplates() { return foundry.applications.handlebars.loadTemplates([ // ui partials. @@ -64,6 +66,7 @@ Hooks.once("init", () => { character: PlayerCharacterDataModel, group: GroupDataModel, creature: CreatureDataModel, + Merchant: MerchantDataModel, }; CONFIG.Item.dataModels = { @@ -152,6 +155,11 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.ProfessionLabels.Profession' }) + foundry.documents.collections.Actors.registerSheet('dsa41.merchant', MerchantSheet, { + types: ['Merchant'], + makeDefault: true, + label: 'DSA41.MerchantLabels.MerchantLabel' + }) game.settings.register('DSA_4-1', 'optional_colorfuldice', { name: "Optional: Farbige Würfel nach Paramanthus", @@ -209,6 +217,63 @@ Hooks.once("init", () => { requiresReload: true }) + Handlebars.registerHelper("currency", (data) => { + + + // schema for Mittelreich: 1 Ducat = 10 Silver = 100 Kreutzer = 1000 Heller + // internally the price is always given in Silver + // so we need to inflate the value of price by 100 to be able to divide beginning from Heller + + const baseValue = data * 100 + + // then we can regex over it + + const currencyRegexp = /(.*)(.)(.)(.)/g + const withDucats = currencyRegexp.exec(baseValue) + let _ = undefined + let ducats = 0 + let silver = 0 + let kreutzer = 0 + let heller = 0 + + if (withDucats) { + [_, ducats, silver, kreutzer, heller] = withDucats + } else { + const currencyRegexp = /(.)(.)(.)/g + const withSilver = currencyRegexp.exec(baseValue) + if (withSilver) { + [_, silver, kreutzer, heller] = withSilver + } else { + const currencyRegexp = /(.)(.)/g + const withKreutzer = currencyRegexp.exec(baseValue) + + if (withKreutzer) { + [_, kreutzer, heller] = withKreutzer + + } else { + heller = baseValue + } + } + } + + let str = `` + if (ducats > 0) { + str += ducats + "" + } + if (silver > 0) { + str += silver + "" + } + if (kreutzer > 0) { + str += kreutzer + "" + } + if (heller > 0) { + str += heller + "" + } + str = str + "" + + return new Handlebars.SafeString(str) + }) + return preloadHandlebarsTemplates(); }) diff --git a/src/module/data/merchant.mjs b/src/module/data/merchant.mjs new file mode 100644 index 00000000..09a30503 --- /dev/null +++ b/src/module/data/merchant.mjs @@ -0,0 +1,39 @@ +const { + SchemaField, + NumberField, + ObjectField, + StringField, + HTMLField, + FilePathField, + DocumentIdField, + ArrayField, +} = foundry.data.fields; + +export class MerchantDataModel extends foundry.abstract.TypeDataModel { + + static defineSchema() { + + return { + description: new HTMLField(), + services: new ArrayField( + new SchemaField({ + image: new FilePathField({ + categories: ["IMAGE"], initial: data => { + return this.getDefaultArtwork(data); + } + }), + name: new StringField(), + price: new NumberField(), + description: new HTMLField(), + availability: new NumberField(), + }) + ), + // goods are based on Item collection + } + + } + + static getDefaultArtwork(data) { + return "icons/commodities/materials/bowl-liquid-red.webp" + } +} \ No newline at end of file diff --git a/src/module/documents/merchant.mjs b/src/module/documents/merchant.mjs new file mode 100644 index 00000000..b175214a --- /dev/null +++ b/src/module/documents/merchant.mjs @@ -0,0 +1,9 @@ +export class Merchant extends Actor { + /** + * @override + */ + prepareData() { + + super.prepareData(); + } +} \ No newline at end of file diff --git a/src/module/sheets/merchantSheet.mjs b/src/module/sheets/merchantSheet.mjs new file mode 100644 index 00000000..362db271 --- /dev/null +++ b/src/module/sheets/merchantSheet.mjs @@ -0,0 +1,251 @@ +const {HandlebarsApplicationMixin} = foundry.applications.api +const {DocumentSheetV2, ActorSheetV2} = foundry.applications.sheets + +export class MerchantSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'actor', 'merchant'], + tag: 'form', + dragDrop: [{ + dropSelector: '.tab.inventory.active' + }], + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: MerchantSheet.#onSubmitForm + }, + window: { + resizable: true, + }, + actions: { + editImage: MerchantSheet.editImage, + editServiceImage: MerchantSheet.#editServiceImage, + editNewServiceImage: MerchantSheet.#editNewServiceImage, + addNewService: MerchantSheet.#addNewService, + removeService: MerchantSheet.#removeService, + } + } + + static TABS = { + sheet: { + tabs: [ + {id: 'goods', group: 'sheet', label: 'Waren'}, + {id: 'services', group: 'sheet', label: 'Dienstleistungen'}, + // Meta is added via GM permission + ], + initial: 'goods' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/merchant/main-sheet.hbs` + }, + goods: { + template: `systems/DSA_4-1/templates/actor/merchant/tab-goods.hbs` + }, + services: { + template: `systems/DSA_4-1/templates/actor/merchant/tab-services.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/actor/merchant/tab-meta.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() + + console.log(formData.object) + + await this.document.update(formData.object) // Note: formData.object + } + + static async #removeService(event, target) { + const {rowId} = target.dataset; + + const services = this.document.services + + services.splice(rowId, 1) + + this.document.update({"system.services": services}) + } + + static async #addNewService(event, target) { + event.preventDefault() + + const fieldset = this.element.querySelector('details') + const image = fieldset.querySelector('img').src + const name = fieldset.querySelector('input[name="new_name"]').value + const price = fieldset.querySelector('input[name="new_price"]').value + const availability = fieldset.querySelector('input[name="new_availability"]').value + const description = fieldset.querySelector('prose-mirror').value + + if (name && price) { + let services = this.document.system.services + services.push({ + image, + name, + price, + availability, + description + }) + + this.document.update({"system.services": services}).then(e => { + this.element.reset() + }) + + + } + + return false + } + + + static async #editNewServiceImage(event, target) { + const field = target.dataset.field || "img" + const current = foundry.utils.getProperty(this.document, field) + + const fp = new foundry.applications.apps.FilePicker({ + type: "image", + current: current, + callback: (path) => { + target.src = path + } + }) + + fp.render(true) + } + + static async #editServiceImage(event, target) { + const field = target.dataset.field || "img" + const current = foundry.utils.getProperty(this.document, field) + + const fp = new foundry.applications.apps.FilePicker({ + type: "image", + current: current, + callback: (path) => { + target.src = path + //foundry.utils.setProperty(this.document, field, path) + target.parentElement.querySelector(`input[name="${field}"][type="hidden"]`).value = path + this.element.submit() + } + }) + + fp.render(true) + } + + + /** + * Handle changing a Document's image. + * @param {MouseEvent} event The click event. + * @returns {Promise} + * @protected + */ + + /* + static _onEditImage(event) { + const attr = event.currentTarget.dataset.edit; + const current = foundry.utils.getProperty(this.object, attr); + const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}; + const fp = new FilePicker.implementation({ + current, + type: "image", + redirectToRoot: img ? [img] : [], + callback: path => { + event.target.src = path; + event.target.dataset.edit + this.document.update({'image': path}) + + }, + top: this.position.top + 40, + left: this.position.left + 10 + }); + return fp.browse(); + }*/ + + _getTabsConfig(group) { + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + + // Modify tabs based on document properties + if (game.user.isGM) { + tabs.tabs.push({id: "meta", group: "sheet", label: "Meta"}) + } + + return tabs + } + + /** @override */ + async _prepareContext(options) { + const context = await super._prepareContext(options) + + context.name = this.document.name + context.image = this.document.img + context.description = this.document.system.description + context.goods = this.document.itemTypes["Equipment"] ?? [] + context.services = this.document.system.services + + 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: ".window-content", + permissions: { + drop: this._canDragDrop.bind(this) + }, + callbacks: { + drop: this._onDrop.bind(this) + } + }).bind(this.element); + } + + _canDragDrop(event, options) { + console.log(event, options) + return true + } + + 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") { + // 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); + } + } + } + +} \ No newline at end of file diff --git a/src/style/atoms/_assets.scss b/src/style/atoms/_assets.scss index e8aa7d05..472639ad 100644 --- a/src/style/atoms/_assets.scss +++ b/src/style/atoms/_assets.scss @@ -1,3 +1,8 @@ $dice-box-background: url('/ui/parchment.jpg') repeat; $tab-background: url('/ui/parchment-white.jpg') repeat; -$tab-pane-background: url('/ui/parchment-white.jpg') repeat; \ No newline at end of file +$tab-pane-background: url('/ui/parchment-white.jpg') repeat; + +$ducat: url('/systems/DSA_4-1/assets/coins/ducat.png') repeat; +$silver: url('/systems/DSA_4-1/assets/coins/silver.png') repeat; +$kreutzer: url('/systems/DSA_4-1/assets/coins/kreutzer.png') repeat; +$heller: url('/systems/DSA_4-1/assets/coins/heller.png') repeat; \ No newline at end of file diff --git a/src/style/molecules/_coins.scss b/src/style/molecules/_coins.scss new file mode 100644 index 00000000..23336b05 --- /dev/null +++ b/src/style/molecules/_coins.scss @@ -0,0 +1,52 @@ +@use "../atoms/assets"; + +.coins { + + .symbol { + + position: relative; + margin-right: 4px; + + &.ducat { + &::after { + background: assets.$ducat; + height: 16px; + width: 16px; + content: ''; + display: inline-block; + } + } + + &.silver { + &::after { + background: assets.$silver; + height: 16px; + width: 16px; + content: ''; + display: inline-block; + } + } + + &.kreutzer { + &::after { + background: assets.$kreutzer; + height: 16px; + width: 16px; + content: ''; + display: inline-block; + } + } + + &.heller { + &::after { + background: assets.$heller; + height: 16px; + width: 16px; + content: ''; + display: inline-block; + } + } + + } + +} \ No newline at end of file diff --git a/src/style/molecules/_sheet-header.scss b/src/style/molecules/_sheet-header.scss new file mode 100644 index 00000000..7d72c3b9 --- /dev/null +++ b/src/style/molecules/_sheet-header.scss @@ -0,0 +1,21 @@ +.sheet-header { + + display: grid; + grid-template-columns: 32px 1fr; + grid-template-rows: 1fr; + height: 32px; + gap: 0 16px; + margin-bottom: 14px; + + img { + width: 32px; + height: 32px; + border-radius: 4px; + } + + input { + height: 32px; + width: 100%; + } + +} \ No newline at end of file diff --git a/src/style/molecules/_tabs.scss b/src/style/molecules/_tabs.scss index 9a42f929..aec6f5d0 100644 --- a/src/style/molecules/_tabs.scss +++ b/src/style/molecules/_tabs.scss @@ -21,7 +21,7 @@ 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; + top: numbers.$tab-border-width*2*2; background: assets.$tab-background; position: relative; z-index: 2; @@ -74,7 +74,7 @@ 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; + top: numbers.$tab-border-width*2; background: assets.$tab-background; position: relative; z-index: 2; diff --git a/src/style/organisms/_merchant-sheet.scss b/src/style/organisms/_merchant-sheet.scss new file mode 100644 index 00000000..99e8d114 --- /dev/null +++ b/src/style/organisms/_merchant-sheet.scss @@ -0,0 +1,254 @@ +.dsa41.actor.merchant { + + .tab.goods.active { + + display: flex; + flex-direction: column; + + } + + .tab.services.active { + + display: flex; + flex-direction: column; + + } + + .merchant-goods { + padding: 8px; + columns: 2; + gap: 16px; + overflow-x: hidden; + overflow-y: auto; + + .merchant-good { + width: 100%; + display: grid; + grid-template-columns: 32px 1fr 32px; + grid-template-rows: 16px 16px; + grid-template-areas: "img title options" "img price options"; + + .img { + grid-area: img; + } + + .name { + grid-area: title; + } + + button { + grid-area: options; + } + + .price { + grid-area: price; + } + + } + + + } + + .services { + + padding: 8px; + overflow-x: hidden; + overflow-y: auto; + + .service { + + border: 1px inset rgba(0, 0, 0, 1); + background-color: rgba(0, 0, 0, 0.2); + border-radius: 4px; + padding: 4px; + margin: 4px 0; + + display: grid; + grid-template-columns: 32px 1fr 32px; + grid-template-rows: 16px 16px; + gap: 0 4px; + grid-template-areas: "image name options" "image price options"; + position: relative; + + .name { + grid-area: name; + } + + .price { + grid-area: price; + position: relative; + top: -2px; + } + + img { + grid-area: image; + width: 32px; + height: 32px; + border-radius: 4px; + } + + .availability { + position: absolute; + left: 0; + bottom: 1px; + width: 36px; + + color: gold; + text-shadow: 1px 1px 1px #000; + vertical-align: bottom; + display: block; + text-align: right; + + &::before { + content: 'x'; + } + + &.infinite { + &::before { + content: '∞'; + } + } + } + + .actions { + grid-area: options; + align-self: end; + height: 32px; + } + + .description { + grid-area: description; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + prose-mirror { + flex: 1; + } + } + + &.editable { + display: grid; + grid-template-columns: 1fr 80px 120px 32px; + grid-template-rows: 48px 1fr; + gap: 8px; + grid-template-areas: "name price availability options" "description description description description"; + + .name { + display: grid; + grid-template-columns: 32px 1fr; + grid-template-rows: 20px 1fr; + grid-template-areas: "label label" "img name"; + + label { + grid-area: label; + } + + img { + grid-area: img; + } + + input { + grid-area: name; + } + } + + .availability { + position: inherit; + left: inherit; + bottom: inherit; + width: inherit; + + color: inherit; + text-shadow: unset; + vertical-align: unset; + display: unset; + text-align: unset; + + &::before { + content: ''; + } + } + + .actions { + position: relative; + bottom: -4px; + } + + } + + } + + .editor { + + .pane { + display: grid; + grid-template-columns: 1fr 80px 120px 32px; + grid-template-rows: 48px 1fr; + gap: 8px; + grid-template-areas: "name price availability options" "description description description description"; + + .name { + display: grid; + grid-template-columns: 32px 1fr; + grid-template-rows: 20px 1fr; + grid-template-areas: "label label" "img name"; + + label { + grid-area: label; + } + + img { + grid-area: img; + border: 1px inset rgba(0, 0, 0, 1); + background: rgba(0, 0, 0, 0.5); + } + + input { + grid-area: name; + } + } + + .description { + grid-area: description; + } + + .availability { + position: inherit; + left: inherit; + bottom: inherit; + width: inherit; + + color: inherit; + text-shadow: unset; + vertical-align: unset; + display: unset; + text-align: unset; + + &::before { + content: ''; + } + } + + .actions { + position: relative; + bottom: -4px; + } + + } + } + + + } + + section.tab > div { + display: unset; + flex-direction: unset; + height: unset; + gap: unset; + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_inventory.scss b/src/style/organisms/character-tabs/_inventory.scss index 97abd3e5..9a804269 100644 --- a/src/style/organisms/character-tabs/_inventory.scss +++ b/src/style/organisms/character-tabs/_inventory.scss @@ -1,3 +1,5 @@ +@use "../../atoms/assets"; + @mixin tab { & > div { @@ -43,20 +45,60 @@ .inventory-table { flex: 1; + display: flex; + flex-direction: column; .equipment { + position: relative; height: 32px; + display: grid; + grid-template-columns: 32px 24px 1fr 48px; + grid-template-rows: 1fr; + padding: 2px 0 0 2px; + margin: 4px 0 0 4px; + gap: 8px; + background: assets.$tab-pane-background; .icon { width: 32px; padding: 0; } - } - } - .equipment:hover { - .item-name { - text-shadow: 0 0 10px rgb(255 0 0); + .name, .weight { + height: 32px; + line-height: 32px; + vertical-align: middle; + } + + input.quantity { + padding: 0; + border: unset; + border-radius: 0; + height: 24px; + width: 24px; + margin: 4px 0; + text-align: right; + background: unset; + box-shadow: unset; + + &:hover { + text-decoration: underline; + } + } + + transition: box-shadow 0.2s, border 0.2s, margin 0.2s, padding 0.2s; + + &:hover { + .name { + text-shadow: 0 0 10px rgb(255 0 0); + } + + border: 1px solid #ccc; + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5); + margin: -4px 4px 4px -4px; + padding: 0 0 0 0; + z-index: 2; + } } } } diff --git a/src/style/styles.scss b/src/style/styles.scss index 208a171a..c67b1bae 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -7,6 +7,8 @@ @use "molecules/attributes"; @use "molecules/sidebar-elements"; @use "molecules/rows-and-columns"; +@use "molecules/sheet-header"; +@use "molecules/coins"; @use "molecules/tabs"; @use "molecules/paperdoll"; @@ -26,4 +28,4 @@ @use "organisms/profession-sheet"; @use "organisms/xml-import-dialog"; @use "organisms/combat-action-dialog"; - +@use "organisms/merchant-sheet"; diff --git a/src/system.json b/src/system.json index 565610b0..58e41840 100644 --- a/src/system.json +++ b/src/system.json @@ -150,6 +150,15 @@ "zauber", "heldenausruestung" ] + }, + "Merchant": { + "schemaFields": [ + "goods", + "services" + ], + "htmlFields": [ + "description" + ] } }, "Item": { diff --git a/src/templates/actor/merchant/main-sheet.hbs b/src/templates/actor/merchant/main-sheet.hbs new file mode 100644 index 00000000..581a9537 --- /dev/null +++ b/src/templates/actor/merchant/main-sheet.hbs @@ -0,0 +1,26 @@ +
+ {{#if editable}} + +
+ + {{name}} + + +
+ {{/if}} + + {{!-- Sheet Tab Navigation --}} + + +
\ No newline at end of file diff --git a/src/templates/actor/merchant/tab-goods.hbs b/src/templates/actor/merchant/tab-goods.hbs new file mode 100644 index 00000000..9a271dec --- /dev/null +++ b/src/templates/actor/merchant/tab-goods.hbs @@ -0,0 +1,16 @@ +
+ +
+ {{#each goods}} +
+ + {{this.name}} + {{currency this.system.price}} + +
+ {{/each}} +
+ +
\ No newline at end of file diff --git a/src/templates/actor/merchant/tab-meta.hbs b/src/templates/actor/merchant/tab-meta.hbs new file mode 100644 index 00000000..6578c416 --- /dev/null +++ b/src/templates/actor/merchant/tab-meta.hbs @@ -0,0 +1,13 @@ +
+ + + {{{system.description}}} + + +
\ No newline at end of file diff --git a/src/templates/actor/merchant/tab-services.hbs b/src/templates/actor/merchant/tab-services.hbs new file mode 100644 index 00000000..6f69dd1d --- /dev/null +++ b/src/templates/actor/merchant/tab-services.hbs @@ -0,0 +1,81 @@ +
+ +
+ {{#each services}} + {{#if ../editable}} +
+
+ + {{name}} + + +
+ + + +
+ + + {{{this.description}}} + +
+
+ {{else}} +
+ {{this.name}} + {{this.name}} + {{currency this.price}} + {{this.availability}} + +
+ {{/if}} + {{/each}} +
+ +
+ + {{#if editable}} +
+ Neue Dienstleistung +
+
+ {{name}} + +
+ + +
+ + + +
+
+ +
+ + {{/if}} +
+
\ 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 7f7d0ac6..87898b6b 100644 --- a/src/templates/ui/partial-equipment-button.hbs +++ b/src/templates/ui/partial-equipment-button.hbs @@ -1,22 +1,12 @@ - - - - - - - - - - - +
{{#each this}} -
- - - - - +
+ + + × {{this.name}} + {{this.weight}} +
{{/each}} - -
AnzahlGewicht
{{this.name}}{{this.quantity}}{{#if this.worn}}({{/if}}{{this.weight}}{{#if this.worn}}){{/if}}
+ +