From 011f5d2b144b1ced382ba3d6bb429c5193920dfb Mon Sep 17 00:00:00 2001 From: WBHarry Date: Fri, 18 Jul 2025 15:05:12 +0200 Subject: [PATCH] Finished Evolved --- lang/en.json | 16 +- .../applications/dialogs/beastformDialog.mjs | 146 +++++++++++++++--- .../applications/sheets/items/beastform.mjs | 24 +++ module/applications/ui/hotbar.mjs | 6 +- module/config/actorConfig.mjs | 6 + module/config/generalConfig.mjs | 19 +++ module/data/action/beastformAction.mjs | 29 +++- module/data/item/beastform.mjs | 37 +++-- module/helpers/utils.mjs | 70 --------- styles/less/dialog/beastform/sheet.less | 117 +++++++++----- styles/less/sheets/index.less | 1 + styles/less/sheets/items/beastform.less | 9 ++ system.json | 11 +- templates/dialogs/beastformDialog.hbs | 27 +++- templates/sheets/items/beastform/advanced.hbs | 4 +- templates/sheets/items/beastform/settings.hbs | 18 ++- 16 files changed, 378 insertions(+), 162 deletions(-) create mode 100644 styles/less/sheets/items/beastform.less diff --git a/lang/en.json b/lang/en.json index f9b8fa2c..18812e19 100755 --- a/lang/en.json +++ b/lang/en.json @@ -13,6 +13,9 @@ "armor": "Armor", "beastform": "Beastform" }, + "ActiveEffect": { + "beastform": "Beastform" + }, "Actor": { "character": "Character", "companion": "Companion", @@ -1298,6 +1301,7 @@ "FIELDS": { "beastformType": { "label": "Beastform Type" }, "tier": { "label": "Tier" }, + "mainTrait": { "label": "Main Trait" }, "examples": { "label": "Examples" }, "advantageOn": { "label": "Gain Advantage On" }, "tokenImg": { "label": "Token Image" }, @@ -1308,7 +1312,8 @@ "width": { "label": "Width" } }, "evolved": { - "maximumTier": { "label": "Maximum Tier" } + "maximumTier": { "label": "Maximum Tier" }, + "mainTraitBonus": { "label": "Main Trait Bonus" } }, "hybrid": { "beastformOptions": { "label": "Nr Beastforms" }, @@ -1319,7 +1324,11 @@ "dialogTitle": "Beastform Selection", "tokenTitle": "Beastform Token", "transform": "Transform", - "beastformEffect": "Beastform Transformation" + "beastformEffect": "Beastform Transformation", + "evolve": "Evolve", + "evolvedFeatureTitle": "Evolved", + "hybridize": "Hybridize", + "hybridFeatureTitle": "Hybrid Features" }, "Class": { "hopeFeatures": "Hope Features", @@ -1563,7 +1572,8 @@ "featureNotSecondary": "This feature is used as something else than a Secondary feature and cannot be used here.", "featureNotFoundation": "This feature is used as something else than a Foundation feature and cannot be used here.", "featureNotSpecialization": "This feature is used as something else than a Specialization feature and cannot be used here.", - "featureNotMastery": "This feature is used as something else than a Mastery feature and cannot be used here." + "featureNotMastery": "This feature is used as something else than a Mastery feature and cannot be used here.", + "beastformMissingEffect": "The Beastform is missing a Beastform Effect. Cannot be used." }, "Tooltip": { "openItemWorld": "Open Item World", diff --git a/module/applications/dialogs/beastformDialog.mjs b/module/applications/dialogs/beastformDialog.mjs index c7429e70..db9f9da5 100644 --- a/module/applications/dialogs/beastformDialog.mjs +++ b/module/applications/dialogs/beastformDialog.mjs @@ -6,13 +6,17 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat this.configData = configData; this.selected = null; + this.evolved = { form: null }; + this.hybrid = null; + + this._dragDrop = this._createDragDropHandlers(); } static DEFAULT_OPTIONS = { tag: 'form', classes: ['daggerheart', 'views', 'dh-style', 'beastform-selection'], position: { - width: 600, + width: 'auto', height: 'auto' }, actions: { @@ -23,7 +27,8 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat handler: this.updateBeastform, submitOnChange: true, submitOnClose: false - } + }, + dragDrop: [{ dragSelector: '.beastform-container', dropSelector: '.advanced-form-container' }] }; get title() { @@ -37,29 +42,73 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } }; - // _attachPartListeners(partId, htmlElement, options) { - // super._attachPartListeners(partId, htmlElement, options); + _createDragDropHandlers() { + return this.options.dragDrop.map(d => { + d.callbacks = { + dragstart: this._onDragStart.bind(this), + drop: this._onDrop.bind(this) + }; + return new foundry.applications.ux.DragDrop.implementation(d); + }); + } - // htmlElement.querySelector(''); - // } + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + this._dragDrop.forEach(d => d.bind(htmlElement)); + } async _prepareContext(_options) { const context = await super._prepareContext(_options); - context.beastformTiers = game.items.reduce((acc, x) => { - const tier = CONFIG.DH.GENERAL.tiers[x.system.tier]; - if (x.type !== 'beastform' || tier.value > this.configData.tierLimit) return acc; + context.selected = this.selected; + context.selectedBeastformEffect = this.selected?.effects?.find?.(x => x.type === 'beastform'); - if (!acc[tier.value]) acc[tier.value] = { label: game.i18n.localize(tier.label), values: {} }; - acc[tier.value].values[x.uuid] = { selected: this.selected == x.uuid, value: x }; + context.evolved = this.evolved; + context.hybrid = this.hybrid; - return acc; - }, {}); // Also get from compendium when added - context.canSubmit = this.selected; + const maximumDragTier = Math.max( + this.selected?.system?.evolved?.maximumTier ?? 0, + this.selected?.system?.hybrid?.maximumTier ?? 0 + ); + + const compendiumBeastforms = await game.packs.get(`daggerheart.beastforms`)?.getDocuments(); + context.beastformTiers = [...(compendiumBeastforms ? compendiumBeastforms : []), ...game.items].reduce( + (acc, x) => { + const tier = CONFIG.DH.GENERAL.tiersAlternate[x.system.tier]; + if (x.type !== 'beastform' || tier.id > this.configData.tierLimit) return acc; + + if (!acc[tier.id]) acc[tier.id] = { label: game.i18n.localize(tier.label), values: {} }; + + acc[tier.id].values[x.uuid] = { + selected: this.selected?.uuid == x.uuid, + value: x, + draggable: maximumDragTier ? x.system.tier <= maximumDragTier : false + }; + + return acc; + }, + {} + ); // Also get from compendium when added + + context.canSubmit = this.canSubmit(); return context; } + canSubmit() { + if (this.selected) { + switch (this.selected.system.beastformType) { + case 'normal': + return true; + case 'evolved': + return this.evolved.form; + } + } + + return false; + } + static updateBeastform(event, _, formData) { this.selected = foundry.utils.mergeObject(this.selected, formData.object); @@ -67,12 +116,26 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } static async selectBeastform(_, target) { - this.selected = this.selected === target.dataset.uuid ? null : target.dataset.uuid; - const beastform = this.selected ? await foundry.utils.fromUuid(this.selected) : null; - if (beastform && beastform.system.beastformType !== CONFIG.DH.ITEM.beastformTypes.normal.id) { - this.element.classList.add('expanded'); + this.element.querySelectorAll('.beastform-container ').forEach(element => { + if (element.dataset.uuid === target.dataset.uuid && this.selected?.uuid !== target.dataset.uuid) { + element.classList.remove('inactive'); + } else { + element.classList.add('inactive'); + } + }); + + const uuid = this.selected?.uuid === target.dataset.uuid ? null : target.dataset.uuid; + this.selected = uuid ? await foundry.utils.fromUuid(uuid) : null; + + if (this.selected && this.selected.system.beastformType !== CONFIG.DH.ITEM.beastformTypes.normal.id) { + this.element.querySelector('.advanced-container').classList.add('expanded'); } else { - this.element.classList.remove('expanded'); + this.element.querySelector('.advanced-container').classList.remove('expanded'); + } + + if (this.selected) { + if (this.selected.system.beastformType !== 'evolved') this.evolved.form = null; + if (this.selected.system.beastformType !== 'hybrid') this.hybrid = null; } this.render(); @@ -84,14 +147,55 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat /** @override */ _onClose(options = {}) { - if (!options.submitted) this.config = false; + if (!options.submitted) this.selected = null; } static async configure(configData) { return new Promise(resolve => { const app = new this(configData); - app.addEventListener('close', () => resolve(app.selected), { once: true }); + app.addEventListener( + 'close', + () => resolve({ selected: app.selected, evolved: app.evolved, hybrid: app.hybrid }), + { once: true } + ); app.render({ force: true }); }); } + + async _onDragStart(event) { + const target = event.currentTarget; + if (!this.selected) { + event.preventDefault(); + return; + } + + const draggedForm = await foundry.utils.fromUuid(target.dataset.uuid); + if (this.selected.system.beastformType === 'evolved') { + if (draggedForm.system.tier > this.selected.system.evolved.maximumTier) { + event.preventDefault(); + return; + } + } + if (this.selected.system.beastformType === 'hybrid') { + if (draggedForm.system.tier > this.selected.system.hybrid.maximumTier) { + event.preventDefault(); + return; + } + } + + event.dataTransfer.setData('text/plain', JSON.stringify(target.dataset)); + event.dataTransfer.setDragImage(target, 60, 0); + } + + async _onDrop(event) { + event.stopPropagation(); + const data = foundry.applications.ux.TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + + if (event.target.closest('.advanced-form-container.evolved')) { + this.evolved.form = item; + } + + this.render(); + } } diff --git a/module/applications/sheets/items/beastform.mjs b/module/applications/sheets/items/beastform.mjs index 17df8568..bb77e35d 100644 --- a/module/applications/sheets/items/beastform.mjs +++ b/module/applications/sheets/items/beastform.mjs @@ -1,4 +1,5 @@ import DHBaseItemSheet from '../api/base-item.mjs'; +import Tagify from '@yaireo/tagify'; export default class BeastformSheet extends DHBaseItemSheet { /**@inheritdoc */ @@ -30,6 +31,17 @@ export default class BeastformSheet extends DHBaseItemSheet { } }; + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + const advantageOnInput = htmlElement.querySelector('.advantageon-input'); + if (advantageOnInput) { + const tagifyElement = new Tagify(advantageOnInput); + tagifyElement.on('add', this.advantageOnAdd.bind(this)); + tagifyElement.on('remove', this.advantageOnRemove.bind(this)); + } + } + /**@inheritdoc */ async _prepareContext(_options) { const context = await super._prepareContext(_options); @@ -52,4 +64,16 @@ export default class BeastformSheet extends DHBaseItemSheet { return context; } + + async advantageOnAdd(event) { + await this.document.update({ + 'system.advantageOn': [...this.document.system.advantageOn, event.detail.data.value] + }); + } + + async advantageOnRemove(event) { + await this.document.update({ + 'system.advantageOn': this.document.system.advantageOn.filter(x => x !== event.detail.data.value) + }); + } } diff --git a/module/applications/ui/hotbar.mjs b/module/applications/ui/hotbar.mjs index b4ebc05c..9d102c6c 100644 --- a/module/applications/ui/hotbar.mjs +++ b/module/applications/ui/hotbar.mjs @@ -99,7 +99,7 @@ export default class DhHotbar extends foundry.applications.ui.Hotbar { async createItemMacro(data, slot) { const macro = await Macro.implementation.create({ - name: `${game.i18n.localize('Display')} ${name}`, + name: data.name, type: CONST.MACRO_TYPES.SCRIPT, img: data.img, command: `await game.system.api.applications.ui.DhHotbar.useItem("${data.uuid}");` @@ -109,7 +109,7 @@ export default class DhHotbar extends foundry.applications.ui.Hotbar { async createActionMacro(data, slot) { const macro = await Macro.implementation.create({ - name: `${game.i18n.localize('Display')} ${name}`, + name: data.data.name, type: CONST.MACRO_TYPES.SCRIPT, img: data.data.img, command: `await game.system.api.applications.ui.DhHotbar.useAction("${data.data.itemUuid}", "${data.data.id}");` @@ -119,7 +119,7 @@ export default class DhHotbar extends foundry.applications.ui.Hotbar { async createAttackMacro(data, slot) { const macro = await Macro.implementation.create({ - name: `${game.i18n.localize('Display')} ${name}`, + name: data.name, type: CONST.MACRO_TYPES.SCRIPT, img: data.img, command: `await game.system.api.applications.ui.DhHotbar.useAttack("${data.actorUuid}");` diff --git a/module/config/actorConfig.mjs b/module/config/actorConfig.mjs index d05dc81c..edf3a9f3 100644 --- a/module/config/actorConfig.mjs +++ b/module/config/actorConfig.mjs @@ -1,5 +1,6 @@ export const abilities = { agility: { + id: 'agility', label: 'DAGGERHEART.CONFIG.Traits.agility.name', verbs: [ 'DAGGERHEART.CONFIG.Traits.agility.verb.sprint', @@ -8,6 +9,7 @@ export const abilities = { ] }, strength: { + id: 'strength', label: 'DAGGERHEART.CONFIG.Traits.strength.name', verbs: [ 'DAGGERHEART.CONFIG.Traits.strength.verb.lift', @@ -16,6 +18,7 @@ export const abilities = { ] }, finesse: { + id: 'finesse', label: 'DAGGERHEART.CONFIG.Traits.finesse.name', verbs: [ 'DAGGERHEART.CONFIG.Traits.finesse.verb.control', @@ -24,6 +27,7 @@ export const abilities = { ] }, instinct: { + id: 'instinct', label: 'DAGGERHEART.CONFIG.Traits.instinct.name', verbs: [ 'DAGGERHEART.CONFIG.Traits.instinct.verb.perceive', @@ -32,6 +36,7 @@ export const abilities = { ] }, presence: { + id: 'presence', label: 'DAGGERHEART.CONFIG.Traits.presence.name', verbs: [ 'DAGGERHEART.CONFIG.Traits.presence.verb.charm', @@ -40,6 +45,7 @@ export const abilities = { ] }, knowledge: { + id: 'knowledge', label: 'DAGGERHEART.CONFIG.Traits.knowledge.name', verbs: [ 'DAGGERHEART.CONFIG.Traits.knowledge.verb.recall', diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 704a5401..bceec2a5 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -279,6 +279,25 @@ export const tiers = { } }; +export const tiersAlternate = { + 1: { + id: 1, + label: 'DAGGERHEART.GENERAL.Tiers.tier1' + }, + 2: { + id: 2, + label: 'DAGGERHEART.GENERAL.Tiers.tier2' + }, + 3: { + id: 3, + label: 'DAGGERHEART.GENERAL.Tiers.tier3' + }, + 4: { + id: 4, + label: 'DAGGERHEART.GENERAL.Tiers.tier4' + } +}; + export const diceTypes = { d4: 'd4', d6: 'd6', diff --git a/module/data/action/beastformAction.mjs b/module/data/action/beastformAction.mjs index 98d8053f..e8a5d779 100644 --- a/module/data/action/beastformAction.mjs +++ b/module/data/action/beastformAction.mjs @@ -10,10 +10,10 @@ export default class DhBeastformAction extends DHBaseAction { const abort = await this.handleActiveTransformations(); if (abort) return; - const beastformUuid = await BeastformDialog.configure(beastformConfig); - if (!beastformUuid) return; + const { selected, evolved, hybrid } = await BeastformDialog.configure(beastformConfig); + if (!selected) return; - await this.transform(beastformUuid); + await this.transform(selected, evolved, hybrid); } prepareBeastformConfig(config) { @@ -29,9 +29,26 @@ export default class DhBeastformAction extends DHBaseAction { }; } - async transform(beastformUuid) { - const beastform = await foundry.utils.fromUuid(beastformUuid); - this.actor.createEmbeddedDocuments('Item', [beastform.toObject()]); + async transform(selectedForm, evolvedData, hybridData) { + const formData = evolvedData?.form ? evolvedData.form.toObject() : selectedForm.toObject(); + const beastformEffect = formData.effects.find(x => x.type === 'beastform'); + if (!beastformEffect) { + ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect'); + return; + } + + if (evolvedData?.form) { + const evolvedForm = selectedForm.effects.find(x => x.type === 'beastform'); + if (!evolvedForm) { + ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect'); + return; + } + + beastformEffect.changes = [...beastformEffect.changes, ...evolvedForm.changes]; + formData.system.features = [...formData.system.features, ...selectedForm.system.features.map(x => x.uuid)]; + } + + this.actor.createEmbeddedDocuments('Item', [formData]); } async handleActiveTransformations() { diff --git a/module/data/item/beastform.mjs b/module/data/item/beastform.mjs index 2188305b..c43e5119 100644 --- a/module/data/item/beastform.mjs +++ b/module/data/item/beastform.mjs @@ -24,10 +24,11 @@ export default class DHBeastform extends BaseDataItem { choices: CONFIG.DH.ITEM.beastformTypes, initial: CONFIG.DH.ITEM.beastformTypes.normal.id }), - tier: new fields.StringField({ + tier: new fields.NumberField({ required: true, - choices: CONFIG.DH.GENERAL.tiers, - initial: CONFIG.DH.GENERAL.tiers.tier1.id + integer: true, + choices: CONFIG.DH.GENERAL.tiersAlternate, + initial: CONFIG.DH.GENERAL.tiersAlternate[1].id }), tokenImg: new fields.FilePathField({ initial: 'icons/svg/mystery-man.svg', @@ -43,21 +44,30 @@ export default class DHBeastform extends BaseDataItem { height: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }), width: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }) }), + mainTrait: new fields.StringField({ + required: true, + choices: CONFIG.DH.ACTOR.abilities, + initial: CONFIG.DH.ACTOR.abilities.agility.id + }), examples: new fields.StringField(), - advantageOn: new fields.StringField(), + advantageOn: new fields.ArrayField(new fields.StringField()), features: new ForeignDocumentUUIDArrayField({ type: 'Item' }), evolved: new fields.SchemaField({ - maximumTier: new fields.StringField({ + maximumTier: new fields.NumberField({ + integer: true, + choices: CONFIG.DH.GENERAL.tiersAlternate + }), + mainTraitBonus: new fields.NumberField({ required: true, - choices: CONFIG.DH.GENERAL.tiers, - initial: CONFIG.DH.GENERAL.tiers.tier1.id + integer: true, + min: 0, + initial: 0 }) }), hybrid: new fields.SchemaField({ - maximumTier: new fields.StringField({ - required: true, - choices: CONFIG.DH.GENERAL.tiers, - initial: CONFIG.DH.GENERAL.tiers.tier1.id, + maximumTier: new fields.NumberField({ + integer: true, + choices: CONFIG.DH.GENERAL.tiersAlternate, label: 'DAGGERHEART.ITEMS.Beastform.FIELDS.evolved.maximumTier.label' }), beastformOptions: new fields.NumberField({ required: true, integer: true, initial: 2, min: 2 }), @@ -92,7 +102,10 @@ export default class DHBeastform extends BaseDataItem { const beastformEffect = this.parent.effects.find(x => x.type === 'beastform'); await beastformEffect.updateSource({ - changes: [...beastformEffect.changes, { key: 'system.advantageSources', mode: 2, value: this.advantageOn }], + changes: [ + ...beastformEffect.changes, + { key: 'system.advantageSources', mode: 2, value: this.advantageOn.join(', ') } + ], system: { characterTokenData: { tokenImg: this.parent.parent.prototypeToken.texture.src, diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 336ecf5b..eac03654 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -1,80 +1,10 @@ import { diceTypes, getDiceSoNicePresets, range } from '../config/generalConfig.mjs'; import Tagify from '@yaireo/tagify'; -export const loadCompendiumOptions = async compendiums => { - const compendiumValues = []; - - for (var compendium of compendiums) { - const values = await getCompendiumOptions(compendium); - compendiumValues.push(values); - } - - return compendiumValues; -}; - -const getCompendiumOptions = async compendium => { - const compendiumPack = await game.packs.get(compendium); - - const values = []; - for (var value of compendiumPack.index) { - const document = await compendiumPack.getDocument(value._id); - values.push(document); - } - - return values; -}; - -export const getWidthOfText = (txt, fontsize, allCaps, bold) => { - const text = allCaps ? txt.toUpperCase() : txt; - if (getWidthOfText.c === undefined) { - getWidthOfText.c = document.createElement('canvas'); - getWidthOfText.ctx = getWidthOfText.c.getContext('2d'); - } - var fontspec = `${bold ? 'bold' : ''} ${fontsize}px` + ' ' + 'Signika, sans-serif'; - if (getWidthOfText.ctx.font !== fontspec) getWidthOfText.ctx.font = fontspec; - - return getWidthOfText.ctx.measureText(text).width; -}; - -export const padArray = (arr, len, fill) => { - return arr.concat(Array(len).fill(fill)).slice(0, len); -}; - -export const getTier = (level, asNr) => { - switch (Math.floor((level + 1) / 3)) { - case 1: - return asNr ? 1 : 'tier1'; - case 2: - return asNr ? 2 : 'tier2'; - case 3: - return asNr ? 3 : 'tier3'; - default: - return asNr ? 0 : 'tier0'; - } -}; - export const capitalize = string => { return string.charAt(0).toUpperCase() + string.slice(1); }; -export const getPathValue = (path, entity, numeric) => { - const pathValue = foundry.utils.getProperty(entity, path); - if (pathValue) return numeric ? Number.parseInt(pathValue) : pathValue; - - return numeric ? Number.parseInt(path) : path; -}; - -export const generateId = (title, length) => { - const id = title - .split(' ') - .map((w, i) => { - const p = w.slugify({ replacement: '', strict: true }); - return i ? p.titleCase() : p; - }) - .join(''); - return Number.isNumeric(length) ? id.slice(0, length).padEnd(length, '0') : id; -}; - export function rollCommandToJSON(text) { if (!text) return {}; diff --git a/styles/less/dialog/beastform/sheet.less b/styles/less/dialog/beastform/sheet.less index 6d8cba9e..5635fed3 100644 --- a/styles/less/dialog/beastform/sheet.less +++ b/styles/less/dialog/beastform/sheet.less @@ -3,32 +3,37 @@ .appTheme({ &.beastform-selection { - .beastforms-container .beastforms-tier .beastform-container .beastform-title { - background-image: url('../assets/parchments/dh-parchment-dark.png'); + .beastforms-outer-container .beastform-title { + background-image: url('../assets/parchments/dh-parchment-light.png'); } } }, {}); .application.daggerheart.dh-style.views.beastform-selection { - transition: all 0.3s ease; - - &.expanded { - width: 900px !important; - - .beastforms-outer-container .advanced-container { - max-width: 300px; - } - } - .beastforms-outer-container { display: flex; overflow: hidden; + .beastform-title { + position: absolute; + top: 4px; + padding: 0 2px; + display: flex; + flex-wrap: wrap; + text-align: center; + font-size: 16px; + margin: 0 4px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + color: light-dark(@dark, @beige); + background-image: url('../assets/parchments/dh-parchment-dark.png'); + } + .beastforms-container { display: flex; flex-direction: column; gap: 4px; - max-width: 566px; + width: 600px; .beastforms-tier { display: grid; @@ -42,48 +47,84 @@ border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; cursor: pointer; + width: 120px; + height: 120px; &.inactive { opacity: 0.4; + cursor: default; + } + + &.draggable { + cursor: pointer; + filter: drop-shadow(0 0 15px light-dark(@dark-blue, @golden)); } img { width: 100%; border-radius: 6px; } - - .beastform-title { - position: absolute; - top: 4px; - display: flex; - flex-wrap: wrap; - font-size: 16px; - margin: 0 4px; - border: 1px solid light-dark(@dark-blue, @golden); - border-radius: 6px; - color: light-dark(@dark, @beige); - background-image: url('../assets/parchments/dh-parchment-light.png'); - } } } } .advanced-container { - max-width: 0; - transition: all 0.3s ease; + width: 0; + display: flex; + flex-direction: column; + align-items: center; + padding-top: 12px; + transition: width 0.3s ease; + + &.expanded { + width: 300px; + } + + .advanced-form-container { + position: relative; + display: flex; + justify-content: center; + border: 1px solid light-dark(#18162e, #f3c267); + border-radius: 6px; + cursor: pointer; + width: 120px; + height: 120px; + align-items: center; + text-align: center; + + .empty-form { + display: flex; + flex-direction: column; + align-items: center; + } + } + + .form-features { + display: flex; + flex-direction: column; + gap: 8px; + padding: 0 16px; + margin-top: 8px; + + .form-feature { + display: flex; + flex-direction: column; + gap: 4px; + padding: 0 2px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + color: light-dark(@dark, @beige); + background-image: url('../assets/parchments/dh-parchment-dark.png'); + + h4 { + text-align: center; + margin: 0; + } + } + } } } - // .advanced-container { - // position: absolute; - // top: 0; - // right: -300px; - // height: 100%; - // width: 300px; - // border: 1px solid @golden; - // background: url("../systems/daggerheart/assets/parchments/dh-parchment-light.png") no-repeat center; - // } - footer { margin-top: 8px; display: flex; diff --git a/styles/less/sheets/index.less b/styles/less/sheets/index.less index 89370ec6..3470de37 100644 --- a/styles/less/sheets/index.less +++ b/styles/less/sheets/index.less @@ -18,6 +18,7 @@ @import './actors/environment/header.less'; @import './actors/environment/sheet.less'; +@import './items/beastform.less'; @import './items/class.less'; @import './items/domain-card.less'; @import './items/feature.less'; diff --git a/styles/less/sheets/items/beastform.less b/styles/less/sheets/items/beastform.less new file mode 100644 index 00000000..162c4925 --- /dev/null +++ b/styles/less/sheets/items/beastform.less @@ -0,0 +1,9 @@ +.application.sheet.daggerheart.dh-style.beastform { + .settings.tab { + .advantage-on-section { + display: flex; + flex-direction: column; + margin-top: 10px; + } + } +} diff --git a/system.json b/system.json index 39b1c37f..efafdebd 100644 --- a/system.json +++ b/system.json @@ -138,6 +138,15 @@ "type": "Item", "private": false, "flags": {} + }, + { + "name": "beastforms", + "label": "Beastforms", + "system": "daggerheart", + "path": "packs/beastforms.db", + "type": "Item", + "private": false, + "flags": {} } ], "packFolders": [ @@ -151,7 +160,7 @@ "name": "Character Options", "sorting": "m", "color": "#000000", - "packs": ["ancestries", "communities", "classes", "subclasses", "domains"] + "packs": ["ancestries", "communities", "classes", "subclasses", "domains", "beastforms"] }, { "name": "Items", diff --git a/templates/dialogs/beastformDialog.hbs b/templates/dialogs/beastformDialog.hbs index 0988e4f8..f3b21dac 100644 --- a/templates/dialogs/beastformDialog.hbs +++ b/templates/dialogs/beastformDialog.hbs @@ -5,7 +5,7 @@
{{tier.label}} {{#each tier.values as |form uuid|}} -
+
{{form.value.name}}
@@ -13,8 +13,29 @@
{{/each}} -
- Test +
+ {{#if (eq selected.system.beastformType 'evolved')}} +

{{localize "DAGGERHEART.ITEMS.Beastform.evolve"}}

+
+ {{#if evolved.form}} +
{{concat (localize "DAGGERHEART.CONFIG.BeastformType.evolved") " " evolved.form.name}}
+ + {{else}} +
+ + +
+ {{/if}} +
+
+ {{#if selectedBeastformEffect}} +
+

{{localize "DAGGERHEART.ITEMS.Beastform.evolvedFeatureTitle"}}

+
{{{selectedBeastformEffect.description}}}
+
+ {{/if}} +
+ {{/if}}
diff --git a/templates/sheets/items/beastform/advanced.hbs b/templates/sheets/items/beastform/advanced.hbs index b068834f..aefec003 100644 --- a/templates/sheets/items/beastform/advanced.hbs +++ b/templates/sheets/items/beastform/advanced.hbs @@ -6,9 +6,11 @@ {{formGroup systemFields.beastformType value=source.system.beastformType localize=true blank=false}} {{#if (eq source.system.beastformType 'evolved')}} -
+
{{localize "DAGGERHEART.CONFIG.BeastformType.evolved"}} + {{formGroup systemFields.evolved.fields.maximumTier value=source.system.evolved.maximumTier localize=true blank=false}} + {{formGroup systemFields.evolved.fields.mainTraitBonus value=source.system.evolved.mainTraitBonus localize=true}}
{{/if}} diff --git a/templates/sheets/items/beastform/settings.hbs b/templates/sheets/items/beastform/settings.hbs index 4a1c4006..d566da0d 100644 --- a/templates/sheets/items/beastform/settings.hbs +++ b/templates/sheets/items/beastform/settings.hbs @@ -3,12 +3,22 @@ data-tab='{{tabs.settings.id}}' data-group='{{tabs.settings.group}}' > -
+ {{#if (eq source.system.beastformType 'evolved')}} {{formGroup systemFields.tier value=source.system.tier localize=true}} - {{formGroup systemFields.examples value=source.system.examples localize=true}} -
+ {{else}} +
+ {{formGroup systemFields.tier value=source.system.tier localize=true}} + {{formGroup systemFields.mainTrait value=source.system.mainTrait blank=false localize=true}} +
+ + {{formGroup systemFields.examples value=source.system.examples localize=true}} + +
+ + +
+ {{/if}} - {{formGroup systemFields.advantageOn value=source.system.advantageOn localize=true}}
{{localize "DAGGERHEART.ITEMS.Beastform.tokenTitle"}}