mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-15 13:11:08 +01:00
Changed from index based to object
This commit is contained in:
parent
0e1320e31d
commit
3dfefa0f4f
6 changed files with 134 additions and 79 deletions
|
|
@ -1096,9 +1096,11 @@
|
||||||
"UsedMarks": "Used Marks",
|
"UsedMarks": "Used Marks",
|
||||||
"Stress": "Stress",
|
"Stress": "Stress",
|
||||||
"ArmorWithStress": "Spend 1 stress to use an extra mark",
|
"ArmorWithStress": "Spend 1 stress to use an extra mark",
|
||||||
|
"UnncessaryStress": "You don't need to expend stress",
|
||||||
"StressReduction": "Reduce By Stress",
|
"StressReduction": "Reduce By Stress",
|
||||||
"Notifications": {
|
"Notifications": {
|
||||||
"DamageAlreadyNone": "The damage has already been reduced to none",
|
"DamageAlreadyNone": "The damage has already been reduced to none",
|
||||||
|
"NoAvailableArmorMarks": "You have no more available armor marks",
|
||||||
"DamageIgnore": "{character} did not take damage"
|
"DamageIgnore": "{character} did not take damage"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,20 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.damage = damage;
|
this.damage = damage;
|
||||||
|
|
||||||
const maxUseable = actor.system.armorScore - actor.system.armor.system.marks.value;
|
const maxArmorMarks = Math.min(
|
||||||
this.availableArmorMarks = {
|
actor.system.armorScore - actor.system.armor.system.marks.value,
|
||||||
max: Math.min(
|
actor.system.rules.maxArmorMarked.total
|
||||||
maxUseable,
|
);
|
||||||
actor.system.rules.maxArmorMarked.total + (actor.system.rules.maxArmorMarked.stressExtra ?? 0)
|
|
||||||
),
|
const armor = [...Array(maxArmorMarks).keys()].reduce((acc, _) => {
|
||||||
stressIndex: actor.system.rules.maxArmorMarked.total,
|
acc[foundry.utils.randomID()] = { selected: false };
|
||||||
selected: 0
|
return acc;
|
||||||
};
|
}, {});
|
||||||
|
const stress = [...Array(actor.system.rules.maxArmorMarked.stressExtra ?? 0).keys()].reduce((acc, _) => {
|
||||||
|
acc[foundry.utils.randomID()] = { selected: false };
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
this.marks = { armor, stress };
|
||||||
|
|
||||||
this.availableStressReductions = Object.keys(actor.system.rules.stressDamageReduction).reduce((acc, key) => {
|
this.availableStressReductions = Object.keys(actor.system.rules.stressDamageReduction).reduce((acc, key) => {
|
||||||
const dr = actor.system.rules.stressDamageReduction[key];
|
const dr = actor.system.rules.stressDamageReduction[key];
|
||||||
|
|
@ -79,32 +84,31 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
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 { selectedArmorMarks, selectedStressMarks, stressReductions, currentMarks, currentDamage } =
|
||||||
|
this.getDamageInfo();
|
||||||
|
|
||||||
|
context.armorScore = this.actor.system.armorScore;
|
||||||
|
context.armorMarks = currentMarks;
|
||||||
|
context.basicMarksUsed = selectedArmorMarks.length === this.actor.system.rules.maxArmorMarked.total;
|
||||||
|
|
||||||
const stressReductionStress = this.availableStressReductions
|
const stressReductionStress = this.availableStressReductions
|
||||||
? selectedStressReductions.reduce((acc, red) => acc + red.cost, 0)
|
? stressReductions.reduce((acc, red) => acc + red.cost, 0)
|
||||||
: 0;
|
: 0;
|
||||||
context.stress =
|
context.stress =
|
||||||
this.availableArmorMarks.stressIndex || this.availableStressReductions
|
selectedStressMarks.length > 0 || this.availableStressReductions
|
||||||
? {
|
? {
|
||||||
value:
|
value:
|
||||||
this.actor.system.resources.stress.value +
|
this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress,
|
||||||
(Math.max(this.availableArmorMarks.selected - this.availableArmorMarks.stressIndex, 0) +
|
|
||||||
stressReductionStress),
|
|
||||||
maxTotal: this.actor.system.resources.stress.maxTotal
|
maxTotal: this.actor.system.resources.stress.maxTotal
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
context.availableArmorMarks = this.availableArmorMarks;
|
context.marks = this.marks;
|
||||||
context.availableStressReductions = this.availableStressReductions;
|
context.availableStressReductions = this.availableStressReductions;
|
||||||
|
|
||||||
context.damage = getDamageLabel(this.damage);
|
context.damage = getDamageLabel(this.damage);
|
||||||
context.reducedDamage =
|
context.reducedDamage = currentDamage !== this.damage ? getDamageLabel(currentDamage) : null;
|
||||||
this.availableArmorMarks.selected > 0 || selectedStressReductions.length > 0
|
|
||||||
? getDamageLabel(this.damage - this.availableArmorMarks.selected - selectedStressReductions.length)
|
|
||||||
: null;
|
|
||||||
context.currentDamage = context.reducedDamage ?? context.damage;
|
context.currentDamage = context.reducedDamage ?? context.damage;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
@ -115,47 +119,64 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
this.render(true);
|
this.render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDamageInfo = () => {
|
||||||
|
const selectedArmorMarks = Object.values(this.marks.armor).filter(x => x.selected);
|
||||||
|
const selectedStressMarks = Object.values(this.marks.stress).filter(x => x.selected);
|
||||||
|
const stressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
||||||
|
const currentMarks =
|
||||||
|
this.actor.system.armor.system.marks.value + selectedArmorMarks.length + selectedStressMarks.length;
|
||||||
|
|
||||||
|
const currentDamage =
|
||||||
|
this.damage - selectedArmorMarks.length - selectedStressMarks.length - stressReductions.length;
|
||||||
|
|
||||||
|
return { selectedArmorMarks, selectedStressMarks, stressReductions, currentMarks, currentDamage };
|
||||||
|
};
|
||||||
|
|
||||||
static setMarks(_, target) {
|
static setMarks(_, target) {
|
||||||
const index = Number(target.dataset.index);
|
const currentMark = this.marks[target.dataset.type][target.dataset.key];
|
||||||
const isDecreasing = index < this.availableArmorMarks.selected;
|
const { selectedStressMarks, stressReductions, currentMarks, currentDamage } = this.getDamageInfo();
|
||||||
if (!isDecreasing && this.damage - this.availableArmorMarks.selected === 0) {
|
if (!currentMark.selected && currentDamage === 0) {
|
||||||
ui.notifications.info(game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.DamageAlreadyNone'));
|
ui.notifications.info(game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.DamageAlreadyNone'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDecreasing) {
|
if (!currentMark.selected && currentMarks === this.actor.system.armorScore) {
|
||||||
const selectedStressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
ui.notifications.info(
|
||||||
const reducedDamage =
|
game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.NoAvailableArmorMarks')
|
||||||
this.availableArmorMarks.selected > 0 || selectedStressReductions.length > 0
|
);
|
||||||
? getDamageLabel(this.damage - this.availableArmorMarks.selected - selectedStressReductions.length)
|
return;
|
||||||
: null;
|
}
|
||||||
const currentDamage = reducedDamage ?? getDamageLabel(this.damage);
|
|
||||||
for (let reduction of selectedStressReductions) {
|
if (currentMark.selected) {
|
||||||
if (reduction.selected && reduction.to === currentDamage) {
|
const currentDamageLabel = getDamageLabel(currentDamage);
|
||||||
|
for (let reduction of stressReductions) {
|
||||||
|
if (reduction.selected && reduction.to === currentDamageLabel) {
|
||||||
reduction.selected = false;
|
reduction.selected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (target.dataset.type === 'armor' && selectedStressMarks.length > 0) {
|
||||||
|
selectedStressMarks.forEach(mark => (mark.selected = false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.availableArmorMarks.selected = isDecreasing ? index : index + 1;
|
currentMark.selected = !currentMark.selected;
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
static useStressReduction(_, target) {
|
static useStressReduction(_, target) {
|
||||||
const damageValue = Number(target.dataset.reduction);
|
const damageValue = Number(target.dataset.reduction);
|
||||||
const stressReduction = this.availableStressReductions[damageValue];
|
const stressReduction = this.availableStressReductions[damageValue];
|
||||||
|
const { currentDamage } = this.getDamageInfo();
|
||||||
|
|
||||||
if (stressReduction.selected) {
|
if (stressReduction.selected) {
|
||||||
stressReduction.selected = false;
|
stressReduction.selected = false;
|
||||||
this.render();
|
this.render();
|
||||||
} else {
|
} else {
|
||||||
const selectedStressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
const reducedDamage = currentDamage !== this.damage ? getDamageLabel(currentDamage) : null;
|
||||||
const reducedDamage =
|
const currentDamageLabel = reducedDamage ?? getDamageLabel(this.damage);
|
||||||
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;
|
if (stressReduction.from !== currentDamageLabel) return;
|
||||||
|
|
||||||
stressReduction.selected = true;
|
stressReduction.selected = true;
|
||||||
this.render();
|
this.render();
|
||||||
|
|
@ -163,10 +184,11 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
}
|
}
|
||||||
|
|
||||||
static async takeDamage() {
|
static async takeDamage() {
|
||||||
const armorSpent = this.availableArmorMarks.selected;
|
const { selectedArmorMarks, selectedStressMarks, stressReductions, currentDamage } = this.getDamageInfo();
|
||||||
const modifiedDamage = this.damage - armorSpent;
|
const armorSpent = selectedArmorMarks.length + selectedStressMarks.length;
|
||||||
|
const stressSpent = selectedStressMarks.length + stressReductions.reduce((acc, red) => acc + red.cost, 0);
|
||||||
|
|
||||||
this.resolve({ modifiedDamage, armorSpent });
|
this.resolve({ modifiedDamage: currentDamage, armorSpent, stressSpent });
|
||||||
await this.close(true);
|
await this.close(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -516,10 +516,11 @@ export default class DhpActor extends Actor {
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
new DamageReductionDialog(resolve, reject, this, hpDamage).render(true);
|
new DamageReductionDialog(resolve, reject, this, hpDamage).render(true);
|
||||||
})
|
})
|
||||||
.then(async ({ modifiedDamage, armorSpent }) => {
|
.then(async ({ modifiedDamage, armorSpent, stressSpent }) => {
|
||||||
const resources = [
|
const resources = [
|
||||||
{ value: modifiedDamage, type: 'hitPoints' },
|
{ value: modifiedDamage, type: 'hitPoints' },
|
||||||
...(armorSpent ? [{ value: armorSpent, type: 'armorStack' }] : [])
|
...(armorSpent ? [{ value: armorSpent, type: 'armorStack' }] : []),
|
||||||
|
...(stressSpent ? [{ value: stressSpent, type: 'stress' }] : [])
|
||||||
];
|
];
|
||||||
await this.modifyResource(resources);
|
await this.modifyResource(resources);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -3151,11 +3151,17 @@ div.daggerheart.views.multiclass {
|
||||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection {
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-container {
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner:not(:last-child) {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid light-dark(#18162e, #f3c267);
|
border: 1px solid light-dark(#18162e, #f3c267);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|
@ -3167,10 +3173,14 @@ div.daggerheart.views.multiclass {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-container.selected {
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container.selected {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-container .fa-shield {
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container.inactive {
|
||||||
|
cursor: initial;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container .fa-shield {
|
||||||
position: relative;
|
position: relative;
|
||||||
right: 0.5px;
|
right: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,29 +41,42 @@
|
||||||
.mark-selection {
|
.mark-selection {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
.mark-container {
|
.mark-selection-inner {
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid light-dark(@dark-blue, @golden);
|
|
||||||
border-radius: 6px;
|
|
||||||
height: 26px;
|
|
||||||
padding: 0 1px;
|
|
||||||
font-size: 18px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
gap: 2px;
|
||||||
justify-content: center;
|
|
||||||
opacity: 0.4;
|
|
||||||
|
|
||||||
&.selected {
|
&:not(:last-child) {
|
||||||
opacity: 1;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-shield {
|
.mark-container {
|
||||||
position: relative;
|
cursor: pointer;
|
||||||
right: 0.5px;
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 26px;
|
||||||
|
padding: 0 1px;
|
||||||
|
font-size: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0.4;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inactive {
|
||||||
|
cursor: initial;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-shield {
|
||||||
|
position: relative;
|
||||||
|
right: 0.5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,26 @@
|
||||||
|
|
||||||
<div class="section-container">
|
<div class="section-container">
|
||||||
<h4 class="mark-selection divider">
|
<h4 class="mark-selection divider">
|
||||||
{{#times availableArmorMarks.max}}
|
<div class="mark-selection-inner">
|
||||||
<div
|
{{#each marks.armor}}
|
||||||
class="mark-container {{#if (lt this @root.availableArmorMarks.selected)}}selected{{/if}}"
|
<div
|
||||||
data-action="setMarks" data-index="{{this}}" {{#if (gte this @root.availableArmorMarks.stressIndex)}}data-tooltip="{{localize "DAGGERHEART.DamageReduction.ArmorWithStress"}}"{{/if}}
|
class="mark-container {{#if this.selected}}selected{{/if}}"
|
||||||
>
|
data-action="setMarks" data-key="{{@key}}" data-type="armor"
|
||||||
{{#if (or (not @root.availableArmorMarks.stressIndex) (lt this @root.availableArmorMarks.stressIndex))}}
|
>
|
||||||
<i class="fa-solid fa-shield"></i>
|
<i class="fa-solid fa-shield"></i>
|
||||||
{{else}}
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
<div class="mark-selection-inner">
|
||||||
|
{{#each marks.stress}}
|
||||||
|
<div
|
||||||
|
class="mark-container {{#if this.selected}}selected{{/if}} {{#if (not @root.basicMarksUsed)}}inactive{{/if}}"
|
||||||
|
{{#if @root.basicMarksUsed}}data-action="setMarks"{{/if}} data-key="{{@key}}" data-type="stress" data-tooltip="{{#if @root.basicMarksUsed}}{{localize "DAGGERHEART.DamageReduction.ArmorWithStress"}}{{else}}{{localize "DAGGERHEART.DamageReduction.UnncessaryStress"}}{{/if}}"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-bolt"></i>
|
<i class="fa-solid fa-bolt"></i>
|
||||||
{{/if}}
|
</div>
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/times}}
|
|
||||||
</h4>
|
</h4>
|
||||||
<div class="markers-subtitle bold">{{localize "DAGGERHEART.DamageReduction.UsedMarks"}}</div>
|
<div class="markers-subtitle bold">{{localize "DAGGERHEART.DamageReduction.UsedMarks"}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue