Add uses in action dialog

This commit is contained in:
Dapoolp 2025-06-23 11:05:52 +02:00
parent 0d60cd90b6
commit 5a8aed73d2
6 changed files with 78 additions and 46 deletions

View file

@ -1,9 +1,10 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class CostSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(costs, action, resolve) {
constructor(costs, uses, action, resolve) {
super({});
this.costs = costs;
this.uses = uses;
this.action = action;
this.resolve = resolve;
}
@ -41,21 +42,25 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl
}
async _prepareContext(_options) {
const updatedCosts = this.action.calcCosts(this.costs);
const updatedCosts = this.action.calcCosts(this.costs),
updatedUses = this.action.calcUses(this.uses);
return {
costs: updatedCosts,
canUse: this.action.getRealCosts(updatedCosts)?.hasCost
uses: updatedUses,
canUse: this.action.getRealCosts(updatedCosts)?.hasCost && this.action.hasUses(updatedUses)
};
}
static async updateForm(event, _, formData) {
this.costs = foundry.utils.mergeObject(this.costs, foundry.utils.expandObject(formData.object).costs);
const data = foundry.utils.expandObject(formData.object);
this.costs = foundry.utils.mergeObject(this.costs, data.costs);
this.uses = foundry.utils.mergeObject(this.uses, data.uses);
this.render(true)
}
static sendCost(event) {
event.preventDefault();
this.resolve(this.action.getRealCosts(this.costs));
this.resolve({ costs: this.action.getRealCosts(this.costs), uses: this.uses});
this.close();
}
}

View file

@ -69,7 +69,6 @@ export class DHRoll extends Roll {
static async postEvaluate(roll, config={}) {}
static async toMessage(roll, config) {
console.log(config)
const cls = getDocumentClass("ChatMessage"),
msg = {
type: this.messageType,
@ -80,7 +79,6 @@ export class DHRoll extends Roll {
content: await this.messageTemplate(config),
rolls: [roll]
};
console.log(msg)
await cls.create(msg);
}

View file

@ -214,16 +214,20 @@ export class DHBaseAction extends foundry.abstract.DataModel {
config.range = await this.checkRange(config);
if(!config.range.hasRange) return ui.notifications.warn("No Target within range.");
// Display Costs Dialog & Check if Actor get enough resources
config.costs = await this.getCost(config);
if(!this.hasRoll() && !config.costs.hasCost) return ui.notifications.warn("You don't have the resources to use that action.");
// Display Uses/Costs Dialog & Check if Actor get enough resources
config = {
...config,
...await this.getCost(config)
}
if(!this.hasRoll() && (!config.costs.hasCost || !this.hasUses(config.uses))) return ui.notifications.warn("You don't have the resources to use that action.");
// Proceed with Roll
config = await this.proceedRoll(config);
if(!config) return;
if(this.roll && !config.roll.result) return;
// Update Actor resources based on Action Cost configuration
this.spendCost(config.costs.values);
this.spendUses(config.uses);
// console.log(config)
@ -238,31 +242,32 @@ export class DHBaseAction extends foundry.abstract.DataModel {
async proceedRoll(config) {
if (!this.hasRoll()) return config;
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),
type: this.actionType,
difficulty: this.roll?.difficulty
}
config = {
...config,
roll: {
modifiers: [],
trait: this.roll?.trait,
label: game.i18n.localize(abilities[this.roll.trait].label),
type: this.actionType,
difficulty: this.roll?.difficulty
}
return await this.actor.diceRoll(config, this);
}
// config = await this.actor.diceRoll(config, this);
return this.actor.diceRoll(config, this);
}
/* ROLL */
/* COST */
async getCost(config) {
if(!this.cost?.length || !this.actor) return {values: [], hasCost: true};
let cost = foundry.utils.deepClone(this.cost);
let costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : {values: [], hasCost: true};
let uses = this.getUses();
if (!config.event.shiftKey && !this.hasRoll()) {
const dialogClosed = new Promise((resolve, _) => {
new CostSelectionDialog(cost, this, resolve).render(true);
new CostSelectionDialog(costs, uses, this, resolve).render(true);
});
cost = await dialogClosed;
({costs, uses} = await dialogClosed);
}
return cost;
return {costs, uses};
}
getRealCosts(costs) {
@ -292,8 +297,28 @@ export class DHBaseAction extends foundry.abstract.DataModel {
/* USES */
async spendUses(config) {
if(!this.uses.max) return;
if(!this.uses.max || config.enabled === false) return;
const newActions = foundry.utils.getProperty(this.item.system, this.systemPath).map(x => x.toObject());
newActions[this.index].uses.value++;
await this.item.update({ [`system.${this.systemPath}`]: newActions });
}
getUses() {
if(!this.uses) return {hasUse: true}
const uses = foundry.utils.deepClone(this.uses);
if(!uses.value) uses.value = 0;
return uses;
}
calcUses(uses) {
return {
...uses,
enabled: uses.hasOwnProperty('enabled') ? uses.enabled : true
};
}
hasUses(uses) {
return !uses.enabled || uses.value + 1 <= uses.max;
}
/* USES */
@ -385,13 +410,12 @@ export class DHDamageAction extends DHBaseAction {
async use(event, ...args) {
const config = await super.use(event, args);
if(['error', 'warning'].includes(config.type)) return;
if(!config || ['error', 'warning'].includes(config.type)) return;
if(!this.directDamage) return;
return await this.rollDamage(event, config);
}
async rollDamage(event, data) {
console.log(event, data)
let formula = this.damage.parts.map(p => p.getFormula(this.actor)).join(' + ');
if (!formula || formula == '') return;
@ -449,7 +473,7 @@ export class DHHealingAction extends DHBaseAction {
async use(event, ...args) {
const config = await super.use(event, args);
if(['error', 'warning'].includes(config.type)) return;
if(!config || ['error', 'warning'].includes(config.type)) return;
if(this.hasRoll()) return;
return await this.rollHealing(event, config);
}

View file

@ -7,8 +7,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config = config;
this.config.experiences = [];
this.item = config.actor.parent.items.get(config.source.item);
this.action = this.item.system.actions.find(a => a._id === config.source.action);
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);
}
}
static DEFAULT_OPTIONS = {
@ -55,13 +57,17 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
context.costs = updatedCosts
context.canRoll = this.action.getRealCosts(updatedCosts)?.hasCost;
}
if(this.config.uses?.max) {
context.uses = this.action.calcUses(this.config.uses);
context.canRoll = context.canRoll && this.action.hasUses(context.uses);
}
return context;
}
static updateRollConfiguration(event, _, formData) {
const { ...rest } = foundry.utils.expandObject(formData.object);
console.log(formData.object, rest)
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();
}

View file

@ -268,19 +268,10 @@ export default class DhpActor extends Actor {
// console.log(config)
config.source = {...(config.source ?? {}), actor: this.id};
const newConfig = {
// data: {
...config,
/* action, */
// actor: this.getRollData(),
actor: this.system
// },
// options: {
// dialog: false,
// },
// event: config.event
...config,
actor: this.system
}
// console.log(this, newConfig)
const roll = CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(newConfig)
const roll = await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(newConfig)
return config;
/* let hopeDice = 'd12',
fearDice = 'd12',

View file

@ -1,4 +1,12 @@
<div>
{{#if uses}}
<div class="form-group">
<div class="form-fields">
<label for="uses.enabled">Uses: {{uses.value}}/{{uses.max}}</label>
<input name="uses.enabled" type="checkbox"{{#if uses.enabled}} checked{{/if}}>
</div>
</div>
{{/if}}
{{#each costs as | cost index |}}
<div class="form-group">
<div class="form-fields">