diff --git a/lang/en.json b/lang/en.json index 90250d05..dae24038 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1566,6 +1566,9 @@ }, "spellcast": { "name": "SpellCast" + }, + "diceSet": { + "name": "Dice Set" } } } diff --git a/module/applications/roll.mjs b/module/applications/roll.mjs index b5f53abc..51a02dc3 100644 --- a/module/applications/roll.mjs +++ b/module/applications/roll.mjs @@ -11,6 +11,10 @@ export class DHRoll extends Roll { super(formula, data, options); } + static messageType = 'adversaryRoll'; + + static DefaultDialog = D20RollDialog; + static async build(config = {}, message = {}) { const roll = await this.buildConfigure(config, message); if (!roll) return; @@ -25,22 +29,21 @@ export class DHRoll extends Roll { for (const hook of config.hooks) { if (Hooks.call(`${SYSTEM.id}.preRoll${hook.capitalize()}`, config, message) === false) return null; } - + this.applyKeybindings(config); + let roll = new this(config.roll.formula, config.data, config); if (config.dialog.configure !== false) { // Open Roll Dialog const DialogClass = config.dialog?.class ?? this.DefaultDialog; - config = await DialogClass.configure(config, message); - if (!config) return; + const configDialog = await DialogClass.configure(roll, config, message); + if (!configDialog) return; } - 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 []; } - return roll; } @@ -62,7 +65,20 @@ export class DHRoll extends Roll { } } - static async postEvaluate(roll, config = {}) {} + static postEvaluate(roll, config = {}) { + if(!config.roll) config.roll = {}; + config.roll.total = roll.total; + config.roll.formula = roll.formula; + config.roll.dice = []; + roll.dice.forEach(d => { + config.roll.dice.push({ + dice: d.denomination, + total: d.total, + formula: d.formula, + results: d.results + }); + }); + } static async toMessage(roll, config) { const cls = getDocumentClass('ChatMessage'), @@ -77,15 +93,16 @@ export class DHRoll extends Roll { } static applyKeybindings(config) { - config.dialog.configure ??= true; + config.dialog.configure ??= !(config.event.shiftKey || config.event.altKey || config.event.ctrlKey); + } + + constructFormula(config) { + // const formula = Roll.replaceFormulaData(this.options.roll.formula, config.data); + this.terms = Roll.parse(this.options.roll.formula, config.data) + return (this._formula = this.constructor.getFormula(this.terms)); } } -// DHopeDie -// DFearDie -// DualityDie -// D20Die - export class DualityDie extends foundry.dice.terms.Die { constructor({ number = 1, faces = 12, ...args } = {}) { super({ number, faces, ...args }); @@ -95,10 +112,11 @@ export class DualityDie extends foundry.dice.terms.Die { export class D20Roll extends DHRoll { constructor(formula, data = {}, options = {}) { super(formula, data, options); - this.createBaseDice(); - this.configureModifiers(); + // this.createBaseDice(); + // this.configureModifiers(); - this._formula = this.resetFormula(); + // this._formula = this.resetFormula(); + this.constructFormula(); } static ADV_MODE = { @@ -165,7 +183,7 @@ export class D20Roll extends DHRoll { applyAdvantage() { this.d20.modifiers.findSplice(m => ['kh', 'kl'].includes(m)); - if (!this.hasAdvantage && !this.hasAdvantage) this.number = 1; + if (!this.hasAdvantage && !this.hasDisadvantage) this.number = 1; else { this.d20.number = 2; this.d20.modifiers.push(this.hasAdvantage ? 'kh' : 'kl'); @@ -175,62 +193,62 @@ export class D20Roll extends DHRoll { // Trait bonus != Adversary configureModifiers() { this.applyAdvantage(); - + // this.options.roll.modifiers = []; this.applyBaseBonus(); - + this.options.experiences?.forEach(m => { if (this.options.data.experiences?.[m]) this.options.roll.modifiers.push({ - label: this.options.data.experiences[m].description, - value: this.options.data.experiences[m].total + label: this.options.data.experiences[m].name, + value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value }); }); this.options.roll.modifiers?.forEach(m => { this.terms.push(...this.formatModifier(m.value)); }); - if (this.options.extraFormula) + if (this.options.extraFormula) { this.terms.push( new foundry.dice.terms.OperatorTerm({ operator: '+' }), ...this.constructor.parse(this.options.extraFormula, this.getRollData()) ); - + } // this.resetFormula(); } - applyBaseBonus() { - if (this.options.type === 'attack') - this.terms.push(...this.formatModifier(this.options.data.attack.roll.bonus)); + constructFormula(config) { + this.terms = []; + this.createBaseDice(); + this.configureModifiers(); + this.resetFormula(); + return this._formula; } - static async postEvaluate(roll, config = {}) { + applyBaseBonus() { + this.options.roll.modifiers = [{ + label : 'Bonus to Hit', + value: Roll.replaceFormulaData('@attackBonus', this.data) + }]; + } + + static postEvaluate(roll, config = {}) { + super.postEvaluate(roll, config); if (config.targets?.length) { config.targets.forEach(target => { const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion; target.hit = this.isCritical || roll.total >= difficulty; }); } else if (config.roll.difficulty) config.roll.success = roll.isCritical || roll.total >= config.roll.difficulty; - config.roll.total = roll.total; - config.roll.formula = roll.formula; config.roll.advantage = { type: config.advantage, dice: roll.dAdvantage?.denomination, 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 - }); - }); + config.roll.modifierTotal = config.roll.modifiers.reduce((a, c) => a + Number(c.value), 0); } getRollData() { - return this.options.data(); + return this.options.data; } formatModifier(modifier) { @@ -332,7 +350,7 @@ export class DualityRoll extends D20Roll { bardRallyFaces = this.hasBarRally, advDie = new foundry.dice.terms.Die({ faces: dieFaces }); if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) - this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: '+' })); + this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: (this.hasDisadvantage ? '-' : '+') })); if (bardRallyFaces) { const rallyDie = new foundry.dice.terms.Die({ faces: bardRallyFaces }); if (this.hasAdvantage) { @@ -349,15 +367,13 @@ export class DualityRoll extends D20Roll { } applyBaseBonus() { - 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 - }); + this.options.roll.modifiers = [{ + label : `DAGGERHEART.Abilities.${this.options.roll.trait}.name`, + value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.total`, this.data) + }]; } - static async postEvaluate(roll, config = {}) { + static postEvaluate(roll, config = {}) { super.postEvaluate(roll, config); config.roll.hope = { dice: roll.dHope.denomination, @@ -372,6 +388,7 @@ export class DualityRoll extends D20Roll { total: roll.dHope.total + roll.dFear.total, label: roll.totalLabel }; + console.log(roll, config) } } @@ -385,19 +402,7 @@ export class DamageRoll extends DHRoll { static DefaultDialog = DamageDialog; static async postEvaluate(roll, config = {}) { - config.roll = { - total: roll.total, - formula: roll.formula, - type: config.type - }; - config.roll.dice = []; - roll.dice.forEach(d => { - config.roll.dice.push({ - dice: d.denomination, - total: d.total, - formula: d.formula, - results: d.results - }); - }); + super.postEvaluate(roll, config); + config.roll.type = config.type; } } diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index f6607c44..1af01b61 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -73,23 +73,15 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { 'systems/daggerheart/templates/views/actionType.hbs', { types: SYSTEM.ACTIONS.actionTypes } ), - title = 'Select Action Type', //useless var - type = 'form', - data = {}; //useless var - //TODO: use DialogV2 - return Dialog.prompt({ - title, - label: title, + title = 'Select Action Type' + + return foundry.applications.api.DialogV2.prompt({ + window: { title }, content, - type, //this prop is useless - 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 + ok: { + label: title, + callback: (event, button, dialog) => button.form.elements.type.value + } }); } @@ -100,13 +92,14 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { */ static async #addAction(_event, _button) { const actionType = await DHBaseItemSheet.selectActionType(); + if(!actionType) return; try { - const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack, + const cls = actionsTypes[actionType] ?? actionsTypes.attack, action = new cls( { _id: foundry.utils.randomID(), - type: actionType.type, - name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name), + type: actionType, + name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType].name), ...cls.getSourceConfig(this.document) }, { diff --git a/module/config/actionConfig.mjs b/module/config/actionConfig.mjs index a0af78eb..91004bdd 100644 --- a/module/config/actionConfig.mjs +++ b/module/config/actionConfig.mjs @@ -77,3 +77,31 @@ export const damageOnSave = { mod: 1 } } + +export const diceCompare = { + below: { + id: 'below', + label: 'Below', + operator: '<' + }, + belowEqual: { + id: 'belowEqual', + label: 'Below or Equal', + operator: '<=' + }, + equal: { + id: 'equal', + label: 'Equal', + operator: '=' + }, + aboveEqual: { + id: 'aboveEqual', + label: 'Above or Equal', + operator: '>=' + }, + above: { + id: 'above', + label: 'Above', + operator: '>' + } +} diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 7b6fba4e..a6484b61 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -313,11 +313,20 @@ export const diceTypes = { }; export const multiplierTypes = { - proficiency: 'Proficiency', - spellcast: 'Spellcast', + prof: 'Proficiency', + cast: 'Spellcast', + scale: 'Cost Scaling', + result: 'Roll Result', flat: 'Flat' }; +export const diceSetNumbers = { + prof: 'Proficiency', + cast: 'Spellcast', + scale: 'Cost Scaling', + flat: 'Flat' +} + export const getDiceSoNicePresets = () => { const { diceSoNice } = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance); @@ -437,6 +446,10 @@ export const rollTypes = { ability: { id: 'ability', label: 'DAGGERHEART.RollTypes.ability.name' + }, + diceSet: { + id: 'diceSet', + label: 'DAGGERHEART.RollTypes.diceSet.name' } }; diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs index 3beb92a9..ee9bbabe 100644 --- a/module/data/action/action.mjs +++ b/module/data/action/action.mjs @@ -1,5 +1,5 @@ import CostSelectionDialog from '../../applications/costSelectionDialog.mjs'; -import { DHActionDiceData, DHDamageData, DHDamageField } from './actionDice.mjs'; +import { DHActionDiceData, DHActionRollData, DHDamageData, DHDamageField } from './actionDice.mjs'; import DhpActor from '../../documents/actor.mjs'; import D20RollDialog from '../../dialogs/d20RollDialog.mjs'; @@ -69,12 +69,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { static defineExtraSchema() { const extraFields = { damage: new DHDamageField(), - 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 }), - bonus: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }) - }), + roll: new fields.EmbeddedDataField(DHActionRollData), save: new fields.SchemaField({ trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }), difficulty: new fields.NumberField({ nullable: true, initial: 10, integer: true, min: 0 }), @@ -158,20 +153,24 @@ export class DHBaseAction extends foundry.abstract.DataModel { return updateSource; } - getRollData() { + getRollData(data={}) { const actorData = this.actor.getRollData(false); // Remove when included directly in Actor getRollData - actorData.prof = actorData.proficiency?.value ?? 1, - actorData.cast = actorData.spellcast?.value ?? 1, - actorData.scale = this.cost.length - ? this.cost.reduce((a, c) => { + actorData.prof = actorData.proficiency?.value ?? 1; + actorData.cast = actorData.spellcast?.value ?? 1; + actorData.result = data.roll?.total ?? 1; + /* actorData.scale = data.costs?.length + ? data.costs.reduce((a, c) => { a[c.type] = c.value; return a; }, {}) - : 1, - actorData.roll = {} - + : 1; */ + actorData.scale = data.costs?.length // Right now only return the first scalable cost. + ? (data.costs.find(c => c.scalable)?.total ?? 1) + : 1; + actorData.roll = {}; + return actorData; } @@ -215,7 +214,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { if ( Hooks.call(`${SYSTEM.id}.preUseAction`, this, config) === false ) return; // Display configuration window if necessary - if ( config.dialog.configure && this.requireConfigurationDialog(config) ) { + if ( config.dialog?.configure && this.requireConfigurationDialog(config) ) { config = await D20RollDialog.configure(config); if (!config) return; } @@ -281,11 +280,8 @@ export class DHBaseAction extends foundry.abstract.DataModel { source: { item: this.item._id, action: this._id - // action: this - }, - dialog: { - configure: true }, + dialog: {}, type: this.type, hasDamage: !!this.damage?.parts?.length, hasHealing: !!this.healing, @@ -295,7 +291,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { } requireConfigurationDialog(config) { - return !config.event.shiftkey && !this.hasRoll && (config.costs?.length || config.uses); + return !config.event.shiftKey && !this.hasRoll && (config.costs?.length || config.uses); } prepareCost() { @@ -335,8 +331,11 @@ export class DHBaseAction extends foundry.abstract.DataModel { trait: this.roll?.trait, label: 'Attack', type: this.actionType, - difficulty: this.roll?.difficulty + difficulty: this.roll?.difficulty, + formula: this.roll.getFormula() }; + if(this.roll?.type === 'diceSet') roll.lite = true; + return roll; } @@ -346,8 +345,9 @@ export class DHBaseAction extends foundry.abstract.DataModel { async consume(config) { const resources = config.costs.filter(c => c.enabled !== false).map(c => { - return { type: c.type, value: c.total * -1 }; + return { type: c.type, value: (c.total ?? c.value) * -1 }; }); + await this.actor.modifyResource(resources); if(config.uses?.enabled) { const newActions = foundry.utils.getProperty(this.item.system, this.systemPath).map(x => x.toObject()); @@ -490,7 +490,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { }, data: target.actor.getRollData() }).then(async (result) => { - this.updateChatMessage(message, target.id, {result: result.roll.total, success: result.roll.success}); + if(result) this.updateChatMessage(message, target.id, {result: result.roll.total, success: result.roll.success}); }) } @@ -536,12 +536,15 @@ export class DHDamageAction extends DHBaseAction { let roll = { formula: formula, total: formula }, bonusDamage = []; + if(isNaN(formula)) formula = Roll.replaceFormulaData(formula, this.getRollData(data.system ?? data)); + const config = { title: game.i18n.format('DAGGERHEART.Chat.DamageRoll.Title', { damage: this.name }), - formula, + roll: {formula}, targets: (data.system?.targets.filter(t => t.hit) ?? data.targets), hasSave: this.hasSave, - source: data.system?.source + source: data.system?.source, + event }; if(this.hasSave) config.onSave = this.save.damageMod; if(data.system) { @@ -575,7 +578,7 @@ export class DHAttackAction extends DHDamageAction { getParentDamage() { return { value: { - multiplier: 'proficiency', + multiplier: 'prof', dice: this.item?.system?.damage.value, bonus: this.item?.system?.damage.bonus ?? 0 }, @@ -610,10 +613,11 @@ export class DHHealingAction extends DHBaseAction { title: game.i18n.format('DAGGERHEART.Chat.HealingRoll.Title', { healing: game.i18n.localize(SYSTEM.GENERAL.healingTypes[this.healing.type].label) }), - formula, + roll: {formula}, targets: (data.system?.targets ?? data.targets).filter(t => t.hit), messageType: 'healing', - type: this.healing.type + type: this.healing.type, + event }; roll = CONFIG.Dice.daggerheart.DamageRoll.build(config); diff --git a/module/data/action/actionDice.mjs b/module/data/action/actionDice.mjs index 3bb51b50..e422b856 100644 --- a/module/data/action/actionDice.mjs +++ b/module/data/action/actionDice.mjs @@ -2,13 +2,60 @@ import FormulaField from '../fields/formulaField.mjs'; const fields = foundry.data.fields; +/* Roll Field */ + +export class DHActionRollData extends foundry.abstract.DataModel { + /** @override */ + static defineSchema() { + return { + 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 }), + bonus: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }), + diceRolling: new fields.SchemaField({ + multiplier: new fields.StringField({ + choices: SYSTEM.GENERAL.diceSetNumbers, + initial: 'prof', + label: 'Dice Number' + }), + flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }), + dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Dice Type' }), + compare: new fields.StringField({ + choices: SYSTEM.ACTIONS.diceCompare, + initial: 'above', + label: 'Should be' + }), + treshold: new fields.NumberField({ initial: 1, integer: true, min: 1, label: 'Treshold' }), + }) + }; + } + + getFormula() { + if(!this.type) return; + let formula = ''; + switch (this.type) { + case 'diceSet': + const multiplier = this.diceRolling.multiplier === 'flat' ? this.diceRolling.flatMultiplier : `@${this.diceRolling.multiplier}`; + formula = `${multiplier}${this.diceRolling.dice}cs${SYSTEM.ACTIONS.diceCompare[this.diceRolling.compare].operator}${this.diceRolling.treshold}`; + break; + default: + // formula = `${(!!this.parent?.actor?.system?.attack ? `@attackBonus` : `@traits.${this.trait}.total`)}`; + formula = ''; + break; + } + return formula; + } +} + +/* Damage & Healing Field */ + export class DHActionDiceData extends foundry.abstract.DataModel { /** @override */ static defineSchema() { return { multiplier: new fields.StringField({ choices: SYSTEM.GENERAL.multiplierTypes, - initial: 'proficiency', + initial: 'prof', label: 'Multiplier' }), flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }), @@ -22,10 +69,15 @@ export class DHActionDiceData extends foundry.abstract.DataModel { } getFormula(actor) { - const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : actor.system[this.multiplier]?.total; + /* const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : actor.system[this.multiplier]?.total; return this.custom.enabled ? this.custom.formula - : `${multiplier ?? 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}`) : ''}`; */ + const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`, + bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''; + return this.custom.enabled + ? this.custom.formula + : `${multiplier ?? 1}${this.dice}${bonus}`; } } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 5ac80969..b1ed29ec 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -77,4 +77,8 @@ export default class DhpAdversary extends BaseDataActor { }) }; } + + get attackBonus() { + return this.attack.roll.bonus; + } } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 1df2176d..fb3466bb 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -62,7 +62,7 @@ export default class DhCharacter extends BaseDataActor { }), experiences: new fields.TypedObjectField( new fields.SchemaField({ - description: new fields.StringField({}), + name: new fields.StringField(), value: new fields.NumberField({ integer: true, initial: 0 }), bonus: new fields.NumberField({ integer: true, initial: 0 }) }) diff --git a/module/data/chat-message/dualityRoll.mjs b/module/data/chat-message/dualityRoll.mjs index 0f3f12de..1fdb537c 100644 --- a/module/data/chat-message/dualityRoll.mjs +++ b/module/data/chat-message/dualityRoll.mjs @@ -26,6 +26,7 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel { }) }) ), + costs: new fields.ArrayField(new fields.ObjectField()), hasDamage: new fields.BooleanField({ initial: false }), hasHealing: new fields.BooleanField({ initial: false }), hasEffect: new fields.BooleanField({ initial: false }), diff --git a/module/dialogs/d20RollDialog.mjs b/module/dialogs/d20RollDialog.mjs index 0b64615b..30c0c40e 100644 --- a/module/dialogs/d20RollDialog.mjs +++ b/module/dialogs/d20RollDialog.mjs @@ -1,9 +1,10 @@ const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export default class D20RollDialog extends HandlebarsApplicationMixin(ApplicationV2) { - constructor(config = {}, options = {}) { + constructor(roll, config = {}, options = {}) { super(options); + this.roll = roll; this.config = config; this.config.experiences = []; @@ -59,22 +60,26 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.advantage = this.config.advantage; /* context.diceOptions = this.diceOptions; */ context.canRoll = true; + context.isLite = this.config.roll?.lite; if (this.config.costs?.length) { const updatedCosts = this.action.calcCosts(this.config.costs); context.costs = updatedCosts; context.canRoll = this.action.hasCost(updatedCosts); + this.config.data.scale = this.config.costs[0].total; } if (this.config.uses?.max) { context.uses = this.action.calcUses(this.config.uses); context.canRoll = context.canRoll && this.action.hasUses(context.uses); } - console.log(context, _options) + context.formula = this.roll.constructFormula(this.config); return context; } static updateRollConfiguration(event, _, formData) { const { ...rest } = foundry.utils.expandObject(formData.object); - if (this.config.costs) this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs); + if (this.config.costs) { + this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs); + } if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses); this.render(); } @@ -86,11 +91,12 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio } static selectExperience(_, button) { - if (this.config.experiences.find(x => x === button.dataset.key)) { + /* if (this.config.experiences.find(x => x === button.dataset.key)) { this.config.experiences = this.config.experiences.filter(x => x !== button.dataset.key); } else { this.config.experiences = [...this.config.experiences, button.dataset.key]; - } + } */ + this.config.experiences = this.config.experiences.indexOf(button.dataset.key) > -1 ? this.config.experiences.filter(x => x !== button.dataset.key) : [...this.config.experiences, button.dataset.key]; this.render(); } @@ -103,9 +109,9 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio if (!options.submitted) this.config = false; } - static async configure(config = {}, options={}) { + static async configure(roll, config = {}, options={}) { return new Promise(resolve => { - const app = new this(config, options); + const app = new this(roll, config, options); app.addEventListener('close', () => resolve(app.config), { once: true }); app.render({ force: true }); }); diff --git a/module/dialogs/damageDialog.mjs b/module/dialogs/damageDialog.mjs index 5915f6e2..d3c571a9 100644 --- a/module/dialogs/damageDialog.mjs +++ b/module/dialogs/damageDialog.mjs @@ -1,9 +1,10 @@ const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export default class DamageDialog extends HandlebarsApplicationMixin(ApplicationV2) { - constructor(config={}, options={}) { + constructor(roll, config={}, options={}) { super(options); + this.roll = roll; this.config = config; } @@ -36,7 +37,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application async _prepareContext(_options) { const context = await super._prepareContext(_options); context.title = this.config.title; - context.formula = this.config.formula; + context.formula = this.config.roll.formula; return context; } @@ -49,9 +50,9 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application if ( !options.submitted ) this.config = false; } - static async configure(config={}) { + static async configure(roll, config={}) { return new Promise(resolve => { - const app = new this(config); + const app = new this(roll, config); app.addEventListener("close", () => resolve(app.config), { once: true }); app.render({ force: true }); }); diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 350c39a1..6e475d7e 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -268,7 +268,8 @@ export default class DhpActor extends Actor { async diceRoll(config) { config.source = {...(config.source ?? {}), actor: this.uuid}; config.data = this.getRollData(); - return await this.rollClass.build(config); + const rollClass = config.roll.lite ? CONFIG.Dice.daggerheart['DHRoll'] : this.rollClass; + return await rollClass.build(config); } get rollClass() { @@ -421,13 +422,14 @@ export default class DhpActor extends Actor { break; default: updates.actor.resources[`system.resources.${r.type}.value`] = Math.max( - Math.min(this.system.resources[r.type].value + r.value, this.system.resources[r.type].max), + Math.min(this.system.resources[r.type].value + r.value, (this.system.resources[r.type].maxTotal ?? this.system.resources[r.type].max)), 0 ); break; } }); Object.values(updates).forEach(async u => { + console.log(updates, u) if (Object.keys(u.resources).length > 0) { if (game.user.isGM) { await u.target.update(u.resources); diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 45b9df8e..6158db7b 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -79,23 +79,18 @@ export default class DHItem extends foundry.documents.Item { 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, + 'systems/daggerheart/templates/views/actionSelect.hbs', + { actions: this.system.actions } + ), + title = 'Select Action'; + + return foundry.applications.api.DialogV2.prompt({ + window: { 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 + ok: { + label: title, + callback: (event, button, dialog) => this.system.actions.find(a => a._id === button.form.elements.actionId.value) + } }); } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index d62ff148..d812f043 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -225,11 +225,10 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue // Fix on Foundry native formula replacement for DH const nativeReplaceFormulaData = Roll.replaceFormulaData; -Roll.replaceFormulaData = function (formula, data, { missing, warn = false } = {}) { - const terms = [ - { term: 'prof', default: 1 }, - { term: 'cast', default: 1 } - ]; +Roll.replaceFormulaData = function (formula, data={}, { missing, warn = false } = {}) { + const terms = Object.keys(SYSTEM.GENERAL.multiplierTypes).map(type => { + return { term: type, default: 1} + }) formula = terms.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula); return nativeReplaceFormulaData(formula, data, { missing, warn }); }; diff --git a/module/ui/chatLog.mjs b/module/ui/chatLog.mjs index 3f537adf..dfcc1b8e 100644 --- a/module/ui/chatLog.mjs +++ b/module/ui/chatLog.mjs @@ -155,7 +155,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo : Array.from(game.user.targets); if(message.system.onSave && event.currentTarget.dataset.targetHit) { - console.log(message.system.targets) const pendingingSaves = message.system.targets.filter(target => target.hit && target.saved.success === null); if(pendingingSaves.length) { const confirm = await foundry.applications.api.DialogV2.confirm({ @@ -171,6 +170,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo for (let target of targets) { let damage = message.system.roll.total; if(message.system.onSave && message.system.targets.find(t => t.id === target.id)?.saved?.success === true) damage = Math.ceil(damage * (SYSTEM.ACTIONS.damageOnSave[message.system.onSave]?.mod ?? 1)); + await target.actor.takeDamage(damage, message.system.roll.type); } }; diff --git a/styles/daggerheart.css b/styles/daggerheart.css index 4dbf6ac4..d620cb5b 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -2570,7 +2570,6 @@ div.daggerheart.views.multiclass { opacity: 1; } .theme-light .daggerheart.dh-style.dialog.character-creation .tab-navigation nav a .descriptor { - background: red; background-image: url('../assets/parchments/dh-parchment-dark.png'); } .theme-light .daggerheart.dh-style.dialog.character-creation .main-selections-container .traits-container .suggested-traits-container .suggested-trait-container, @@ -2581,6 +2580,9 @@ div.daggerheart.views.multiclass { .daggerheart.dh-style.dialog.character-creation .window-content { gap: 16px; } +.daggerheart.dh-style.dialog.character-creation .window-content .tab { + overflow-y: auto; +} .daggerheart.dh-style.dialog.character-creation .tab-navigation nav { flex: 1; } diff --git a/templates/views/actionTypes/roll.hbs b/templates/views/actionTypes/roll.hbs index 7e40a821..c4a7387c 100644 --- a/templates/views/actionTypes/roll.hbs +++ b/templates/views/actionTypes/roll.hbs @@ -7,8 +7,22 @@ {{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 disabled=(not source.type)}} - {{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty disabled=(not source.type)}} + {{#if (eq source.type "diceSet")}} +
+ {{formField fields.diceRolling.fields.multiplier name="roll.diceRolling.multiplier" value=source.diceRolling.multiplier localize=true}} + {{#if (eq source.diceRolling.multiplier 'flat')}}{{formField fields.diceRolling.fields.flatMultiplier value=source.diceRolling.flatMultiplier name="roll.diceRolling.flatMultiplier" }}{{/if}} + {{formField fields.diceRolling.fields.dice name="roll.diceRolling.dice" value=source.diceRolling.dice}} +
+
+ {{formField fields.diceRolling.fields.compare name="roll.diceRolling.compare" value=source.diceRolling.compare localize=true}} + {{formField fields.diceRolling.fields.treshold name="roll.diceRolling.treshold" value=source.diceRolling.treshold localize=true}} +
+ {{else}} +
+ {{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true disabled=(not source.type)}} + {{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty disabled=(not source.type)}} +
+ {{/if}} {{/if}} \ No newline at end of file diff --git a/templates/views/rollSelection.hbs b/templates/views/rollSelection.hbs index 3a9cf786..c3728ccc 100644 --- a/templates/views/rollSelection.hbs +++ b/templates/views/rollSelection.hbs @@ -2,11 +2,12 @@ {{#if @root.hasRoll}}
+ {{#unless @root.isLite}}
{{#each experiences}} - {{#if description}} + {{#if name}}
- {{description}} + {{name}} +{{value}}
{{/if}} @@ -16,6 +17,10 @@
+ {{/unless}} +
+ +
{{!-- {{#if (not isNpc)}} --}} {{!--