From edaf5df9e0926a6aeaaae887fe58fac3605ad152 Mon Sep 17 00:00:00 2001 From: Dapoolp Date: Tue, 10 Jun 2025 23:41:25 +0200 Subject: [PATCH] actions types - attack roll --- daggerheart.mjs | 8 +- lang/en.json | 45 ++- module/applications/config/Action.mjs | 152 +++++++-- .../applications/sheets/daggerheart-sheet.mjs | 1 + .../applications/sheets/items/domainCard.mjs | 3 +- module/applications/sheets/items/feature.mjs | 7 +- module/applications/sheets/items/weapon.mjs | 82 +++++ module/applications/sheets/pc.mjs | 20 ++ module/config/actionConfig.mjs | 38 ++- module/config/generalConfig.mjs | 25 ++ module/data/_module.mjs | 1 + module/data/action.mjs | 123 ------- module/data/action/_module.mjs | 13 + module/data/action/action.mjs | 306 ++++++++++++++++++ module/data/action/damage.mjs | 26 ++ module/data/fields/actionField.mjs | 11 + .../data/fields/foreignDocumentUUIDField.mjs | 4 +- module/data/item/_module.mjs | 2 +- module/data/item/domainCard.mjs | 2 +- module/data/item/feature.mjs | 2 +- module/data/item/weapon.mjs | 5 +- module/documents/item.mjs | 49 +++ styles/application.less | 31 ++ styles/daggerheart.less | 35 ++ templates/sheets/pc/sections/inventory.hbs | 2 +- templates/views/action.hbs | 44 ++- templates/views/actionSelect.hbs | 13 + templates/views/actionType.hbs | 13 + templates/views/actionTypes/cost.hbs | 21 ++ templates/views/actionTypes/damage.hbs | 36 +++ templates/views/actionTypes/effect.hbs | 19 ++ templates/views/actionTypes/range-target.hbs | 11 + templates/views/actionTypes/roll.hbs | 10 + templates/views/actionTypes/target.hbs | 8 + templates/views/actionTypes/uses.hbs | 12 + 35 files changed, 1015 insertions(+), 165 deletions(-) delete mode 100755 module/data/action.mjs create mode 100644 module/data/action/_module.mjs create mode 100644 module/data/action/action.mjs create mode 100644 module/data/action/damage.mjs create mode 100644 module/data/fields/actionField.mjs create mode 100644 templates/views/actionSelect.hbs create mode 100644 templates/views/actionType.hbs create mode 100644 templates/views/actionTypes/cost.hbs create mode 100644 templates/views/actionTypes/damage.hbs create mode 100644 templates/views/actionTypes/effect.hbs create mode 100644 templates/views/actionTypes/range-target.hbs create mode 100644 templates/views/actionTypes/roll.hbs create mode 100644 templates/views/actionTypes/target.hbs create mode 100644 templates/views/actionTypes/uses.hbs diff --git a/daggerheart.mjs b/daggerheart.mjs index 58600ad4..eb846881 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -282,6 +282,12 @@ const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/components/card-preview.hbs', 'systems/daggerheart/templates/views/levelup/parts/selectable-card-preview.hbs', 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs', - 'systems/daggerheart/templates/ui/combat/combatTrackerSection.hbs' + 'systems/daggerheart/templates/ui/combat/combatTrackerSection.hbs', + 'systems/daggerheart/templates/views/actionTypes/damage.hbs', + 'systems/daggerheart/templates/views/actionTypes/uses.hbs', + 'systems/daggerheart/templates/views/actionTypes/roll.hbs', + 'systems/daggerheart/templates/views/actionTypes/cost.hbs', + 'systems/daggerheart/templates/views/actionTypes/range-target.hbs', + 'systems/daggerheart/templates/views/actionTypes/effect.hbs' ]); }; diff --git a/lang/en.json b/lang/en.json index 39d5225c..d03ee946 100755 --- a/lang/en.json +++ b/lang/en.json @@ -145,6 +145,7 @@ } }, "General": { + "Name": "Name", "Hope": "Hope", "Fear": "Fear", "Duality": "Duality", @@ -449,6 +450,10 @@ "twoHanded": "Two-Handed" }, "Range": { + "self": { + "name": "Self", + "description": "means yourself." + }, "melee": { "name": "Melee", "description": "means a character is within touching distance of the target. PCs can generally touch targets up to a few feet away from them, but melee range may be greater for especially large NPCs." @@ -1202,10 +1207,48 @@ } } }, - "Tooltip": { "openItemWorld": "Open Item World", "delete": "Delete" + }, + "Actions": { + "Types": { + "Attack": { + "Name": "Attack" + }, + "Spellcast": { + "Name": "Spellcast" + }, + "Resource": { + "Name": "Resource" + }, + "Damage": { + "Name": "Damage" + }, + "Healing": { + "Name": "Healing" + }, + "Summon": { + "Name": "Summon" + }, + "Effect": { + "Name": "Effect" + }, + "Macro": { + "Name": "Macro" + } + } + }, + "RollTypes": { + "ability": { + "name": "Ability" + }, + "weapon": { + "name": "Weapon" + }, + "spellcast": { + "name": "SpellCast" + } } } } diff --git a/module/applications/config/Action.mjs b/module/applications/config/Action.mjs index 0053fc64..94e68f13 100644 --- a/module/applications/config/Action.mjs +++ b/module/applications/config/Action.mjs @@ -4,9 +4,10 @@ const { ApplicationV2 } = foundry.applications.api; export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { constructor(action) { super({}); - + this.action = action; this.openSection = null; + // console.log(this.action) } // get title(){ @@ -19,11 +20,19 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { classes: ['daggerheart', 'views', 'action'], position: { width: 600, height: 'auto' }, actions: { - toggleSection: this.toggleSection + toggleSection: this.toggleSection, + addEffect: this.addEffect, + removeEffect: this.removeEffect, + addElement: this.addElement, + removeElement: this.removeElement, + editEffect: this.editEffect, + addDamage: this.addDamage, + removeDamage: this.removeDamage }, form: { handler: this.updateForm, - closeOnSubmit: true + submitOnChange: true, + closeOnSubmit: false } }; @@ -36,16 +45,19 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { _getTabs() { const tabs = { - effects: { active: true, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' }, - useage: { active: false, cssClass: '', group: 'primary', id: 'useage', icon: null, label: 'Useage' }, - conditions: { - active: false, - cssClass: '', - group: 'primary', - id: 'conditions', - icon: null, - label: 'Conditions' - } + base: { active: true, cssClass: '', group: 'primary', id: 'base', icon: null, label: 'Base' }, + config: { active: false, cssClass: '', group: 'primary', id: 'config', icon: null, label: 'Configuration' }, + effect: { active: false, cssClass: '', group: 'primary', id: 'effect', icon: null, label: 'Effect' }, + // effects: { active: true, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' }, + // useage: { active: false, cssClass: '', group: 'primary', id: 'useage', icon: null, label: 'Useage' }, + // conditions: { + // active: false, + // cssClass: '', + // group: 'primary', + // id: 'conditions', + // icon: null, + // label: 'Conditions' + // } }; for (const v of Object.values(tabs)) { @@ -58,9 +70,15 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { async _prepareContext(_options) { const context = await super._prepareContext(_options, 'action'); + context.source = this.action.toObject(false); context.openSection = this.openSection; context.tabs = this._getTabs(); - + context.config = SYSTEM; + context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id)); + context.hasBaseDamage = !!this.action.parent.damage; + context.getRealIndex = this.getRealIndex.bind(this); + + console.log(context, this.action) return context; } @@ -69,15 +87,103 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { this.render(true); } - static async updateForm(event, _, formData) { - const data = foundry.utils.expandObject( - foundry.utils.mergeObject(this.action.toObject(), foundry.utils.expandObject(formData.object)) - ); - const newActions = this.action.parent.actions.map(x => x.toObject()); - if (!newActions.findSplice(x => x.id === data.id, data)) { - newActions.push(data); - } + getRealIndex(index) { + const data = this.action.toObject(false); + return data.damage.parts.find(d => d.base) ? index - 1 : index; + } + + _prepareSubmitData(event, formData) { + const submitData = foundry.utils.expandObject(formData.object); + // this.element.querySelectorAll("fieldset[disabled] :is(input, select)").forEach(input => { + // foundry.utils.setProperty(submitData, input.name, input.value); + // }); + return submitData; + } + + static async updateForm(event, _, formData) { + const submitData = this._prepareSubmitData(event, formData), + data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)), + newActions = this.action.parent.actions.map(x => x.toObject()); // Find better way + if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data); + const updates = await this.action.parent.parent.update({ 'system.actions': newActions }); + if(!updates) return; + this.action = updates.system.actions[this.action.index]; + this.render(); + } + + /* cleanData(data) { + for(let k in data) { + if(typeof data[k] === 'object' && !Array.isArray(data[k])) { + if(!isNaN(Object.keys(data[k])[0])) data[k] = Object.values(data[k]); + } + } + return data; + } */ + + static addElement(event) { + const data = this.action.toObject(), + key = $(event.target).closest('.action-category-data').data('key'); + if ( !this.action[key] ) return; + data[key].push({}); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static removeElement(event) { + const data = this.action.toObject(), + key = $(event.target).closest('.action-category-data').data('key'), + index = $(event.target).data('index'); + data[key].splice(index, 1); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static addDamage(event) { + if ( !this.action.damage.parts ) return; + const data = this.action.toObject(); + data.damage.parts.push({}); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static removeDamage(event) { + if ( !this.action.damage.parts ) return; + const data = this.action.toObject(), + index = $(event.target).data('index'); + data.damage.parts.splice(index, 1); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static async addEffect(event) { + if ( !this.action.effects ) return; + // console.log(this, this.action.item) + const effectData = this._addEffectData.bind(this)(), + [created] = await this.action.item.createEmbeddedDocuments("ActiveEffect", [effectData], { render: false }), + data = this.action.toObject(); + data.effects.push( { '_id': created._id } ) + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + /** + * The data for a newly created applied effect. + * @returns {object} + * @protected + */ + _addEffectData() { + return { + name: this.action.item.name, + img: this.action.item.img, + origin: this.action.item.uuid, + transfer: false + }; + } + + static removeEffect(event) { + if ( !this.action.effects ) return; + const index = $(event.target).data('index'), + effectId = this.action.effects[index]._id; + this.constructor.removeElement.bind(this)(event); + this.action.item.deleteEmbeddedDocuments("ActiveEffect", [effectId]); + } + + static editEffect(event) { - await this.action.parent.parent.update({ 'system.actions': newActions }); } } diff --git a/module/applications/sheets/daggerheart-sheet.mjs b/module/applications/sheets/daggerheart-sheet.mjs index 635d2434..48eaa257 100644 --- a/module/applications/sheets/daggerheart-sheet.mjs +++ b/module/applications/sheets/daggerheart-sheet.mjs @@ -27,6 +27,7 @@ export default function DhpApplicationMixin(Base) { async _prepareContext(_options, objectPath = 'document') { const context = await super._prepareContext(_options); + console.log(this, objectPath) context.source = this[objectPath].toObject(); context.fields = this[objectPath].schema.fields; context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {}; diff --git a/module/applications/sheets/items/domainCard.mjs b/module/applications/sheets/items/domainCard.mjs index 3f26de74..e15f1751 100644 --- a/module/applications/sheets/items/domainCard.mjs +++ b/module/applications/sheets/items/domainCard.mjs @@ -1,4 +1,4 @@ -import DHAction from '../../../data/action.mjs'; +import DHAction from '../../../data/action/action.mjs'; import DHActionConfig from '../../config/Action.mjs'; import DaggerheartSheet from '../daggerheart-sheet.mjs'; @@ -79,6 +79,7 @@ export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) { const action = await new DHAction( { id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0] + 1 : 1}` + // id: foundry.utils.randomID() }, { parent: this.document diff --git a/module/applications/sheets/items/feature.mjs b/module/applications/sheets/items/feature.mjs index cae4dc02..3e0bd17e 100644 --- a/module/applications/sheets/items/feature.mjs +++ b/module/applications/sheets/items/feature.mjs @@ -1,4 +1,4 @@ -import DHAction from '../../../data/action.mjs'; +import DHAction from '../../../data/action/action.mjs'; import DHActionConfig from '../../config/Action.mjs'; import DaggerheartSheet from '../daggerheart-sheet.mjs'; @@ -132,7 +132,10 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) { } static async addAction() { - const action = await new DHAction({ img: this.document.img }, { parent: this.document }); + const action = new DHAction({ + id: foundry.utils.randomID(), + // img: this.document.img + }, { parent: this.document }); await this.document.update({ 'system.actions': [...this.document.system.actions, action] }); await new DHActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render( true diff --git a/module/applications/sheets/items/weapon.mjs b/module/applications/sheets/items/weapon.mjs index 90cde394..228b0614 100644 --- a/module/applications/sheets/items/weapon.mjs +++ b/module/applications/sheets/items/weapon.mjs @@ -1,4 +1,6 @@ +import DHActionConfig from '../../config/Action.mjs'; import DaggerheartSheet from '../daggerheart-sheet.mjs'; +import { actionsTypes } from '../../../data/_module.mjs'; const { ItemSheetV2 } = foundry.applications.sheets; export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { @@ -6,6 +8,11 @@ export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { tag: 'form', classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'weapon'], position: { width: 600 }, + actions: { + addAction: this.addAction, + editAction: this.editAction, + removeAction: this.removeAction + }, form: { handler: this.updateForm, submitOnChange: true, @@ -17,6 +24,10 @@ export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { header: { template: 'systems/daggerheart/templates/sheets/items/weapon/header.hbs' }, tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, description: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-description.hbs' }, + actions: { + template: 'systems/daggerheart/templates/sheets/global/tabs/tab-actions.hbs', + scrollable: ['.actions'] + }, settings: { template: 'systems/daggerheart/templates/sheets/items/weapon/settings.hbs', scrollable: ['.settings'] @@ -32,6 +43,14 @@ export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { icon: null, label: 'DAGGERHEART.Sheets.Feature.Tabs.Description' }, + actions: { + active: false, + cssClass: '', + group: 'primary', + id: 'actions', + icon: null, + label: 'DAGGERHEART.Sheets.Feature.Tabs.Actions' + }, settings: { active: false, cssClass: '', @@ -55,4 +74,67 @@ export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { await this.document.update(formData.object); this.render(); } + + static async selectActionType() { + const content = await foundry.applications.handlebars.renderTemplate( + "systems/daggerheart/templates/views/actionType.hbs", + {types: SYSTEM.ACTIONS.actionTypes} + ), + title = 'Select Action Type', + type = 'form', + data = {}; + return Dialog.prompt({ + title, + label: title, + content, type, + callback: html => { + const form = html[0].querySelector("form"), + fd = new foundry.applications.ux.FormDataExtended(form); + foundry.utils.mergeObject(data, fd.object, { inplace: true }); + // if (!data.name?.trim()) data.name = game.i18n.localize(SYSTEM.ACTIONS.actionTypes[data.type].name); + return data; + }, + rejectClose: false + }) + } + + static async addAction() { + // const actionType = await WeaponSheet.selectActionType(); + const actionType = await WeaponSheet.selectActionType(), + actionIndexes = this.document.system.actions.map(x => x._id.split('-')[2]).sort((a, b) => a - b) + try { + // const cls = DHAction, + const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack, + action = new cls( + { + // id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0] + 1 : 1}` + _id: foundry.utils.randomID(), + type: actionType.type, + name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name), + ...cls.getSourceConfig(this.document) + }, + { + parent: this.document + } + ); + await this.document.update({ 'system.actions': [...this.document.system.actions, action] }); + await new DHActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render(true); + } catch (error) { + console.log(error) + } + } + + static async editAction(_, button) { + const action = this.document.system.actions[button.dataset.index]; + await new DHActionConfig(action).render(true); + } + + static async removeAction(event, button) { + event.stopPropagation(); + await this.document.update({ + 'system.actions': this.document.system.actions.filter( + (_, index) => index !== Number.parseInt(button.dataset.index) + ) + }); + } } diff --git a/module/applications/sheets/pc.mjs b/module/applications/sheets/pc.mjs index b38195d5..8f0df9fa 100644 --- a/module/applications/sheets/pc.mjs +++ b/module/applications/sheets/pc.mjs @@ -46,6 +46,7 @@ export default class PCSheet extends DaggerheartSheet(ActorSheetV2) { selectAncestry: this.selectAncestry, selectCommunity: this.selectCommunity, viewObject: this.viewObject, + useItem: this.useItem, useFeature: this.useFeature, takeShortRest: this.takeShortRest, takeLongRest: this.takeLongRest, @@ -184,6 +185,9 @@ export default class PCSheet extends DaggerheartSheet(ActorSheetV2) { .querySelectorAll('.experience-value') .forEach(element => element.addEventListener('change', this.experienceValueChange.bind(this))); htmlElement.querySelector('.level-value').addEventListener('change', this.onLevelChange.bind(this)); + htmlElement + .querySelectorAll('[data-item-id]') + .forEach(element => element.addEventListener('contextmenu', this.editItem.bind(this))); } async _prepareContext(_options) { @@ -738,6 +742,12 @@ export default class PCSheet extends DaggerheartSheet(ActorSheetV2) { (await game.packs.get('daggerheart.communities'))?.render(true); } + static useItem(event) { + const uuid = event.target.closest('[data-item-id]').dataset.itemId, + item = this.document.items.find(i => i.uuid === uuid); + item.use(event); + } + static async viewObject(_, button) { const object = await fromUuid(button.dataset.value); if (!object) return; @@ -750,6 +760,16 @@ export default class PCSheet extends DaggerheartSheet(ActorSheetV2) { object.sheet.render(true); } + editItem(event) { + const uuid = event.target.closest('[data-item-id]').dataset.itemId, + item = this.document.items.find(i => i.uuid === uuid); + if (!item) return; + + if (item.sheet.editMode) item.sheet.editMode = false; + + item.sheet.render(true); + } + static async takeShortRest() { await new DhpDowntime(this.document, true).render(true); await this.minimize(); diff --git a/module/config/actionConfig.mjs b/module/config/actionConfig.mjs index 792df85d..0bddd315 100644 --- a/module/config/actionConfig.mjs +++ b/module/config/actionConfig.mjs @@ -1,7 +1,43 @@ export const actionTypes = { + attack: { + id: 'attack', + name: 'DAGGERHEART.Actions.Types.Attack.Name', + icon: "fa-swords" + }, + spellcast: { + id: 'spellcast', + name: 'DAGGERHEART.Actions.Types.Spellcast.Name', + icon: "fa-book-sparkles" + }, + resource: { + id: 'resource', + name: 'DAGGERHEART.Actions.Types.Resource.Name', + icon: "fa-honey-pot" + }, damage: { id: 'damage', - name: 'DAGGERHEART.Effects.Types.Health.Name' + name: 'DAGGERHEART.Actions.Types.Damage.Name', + icon: "fa-bone-break" + }, + healing: { + id: 'healing', + name: 'DAGGERHEART.Actions.Types.Healing.Name', + icon: "fa-kit-medical" + }, + summon: { + id: 'summon', + name: 'DAGGERHEART.Actions.Types.Summon.Name', + icon: "fa-ghost" + }, + effect: { + id: 'effect', + name: 'DAGGERHEART.Actions.Types.Effect.Name', + icon: "fa-person-rays" + }, + macro: { + id: 'macro', + name: 'DAGGERHEART.Actions.Types.Macro.Name', + icon: "fa-scroll" } }; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index fb596347..d56c4ce0 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -1,4 +1,9 @@ export const range = { + self: { + label: 'DAGGERHEART.Range.self.name', + description: 'DAGGERHEART.Range.self.description', + distance: 0 + }, melee: { label: 'DAGGERHEART.Range.melee.name', description: 'DAGGERHEART.Range.melee.description', @@ -247,6 +252,11 @@ export const diceTypes = { d20: 'd20' }; +export const multiplierTypes = { + proficiency: 'Proficiency', + spellcast: 'Spellcast' +}; + export const getDiceSoNicePresets = () => { const { diceSoNice } = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance); @@ -311,3 +321,18 @@ export const abilityCosts = { label: 'Stress' } }; + +export const rollTypes = { + weapon: { + id: 'weapon', + label: 'DAGGERHEART.RollTypes.weapon.name' + }, + spellcast: { + id: 'spellcast', + label: 'DAGGERHEART.RollTypes.spellcast.name' + }, + ability: { + id: 'ability', + label: 'DAGGERHEART.RollTypes.ability.name' + } +} diff --git a/module/data/_module.mjs b/module/data/_module.mjs index b70b5a23..8167ff14 100644 --- a/module/data/_module.mjs +++ b/module/data/_module.mjs @@ -7,4 +7,5 @@ export { default as DhpAdversary } from './adversary.mjs'; export { default as DhpEnvironment } from './environment.mjs'; export * as items from './item/_module.mjs'; +export { actionsTypes } from './action/_module.mjs'; export * as messages from './chat-message/_modules.mjs'; diff --git a/module/data/action.mjs b/module/data/action.mjs deleted file mode 100755 index 26dda7f3..00000000 --- a/module/data/action.mjs +++ /dev/null @@ -1,123 +0,0 @@ -export default class DHAction extends foundry.abstract.DataModel { - static defineSchema() { - const fields = foundry.data.fields; - return { - id: new fields.DocumentIdField(), - name: new fields.StringField({ initial: 'New Action' }), - damage: new fields.SchemaField({ - type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }), - value: new fields.StringField({}) - }), - healing: new fields.SchemaField({ - type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }), - value: new fields.StringField() - }), - conditions: new fields.ArrayField( - new fields.SchemaField({ - name: new fields.StringField(), - icon: new fields.StringField(), - description: new fields.StringField() - }) - ), - cost: new fields.SchemaField({ - type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }), - value: new fields.NumberField({ nullable: true, initial: null }) - }), - target: new fields.SchemaField({ - type: new fields.StringField({ - choices: SYSTEM.ACTIONS.targetTypes, - initial: SYSTEM.ACTIONS.targetTypes.other.id - }) - }) - }; - } -} - -const fields = foundry.data.fields; - -export class DHBaseAction extends foundry.abstract.DataModel { - static defineSchema() { - return { - _id: new fields.DocumentIdField(), - type: new fields.StringField({ blank: false, required: true, readOnly: true, initial: () => '' }), - name: new fields.StringField({ initial: 'New Action' }), - // description: new fields.StringField({}), - // shortDescription: new fields.StringField({}), - cost: new fields.SchemaField({ - type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }), - value: new fields.NumberField({ nullable: true, initial: null }) - }), - uses: new fields.SchemaField({ - value: new fields.NumberField({ nullable: true, initial: null }), - max: new fields.NumberField({ nullable: true, initial: null }), - recovery: new fields.StringField({ - // choices: SYSTEM.ACTIONS.targetTypes, - // initial: SYSTEM.ACTIONS.targetTypes.other.id - }) - }), - duration: new fields.SchemaField({ - value: new fields.NumberField({ nullable: true, initial: null }), - units: new fields.StringField({required: true, blank: false, initial: "instant"}) - }), - target: new fields.SchemaField({ - type: new fields.StringField({ - choices: SYSTEM.ACTIONS.targetTypes, - initial: SYSTEM.ACTIONS.targetTypes.other.id - }) - }) - } - } -} - -export class DHAttackAction extends DHBaseAction { - static defineSchema() { - return { - ...super.defineSchema(), - attack: new fields.SchemaField({}), - damage: new fields.SchemaField({}) - } - } -} - -export class DHDamageAction extends DHBaseAction { - static defineSchema() { - return { - ...super.defineSchema(), - damage: new fields.SchemaField({}) - } - } -} - -export class DHHealingAction extends DHBaseAction { - static defineSchema() { - return { - ...super.defineSchema(), - healing: new fields.SchemaField({}) - } - } -} - -export class DHSummonAction extends DHBaseAction { - static defineSchema() { - return { - ...super.defineSchema(), - healing: new fields.SchemaField({}) - } - } -} - -export class DHEffectAction extends DHBaseAction { - static defineSchema() { - return { - ...super.defineSchema() - } - } -} - -export class DHMacroAction extends DHBaseAction { - static defineSchema() { - return { - ...super.defineSchema() - } - } -} diff --git a/module/data/action/_module.mjs b/module/data/action/_module.mjs new file mode 100644 index 00000000..ccde347a --- /dev/null +++ b/module/data/action/_module.mjs @@ -0,0 +1,13 @@ +import { DHAttackAction, DHBaseAction, DHDamageAction, DHEffectAction, DHHealingAction, DHMacroAction, DHResourceAction, DHSpellCastAction, DHSummonAction } from "./action.mjs"; + +export const actionsTypes = { + base: DHBaseAction, + attack: DHAttackAction, + spellcast: DHSpellCastAction, + resource: DHResourceAction, + damage: DHDamageAction, + healing: DHHealingAction, + summon: DHSummonAction, + effect: DHEffectAction, + macro: DHMacroAction +} \ No newline at end of file diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs new file mode 100644 index 00000000..2ee28f31 --- /dev/null +++ b/module/data/action/action.mjs @@ -0,0 +1,306 @@ +import DHDamageData from "./damage.mjs"; +import { abilities } from "../../config/actorConfig.mjs"; +// import DHWeapon from "../item/weapon.mjs"; + +export default class DHAction extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + id: new fields.DocumentIdField(), + name: new fields.StringField({ initial: 'New Action' }), + damage: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }), + value: new fields.StringField({}) + }), + healing: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }), + value: new fields.StringField() + }), + conditions: new fields.ArrayField( + new fields.SchemaField({ + name: new fields.StringField(), + icon: new fields.StringField(), + description: new fields.StringField() + }) + ), + cost: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }), + value: new fields.NumberField({ nullable: true, initial: null }) + }), + target: new fields.SchemaField({ + type: new fields.StringField({ + choices: SYSTEM.ACTIONS.targetTypes, + initial: SYSTEM.ACTIONS.targetTypes.other.id + }) + }) + }; + } +} + +const fields = foundry.data.fields; + +// Create Roll Field +// Create Damage Field + +export class DHBaseAction extends foundry.abstract.DataModel { + static defineSchema() { + return { + _id: new fields.DocumentIdField(), + type: new fields.StringField({ initial: undefined, readonly: true, required: true }), + name: new fields.StringField({ initial: undefined }), + img: new fields.FilePathField({ initial: undefined, categories: ["IMAGE"], base64: false }), + actionType: new fields.StringField({ choices: SYSTEM.ITEM.actionTypes, initial: 'action', nullable: true }), + roll: new fields.SchemaField({ + type: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.GENERAL.rollTypes }), + trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }), + difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }) + }), + cost: new fields.ArrayField( + new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: false, required: true, initial: 'hope' }), + value: new fields.NumberField({ nullable: true, initial: 1 }), + scalable: new fields.BooleanField({ initial: false }), + step: new fields.NumberField({ nullable: true, initial: null }), + }) + /* , + { initial: [ + { type: "hope", value: 1, scalable: false, step: null }, + { type: "stress", value: 2, scalable: true, step: 2 } + ]} */ + ), + uses: new fields.SchemaField({ + value: new fields.NumberField({ nullable: true, initial: null }), + max: new fields.NumberField({ nullable: true, initial: null }), + recovery: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes, initial: null, nullable: true }) + }), + /* duration: new fields.SchemaField({ + value: new fields.NumberField({ nullable: true, initial: null }), + units: new fields.StringField({ required: true, blank: false, initial: "instant" }) + }), */ + target: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.ACTIONS.targetTypes, initial: SYSTEM.ACTIONS.targetTypes.other.id }) + }), + range: new fields.StringField({ choices: SYSTEM.GENERAL.range, required: true, blank: false, initial: "self" }), + effects: new fields.ArrayField( // ActiveEffect + new fields.SchemaField({ + '_id': new fields.DocumentIdField() + }) + ) + } + } + + prepareData() {} + + get index() { + return this.parent.actions.indexOf(this); + } + + get item() { + return this.parent.parent; + } + + get actor() { + return this.item?.actor; + } + + static getRollType() { + return 'ability'; + } + + static getSourceConfig(parent) { + const updateSource = {}; + updateSource.img ??= parent?.img ?? parent?.system?.img; + if(parent?.system?.trait) { + updateSource['roll'] = { + type: this.getRollType(), + trait: parent.system.trait + }; + } + if(parent?.system?.range) { + updateSource['range'] = parent?.system?.range; + } + return updateSource; + } + + async use(event) { + console.log(this) + // console.log(this.item.getRollData(), this.item.actor.getRollData()) + + // const weapon = await fromUuid(button.dataset.weapon); + let damage, modifier, roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString, targets; + if(this.damage.parts.length) { + damage = { + value: `${this.actor.system[this.damage.parts[0].multiplier].value}${this.damage.parts[0].dice}`, + type: this.damage.parts[0].type, + bonusDamage: [this.damage.parts[0].bonus ?? 0, ...this.actor.system.bonuses.damage] + }; + damage.value = damage.value.concat(bonusDamageString); + } + if(this.roll.type && this.roll.trait) { + modifier = this.actor.system.traits[this.roll.trait].value; + ({roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString} = + await this.actor.dualityRoll( + { title: game.i18n.localize(abilities[this.roll.trait].label), value: modifier }, + event.shiftKey, + damage?.bonusDamage ?? 0 + )); + } + console.log(roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString) + // if(this.target?.type) { + targets = Array.from(game.user.targets).map(x => ({ + id: x.id, + name: x.actor.name, + img: x.actor.img, + difficulty: x.actor.system.difficulty, + evasion: x.actor.system.evasion.value + })); + // } + + const systemData = { + title: this.item.name, + origin: this.actor.id, + roll: roll._formula, + modifiers: modifiers, + hope: hope, + fear: fear, + advantage: advantage, + disadvantage: disadvantage, + damage: damage, + targets: targets + }; + + const cls = getDocumentClass('ChatMessage'); + const msg = new cls({ + type: 'dualityRoll', + sound: CONFIG.sounds.dice, + system: systemData, + content: await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/chat/attack-roll.hbs', + systemData + ), + rolls: [roll] + }); + + await cls.create(msg.toObject()); + } +} + +export class DHAttackAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema(), + /* attack: new fields.SchemaField({ + trait: new fields.StringField({ required: true, choices: SYSTEM.ACTOR.abilities, initial: 'agility' }), + bonus: new fields.NumberField({ nullable: true, initial: null }) + }), */ + /* damage: new fields.SchemaField({ + baseDamage: new fields.BooleanField({ initial: true }), // Add damage from source item ? + parts: new fields.ArrayField( + new fields.SchemaField({ // Create DamageField + type: new fields.StringField({ + choices: SYSTEM.GENERAL.damageTypes, + initial: 'physical' + }), + value: new FormulaField({ initial: 'd6' }), + bonus: new fields.NumberField({ nullable: true, initial: null }), + base: new fields.BooleanField({ initial: false, readonly: true }) + }) + ) + }) */ + damage: new fields.SchemaField({ + parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)), + includeBase: new fields.BooleanField({ initial: true }) + }) + } + } + + static getRollType() { + return 'weapon'; + } + + prepareData() { + super.prepareData(); + if ( this.damage.includeBase && !!this.item?.system?.damage ) { + const baseDamage = this.getParentDamage(); + this.damage.parts.unshift(new DHDamageData(baseDamage)); + } + } + + getParentDamage() { + return { + multiplier: 'proficiency', + dice: this.item?.system?.damage.value, + bonus: this.item?.system?.damage.bonus ?? 0, + type: this.item?.system?.damage.type, + base: true + }; + } +} + +export class DHSpellCastAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema(), + } + } + + static getRollType() { + return 'spellcast'; + } +} + +export class DHResourceAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema(), + resource: new fields.SchemaField({ + target: new fields.StringField({ choices: [], required: true, blank: false, initial: "" }), + value: new fields.NumberField({ initial: 0 }) + }) + } + } +} + +export class DHDamageAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema(), + damage: new fields.SchemaField({}) + } + } +} + +export class DHHealingAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema(), + type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, required: true, blan: false, initial: SYSTEM.GENERAL.healingTypes.health.id }), + healing: new fields.SchemaField({}) + } + } +} + +export class DHSummonAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema(), + healing: new fields.SchemaField({}) + } + } +} + +export class DHEffectAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema() + } + } +} + +export class DHMacroAction extends DHBaseAction { + static defineSchema() { + return { + ...super.defineSchema() + } + } +} diff --git a/module/data/action/damage.mjs b/module/data/action/damage.mjs new file mode 100644 index 00000000..081a4966 --- /dev/null +++ b/module/data/action/damage.mjs @@ -0,0 +1,26 @@ +import FormulaField from "../fields/formulaField.mjs"; + +const fields = foundry.data.fields; + +export default class DHDamageData extends foundry.abstract.DataModel { + /** @override */ + static defineSchema() { + return { + multiplier: new fields.StringField({ choices: SYSTEM.GENERAL.multiplierTypes, initial: 'proficiency', label: 'Multiplier' }), + dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }), + bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }), + base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }), + type: new fields.StringField({ + choices: SYSTEM.GENERAL.damageTypes, + initial: 'physical', + label: 'Type', + nullable: false, + required: true + }), + custom: new fields.SchemaField({ + enabled: new fields.BooleanField({ label: 'Custom Formula' }), + formula: new FormulaField( { label: 'Formula' } ) + }) + } + } +} \ No newline at end of file diff --git a/module/data/fields/actionField.mjs b/module/data/fields/actionField.mjs new file mode 100644 index 00000000..94c57231 --- /dev/null +++ b/module/data/fields/actionField.mjs @@ -0,0 +1,11 @@ +import { actionsTypes } from "../action/_module.mjs"; + +// Temporary Solution +export default class ActionField extends foundry.data.fields.EmbeddedDataField { + /** @override */ + initialize(value, model, options={}) { + this.model = actionsTypes[value?.type] ?? actionsTypes.attack; + this.fields = this._initialize(this.model.defineSchema()); + return super.initialize(value, model, options) + } +} \ No newline at end of file diff --git a/module/data/fields/foreignDocumentUUIDField.mjs b/module/data/fields/foreignDocumentUUIDField.mjs index 13bbc80d..00c76eb0 100644 --- a/module/data/fields/foreignDocumentUUIDField.mjs +++ b/module/data/fields/foreignDocumentUUIDField.mjs @@ -24,7 +24,7 @@ export default class ForeignDocumentUUIDField extends foundry.data.fields.Docume /**@override */ initialize(value, _model, _options = {}) { if (this.idOnly) return value; - return () => { + return (() => { try { const doc = fromUuidSync(value); return doc; @@ -32,7 +32,7 @@ export default class ForeignDocumentUUIDField extends foundry.data.fields.Docume console.error(error); return value ?? null; } - }; + })(); } /**@override */ diff --git a/module/data/item/_module.mjs b/module/data/item/_module.mjs index 30db2468..e29898cb 100644 --- a/module/data/item/_module.mjs +++ b/module/data/item/_module.mjs @@ -19,7 +19,7 @@ export { DHFeature, DHMiscellaneous, DHSubclass, - DHWeapon, + DHWeapon } export const config = { diff --git a/module/data/item/domainCard.mjs b/module/data/item/domainCard.mjs index c4a99c1d..f737c696 100644 --- a/module/data/item/domainCard.mjs +++ b/module/data/item/domainCard.mjs @@ -1,4 +1,4 @@ -import DHAction from "../action.mjs"; +import DHAction from "../action/action.mjs"; import BaseDataItem from "./base.mjs"; export default class DHDomainCard extends BaseDataItem { diff --git a/module/data/item/feature.mjs b/module/data/item/feature.mjs index 8199ea40..56ae2489 100644 --- a/module/data/item/feature.mjs +++ b/module/data/item/feature.mjs @@ -1,5 +1,5 @@ import { getTier } from '../../helpers/utils.mjs'; -import DHAction from '../action.mjs'; +import DHAction from '../action/action.mjs'; import BaseDataItem from './base.mjs'; export default class DHFeature extends BaseDataItem { diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index b3c82e52..6d49a036 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -1,5 +1,7 @@ import BaseDataItem from "./base.mjs"; import FormulaField from "../fields/formulaField.mjs"; +import ActionField from "../fields/actionField.mjs" +import { DHBaseAction, DHAttackAction } from "../action/action.mjs"; export default class DHWeapon extends BaseDataItem { /** @inheritDoc */ @@ -33,8 +35,9 @@ export default class DHWeapon extends BaseDataItem { initial: 'physical' }) }), - feature: new fields.StringField({ choices: SYSTEM.ITEM.weaponFeatures, blank: true }), + actions: new fields.ArrayField(new fields.EmbeddedDataField(DHAttackAction)) + // actions: new fields.ArrayField(new ActionField(DHBaseAction)) }; } } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 955c2c27..24fcadb1 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -11,6 +11,13 @@ export default class DhpItem extends Item { // this.system.domains = CONFIG.daggerheart.DOMAIN.classDomainMap[Object.keys(CONFIG.daggerheart.DOMAIN.classDomainMap).find(x => x === this.name.toLowerCase())]; } } + + /** @inheritDoc */ + prepareEmbeddedDocuments() { + super.prepareEmbeddedDocuments(); + for ( const action of this.system.actions ?? [] ) action.prepareData(); + // for ( const action of this.system.actions ?? [] ) console.log(action); + } /** * @inheritdoc @@ -99,4 +106,46 @@ export default class DhpItem extends Item { options }); } + + async selectActionDialog() { + const content = await foundry.applications.handlebars.renderTemplate( + "systems/daggerheart/templates/views/actionSelect.hbs", + {actions: this.system.actions} + ), + title = 'Select Action', + type = 'div', + data = {}; + return Dialog.prompt({ + title, + // label: title, + content, type, + callback: html => { + const form = html[0].querySelector("form"), + fd = new foundry.applications.ux.FormDataExtended(form); + return this.system.actions.find(a => a._id === fd.object.actionId); + }, + rejectClose: false + }) + } + + async use(event) { + const actions = this.system.actions; + if(actions?.length) { + let action = actions[0]; + if(actions.length > 1 && !event?.shiftKey) { + // Actions Choice Dialog + action = await this.selectActionDialog(); + } + if(!action) return; + // Check Target + // If action.roll => Roll Dialog + // Else If action.cost => Cost Dialog + // Then + // Apply Cost + // Apply Effect + + return action.use(event); + } + // Display Item Card in chat + } } diff --git a/styles/application.less b/styles/application.less index 82da864b..0c583acb 100644 --- a/styles/application.less +++ b/styles/application.less @@ -452,6 +452,37 @@ div.daggerheart.views.multiclass { &.open { max-height: initial; } + + .multi-display { + display: flex; + gap: 1rem; + align-items: center; + .form-group { + flex: 1; + } + } + + .form-group { + display: flex; + align-items: center; + margin-bottom: .5rem; + label { + flex: 2; + } + .form-fields { + flex: 3; + } + img { + width: 1.5rem; + height: 1.5rem; + } + } + + .data-form-array { + border: 1px solid var(--color-fieldset-border); + padding: .5rem; + margin-bottom: .5rem; + } } } } diff --git a/styles/daggerheart.less b/styles/daggerheart.less index 6869e316..1910176e 100755 --- a/styles/daggerheart.less +++ b/styles/daggerheart.less @@ -125,3 +125,38 @@ } } } + +.unlist { + list-style: none; + padding-inline-start: 0; +} + +.list-select { + margin: 1rem; + li { + &:not(:last-child) { + border-bottom: 1px solid #bbb; + } + label { + padding: 4px 8px; + display: flex; + align-items: center; + gap: 1rem; + cursor: pointer; + > span { + flex: 1; + font-weight: bold; + font-size: var(--font-size-16); + } + } + } +} + +dh-icon, dh-icon > img { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + font-size: x-large; +} diff --git a/templates/sheets/pc/sections/inventory.hbs b/templates/sheets/pc/sections/inventory.hbs index 6f4aeb49..f56138dc 100644 --- a/templates/sheets/pc/sections/inventory.hbs +++ b/templates/sheets/pc/sections/inventory.hbs @@ -13,7 +13,7 @@
  • -
    +
    {{item.name}}
    diff --git a/templates/views/action.hbs b/templates/views/action.hbs index 0b034ea4..a699ab42 100644 --- a/templates/views/action.hbs +++ b/templates/views/action.hbs @@ -1,6 +1,6 @@
    - {{formField fields.name value=source.name label="Name" name="name" rootId=partId}} + {{!-- {{formField fields.name value=source.name label="Name" name="name" rootId=partId}} --}}
    -
    +
    +
    + +
    Identity
    +
    +
    + {{formField fields.name value=source.name label="Name" name="name"}} + {{formField fields.img value=source.img label="Icon" name="img"}} + {{formField fields.actionType value=source.actionType label="Type" name="actionType" localize=true}} +
    +
    + {{> 'systems/daggerheart/templates/views/actionTypes/roll.hbs' fields=fields.roll.fields source=source.roll}} +
    +
    + {{> 'systems/daggerheart/templates/views/actionTypes/uses.hbs' fields=fields.uses.fields source=source.uses}} + {{> 'systems/daggerheart/templates/views/actionTypes/cost.hbs' fields=fields.cost.element.fields source=source.cost}} + {{> 'systems/daggerheart/templates/views/actionTypes/range-target.hbs' fields=(object range=fields.range target=fields.target.fields) source=(object target=source.target range=source.range)}} +
    +
    + {{#if source.damage}} + {{> 'systems/daggerheart/templates/views/actionTypes/damage.hbs' fields=fields.damage.fields.parts.element.fields source=source.damage}} + {{/if}} + {{!-- {{#switch source.type}} + {{#case 'attack'}} + {{> 'systems/daggerheart/templates/views/actionTypes/damage.hbs' fields=fields.damage.element.fields source=source.damage}} + {{/case}} + {{#case 'spellcast'}} +
    SpellCast
    + {{/case}} + {{/switch}} --}} + {{> 'systems/daggerheart/templates/views/actionTypes/effect.hbs'}} +
    + {{!--
    Damage
    @@ -48,14 +80,14 @@ {{formField fields.target.fields.type value=source.target.type label="Target Type" name="target.type" rootId=partId}}
    - {{!--

    +

    {{localize "Conditions"}} -

    --}} -
    + +
    --}}
    - + {{!-- --}}
    \ No newline at end of file diff --git a/templates/views/actionSelect.hbs b/templates/views/actionSelect.hbs new file mode 100644 index 00000000..2ea76cae --- /dev/null +++ b/templates/views/actionSelect.hbs @@ -0,0 +1,13 @@ +
    +
      + {{#each actions}} +
    • + +
    • + {{/each}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionType.hbs b/templates/views/actionType.hbs new file mode 100644 index 00000000..75dceeb7 --- /dev/null +++ b/templates/views/actionType.hbs @@ -0,0 +1,13 @@ +
    +
      + {{#each types}} +
    • + +
    • + {{/each}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionTypes/cost.hbs b/templates/views/actionTypes/cost.hbs new file mode 100644 index 00000000..7c9166e4 --- /dev/null +++ b/templates/views/actionTypes/cost.hbs @@ -0,0 +1,21 @@ +
    + +
    Cost
    +
    +
    +
    + {{#each source as |cost index|}} +
    +
    + {{formField ../fields.type label="Resource" value=cost.type name=(concat "cost." index ".type") localize=true}} + {{formField ../fields.value label="Value" value=cost.value name=(concat "cost." index ".value")}} +
    +
    + {{formField ../fields.scalable label="Scalable" value=cost.scalable name=(concat "cost." index ".scalable")}} + {{formField ../fields.step label="Step" value=cost.step name=(concat "cost." index ".step")}} +
    +
    +
    + {{/each}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionTypes/damage.hbs b/templates/views/actionTypes/damage.hbs new file mode 100644 index 00000000..13e2fffe --- /dev/null +++ b/templates/views/actionTypes/damage.hbs @@ -0,0 +1,36 @@ + +
    + +
    Damage
    +
    +
    +
    + {{#if @root.hasBaseDamage}} +
    + {{!-- --}} + {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }} +
    + {{/if}} + {{#each source.parts as |dmg index|}} + {{#with (@root.getRealIndex index) as | realIndex |}} + + {{#unless dmg.base}} + {{formField ../../fields.custom.fields.enabled value=dmg.custom.enabled name=(concat "damage.parts." realIndex ".custom.enabled")}} + {{/unless}} + {{#if dmg.custom.enabled}} + {{formField ../../fields.custom.fields.formula value=dmg.custom.formula name=(concat "damage.parts." realIndex ".custom.formula") localize=true}} + {{else}} +
    + {{formField ../../fields.multiplier value=dmg.multiplier name=(concat "damage.parts." realIndex ".multiplier") localize=true}} + {{formField ../../fields.dice value=dmg.dice name=(concat "damage.parts." realIndex ".dice")}} + {{formField ../../fields.bonus value=dmg.bonus name=(concat "damage.parts." realIndex ".bonus") localize=true}} +
    + {{/if}} + {{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} + + {{#unless dmg.base}}
    {{/unless}} +
    + {{/with}} + {{/each}} +
    + \ No newline at end of file diff --git a/templates/views/actionTypes/effect.hbs b/templates/views/actionTypes/effect.hbs new file mode 100644 index 00000000..0f99327e --- /dev/null +++ b/templates/views/actionTypes/effect.hbs @@ -0,0 +1,19 @@ +
    + +
    Effects
    +
    +
    +
    + {{#each @root.effects as | effect index | }} +
    + {{!--
    --}} +
    + + +
    +
    + {{!--
    --}} +
    + {{/each}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionTypes/range-target.hbs b/templates/views/actionTypes/range-target.hbs new file mode 100644 index 00000000..f4c0f446 --- /dev/null +++ b/templates/views/actionTypes/range-target.hbs @@ -0,0 +1,11 @@ +
    + +
    Range & Target
    +
    +
    + {{formField fields.range value=source.range label="Range" name="range" localize=true}} +
    +
    + {{formField fields.target.type value=source.target.type label="Target" name="target.type" localize=true}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionTypes/roll.hbs b/templates/views/actionTypes/roll.hbs new file mode 100644 index 00000000..a3b1a31a --- /dev/null +++ b/templates/views/actionTypes/roll.hbs @@ -0,0 +1,10 @@ +
    + +
    Roll
    +
    +
    + {{formField fields.type label="Type" name="roll.type" value=source.type localize=true}} + {{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true}} + {{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionTypes/target.hbs b/templates/views/actionTypes/target.hbs new file mode 100644 index 00000000..ec7ebfb2 --- /dev/null +++ b/templates/views/actionTypes/target.hbs @@ -0,0 +1,8 @@ +
    + +
    Target
    +
    +
    + {{formField targetField.type label="Target" name="target" rootId=partId localize=true}} +
    +
    \ No newline at end of file diff --git a/templates/views/actionTypes/uses.hbs b/templates/views/actionTypes/uses.hbs new file mode 100644 index 00000000..9015987e --- /dev/null +++ b/templates/views/actionTypes/uses.hbs @@ -0,0 +1,12 @@ +
    + +
    Uses
    +
    +
    +
    + {{formField fields.value label="Value" value=source.value name="uses.value" rootId=partId}} + {{formField fields.max label="Max" value=source.max name="uses.max" rootId=partId}} +
    + {{formField fields.recovery label="Recovery" value=source.recovery name="uses.recovery" rootId=partId localize=true}} +
    +
    \ No newline at end of file