Fixed up Summary. Fixed multiclass/subclass blocking on selection

This commit is contained in:
WBHarry 2025-06-01 11:50:43 +02:00
parent 57334b0a63
commit 6d075ec44e
7 changed files with 320 additions and 82 deletions

View file

@ -773,7 +773,9 @@
"levelAchievements": "Level Achievements",
"levelAdvancements": "Level Advancements",
"proficiencyIncrease": "Proficiency Increased: {proficiency}",
"statisticIncreases": "Statistic Increases",
"hpIncrease": "Hit Points Increased: {hitPoints}",
"stressIncrease": "Stress Increased: {stress}",
"evasionIncrease": "Evasion Increased: {evasion}",
"damageThresholdMajorIncrease": "Major: {threshold}",
"damageThresholdSevereIncrease": "Severe: {threshold}",
"newExperiences": "New Experiences",
@ -782,7 +784,8 @@
"subclass": "Subclass",
"multiclass": "Multiclass",
"traits": "Increased Traits",
"experienceIncreases": "Experience Increases"
"experienceIncreases": "Experience Increases",
"damageThresholds": "Damage Thresholds"
},
"notifications": {
"info": {

View file

@ -200,27 +200,126 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
case 'summary':
const actorArmor = this.actor.system.armor;
const { current: currentLevel, changed: changedLevel } = this.actor.system.levelData.level;
context.levelAchievements = {
statisticIncreases: {
proficiency: {
old: this.actor.system.proficiency,
new: this.actor.system.proficiency + this.levelup.allInitialAchievements.proficiency
const achievementCards = [];
for (var card of Object.values(this.levelup.domainCards)) {
if (card.uuid) {
const itemCard = await foundry.utils.fromUuid(card.uuid);
achievementCards.push(itemCard);
}
}
context.achievements = {
proficiency: {
old: this.actor.system.proficiency,
new:
this.actor.system.proficiency +
Object.values(this.levelup.allInitialAchievements).reduce(
(acc, x) => acc + x.proficiency,
0
)
},
damageThresholds: {
major: {
old: this.actor.system.damageThresholds.major,
new: this.actor.system.damageThresholds.major + changedLevel - currentLevel
},
damageThresholds: {
major: {
old: this.actor.system.damageThresholds.major,
new: this.actor.system.damageThresholds.major + changedLevel - currentLevel
},
severe: {
old: this.actor.system.damageThresholds.severe,
new:
this.actor.system.damageThresholds.severe +
(actorArmor ? changedLevel - currentLevel : (changedLevel - currentLevel) * 2)
},
unarmored: !actorArmor
}
severe: {
old: this.actor.system.damageThresholds.severe,
new:
this.actor.system.damageThresholds.severe +
(actorArmor ? changedLevel - currentLevel : (changedLevel - currentLevel) * 2)
},
unarmored: !actorArmor
},
domainCards: {
values: achievementCards,
shown: achievementCards.length > 0
},
experiences: {
values: Object.values(this.levelup.allInitialAchievements).flatMap(achievements => {
return Object.values(achievements.newExperiences).reduce((acc, experience) => {
if (experience.name) acc.push(experience);
return acc;
}, []);
})
}
};
context.achievements.proficiency.shown =
context.achievements.proficiency.new > context.achievements.proficiency.old;
context.achievements.experiences.shown = context.achievements.experiences.values.length > 0;
const advancementChoices = this.levelup.selectionData.reduce((acc, data) => {
const advancementChoice = {
...data,
path: `tiers.${data.tier}.levels.${data.level}.optionSelections.${data.optionKey}.${data.checkboxNr}.data`
};
if (acc[data.type]) acc[data.type].push(advancementChoice);
else acc[data.type] = [advancementChoice];
return acc;
}, {});
const advancementCards = [];
const cardChoices = advancementChoices.domainCard ?? [];
for (var card of cardChoices) {
if (card.data.length > 0) {
for (var data of card.data) {
const itemCard = await foundry.utils.fromUuid(data);
advancementCards.push(itemCard);
}
}
}
context.advancements = {
statistics: {
proficiency: {
old: context.achievements.proficiency.new,
new:
context.achievements.proficiency.new +
Object.values(advancementChoices.proficiency ?? {}).reduce((acc, x) => acc + x.value, 0)
},
hitPoints: {
old: this.actor.system.resources.health.max,
new:
this.actor.system.resources.health.max +
Object.values(advancementChoices.hitPoint ?? {}).reduce((acc, x) => acc + x.value, 0)
},
stress: {
old: this.actor.system.resources.stress.max,
new:
this.actor.system.resources.stress.max +
Object.values(advancementChoices.stress ?? {}).reduce((acc, x) => acc + x.value, 0)
},
evasion: {
old: this.actor.system.evasion.value,
new:
this.actor.system.evasion.value +
Object.values(advancementChoices.evasion ?? {}).reduce((acc, x) => acc + x.value, 0)
}
},
traits: Object.values(advancementChoices.trait ?? {}).flatMap(x =>
x.data.map(data => game.i18n.localize(abilities[data].label))
),
domainCards: advancementCards,
experiences: Object.values(advancementChoices.experience ?? {}).flatMap(x =>
x.data.map(data => ({ name: data, modifier: x.value }))
)
};
context.advancements.statistics.proficiency.shown =
context.advancements.statistics.proficiency.new > context.advancements.statistics.proficiency.old;
context.advancements.statistics.hitPoints.shown =
context.advancements.statistics.hitPoints.new > context.advancements.statistics.hitPoints.old;
context.advancements.statistics.stress.shown =
context.advancements.statistics.stress.new > context.advancements.statistics.stress.old;
context.advancements.statistics.evasion.shown =
context.advancements.statistics.evasion.new > context.advancements.statistics.evasion.old;
context.advancements.statistics.shown =
context.advancements.statistics.proficiency.shown ||
context.advancements.statistics.hitPoints.shown ||
context.advancements.statistics.stress.shown ||
context.advancements.statistics.evasion.shown;
break;
}

View file

@ -223,6 +223,66 @@ export class DhLevelup extends foundry.abstract.DataModel {
return acc;
}, {});
}
/* Data to render all options from */
get tierCheckboxGroups() {
const multiclassSelected = Object.values(this.tiers).some(tier =>
Object.values(tier.levels).some(level => {
return Object.keys(level.optionSelections).some(option =>
Object.values(level.optionSelections[option]).some(x => option === 'multiclass' && x.selected)
);
})
);
return Object.keys(this.tiers).map(tierKey => {
const tier = this.tiers[tierKey];
const subclassSelected = Object.values(tier.levels).some(level => {
return Object.keys(level.optionSelections).some(option =>
Object.values(level.optionSelections[option]).some(x => option === 'subclass' && x.selected)
);
});
return {
tierActive: tier.active,
tierName: tier.name,
groups: Object.keys(tier.options).map(optionKey => {
const option = tier.options[optionKey];
const checkboxes = [...Array(option.checkboxSelections).keys()].flatMap(checkboxNr => {
const levelId = Object.keys(tier.levels).find(levelKey => {
const optionSelect = tier.levels[levelKey].optionSelections;
return Object.keys(optionSelect)
.filter(key => key === optionKey)
.some(optionKey => optionSelect[optionKey][checkboxNr]?.selected);
});
const selected = Boolean(levelId);
const disabled = !levelId
? false
: tier.levels[levelId].optionSelections[optionKey][checkboxNr]?.locked;
const multiclassDisabled =
!selected && optionKey === 'multiclass' && (multiclassSelected || subclassSelected);
return [...Array(option.minCost)].map(_ => ({
...option,
tier: tierKey,
level: levelId,
selected: selected,
optionKey: optionKey,
checkboxNr: checkboxNr,
disabled: disabled || multiclassDisabled,
cost: option.minCost
}));
});
return {
label: game.i18n.localize(option.label),
checkboxGroups: chunkify(checkboxes, option.minCost, chunkedBoxes => ({
multi: option.minCost > 1,
checkboxes: chunkedBoxes
}))
};
})
};
});
}
}
class DhLevelupTier extends foundry.abstract.DataModel {
@ -304,40 +364,6 @@ class DhLevelupTier extends foundry.abstract.DataModel {
total: allSelections.total
};
}
/* Data to render all options in a Tier from */
get tierCheckboxGroups() {
return Object.keys(this.options).map(optionKey => {
const option = this.options[optionKey];
const checkboxes = [...Array(option.checkboxSelections).keys()].flatMap(checkboxNr => {
const levelId = Object.keys(this.levels).find(levelKey => {
const optionSelect = this.levels[levelKey].optionSelections;
return Object.keys(optionSelect)
.filter(key => key === optionKey)
.some(optionKey => optionSelect[optionKey][checkboxNr]?.selected);
});
return [...Array(option.minCost)].map(_ => ({
...option,
tier: this.tier,
level: levelId,
selected: Boolean(levelId),
optionKey: optionKey,
checkboxNr: checkboxNr,
disabled: !levelId ? false : this.levels[levelId].optionSelections[optionKey][checkboxNr]?.locked,
cost: option.minCost
}));
});
return {
label: game.i18n.localize(option.label),
checkboxGroups: chunkify(checkboxes, option.minCost, chunkedBoxes => ({
multi: option.minCost > 1,
checkboxes: chunkedBoxes
}))
};
});
}
}
class DhLevelupTierOption extends foundry.abstract.DataModel {

View file

@ -2866,15 +2866,20 @@ div.daggerheart.views.multiclass {
position: relative;
right: 2px;
}
.daggerheart.levelup .levelup-summary-container .level-achievements-container {
.daggerheart.levelup .levelup-summary-container .level-achievements-container,
.daggerheart.levelup .levelup-summary-container .level-advancements-container {
display: flex;
flex-direction: column;
gap: 8px;
}
.daggerheart.levelup .levelup-summary-container .level-achievements-container h2,
.daggerheart.levelup .levelup-summary-container .level-advancements-container h2,
.daggerheart.levelup .levelup-summary-container .level-achievements-container h3,
.daggerheart.levelup .levelup-summary-container .level-advancements-container h3,
.daggerheart.levelup .levelup-summary-container .level-achievements-container h4,
.daggerheart.levelup .levelup-summary-container .level-achievements-container h5 {
.daggerheart.levelup .levelup-summary-container .level-advancements-container h4,
.daggerheart.levelup .levelup-summary-container .level-achievements-container h5,
.daggerheart.levelup .levelup-summary-container .level-advancements-container h5 {
margin: 0;
color: var(--color-text-secondary);
}
@ -2884,6 +2889,16 @@ div.daggerheart.views.multiclass {
gap: 4px;
font-size: 20px;
}
.daggerheart.levelup .levelup-summary-container .summary-selection-container {
display: flex;
gap: 8px;
}
.daggerheart.levelup .levelup-summary-container .summary-selection-container .summary-selection {
border: 2px solid;
border-radius: 6px;
padding: 0 4px;
font-size: 18px;
}
.daggerheart.levelup .levelup-footer {
display: flex;
}
@ -2998,7 +3013,7 @@ div.daggerheart.views.multiclass {
#resources .window-content #resource-fear.isGM i:hover {
font-size: var(--font-size-20);
}
#resources button[data-action="close"] {
#resources button[data-action='close'] {
display: none;
}
#resources:not(:hover):not(.minimized) {

View file

@ -185,7 +185,8 @@
}
.levelup-summary-container {
.level-achievements-container {
.level-achievements-container,
.level-advancements-container {
display: flex;
flex-direction: column;
gap: 8px;
@ -205,6 +206,18 @@
gap: 4px;
font-size: 20px;
}
.summary-selection-container {
display: flex;
gap: 8px;
.summary-selection {
border: 2px solid;
border-radius: 6px;
padding: 0 4px;
font-size: 18px;
}
}
}
.levelup-footer {

View file

@ -5,11 +5,11 @@
>
<div class="section-container">
<div class="tiers-container">
{{#each this.levelup.tiers as |tier key|}}
<fieldset class="tier-container {{#if (not tier.active)}}inactive{{/if}}">
<legend>{{tier.name}}</legend>
{{#each this.levelup.tierCheckboxGroups as |tier key|}}
<fieldset class="tier-container {{#if (not tier.tierActive)}}inactive{{/if}}">
<legend>{{tier.tierName}}</legend>
{{#each tier.tierCheckboxGroups}}
{{#each tier.groups}}
<div class="checkbox-group-container">
<div class="checkboxes-container">
{{#each this.checkboxGroups}}

View file

@ -8,41 +8,123 @@
<legend>{{localize "DAGGERHEART.Application.LevelUp.summary.levelAchievements"}}</legend>
<div class="level-achievements-container">
{{#if this.achievements.proficiency.shown}}
<div>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.proficiencyIncrease" proficiency=this.achievements.proficiency.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.proficiency.new}}
</div>
</div>
{{/if}}
<div>
<h3>{{localize "DAGGERHEART.Application.LevelUp.summary.statisticIncreases"}}</h3>
<h5 class="summary-section">{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholds"}}{{#if this.levelAchievements.damageThresholds.unarmored}}({{localize "DAGGERHEART.General.unarmored"}}){{/if}}</h5>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.proficiencyIncrease" proficiency=this.levelAchievements.statisticIncreases.proficiency.old }}
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdMajorIncrease" threshold=this.achievements.damageThresholds.major.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.levelAchievements.statisticIncreases.proficiency.new}}
</div>
<h5>{{localize "Damage Thresholds"}}{{#if this.levelAchievements.statisticIncreases.damageThresholds.unarmored}}({{localize "DAGGERHEART.General.unarmored"}}){{/if}}</h5>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdMajorIncrease" threshold=this.levelAchievements.statisticIncreases.damageThresholds.major.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.levelAchievements.statisticIncreases.damageThresholds.major.new}}
{{this.achievements.damageThresholds.major.new}}
</div>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdSevereIncrease" threshold=this.levelAchievements.statisticIncreases.damageThresholds.severe.old }}
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdSevereIncrease" threshold=this.achievements.damageThresholds.severe.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.levelAchievements.statisticIncreases.damageThresholds.severe.new}}
{{this.achievements.damageThresholds.severe.new}}
</div>
</div>
{{#if this.achievements.domainCards.shown}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.domainCards"}}</h5>
<div class="summary-selection-container">
{{#each this.achievements.domainCards.values}}
<div class="summary-selection">{{this.name}}</div>
{{/each}}
</div>
</div>
{{/if}}
{{#if this.achievements.experiences.shown}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.newExperiences"}}</h5>
<div class="summary-selection-container">
{{#each this.achievements.experiences.values}}
<div class="summary-selection">{{this.name}} {{signedNumber this.modifier}}</div>
{{/each}}
</div>
</div>
{{/if}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "DAGGERHEART.Application.LevelUp.summary.levelAdvancements"}}</legend>
{{!-- <div>
<h4>{{localize "DAGGERHEART.General.Experience.plural"}}</h4>
<div class="level-experience-cards">
{{#each this.levelAchievements.experience}}
<div class="level-experience-card">
{{this.label}}
<div class="level-advancements-container">
{{#if this.advancements.statistics.shown}}
<div>
{{#if this.advancements.statistics.proficiency.shown}}
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.proficiencyIncrease" proficiency=this.advancements.statistics.proficiency.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.advancements.statistics.proficiency.new}}
</div>
{{/if}}
{{#if this.advancements.statistics.hitPoints.shown}}
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.hpIncrease" hitPoints=this.advancements.statistics.hitPoints.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.advancements.statistics.hitPoints.new}}
</div>
{{/if}}
{{#if this.advancements.statistics.stress.shown}}
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.stressIncrease" stress=this.advancements.statistics.stress.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.advancements.statistics.stress.new}}
</div>
{{/if}}
{{#if this.advancements.statistics.evasion.shown}}
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.evasionIncrease" stress=this.advancements.statistics.evasion.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.advancements.statistics.evasion.new}}
</div>
{{/if}}
</div>
{{/if}}
{{#if this.advancements.traits}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.traits"}}</h5>
<div class="summary-selection-container">
{{#each this.advancements.traits}}
<div class="summary-selection">{{this}}</div>
{{/each}}
</div>
{{/each}}
</div>
</div> --}}
</div>
{{/if}}
{{#if this.advancements.domainCards}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.domainCards"}}</h5>
<div class="summary-selection-container">
{{#each this.advancements.domainCards}}
<div class="summary-selection">{{this.name}}</div>
{{/each}}
</div>
</div>
{{/if}}
{{#if this.advancements.experiences}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.experienceIncreases"}}</h5>
<div class="summary-selection-container">
{{#each this.advancements.experiences}}
<div class="summary-selection">{{this.name}} {{signedNumber this.modifier}}</div>
{{/each}}
</div>
</div>
{{/if}}
</div>
</fieldset>
<footer class="levelup-footer">