[Feature] Damage-Reroll (#753)

* Added rerolls for damage dice in chat

* Fixed multiple dice

* Added reroll icon

* Fixed new style of dialog
This commit is contained in:
WBHarry 2025-08-10 01:32:12 +02:00 committed by GitHub
parent 2aaab73699
commit 300719c116
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 1094 additions and 167 deletions

View file

@ -224,11 +224,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
.filter(
c =>
(!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
(successCost && c.consumeOnSuccess)
(successCost && c.consumeOnSuccess)
)
.reduce((a, c) => {
const resource = usefulResources[c.key];
if( resource ) {
if (resource) {
a.push({
key: c.key,
value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1),
@ -247,9 +247,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
)
this.update({ 'uses.value': this.uses.value + 1 });
if(config.roll?.success || successCost) {
if (config.roll?.success || successCost) {
setTimeout(() => {
(config.message ?? config.parent).update({'system.successConsumed': true})
(config.message ?? config.parent).update({ 'system.successConsumed': true });
}, 50);
}
}
@ -371,11 +371,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
async updateChatMessage(message, targetId, changes, chain = true) {
setTimeout(async () => {
const chatMessage = ui.chat.collection.get(message._id);
await chatMessage.update({
flags: {
[game.system.id]: {
"reactionRolls": {
reactionRolls: {
[targetId]: changes
}
}

View file

@ -18,7 +18,6 @@ const targetsField = () =>
);
export default class DHActorRoll extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
title: new fields.StringField(),
@ -65,7 +64,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
}
set targetMode(mode) {
if(!this.parent.isAuthor) return;
if (!this.parent.isAuthor) return;
this.parent.targetSelection = mode;
this.registerTargetHook();
this.updateTargets();
@ -76,13 +75,14 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
}
async updateTargets() {
if(!ui.chat.collection.get(this.parent.id)) return;
if (!ui.chat.collection.get(this.parent.id)) return;
let targets;
if(this.targetMode)
targets = this.targets;
if (this.targetMode) targets = this.targets;
else
targets = Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t));
targets = Array.from(game.user.targets).map(t =>
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
);
await this.parent.update({
flags: {
[game.system.id]: {
@ -90,16 +90,19 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
targetMode: this.targetMode
}
}
})
});
}
registerTargetHook() {
if(!this.parent.isAuthor) return;
if(this.targetMode && this.parent.targetHook !== null) {
Hooks.off("targetToken", this.parent.targetHook);
return this.parent.targetHook = null;
if (!this.parent.isAuthor) return;
if (this.targetMode && this.parent.targetHook !== null) {
Hooks.off('targetToken', this.parent.targetHook);
return (this.parent.targetHook = null);
} else if (!this.targetMode && this.parent.targetHook === null) {
return this.parent.targetHook = Hooks.on('targetToken', foundry.utils.debounce(this.updateTargets.bind(this), 50));
return (this.parent.targetHook = Hooks.on(
'targetToken',
foundry.utils.debounce(this.updateTargets.bind(this), 50)
));
}
}
@ -107,13 +110,16 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
if (this.hasTarget) {
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
this.currentTargets = this.getTargetList();
if(this.targetMode === true && this.hasRoll) {
this.targetShort = this.targets.reduce((a,c) => {
if(c.hit) a.hit += 1;
else a.miss += 1;
return a;
}, {hit: 0, miss: 0})
if (this.targetMode === true && this.hasRoll) {
this.targetShort = this.targets.reduce(
(a, c) => {
if (c.hit) a.hit += 1;
else a.miss += 1;
return a;
},
{ hit: 0, miss: 0 }
);
}
if (this.hasSave) this.setPendingSaves();
}
@ -123,13 +129,16 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
}
getTargetList() {
const targets = this.targetMode && this.parent.isAuthor ? this.targets : (this.parent.getFlag(game.system.id, "targets") ?? this.targets),
reactionRolls = this.parent.getFlag(game.system.id, "reactionRolls");
const targets =
this.targetMode && this.parent.isAuthor
? this.targets
: (this.parent.getFlag(game.system.id, 'targets') ?? this.targets),
reactionRolls = this.parent.getFlag(game.system.id, 'reactionRolls');
if(reactionRolls) {
if (reactionRolls) {
Object.entries(reactionRolls).forEach(([k, r]) => {
const target = targets.find(t => t.id === k);
if(target) target.saved = r;
if (target) target.saved = r;
});
}

View file

@ -12,7 +12,10 @@ export default class CostField extends fields.ArrayField {
value: new fields.NumberField({ nullable: true, initial: 1, min: 0 }),
scalable: new fields.BooleanField({ initial: false }),
step: new fields.NumberField({ nullable: true, initial: null }),
consumeOnSuccess: new fields.BooleanField({ initial: false, label: "DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.label" })
consumeOnSuccess: new fields.BooleanField({
initial: false,
label: 'DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.label'
})
});
super(element, options, context);
}
@ -47,7 +50,7 @@ export default class CostField extends fields.ArrayField {
static hasCost(costs) {
const realCosts = CostField.getRealCosts.call(this, costs),
hasFearCost = realCosts.findIndex(c => c.key === 'fear');
if (hasFearCost > -1) {
const fearCost = realCosts.splice(hasFearCost, 1)[0];
if (
@ -72,7 +75,8 @@ export default class CostField extends fields.ArrayField {
static getResources(costs) {
const actorResources = foundry.utils.deepClone(this.actor.system.resources);
if(this.actor.system.partner) actorResources.hope = foundry.utils.deepClone(this.actor.system.partner.system.resources.hope);
if (this.actor.system.partner)
actorResources.hope = foundry.utils.deepClone(this.actor.system.partner.system.resources.hope);
const itemResources = {};
for (let itemResource of costs) {
if (itemResource.keyIsID) {
@ -92,9 +96,9 @@ export default class CostField extends fields.ArrayField {
static getRealCosts(costs) {
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
let mergedCosts = [];
realCosts.forEach(c => {
realCosts.forEach(c => {
const getCost = Object.values(mergedCosts).find(gc => gc.key === c.key);
if(getCost) getCost.total += c.total;
if (getCost) getCost.total += c.total;
else mergedCosts.push(c);
});
return mergedCosts;

View file

@ -227,7 +227,7 @@ export function ActionMixin(Base) {
} else {
result = await this.item.update({ [path]: updates }, options);
}
return this.inCollection
? foundry.utils.getProperty(result, basePath)?.get(this.id)
: foundry.utils.getProperty(result, basePath);