mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 19:51:08 +01:00
Fixed Stress Reductions
This commit is contained in:
parent
f4539ab158
commit
0e1320e31d
8 changed files with 279 additions and 74 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { getDamageLabel } from '../helpers/utils.mjs';
|
||||
import { damageKeyToNumber, getDamageLabel } from '../helpers/utils.mjs';
|
||||
|
||||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
|
|
@ -11,13 +11,32 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
|||
this.actor = actor;
|
||||
this.damage = damage;
|
||||
|
||||
const maxUseable = actor.system.armorScore - actor.system.armor.system.marks.value;
|
||||
this.availableArmorMarks = {
|
||||
max: actor.system.rules.maxArmorMarked.total + (actor.system.rules.stressExtra ?? 0),
|
||||
maxUseable: actor.system.armorScore - actor.system.armor.system.marks.value,
|
||||
stressIndex:
|
||||
(actor.system.rules.stressExtra ?? 0) > 0 ? actor.system.rules.maxArmorMarked.total : undefined,
|
||||
max: Math.min(
|
||||
maxUseable,
|
||||
actor.system.rules.maxArmorMarked.total + (actor.system.rules.maxArmorMarked.stressExtra ?? 0)
|
||||
),
|
||||
stressIndex: actor.system.rules.maxArmorMarked.total,
|
||||
selected: 0
|
||||
};
|
||||
|
||||
this.availableStressReductions = Object.keys(actor.system.rules.stressDamageReduction).reduce((acc, key) => {
|
||||
const dr = actor.system.rules.stressDamageReduction[key];
|
||||
if (dr.enabled) {
|
||||
if (acc === null) acc = {};
|
||||
|
||||
const damage = damageKeyToNumber(key);
|
||||
acc[damage] = {
|
||||
cost: dr.cost,
|
||||
selected: false,
|
||||
from: getDamageLabel(damage),
|
||||
to: getDamageLabel(damage - 1)
|
||||
};
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, null);
|
||||
}
|
||||
|
||||
get title() {
|
||||
|
|
@ -33,6 +52,7 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
|||
},
|
||||
actions: {
|
||||
setMarks: this.setMarks,
|
||||
useStressReduction: this.useStressReduction,
|
||||
takeDamage: this.takeDamage
|
||||
},
|
||||
form: {
|
||||
|
|
@ -61,13 +81,31 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
|||
const context = await super._prepareContext(_options);
|
||||
context.armorScore = this.actor.system.armorScore;
|
||||
context.armorMarks = this.actor.system.armor.system.marks.value + this.availableArmorMarks.selected;
|
||||
|
||||
const selectedStressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
||||
const stressReductionStress = this.availableStressReductions
|
||||
? selectedStressReductions.reduce((acc, red) => acc + red.cost, 0)
|
||||
: 0;
|
||||
context.stress =
|
||||
this.availableArmorMarks.stressIndex || this.availableStressReductions
|
||||
? {
|
||||
value:
|
||||
this.actor.system.resources.stress.value +
|
||||
(Math.max(this.availableArmorMarks.selected - this.availableArmorMarks.stressIndex, 0) +
|
||||
stressReductionStress),
|
||||
maxTotal: this.actor.system.resources.stress.maxTotal
|
||||
}
|
||||
: null;
|
||||
|
||||
context.availableArmorMarks = this.availableArmorMarks;
|
||||
context.availableStressReductions = this.availableStressReductions;
|
||||
|
||||
context.damage = getDamageLabel(this.damage);
|
||||
context.reducedDamage =
|
||||
this.availableArmorMarks.selected > 0
|
||||
? getDamageLabel(this.damage - this.availableArmorMarks.selected)
|
||||
this.availableArmorMarks.selected > 0 || selectedStressReductions.length > 0
|
||||
? getDamageLabel(this.damage - this.availableArmorMarks.selected - selectedStressReductions.length)
|
||||
: null;
|
||||
context.currentDamage = context.reducedDamage ?? context.damage;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
@ -79,21 +117,51 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
|||
|
||||
static setMarks(_, target) {
|
||||
const index = Number(target.dataset.index);
|
||||
if (index >= this.availableArmorMarks.maxUseable) {
|
||||
ui.notifications.info(game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.NotEnoughArmor'));
|
||||
return;
|
||||
}
|
||||
|
||||
const isDecreasing = index < this.availableArmorMarks.selected;
|
||||
if (!isDecreasing && this.damage - this.availableArmorMarks.selected === 0) {
|
||||
ui.notifications.info(game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.DamageAlreadyNone'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDecreasing) {
|
||||
const selectedStressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
||||
const reducedDamage =
|
||||
this.availableArmorMarks.selected > 0 || selectedStressReductions.length > 0
|
||||
? getDamageLabel(this.damage - this.availableArmorMarks.selected - selectedStressReductions.length)
|
||||
: null;
|
||||
const currentDamage = reducedDamage ?? getDamageLabel(this.damage);
|
||||
for (let reduction of selectedStressReductions) {
|
||||
if (reduction.selected && reduction.to === currentDamage) {
|
||||
reduction.selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.availableArmorMarks.selected = isDecreasing ? index : index + 1;
|
||||
this.render();
|
||||
}
|
||||
|
||||
static useStressReduction(_, target) {
|
||||
const damageValue = Number(target.dataset.reduction);
|
||||
const stressReduction = this.availableStressReductions[damageValue];
|
||||
if (stressReduction.selected) {
|
||||
stressReduction.selected = false;
|
||||
this.render();
|
||||
} else {
|
||||
const selectedStressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
||||
const reducedDamage =
|
||||
this.availableArmorMarks.selected > 0 || selectedStressReductions.length > 0
|
||||
? getDamageLabel(this.damage - this.availableArmorMarks.selected - selectedStressReductions.length)
|
||||
: null;
|
||||
const currentDamage = reducedDamage ?? getDamageLabel(this.damage);
|
||||
|
||||
if (stressReduction.from !== currentDamage) return;
|
||||
|
||||
stressReduction.selected = true;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
static async takeDamage() {
|
||||
const armorSpent = this.availableArmorMarks.selected;
|
||||
const modifiedDamage = this.damage - armorSpent;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ const resourceField = max =>
|
|||
max: new foundry.data.fields.NumberField({ initial: max, integer: true })
|
||||
});
|
||||
|
||||
const stressDamageReductionRule = () =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
enabled: new foundry.data.fields.BooleanField({ required: true, initial: false }),
|
||||
cost: new foundry.data.fields.NumberField({ integer: true })
|
||||
});
|
||||
|
||||
export default class DhCharacter extends BaseDataActor {
|
||||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
|
|
@ -98,9 +104,9 @@ export default class DhCharacter extends BaseDataActor {
|
|||
stressExtra: new fields.NumberField({ required: true, integer: true, initial: 0 })
|
||||
}),
|
||||
stressDamageReduction: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({ required: true, initial: false }),
|
||||
cost: new fields.NumberField({ integer: true }),
|
||||
fromSeverity: new fields.NumberField({ integer: true, max: 3 })
|
||||
severe: stressDamageReductionRule(),
|
||||
major: stressDamageReductionRule(),
|
||||
minor: stressDamageReductionRule()
|
||||
})
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -515,13 +515,24 @@ export default class DhpActor extends Actor {
|
|||
) {
|
||||
new Promise((resolve, reject) => {
|
||||
new DamageReductionDialog(resolve, reject, this, hpDamage).render(true);
|
||||
}).then(async ({ modifiedDamage, armorSpent }) => {
|
||||
const resources = [
|
||||
{ value: modifiedDamage, type: 'hitPoints' },
|
||||
...(armorSpent ? [{ value: armorSpent, type: 'armorStack' }] : [])
|
||||
];
|
||||
await this.modifyResource(resources);
|
||||
});
|
||||
})
|
||||
.then(async ({ modifiedDamage, armorSpent }) => {
|
||||
const resources = [
|
||||
{ value: modifiedDamage, type: 'hitPoints' },
|
||||
...(armorSpent ? [{ value: armorSpent, type: 'armorStack' }] : [])
|
||||
];
|
||||
await this.modifyResource(resources);
|
||||
})
|
||||
.catch(() => {
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = new cls({
|
||||
user: game.user.id,
|
||||
content: game.i18n.format('DAGGERHEART.DamageReduction.Notifications.DamageIgnore', {
|
||||
character: this.name
|
||||
})
|
||||
});
|
||||
cls.create(msg.toObject());
|
||||
});
|
||||
} else {
|
||||
await this.modifyResource([{ value: hpDamage, type: 'hitPoints' }]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,3 +248,16 @@ export const getDamageLabel = damage => {
|
|||
return game.i18n.localize('DAGGERHEART.General.Damage.None');
|
||||
}
|
||||
};
|
||||
|
||||
export const damageKeyToNumber = key => {
|
||||
switch (key) {
|
||||
case 'severe':
|
||||
return 3;
|
||||
case 'major':
|
||||
return 2;
|
||||
case 'minor':
|
||||
return 1;
|
||||
case 'none':
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue