From 2981aab917a167dfbe827ba6e5ddc6330d9caed3 Mon Sep 17 00:00:00 2001 From: Dapoolp Date: Tue, 24 Jun 2025 21:28:49 +0200 Subject: [PATCH] Adversary Attack --- module/applications/config/Action.mjs | 11 +- module/applications/costSelectionDialog.mjs | 1 + module/applications/roll.mjs | 88 ++----- module/applications/sheets/adversary.mjs | 30 +-- module/config/generalConfig.mjs | 4 +- module/data/action/action.mjs | 27 +- module/data/action/actionDice.mjs | 4 +- module/data/actor/adversary.mjs | 59 ++++- module/data/chat-message/adversaryRoll.mjs | 37 +-- module/data/chat-message/dualityRoll.mjs | 61 ----- module/dialogs/d20RollDialog.mjs | 6 +- module/documents/actor.mjs | 250 +------------------ module/ui/chatLog.mjs | 38 +-- templates/chat/adversary-roll.hbs | 44 +++- templates/sheets/actors/adversary/main.hbs | 32 ++- templates/views/action.hbs | 2 + templates/views/actionTypes/damage.hbs | 58 +++-- templates/views/actionTypes/range-target.hbs | 6 +- templates/views/actionTypes/roll.hbs | 10 +- 19 files changed, 269 insertions(+), 499 deletions(-) diff --git a/module/applications/config/Action.mjs b/module/applications/config/Action.mjs index a3ae12b2..afd03e55 100644 --- a/module/applications/config/Action.mjs +++ b/module/applications/config/Action.mjs @@ -63,6 +63,8 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') context.hasBaseDamage = !!this.action.parent.damage; context.getRealIndex = this.getRealIndex.bind(this); context.disableOption = this.disableOption.bind(this); + context.isNPC = this.action.actor.type !== 'character'; + return context; } @@ -95,11 +97,16 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { static async updateForm(event, _, formData) { const submitData = this._prepareSubmitData(event, formData), data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)), + container = foundry.utils.getProperty(this.action.parent, this.action.systemPath); + let newActions; + if(Array.isArray(container)) { newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); // Find better way - if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data); + if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data); + } else newActions = data; + const updates = await this.action.parent.parent.update({ [`system.${this.action.systemPath}`]: newActions }); if (!updates) return; - this.action = foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index]; + this.action = Array.isArray(container) ? foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index] : foundry.utils.getProperty(updates.system, this.action.systemPath); this.render(); } diff --git a/module/applications/costSelectionDialog.mjs b/module/applications/costSelectionDialog.mjs index 0afac2a2..2b948a04 100644 --- a/module/applications/costSelectionDialog.mjs +++ b/module/applications/costSelectionDialog.mjs @@ -42,6 +42,7 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl } async _prepareContext(_options) { + console.log(this.costs) const updatedCosts = this.action.calcCosts(this.costs), updatedUses = this.action.calcUses(this.uses); return { diff --git a/module/applications/roll.mjs b/module/applications/roll.mjs index 647d6195..dbe52961 100644 --- a/module/applications/roll.mjs +++ b/module/applications/roll.mjs @@ -27,18 +27,14 @@ export class DHRoll extends Roll { } this.applyKeybindings(config); - - // let roll; - // if(config.dialog?.configure === false) { - // roll = new this('', config.actor, config); - // } else { + if(config.dialog.configure !== false) { // Open Roll Dialog const DialogClass = config.dialog?.class ?? this.DefaultDialog; config = await DialogClass.configure(config, message); if(!config) return; } - let roll = new this(config.formula, config.actor, config); + let roll = new this(config.formula, config.data, config); for ( const hook of config.hooks ) { if ( Hooks.call(`${SYSTEM.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false ) return []; @@ -101,9 +97,6 @@ export class DualityDie extends foundry.dice.terms.Die { export class D20Roll extends DHRoll { constructor(formula, data={}, options={}) { super(formula, data, options); - // console.log(data, options) - // this.options = this._prepareData(data); - // this.options = options; this.createBaseDice(); this.configureModifiers(); @@ -195,10 +188,10 @@ export class D20Roll extends DHRoll { this.applyBaseBonus(); this.options.experiences?.forEach(m => { - if(this.options.actor.experiences?.[m]) this.options.roll.modifiers.push( + if(this.options.data.experiences?.[m]) this.options.roll.modifiers.push( { - label: this.options.actor.experiences[m].description, - value: this.options.actor.experiences[m].total + label: this.options.data.experiences[m].description, + value: this.options.data.experiences[m].total } ); }) @@ -212,30 +205,16 @@ export class D20Roll extends DHRoll { } applyBaseBonus() { - // if(this.options.action) { - if(this.options.type === "attack") this.terms.push(...this.formatModifier(this.options.actor.system.attack.modifier)); - /* this.options.roll.modifiers?.forEach(m => { - this.terms.push(...this.formatModifier(m)); - }) */ - // } + if(this.options.type === "attack") this.terms.push(...this.formatModifier(this.options.data.attack.roll.bonus)); } static async postEvaluate(roll, config={}) { if (config.targets?.length) { - /* targets = config.targets.map(target => { - const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion - target.hit = roll.total >= difficulty; - return target; - }); */ config.targets.forEach(target => { - const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion + const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion target.hit = roll.total >= difficulty; }) } else if(config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty; - // config.roll.advantage = { - // dice: roll.dHope.faces, - // value: roll.dHope.total - // } config.roll.total = roll.total; config.roll.formula = roll.formula; config.roll.advantage = { @@ -244,10 +223,19 @@ export class D20Roll extends DHRoll { value: roll.dAdvantage?.total } config.roll.modifierTotal = config.roll.modifiers.reduce((a,c) => a + c.value, 0); + config.roll.dice = []; + roll.dice.forEach(d => { + config.roll.dice.push({ + dice: d.denomination, + total: d.total, + formula: d.formula, + results: d.results + }) + }) } getRollData() { - return this.options.actor.getRollData(); + return this.options.data(); } formatModifier(modifier) { @@ -348,7 +336,6 @@ export class DualityRoll extends D20Roll { const dieFaces = 6, bardRallyFaces = this.hasBarRally, advDie = new foundry.dice.terms.Die({faces: dieFaces}); - // console.log(this.hasAdvantage, this.hasDisadvantage) if(this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) this.terms.push(new foundry.dice.terms.OperatorTerm({operator:'+'})); if(bardRallyFaces) { const rallyDie = new foundry.dice.terms.Die({faces: bardRallyFaces}); @@ -364,23 +351,16 @@ export class DualityRoll extends D20Roll { } applyBaseBonus() { - // if(this.options.action) { - // console.log(this.options, this.options.actor.system.traits[this.options.roll.trait].bonus) - // console.log(this.options.actor.system); - /* if(this.options.roll?.trait) this.terms.push(...this.formatModifier(this.options.actor.traits[this.options.roll.trait].total)); */ - if(!this.options.roll.modifiers) this.options.roll.modifiers = []; - if(this.options.roll?.trait) this.options.roll.modifiers.push( - { - label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`, - value: this.options.actor.traits[this.options.roll.trait].total - } - ); - console.log(this.options) - // } else if(this.options.trait) this.terms.push(...this.formatModifier(this.options.actor.system.traits[this.options.roll.trait].total)); + if(!this.options.roll.modifiers) this.options.roll.modifiers = []; + if(this.options.roll?.trait) this.options.roll.modifiers.push( + { + label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`, + value: this.options.data.traits[this.options.roll.trait].total + } + ); } static async postEvaluate(roll, config={}) { - console.log(roll,config); super.postEvaluate(roll, config); config.roll.hope = { dice: roll.dHope.denomination, @@ -416,30 +396,10 @@ export class DamageRoll extends DHRoll { static DefaultDialog = DamageDialog; static async postEvaluate(roll, config={}) { - console.log(roll, config) config.roll = { - // formula : config.formula, result: roll.total, dice: roll.dice } if(roll.healing) config.roll.type = roll.healing.type - /* const dice = []; - const modifiers = []; - for (var i = 0; i < roll.terms.length; i++) { - const term = roll.terms[i]; - if (term.faces) { - dice.push({ - type: `d${term.faces}`, - rolls: term.results.map(x => x.result), - total: term.results.reduce((acc, x) => acc + x.result, 0) - }); - } else if (term.operator) { - } else if (term.number) { - const operator = i === 0 ? '' : roll.terms[i - 1].operator; - modifiers.push({ value: term.number, operator: operator }); - } - } - config.roll.dice = dice; - config.roll.modifiers = modifiers; */ } } \ No newline at end of file diff --git a/module/applications/sheets/adversary.mjs b/module/applications/sheets/adversary.mjs index aab25977..ee1f40a5 100644 --- a/module/applications/sheets/adversary.mjs +++ b/module/applications/sheets/adversary.mjs @@ -1,3 +1,4 @@ +import DHActionConfig from '../config/Action.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs'; const { ActorSheetV2 } = foundry.applications.sheets; @@ -9,6 +10,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { actions: { reactionRoll: this.reactionRoll, attackRoll: this.attackRoll, + attackConfigure: this.attackConfigure, addExperience: this.addExperience, removeExperience: this.removeExperience, toggleHP: this.toggleHP, @@ -51,7 +53,9 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { const context = await super._prepareContext(_options); context.document = this.document; context.tabs = super._getTabs(this.constructor.TABS); - + context.systemFields.attack.fields = this.document.system.attack.schema.fields; + context.isNPC = true; + console.log(context) return context; } @@ -78,25 +82,11 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { } static async attackRoll(event) { - const { modifier, damage, name: attackName } = this.actor.system.attack, - config = { - event: event, - title: attackName, - roll: { - modifier: modifier, - type: 'action' - }, - chatMessage: { - type: 'adversaryRoll', - template: 'systems/daggerheart/templates/chat/adversary-attack-roll.hbs' - }, - damage: { - value: damage.value, - type: damage.type - }, - checkTarget: true - }; - this.actor.diceRoll(config); + this.actor.system.attack.use(event); + } + + static async attackConfigure(event) { + await new DHActionConfig(this.document.system.attack).render(true); } static async addExperience() { diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 81784d13..cf32431f 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -300,13 +300,15 @@ export const diceTypes = { d4: 'd4', d6: 'd6', d8: 'd8', + d10: 'd10', d12: 'd12', d20: 'd20' }; export const multiplierTypes = { proficiency: 'Proficiency', - spellcast: 'Spellcast' + spellcast: 'Spellcast', + flat: 'Flat' }; export const getDiceSoNicePresets = () => { diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs index 63dfd1db..679f23d2 100644 --- a/module/data/action/action.mjs +++ b/module/data/action/action.mjs @@ -2,6 +2,7 @@ import DamageSelectionDialog from '../../applications/damageSelectionDialog.mjs' import CostSelectionDialog from '../../applications/costSelectionDialog.mjs'; import { abilities } from '../../config/actorConfig.mjs'; import { DHActionDiceData, DHDamageData, DHDamageField } from './actionDice.mjs'; +import DhpActor from '../../documents/actor.mjs'; const fields = foundry.data.fields; @@ -87,7 +88,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { choices: SYSTEM.GENERAL.range, required: false, blank: true, - initial: null + // initial: null }), ...this.defineExtraSchema() }; @@ -99,7 +100,8 @@ export class DHBaseAction extends foundry.abstract.DataModel { 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 }) + difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }), + bonus: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }) }), save: new fields.SchemaField({ trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }), @@ -150,7 +152,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { } get actor() { - return this.item?.actor; + return this.item instanceof DhpActor ? this.item : this.item?.actor; } get chatTemplate() { @@ -197,6 +199,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { source: { item: this.item._id, action: this._id + // action: this }, type: this.type, hasDamage: !!this.damage?.parts?.length, @@ -229,25 +232,25 @@ export class DHBaseAction extends foundry.abstract.DataModel { this.spendCost(config.costs.values); this.spendUses(config.uses); - // console.log(config) - return config; } /* ROLL */ hasRoll() { - return this.roll?.type && this.roll?.trait; + // return this.roll?.type && this.roll?.trait; + return this.roll?.type; } async proceedRoll(config) { if (!this.hasRoll()) return config; - const modifierValue = this.actor.system.traits[this.roll.trait].value; + // const modifierValue = this.actor.system.traits[this.roll.trait].value; config = { ...config, roll: { modifiers: [], trait: this.roll?.trait, - label: game.i18n.localize(abilities[this.roll.trait].label), + // label: game.i18n.localize(abilities[this.roll.trait].label), + label: 'Attack', type: this.actionType, difficulty: this.roll?.difficulty } @@ -347,7 +350,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { name: actor.actor.name, img: actor.actor.img, difficulty: actor.actor.system.difficulty, - evasion: actor.actor.system.evasion?.value + evasion: actor.actor.system.evasion?.total } } /* TARGET */ @@ -363,7 +366,6 @@ export class DHBaseAction extends foundry.abstract.DataModel { async applyEffects(event, data, force=false) { if(!this.effects?.length || !data.system.targets.length) return; data.system.targets.forEach(async (token) => { - // console.log(token, force) if(!token.hit && !force) return; this.effects.forEach(async (e) => { const actor = canvas.tokens.get(token.id)?.actor, @@ -417,7 +419,7 @@ export class DHDamageAction extends DHBaseAction { async rollDamage(event, data) { let formula = this.damage.parts.map(p => p.getFormula(this.actor)).join(' + '); - + if (!formula || formula == '') return; let roll = { formula: formula, total: formula }, bonusDamage = []; @@ -427,7 +429,7 @@ export class DHDamageAction extends DHBaseAction { formula, targets: (data.system?.targets ?? data.targets).map(x => ({ id: x.id, name: x.name, img: x.img, hit: true })) } - + roll = CONFIG.Dice.daggerheart.DamageRoll.build(config) } } @@ -479,7 +481,6 @@ export class DHHealingAction extends DHBaseAction { } async rollHealing(event, data) { - console.log(event, data) let formula = this.healing.value.getFormula(this.actor); if (!formula || formula == '') return; diff --git a/module/data/action/actionDice.mjs b/module/data/action/actionDice.mjs index 8ec327a0..5cbd1558 100644 --- a/module/data/action/actionDice.mjs +++ b/module/data/action/actionDice.mjs @@ -11,6 +11,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel { initial: 'proficiency', label: 'Multiplier' }), + flatMultiplier : new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }), dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }), bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }), custom: new fields.SchemaField({ @@ -21,9 +22,10 @@ export class DHActionDiceData extends foundry.abstract.DataModel { } getFormula(actor) { + const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : actor.system[this.multiplier]?.total; return this.custom.enabled ? this.custom.formula - : `${actor.system[this.multiplier]?.total ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`; + : `${multiplier ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`; } } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 834c5f17..f1bd2684 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -1,3 +1,6 @@ +import DhpItem from '../../documents/item.mjs'; +import ActionField from '../fields/actionField.mjs'; +import DHWeapon from '../item/weapon.mjs'; import BaseDataActor from './base.mjs'; const resourceField = () => @@ -39,7 +42,7 @@ export default class DhpAdversary extends BaseDataActor { hitPoints: resourceField(), stress: resourceField() }), - attack: new fields.SchemaField({ + /* attack: new fields.SchemaField({ name: new fields.StringField({}), modifier: new fields.NumberField({ required: true, integer: true, initial: 0 }), range: new fields.StringField({ @@ -55,6 +58,43 @@ export default class DhpAdversary extends BaseDataActor { initial: SYSTEM.GENERAL.damageTypes.physical.id }) }) + }), */ + /* attack: new fields.EmbeddedDocumentField(DhpItem, + { + // type: 'weapon' + // initial: new DhpItem( + // { + // name: 'Attack', + // type: 'weapon' + // }, + // { + // parent: this.parent, + // parentCollection: 'items' + // } + // ) + // initial: {type: 'weapon'} + } + ), */ + attack: new ActionField({ + initial: { + name: 'Attack', + _id: foundry.utils.randomID(), + systemPath: 'attack', + type: 'attack', + range: 'melee', + target: { + type: 'any', + amount: 1 + }, + roll: { + type: 'weapon' + }, + damage: { + parts: [{ + multiplier: 'flat' + }] + } + } }), experiences: new fields.TypedObjectField( new fields.SchemaField({ @@ -65,4 +105,21 @@ export default class DhpAdversary extends BaseDataActor { /* Features waiting on pseudo-document data model addition */ }; } + + prepareBaseData() { + // console.log(this.attack) + /* if(!this.attack) { + this.attack = new DhpItem( + { + name: 'Attack', + type: 'weapon', + _id: foundry.utils.randomID() + }, + { + parent: this.parent, + parentCollection: 'items' + } + ) + } */ + } } diff --git a/module/data/chat-message/adversaryRoll.mjs b/module/data/chat-message/adversaryRoll.mjs index 6e970388..46c550be 100644 --- a/module/data/chat-message/adversaryRoll.mjs +++ b/module/data/chat-message/adversaryRoll.mjs @@ -1,23 +1,13 @@ +import DhpActor from "../../documents/actor.mjs"; +import ActionField from "../fields/actionField.mjs"; + export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel { static defineSchema() { const fields = foundry.data.fields; return { title: new fields.StringField(), - origin: new fields.StringField({ required: true }), - dice: new fields.DataField(), roll: new fields.DataField(), - modifiers: new fields.ArrayField( - new fields.SchemaField({ - value: new fields.NumberField({ integer: true }), - label: new fields.StringField({}) - }) - ), - advantageState: new fields.BooleanField({ nullable: true, initial: null }), - advantage: new fields.SchemaField({ - dice: new fields.StringField({}), - value: new fields.NumberField({ integer: true }) - }), targets: new fields.ArrayField( new fields.SchemaField({ id: new fields.StringField({}), @@ -29,24 +19,13 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel { }) ), hasDamage: new fields.BooleanField({ initial: false }), + hasHealing: new fields.BooleanField({ initial: false }), hasEffect: new fields.BooleanField({ initial: false }), - /* damage: new fields.SchemaField( - { - value: new fields.StringField({}), - type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }) - }, - { nullable: true, initial: null } - ), */ - action: new fields.SchemaField({ - itemId: new fields.StringField(), - actionId: new fields.StringField() + source: new fields.SchemaField({ + actor: new fields.StringField(), + item: new fields.StringField(), + action: new fields.StringField() }) }; } - - prepareDerivedData() { - this.targets.forEach(target => { - target.hit = target.difficulty ? this.total >= target.difficulty : this.total >= target.evasion; - }); - } } diff --git a/module/data/chat-message/dualityRoll.mjs b/module/data/chat-message/dualityRoll.mjs index 134b1473..55b20444 100644 --- a/module/data/chat-message/dualityRoll.mjs +++ b/module/data/chat-message/dualityRoll.mjs @@ -1,11 +1,4 @@ -import { DualityRollColor } from '../settings/Appearance.mjs'; - const fields = foundry.data.fields; -const diceField = () => - new fields.SchemaField({ - dice: new fields.StringField({}), - value: new fields.NumberField({ integer: true }) - }); export default class DHDualityRoll extends foundry.abstract.TypeDataModel { static dualityResult = { @@ -17,18 +10,7 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel { static defineSchema() { return { title: new fields.StringField(), - /* origin: new fields.StringField({ required: true }), */ roll: new fields.DataField({}), - /* modifiers: new fields.ArrayField( - new fields.SchemaField({ - value: new fields.NumberField({ integer: true }), - label: new fields.StringField({}) - }) - ), */ - /* hope: diceField(), - fear: diceField(), - advantageState: new fields.BooleanField({ nullable: true, initial: null }), */ - /* advantage: diceField(), */ targets: new fields.ArrayField( new fields.SchemaField({ id: new fields.StringField({}), @@ -49,47 +31,4 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel { }) }; } - - /* get diceTotal() { - return this.hope.value + this.fear.value; - } - - get modifierTotal() { - const total = this.modifiers.reduce((acc, x) => acc + x.value, 0); - return { - value: total, - label: total > 0 ? `+${total}` : total < 0 ? `${total}` : '' - }; - } - - get dualityResult() { - return this.hope.value > this.fear.value - ? this.constructor.dualityResult.hope - : this.fear.value > this.hope.value - ? this.constructor.dualityResult.fear - : this.constructor.dualityResult.critical; - } - - get totalLabel() { - const label = - this.hope.value > this.fear.value - ? 'DAGGERHEART.General.Hope' - : this.fear.value > this.hope.value - ? 'DAGGERHEART.General.Fear' - : 'DAGGERHEART.General.CriticalSuccess'; - - return game.i18n.localize(label); - } - - get colorful() { - return ( - game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme === - DualityRollColor.colorful.value - ); - } - - prepareDerivedData() { - this.hope.discarded = this.hope.value < this.fear.value; - this.fear.discarded = this.fear.value < this.hope.value; - } */ } diff --git a/module/dialogs/d20RollDialog.mjs b/module/dialogs/d20RollDialog.mjs index 55e26692..0c3c1319 100644 --- a/module/dialogs/d20RollDialog.mjs +++ b/module/dialogs/d20RollDialog.mjs @@ -8,8 +8,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.experiences = []; if(config.source?.action) { - this.item = config.actor.parent.items.get(config.source.item); - this.action = this.item.system.actions.find(a => a._id === config.source.action); + this.item = config.data.parent.items.get(config.source.item); + this.action = config.data.attack?._id == config.source.action ? config.data.attack : this.item.system.actions.find(a => a._id === config.source.action); } } @@ -47,7 +47,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio async _prepareContext(_options) { const context = await super._prepareContext(_options); - context.experiences = Object.keys(this.config.actor.experiences).map(id => ({ id, ...this.config.actor.experiences[id] })); + context.experiences = Object.keys(this.config.data.experiences).map(id => ({ id, ...this.config.data.experiences[id] })); context.selectedExperiences = this.config.experiences; context.advantage = this.config.advantage; /* context.diceOptions = this.diceOptions; */ diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 64aefda8..5ff0e456 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -265,152 +265,14 @@ export default class DhpActor extends Actor { * @param {object} [config.costs] */ async diceRoll(config, action) { - // console.log(config) - config.source = {...(config.source ?? {}), actor: this.id}; - const newConfig = { - ...config, - actor: this.system - } - const roll = await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(newConfig) + config.source = {...(config.source ?? {}), actor: this._id}; + config.data = this.getRollData() + const roll = await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(config) return config; - /* let hopeDice = 'd12', - fearDice = 'd12', - advantageDice = 'd6', - disadvantageDice = 'd6', - advantage = config.event.altKey ? true : config.event.ctrlKey ? false : null, - targets, - modifiers = this.formatRollModifier(config.roll), - rollConfig, - formula, - hope, - fear; + } - if (!config.event.shiftKey && !config.event.altKey && !config.event.ctrlKey) { - const dialogClosed = new Promise((resolve, _) => { - this.type === 'character' - ? new RollSelectionDialog( - this.system.experiences, - config.costs, - action, - resolve - ).render(true) - : new NpcRollSelectionDialog( - this.system.experiences, - resolve - ).render(true); - }); - rollConfig = await dialogClosed; - - advantage = rollConfig.advantage; - hopeDice = rollConfig.hope; - fearDice = rollConfig.fear; - if(rollConfig.costs) config.costs = rollConfig.costs; - - rollConfig.experiences.forEach(x => - modifiers.push({ - value: x.value, - label: x.value >= 0 ? `+${x.value}` : `-${x.value}`, - title: x.description - }) - ); - - if (this.type === 'character') { - const automateHope = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).hope; - - if (automateHope && result.hopeUsed) { - await this.update({ - 'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed - }); - } - } - } - - if (this.type === 'character') { - formula = `1${hopeDice} + 1${fearDice}${advantage === true ? ` + 1d6` : advantage === false ? ` - 1d6` : ''}`; - } else { - formula = `${advantage === true || advantage === false ? 2 : 1}d20${advantage === true ? 'kh' : advantage === false ? 'kl' : ''}`; - } - formula += ` ${modifiers.map(x => `+ ${x.value}`).join(' ')}`; - const roll = await Roll.create(formula).evaluate(), - dice = roll.dice.flatMap(dice => ({ - denomination: dice.denomination, - number: dice.number, - total: dice.total, - results: dice.results.map(result => ({ result: result.result, discarded: !result.active })) - })); - config.roll.evaluated = roll; - - if (this.type === 'character') { - setDiceSoNiceForDualityRoll(roll, advantage); - hope = roll.dice[0].results[0].result; - fear = roll.dice[1].results[0].result; - if ( - game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).hope && - config.roll.type === 'action' - ) { - if (hope > fear) { - await this.update({ - 'system.resources.hope.value': Math.min( - this.system.resources.hope.value + 1, - this.system.resources.hope.max - ) - }); - } else if (hope === fear) { - await this.update({ - 'system.resources': { - 'hope.value': Math.min( - this.system.resources.hope.value + 1, - this.system.resources.hope.max - ), - 'stress.value': Math.max(this.system.resources.stress.value - 1, 0) - } - }); - } - } - } - - if (config.targets?.length) { - targets = config.targets.map(target => { - const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion - target.hit = roll.total >= difficulty; - return target; - }); - } else if(config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty; - - if (config.chatMessage) { - const configRoll = { - title: config.title, - origin: this.id, - dice, - roll, - modifiers: modifiers.filter(x => x.label), - advantageState: advantage, - action: config.source, - hasDamage: config.hasDamage, - hasEffect: config.hasEffect - }; - if (this.type === 'character') { - configRoll.hope = { dice: hopeDice, value: hope }; - configRoll.fear = { dice: fearDice, value: fear }; - configRoll.advantage = { dice: advantageDice, value: roll.dice[2]?.results[0].result ?? null }; - } - // if (damage) configRoll.damage = damage; - if (targets) configRoll.targets = targets; - const systemData = - this.type === 'character' && !config.roll.simple ? new DHDualityRoll(configRoll) : configRoll, - cls = getDocumentClass('ChatMessage'), - msg = new cls({ - type: config.chatMessage.type ?? 'dualityRoll', - sound: config.chatMessage.mute ? null : CONFIG.sounds.dice, - system: systemData, - content: config.chatMessage.template, - rolls: [roll] - }); - - await cls.create(msg.toObject()); - } - - return config; */ + getRollData() { + return this.system; } formatRollModifier(roll) { @@ -561,104 +423,4 @@ export default class DhpActor extends Actor { } }) } - - /* async takeHealing(healing, type) { - let update = {}; - switch (type) { - case SYSTEM.GENERAL.healingTypes.health.id: - update = { - 'system.resources.hitPoints.value': Math.min( - this.system.resources.hitPoints.value + healing, - this.system.resources.hitPoints.max - ) - }; - break; - case SYSTEM.GENERAL.healingTypes.stress.id: - update = { - 'system.resources.stress.value': Math.min( - this.system.resources.stress.value + healing, - this.system.resources.stress.max - ) - }; - break; - } - - if (game.user.isGM) { - await this.update(update); - } else { - await game.socket.emit(`system.${SYSTEM.id}`, { - action: socketEvent.GMUpdate, - data: { - action: GMUpdateEvent.UpdateDocument, - uuid: this.uuid, - update: update - } - }); - } - } */ - - //Move to action-scope? - /* async useAction(action) { - const userTargets = Array.from(game.user.targets); - const otherTarget = action.target.type === SYSTEM.ACTIONS.targetTypes.other.id; - if (otherTarget && userTargets.length === 0) { - ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.ActionRequiresTarget')); - return; - } - - if (action.cost.type != null && action.cost.value != null) { - if ( - this.system.resources[action.cost.type].value - action.cost.value <= - this.system.resources[action.cost.type].min - ) { - ui.notifications.error(game.i18n.localize(`Insufficient ${action.cost.type} to use this ability`)); - return; - } - } - - // const targets = otherTarget ? userTargets : [game.user.character]; - if (action.damage.type) { - let roll = { formula: action.damage.value, result: action.damage.value }; - if (Number.isNaN(Number.parseInt(action.damage.value))) { - roll = await new Roll(`1${action.damage.value}`).evaluate(); - } - - const cls = getDocumentClass('ChatMessage'); - const msg = new cls({ - user: game.user.id, - content: await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/chat/damage-roll.hbs', - { - roll: roll.formula, - total: roll.result, - type: action.damage.type - } - ) - }); - - cls.create(msg.toObject()); - } - - if (action.healing.type) { - let roll = { formula: action.healing.value, result: action.healing.value }; - if (Number.isNaN(Number.parseInt(action.healing.value))) { - roll = await new Roll(`1${action.healing.value}`).evaluate(); - } - - const cls = getDocumentClass('ChatMessage'); - const msg = new cls({ - user: game.user.id, - content: await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/chat/healing-roll.hbs', - { - roll: roll.formula, - total: roll.result, - type: action.healing.type - } - ) - }); - - cls.create(msg.toObject()); - } - } */ } diff --git a/module/ui/chatLog.mjs b/module/ui/chatLog.mjs index 4b1ee434..6c9a766f 100644 --- a/module/ui/chatLog.mjs +++ b/module/ui/chatLog.mjs @@ -60,45 +60,45 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo super.close(options); } + getActor(id) { + return game.actors.get(id); + } + + getAction(actor, itemId, actionId) { + const item = actor.items.get(itemId), + action = actor.system.attack?._id === actionId ? actor.system.attack : item?.system?.actions?.find(a => a._id === actionId); + return action; + } + onRollDamage = async (event, message) => { event.stopPropagation(); - const actor = game.actors.get(message.system.source.actor); + const actor = this.getActor(message.system.source.actor); if (!actor || !game.user.isGM) return true; if(message.system.source.item && message.system.source.action) { - const item = actor.items.get(message.system.source.item), - action = item?.system?.actions?.find(a => a._id === message.system.source.action); - if(!item || !action || !action?.rollDamage) return; + const action = this.getAction(actor, message.system.source.item, message.system.source.action); + if(!action || !action?.rollDamage) return; await action.rollDamage(event, message); - } else { - await actor.damageRoll( - message.system.title, - message.system.damage, - message.system.targets.filter(x => x.hit).map(x => ({ id: x.id, name: x.name, img: x.img })), - event.shiftKey - ); } }; onRollHealing = async (event, message) => { event.stopPropagation(); - const actor = game.actors.get(message.system.source.actor); + const actor = this.getActor(message.system.source.actor); if (!actor || !game.user.isGM) return true; if(message.system.source.item && message.system.source.action) { - const item = actor.items.get(message.system.source.item), - action = item?.system?.actions?.find(a => a._id === message.system.source.action); - if(!item || !action || !action?.rollHealing) return; + const action = this.getAction(actor, message.system.source.item, message.system.source.action); + if(!action || !action?.rollHealing) return; await action.rollHealing(event, message); } }; onApplyEffect = async (event, message) => { event.stopPropagation(); - const actor = game.actors.get(message.system.source.actor); + const actor = this.getActor(message.system.source.actor); if (!actor || !game.user.isGM) return true; if(message.system.source.item && message.system.source.action) { - const item = actor.items.get(message.system.source.item), - action = item?.system?.actions?.find(a => a._id === message.system.source.action); - if(!item || !action || !action.applyEffects) return; + const action = this.getAction(actor, message.system.source.item, message.system.source.action); + if(!action || !action?.applyEffects) return; await action.applyEffects(event, message); } } diff --git a/templates/chat/adversary-roll.hbs b/templates/chat/adversary-roll.hbs index b29f60b5..fa463bad 100644 --- a/templates/chat/adversary-roll.hbs +++ b/templates/chat/adversary-roll.hbs @@ -1,33 +1,51 @@
+
{{title}}
{{roll.formula}}
-
    -
    - {{#each dice}} +
    +
    +
    + {{#each roll.dice}}
    - {{number}}{{denomination}} + {{formula}} {{total}}
      {{#each results}} -
    1. {{result}}
    2. +
    3. {{result}}
    4. {{/each}}
    -
    {{#if ../advantageState}}{{localize "DAGGERHEART.General.Advantage.Full"}}{{/if}}{{#if (eq ../advantageState false)}}{{localize "DAGGERHEART.General.Disadvantage.Full"}}{{/if}}
    +
    + {{#if (eq ../roll.advantage.type 1)}}{{localize "DAGGERHEART.General.Advantage.Full"}}{{/if}}{{#if (eq ../roll.advantage.type -1)}}{{localize "DAGGERHEART.General.Disadvantage.Full"}}{{/if}} +
    {{/each}} -
    -
    - {{#each modifiers}} -
  1. {{label}}
  2. - {{/each}} -
    -
+
+ +
+
{{roll.total}}
+ {{#if (gt targets.length 0)}} +
+ {{#each targets as |target|}} +
+ +
+ {{#if target.hit}}{{localize "Hit"}}{{else}}{{localize "Miss"}}{{/if}} +
+
+ {{/each}} +
+ {{/if}} + {{#if hasDamage}} +
+ +
+ {{/if}} \ No newline at end of file diff --git a/templates/sheets/actors/adversary/main.hbs b/templates/sheets/actors/adversary/main.hbs index 66718b66..9f90228c 100644 --- a/templates/sheets/actors/adversary/main.hbs +++ b/templates/sheets/actors/adversary/main.hbs @@ -49,13 +49,43 @@
{{localize "DAGGERHEART.Sheets.Adversary.Attack"}} + + +
+ +
Name
+
+
+ {{formGroup systemFields.attack.fields.name value=source.system.attack.name name="system.attack.name"}} + {{formGroup systemFields.attack.fields.img value=source.img label="Icon" name="system.attack.img"}} +
+
+
+
+ +
Bonus
+
+
+ {{formField systemFields.attack.fields.roll.fields.bonus value=source.system.attack.roll.bonus name="system.attack.roll.bonus"}} +
+
+ {{> 'systems/daggerheart/templates/views/actionTypes/range-target.hbs' fields=(object range=systemFields.attack.fields.range target=systemFields.attack.fields.target.fields) source=(object target=source.system.attack.target range=source.system.attack.range) path="system.attack."}} +
+ {{> 'systems/daggerheart/templates/views/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=source.system.attack.damage path="system.attack."}} +
+ {{> 'systems/daggerheart/templates/views/actionTypes/effect.hbs'}} +
+ + + + {{!-- {{localize "DAGGERHEART.Sheets.Adversary.Attack"}} {{formGroup systemFields.attack.fields.name value=source.system.attack.name}} {{formGroup systemFields.attack.fields.modifier value=source.system.attack.modifier}} {{formGroup systemFields.attack.fields.range value=source.system.attack.range localize=true}} {{formGroup systemFields.attack.fields.damage.fields.value value=source.system.attack.damage.value}} - {{formGroup systemFields.attack.fields.damage.fields.type value=source.system.attack.damage.type localize=true}} + {{formGroup systemFields.attack.fields.damage.fields.type value=source.system.attack.damage.type localize=true}} --}}
diff --git a/templates/views/action.hbs b/templates/views/action.hbs index 8711cd98..79faf4b8 100644 --- a/templates/views/action.hbs +++ b/templates/views/action.hbs @@ -33,8 +33,10 @@
+ {{#unless isNPC}} {{> '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}} + {{/unless}} {{#if fields.target}}{{> '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}}
diff --git a/templates/views/actionTypes/damage.hbs b/templates/views/actionTypes/damage.hbs index 13e2fffe..633c7725 100644 --- a/templates/views/actionTypes/damage.hbs +++ b/templates/views/actionTypes/damage.hbs @@ -4,33 +4,49 @@
Damage
-
- {{#if @root.hasBaseDamage}} -
- {{!-- --}} - {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }} -
- {{/if}} + {{#unless @root.isNPC}} +
+ {{#if @root.hasBaseDamage}} +
+ {{!-- --}} + {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }} +
+ {{/if}} + {{/unless}} {{#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 @root.isNPC}} + {{formField ../fields.custom.fields.enabled value=dmg.custom.enabled name=(concat ../path "damage.parts." index ".custom.enabled")}} {{#if dmg.custom.enabled}} - {{formField ../../fields.custom.fields.formula value=dmg.custom.formula name=(concat "damage.parts." realIndex ".custom.formula") localize=true}} + {{formField ../fields.custom.fields.formula value=dmg.custom.formula name=(concat ../path "damage.parts." index ".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}} + {{formField ../fields.flatMultiplier value=dmg.flatMultiplier name=(concat "damage.parts." realIndex ".flatMultiplier") label="Multiplier" }} + {{formField ../fields.dice value=dmg.dice name=(concat ../path "damage.parts." index ".dice")}} + {{formField ../fields.bonus value=dmg.bonus name=(concat ../path "damage.parts." index ".bonus") localize=true}}
{{/if}} - {{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} - - {{#unless dmg.base}}
{{/unless}} - - {{/with}} + {{else}} + {{#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}} + {{#if (eq dmg.multiplier 'flat')}}{{formField ../../fields.flatMultiplier value=dmg.flatMultiplier name=(concat "damage.parts." realIndex ".flatMultiplier") }}{{/if}} + {{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}} + {{/if}} {{/each}}
\ No newline at end of file diff --git a/templates/views/actionTypes/range-target.hbs b/templates/views/actionTypes/range-target.hbs index 741e7ec9..69bd0ae9 100644 --- a/templates/views/actionTypes/range-target.hbs +++ b/templates/views/actionTypes/range-target.hbs @@ -3,15 +3,15 @@
Range{{#if fields.target}} & Target{{/if}}
- {{formField fields.range value=source.range label="Range" name="range" localize=true}} + {{formField fields.range value=source.range label="Range" name=(concat path "range") localize=true}}
{{#if fields.target}}
{{#if (and source.target.type (not (eq source.target.type 'self')))}} - {{ formField fields.target.amount value=source.target.amount label="Amount" name="target.amount" }} + {{ formField fields.target.amount value=source.target.amount label="Amount" name=(concat path "target.amount") }} {{/if}} - {{ formField fields.target.type value=source.target.type label="Target" name="target.type" localize=true }} + {{ formField fields.target.type value=source.target.type label="Target" name=(concat path "target.type") localize=true }}
{{/if}} diff --git a/templates/views/actionTypes/roll.hbs b/templates/views/actionTypes/roll.hbs index a3b1a31a..79fd1f03 100644 --- a/templates/views/actionTypes/roll.hbs +++ b/templates/views/actionTypes/roll.hbs @@ -3,8 +3,12 @@
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}} + {{#if @root.isNPC}} + {{formField fields.bonus label="Bonus" name="roll.bonus" value=source.bonus}} + {{else}} + {{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}} + {{/if}}
\ No newline at end of file