mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-16 05:31:07 +01:00
Temp
This commit is contained in:
parent
4f5e693c7f
commit
b7f962b22d
16 changed files with 844 additions and 212 deletions
22
lang/en.json
22
lang/en.json
|
|
@ -482,7 +482,15 @@
|
||||||
"evasion": "Permanently gain a +1 bonus to your Evasion.",
|
"evasion": "Permanently gain a +1 bonus to your Evasion.",
|
||||||
"subclass": "Take an upgraded subclass card. Then cross out the multiclass option for this tier.",
|
"subclass": "Take an upgraded subclass card. Then cross out the multiclass option for this tier.",
|
||||||
"proficiency": "Increase your Proficiency by +1.",
|
"proficiency": "Increase your Proficiency by +1.",
|
||||||
"multiclass": "Multiclass: Choose an additional class for your character, then cross out an unused “Take an upgraded subclass card” and the other multiclass option on this sheet."
|
"multiclass": "Multiclass: Choose an additional class for your character, then cross out an unused “Take an upgraded subclass card” and the other multiclass option on this sheet.",
|
||||||
|
"intelligent": "Your companion gains a permanent +1 bonus to a Companion Experience of your choice.",
|
||||||
|
"lightInTheDark": "Gain an additional Hope slot for your character.",
|
||||||
|
"creatureComfort": "Once per rest, when you take time during a quiet moment to give your companion love and attention, you can gain a Hope or you can both clear a Stress.",
|
||||||
|
"armored": "When your companion takes damage, you can mark one of your Armor Slots instead of marking one of their Stress.",
|
||||||
|
"vicious": "Increase your companion's damage dice or range by one step (d6 to d8, Close to Far, etc.)",
|
||||||
|
"resilient": "Your companion gains an additional Stress slot.",
|
||||||
|
"bonded": "When you mark your last Hit Point, your companion rushes to your side to comfort you. Roll a number of d6s equal to the unmarked Stress slots they have and mark them. If any roll a 6, your companion helps you up. Clear your last Hit Point and return to the scene.",
|
||||||
|
"aware": "Your companion gains a permanent +2 bonus to their Evasion."
|
||||||
},
|
},
|
||||||
"Tier2": {
|
"Tier2": {
|
||||||
"Label": "Levels 2-4",
|
"Label": "Levels 2-4",
|
||||||
|
|
@ -953,7 +961,9 @@
|
||||||
"content": "Returning to the previous level selection will remove all selections made for this level. Do you want to proceed?"
|
"content": "Returning to the previous level selection will remove all selections made for this level. Do you want to proceed?"
|
||||||
},
|
},
|
||||||
"Selections": {
|
"Selections": {
|
||||||
"emptyDomainCardHint": "{domain} level {level} or below"
|
"emptyDomainCardHint": "{domain} level {level} or below",
|
||||||
|
"viciousDamage": "Damage",
|
||||||
|
"viciousRange": "Range"
|
||||||
},
|
},
|
||||||
"summary": {
|
"summary": {
|
||||||
"levelAchievements": "Level Achievements",
|
"levelAchievements": "Level Achievements",
|
||||||
|
|
@ -971,7 +981,10 @@
|
||||||
"multiclass": "Multiclass",
|
"multiclass": "Multiclass",
|
||||||
"traits": "Increased Traits",
|
"traits": "Increased Traits",
|
||||||
"experienceIncreases": "Experience Increases",
|
"experienceIncreases": "Experience Increases",
|
||||||
"damageThresholds": "Damage Thresholds"
|
"damageThresholds": "Damage Thresholds",
|
||||||
|
"vicious": "Vicious",
|
||||||
|
"damageIncreased": "Damage Increased: {damage}",
|
||||||
|
"rangeIncreased": "Range Increased: {range}"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"info": {
|
"info": {
|
||||||
|
|
@ -1252,7 +1265,8 @@
|
||||||
"name": { "label": "Attack Name" }
|
"name": { "label": "Attack Name" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Experiences": "Experiences"
|
"Experiences": "Experiences",
|
||||||
|
"Level": "Level"
|
||||||
},
|
},
|
||||||
"Adversary": {
|
"Adversary": {
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
|
|
|
||||||
381
module/applications/levelup/characterLevelup.mjs
Normal file
381
module/applications/levelup/characterLevelup.mjs
Normal file
|
|
@ -0,0 +1,381 @@
|
||||||
|
import LevelUpBase from './levelup.mjs';
|
||||||
|
import { DhLevelup } from '../../data/levelup.mjs';
|
||||||
|
import { domains } from '../../config/domainConfig.mjs';
|
||||||
|
|
||||||
|
export default class DhCharacterLevelUp extends LevelUpBase {
|
||||||
|
constructor(actor) {
|
||||||
|
super(actor);
|
||||||
|
|
||||||
|
this.levelTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers);
|
||||||
|
const playerLevelupData = actor.system.levelData;
|
||||||
|
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
|
||||||
|
}
|
||||||
|
|
||||||
|
async _preparePartContext(partId, context) {
|
||||||
|
await super._preparePartContext(partId, context);
|
||||||
|
|
||||||
|
const currentLevel = this.levelup.levels[this.levelup.currentLevel];
|
||||||
|
switch (partId) {
|
||||||
|
case 'selections':
|
||||||
|
const advancementChoices = Object.keys(currentLevel.choices).reduce((acc, choiceKey) => {
|
||||||
|
Object.keys(currentLevel.choices[choiceKey]).forEach(checkboxNr => {
|
||||||
|
const checkbox = currentLevel.choices[choiceKey][checkboxNr];
|
||||||
|
const data = {
|
||||||
|
...checkbox,
|
||||||
|
path: `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}`,
|
||||||
|
level: this.levelup.currentLevel
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!acc[choiceKey]) acc[choiceKey] = [];
|
||||||
|
acc[choiceKey].push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const traits = Object.values(advancementChoices.trait ?? {});
|
||||||
|
const traitValues = traits.filter(trait => trait.data.length > 0).flatMap(trait => trait.data);
|
||||||
|
context.traits = {
|
||||||
|
values: traitValues,
|
||||||
|
active: traits.length > 0,
|
||||||
|
progress: {
|
||||||
|
selected: traitValues.length,
|
||||||
|
max: traits.reduce((acc, exp) => acc + exp.amount, 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const experienceIncreases = Object.values(advancementChoices.experience ?? {});
|
||||||
|
const experienceIncreaseValues = experienceIncreases
|
||||||
|
.filter(exp => exp.data.length > 0)
|
||||||
|
.flatMap(exp =>
|
||||||
|
exp.data.map(data => {
|
||||||
|
const experience = Object.keys(this.actor.system.experiences).find(x => x === data);
|
||||||
|
return this.actor.system.experiences[experience].description;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
context.experienceIncreases = {
|
||||||
|
values: experienceIncreaseValues,
|
||||||
|
active: experienceIncreases.length > 0,
|
||||||
|
progress: {
|
||||||
|
selected: experienceIncreaseValues.length,
|
||||||
|
max: experienceIncreases.reduce((acc, exp) => acc + exp.amount, 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
context.newExperiences = Object.keys(currentLevel.achievements.experiences).map(key => {
|
||||||
|
const experience = currentLevel.achievements.experiences[key];
|
||||||
|
return {
|
||||||
|
...experience,
|
||||||
|
level: this.levelup.currentLevel,
|
||||||
|
key: key
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const allDomainCards = {
|
||||||
|
...advancementChoices.domainCard,
|
||||||
|
...currentLevel.achievements.domainCards
|
||||||
|
};
|
||||||
|
const allDomainCardKeys = Object.keys(allDomainCards);
|
||||||
|
|
||||||
|
const classDomainsData = this.actor.system.class.value.system.domains.map(domain => ({
|
||||||
|
domain,
|
||||||
|
multiclass: false
|
||||||
|
}));
|
||||||
|
const multiclassDomainsData = (this.actor.system.multiclass?.value?.system?.domains ?? []).map(
|
||||||
|
domain => ({ domain, multiclass: true })
|
||||||
|
);
|
||||||
|
const domainsData = [...classDomainsData, ...multiclassDomainsData];
|
||||||
|
const multiclassDomain = this.levelup.classUpgradeChoices?.multiclass?.domain;
|
||||||
|
if (multiclassDomain) {
|
||||||
|
if (!domainsData.some(x => x.domain === multiclassDomain))
|
||||||
|
domainsData.push({ domain: multiclassDomain, multiclass: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
context.domainCards = [];
|
||||||
|
for (var key of allDomainCardKeys) {
|
||||||
|
const domainCard = allDomainCards[key];
|
||||||
|
if (domainCard.level > this.levelup.endLevel) continue;
|
||||||
|
|
||||||
|
const uuid = domainCard.data?.length > 0 ? domainCard.data[0] : domainCard.uuid;
|
||||||
|
const card = uuid ? await foundry.utils.fromUuid(uuid) : {};
|
||||||
|
|
||||||
|
context.domainCards.push({
|
||||||
|
...(card.toObject?.() ?? card),
|
||||||
|
emptySubtexts: domainsData.map(domain => {
|
||||||
|
const levelBase = domain.multiclass
|
||||||
|
? Math.ceil(this.levelup.currentLevel / 2)
|
||||||
|
: this.levelup.currentLevel;
|
||||||
|
const levelMax = domainCard.secondaryData?.limit
|
||||||
|
? Math.min(domainCard.secondaryData.limit, levelBase)
|
||||||
|
: levelBase;
|
||||||
|
|
||||||
|
return game.i18n.format('DAGGERHEART.Application.LevelUp.Selections.emptyDomainCardHint', {
|
||||||
|
domain: game.i18n.localize(domains[domain.domain].label),
|
||||||
|
level: levelMax
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
path: domainCard.data
|
||||||
|
? `${domainCard.path}.data`
|
||||||
|
: `levels.${domainCard.level}.achievements.domainCards.${key}.uuid`,
|
||||||
|
limit: domainCard.secondaryData?.limit ?? null,
|
||||||
|
compendium: 'domains'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subclassSelections = advancementChoices.subclass?.flatMap(x => x.data) ?? [];
|
||||||
|
const possibleSubclasses = [this.actor.system.class.subclass];
|
||||||
|
if (this.actor.system.multiclass?.subclass) {
|
||||||
|
possibleSubclasses.push(this.actor.system.multiclass.subclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.subclassCards = [];
|
||||||
|
if (advancementChoices.subclass?.length > 0) {
|
||||||
|
const featureStateIncrease = Object.values(this.levelup.levels).reduce((acc, level) => {
|
||||||
|
acc += Object.values(level.choices).filter(choice => {
|
||||||
|
return Object.values(choice).every(checkbox => checkbox.type === 'subclass');
|
||||||
|
}).length;
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
for (var subclass of possibleSubclasses) {
|
||||||
|
const choice =
|
||||||
|
advancementChoices.subclass.find(x => x.data[0] === subclass.uuid) ??
|
||||||
|
advancementChoices.subclass.find(x => x.data.length === 0);
|
||||||
|
const featureState = subclass.system.featureState + featureStateIncrease;
|
||||||
|
const data = await foundry.utils.fromUuid(subclass.uuid);
|
||||||
|
context.subclassCards.push({
|
||||||
|
...data.toObject(),
|
||||||
|
path: choice?.path,
|
||||||
|
uuid: data.uuid,
|
||||||
|
selected: subclassSelections.includes(subclass.uuid),
|
||||||
|
featureState: featureState,
|
||||||
|
featureLabel: game.i18n.localize(subclassFeatureLabels[featureState]),
|
||||||
|
isMulticlass: subclass.system.isMulticlass ? 'true' : 'false'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const multiclasses = Object.values(advancementChoices.multiclass ?? {});
|
||||||
|
if (multiclasses?.[0]) {
|
||||||
|
const data = multiclasses[0];
|
||||||
|
const multiclass = data.data.length > 0 ? await foundry.utils.fromUuid(data.data[0]) : {};
|
||||||
|
|
||||||
|
context.multiclass = {
|
||||||
|
...data,
|
||||||
|
...(multiclass.toObject?.() ?? multiclass),
|
||||||
|
uuid: multiclass.uuid,
|
||||||
|
domains:
|
||||||
|
multiclass?.system?.domains.map(key => {
|
||||||
|
const domain = domains[key];
|
||||||
|
const alreadySelected = this.actor.system.class.value.system.domains.includes(key);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...domain,
|
||||||
|
selected: key === data.secondaryData.domain,
|
||||||
|
disabled:
|
||||||
|
(data.secondaryData.domain && key !== data.secondaryData.domain) ||
|
||||||
|
alreadySelected
|
||||||
|
};
|
||||||
|
}) ?? [],
|
||||||
|
subclasses:
|
||||||
|
multiclass?.system?.subclasses.map(subclass => ({
|
||||||
|
...subclass,
|
||||||
|
uuid: subclass.uuid,
|
||||||
|
selected: data.secondaryData.subclass === subclass.uuid,
|
||||||
|
disabled: data.secondaryData.subclass && data.secondaryData.subclass !== subclass.uuid
|
||||||
|
})) ?? [],
|
||||||
|
compendium: 'classes',
|
||||||
|
limit: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'summary':
|
||||||
|
const { current: currentActorLevel, changed: changedActorLevel } = this.actor.system.levelData.level;
|
||||||
|
const actorArmor = this.actor.system.armor;
|
||||||
|
const levelKeys = Object.keys(this.levelup.levels);
|
||||||
|
let achivementProficiency = 0;
|
||||||
|
const achievementCards = [];
|
||||||
|
let achievementExperiences = [];
|
||||||
|
for (var levelKey of levelKeys) {
|
||||||
|
const level = this.levelup.levels[levelKey];
|
||||||
|
if (Number(levelKey) < this.levelup.startLevel) continue;
|
||||||
|
|
||||||
|
achivementProficiency += level.achievements.proficiency ?? 0;
|
||||||
|
const cards = level.achievements.domainCards ? Object.values(level.achievements.domainCards) : null;
|
||||||
|
if (cards) {
|
||||||
|
for (var card of cards) {
|
||||||
|
const itemCard = await foundry.utils.fromUuid(card.uuid);
|
||||||
|
achievementCards.push(itemCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
achievementExperiences = level.achievements.experiences
|
||||||
|
? Object.values(level.achievements.experiences).reduce((acc, experience) => {
|
||||||
|
if (experience.name) acc.push(experience);
|
||||||
|
return acc;
|
||||||
|
}, [])
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
context.achievements = {
|
||||||
|
proficiency: {
|
||||||
|
old: this.actor.system.proficiency.total,
|
||||||
|
new: this.actor.system.proficiency.total + achivementProficiency,
|
||||||
|
shown: achivementProficiency > 0
|
||||||
|
},
|
||||||
|
damageThresholds: {
|
||||||
|
major: {
|
||||||
|
old: this.actor.system.damageThresholds.major,
|
||||||
|
new: this.actor.system.damageThresholds.major + changedActorLevel - currentActorLevel
|
||||||
|
},
|
||||||
|
severe: {
|
||||||
|
old: this.actor.system.damageThresholds.severe,
|
||||||
|
new:
|
||||||
|
this.actor.system.damageThresholds.severe +
|
||||||
|
(actorArmor
|
||||||
|
? changedActorLevel - currentActorLevel
|
||||||
|
: (changedActorLevel - currentActorLevel) * 2)
|
||||||
|
},
|
||||||
|
unarmored: !actorArmor
|
||||||
|
},
|
||||||
|
domainCards: {
|
||||||
|
values: achievementCards,
|
||||||
|
shown: achievementCards.length > 0
|
||||||
|
},
|
||||||
|
experiences: {
|
||||||
|
values: achievementExperiences
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const advancement = {};
|
||||||
|
for (var levelKey of levelKeys) {
|
||||||
|
const level = this.levelup.levels[levelKey];
|
||||||
|
if (Number(levelKey) < this.levelup.startLevel) continue;
|
||||||
|
|
||||||
|
for (var choiceKey of Object.keys(level.choices)) {
|
||||||
|
const choice = level.choices[choiceKey];
|
||||||
|
for (var checkbox of Object.values(choice)) {
|
||||||
|
switch (choiceKey) {
|
||||||
|
case 'proficiency':
|
||||||
|
case 'hitPoint':
|
||||||
|
case 'stress':
|
||||||
|
case 'evasion':
|
||||||
|
advancement[choiceKey] = advancement[choiceKey]
|
||||||
|
? advancement[choiceKey] + Number(checkbox.value)
|
||||||
|
: Number(checkbox.value);
|
||||||
|
break;
|
||||||
|
case 'trait':
|
||||||
|
if (!advancement[choiceKey]) advancement[choiceKey] = {};
|
||||||
|
for (var traitKey of checkbox.data) {
|
||||||
|
if (!advancement[choiceKey][traitKey]) advancement[choiceKey][traitKey] = 0;
|
||||||
|
advancement[choiceKey][traitKey] += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'domainCard':
|
||||||
|
if (!advancement[choiceKey]) advancement[choiceKey] = [];
|
||||||
|
if (checkbox.data.length === 1) {
|
||||||
|
const choiceItem = await foundry.utils.fromUuid(checkbox.data[0]);
|
||||||
|
advancement[choiceKey].push(choiceItem.toObject());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'experience':
|
||||||
|
if (!advancement[choiceKey]) advancement[choiceKey] = [];
|
||||||
|
const data = checkbox.data.map(data => {
|
||||||
|
const experience = Object.keys(this.actor.system.experiences).find(
|
||||||
|
x => x === data
|
||||||
|
);
|
||||||
|
return this.actor.system.experiences[experience]?.description ?? '';
|
||||||
|
});
|
||||||
|
advancement[choiceKey].push({ data: data, value: checkbox.value });
|
||||||
|
break;
|
||||||
|
case 'subclass':
|
||||||
|
if (checkbox.data[0]) {
|
||||||
|
const subclassItem = await foundry.utils.fromUuid(checkbox.data[0]);
|
||||||
|
if (!advancement[choiceKey]) advancement[choiceKey] = [];
|
||||||
|
advancement[choiceKey].push({
|
||||||
|
...subclassItem.toObject(),
|
||||||
|
featureLabel: game.i18n.localize(
|
||||||
|
subclassFeatureLabels[Number(checkbox.secondaryData.featureState)]
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'multiclass':
|
||||||
|
const multiclassItem = await foundry.utils.fromUuid(checkbox.data[0]);
|
||||||
|
const subclass = multiclassItem
|
||||||
|
? await foundry.utils.fromUuid(checkbox.secondaryData.subclass)
|
||||||
|
: null;
|
||||||
|
advancement[choiceKey] = multiclassItem
|
||||||
|
? {
|
||||||
|
...multiclassItem.toObject(),
|
||||||
|
domain: checkbox.secondaryData.domain
|
||||||
|
? game.i18n.localize(domains[checkbox.secondaryData.domain].label)
|
||||||
|
: null,
|
||||||
|
subclass: subclass ? subclass.name : null
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.advancements = {
|
||||||
|
statistics: {
|
||||||
|
proficiency: {
|
||||||
|
old: context.achievements.proficiency.new,
|
||||||
|
new: context.achievements.proficiency.new + (advancement.proficiency ?? 0)
|
||||||
|
},
|
||||||
|
hitPoints: {
|
||||||
|
old: this.actor.system.resources.hitPoints.maxTotal,
|
||||||
|
new: this.actor.system.resources.hitPoints.maxTotal + (advancement.hitPoint ?? 0)
|
||||||
|
},
|
||||||
|
stress: {
|
||||||
|
old: this.actor.system.resources.stress.maxTotal,
|
||||||
|
new: this.actor.system.resources.stress.maxTotal + (advancement.stress ?? 0)
|
||||||
|
},
|
||||||
|
evasion: {
|
||||||
|
old: this.actor.system.evasion.total,
|
||||||
|
new: this.actor.system.evasion.total + (advancement.evasion ?? 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
traits: Object.keys(this.actor.system.traits).reduce((acc, traitKey) => {
|
||||||
|
if (advancement.trait?.[traitKey]) {
|
||||||
|
if (!acc) acc = {};
|
||||||
|
acc[traitKey] = {
|
||||||
|
label: game.i18n.localize(abilities[traitKey].label),
|
||||||
|
old: this.actor.system.traits[traitKey].total,
|
||||||
|
new: this.actor.system.traits[traitKey].total + advancement.trait[traitKey]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, null),
|
||||||
|
domainCards: advancement.domainCard ?? [],
|
||||||
|
experiences:
|
||||||
|
advancement.experience?.flatMap(x => x.data.map(data => ({ name: data, modifier: x.value }))) ??
|
||||||
|
[],
|
||||||
|
multiclass: advancement.multiclass,
|
||||||
|
subclass: advancement.subclass
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
172
module/applications/levelup/companionLevelup.mjs
Normal file
172
module/applications/levelup/companionLevelup.mjs
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
import BaseLevelUp from './levelup.mjs';
|
||||||
|
import { defaultCompanionTier } from '../../data/levelTier.mjs';
|
||||||
|
import { DhLevelup } from '../../data/levelup.mjs';
|
||||||
|
import { diceTypes, range } from '../../config/generalConfig.mjs';
|
||||||
|
|
||||||
|
export default class DhCompanionLevelUp extends BaseLevelUp {
|
||||||
|
constructor(actor) {
|
||||||
|
super(actor);
|
||||||
|
|
||||||
|
this.levelTiers = defaultCompanionTier;
|
||||||
|
const playerLevelupData = actor.system.levelData;
|
||||||
|
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
|
||||||
|
}
|
||||||
|
|
||||||
|
async _preparePartContext(partId, context) {
|
||||||
|
await super._preparePartContext(partId, context);
|
||||||
|
|
||||||
|
const currentLevel = this.levelup.levels[this.levelup.currentLevel];
|
||||||
|
switch (partId) {
|
||||||
|
case 'selections':
|
||||||
|
const advancementChoices = Object.keys(currentLevel.choices).reduce((acc, choiceKey) => {
|
||||||
|
Object.keys(currentLevel.choices[choiceKey]).forEach(checkboxNr => {
|
||||||
|
const checkbox = currentLevel.choices[choiceKey][checkboxNr];
|
||||||
|
const data = {
|
||||||
|
...checkbox,
|
||||||
|
path: `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}`,
|
||||||
|
level: this.levelup.currentLevel
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!acc[choiceKey]) acc[choiceKey] = [];
|
||||||
|
acc[choiceKey].push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const experienceIncreases = Object.values(advancementChoices.experience ?? {});
|
||||||
|
const experienceIncreaseValues = experienceIncreases
|
||||||
|
.filter(exp => exp.data.length > 0)
|
||||||
|
.flatMap(exp =>
|
||||||
|
exp.data.map(data => {
|
||||||
|
const experience = Object.keys(this.actor.system.experiences).find(x => x === data);
|
||||||
|
return this.actor.system.experiences[experience].description;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
context.experienceIncreases = {
|
||||||
|
values: experienceIncreaseValues,
|
||||||
|
active: experienceIncreases.length > 0,
|
||||||
|
progress: {
|
||||||
|
selected: experienceIncreaseValues.length,
|
||||||
|
max: experienceIncreases.reduce((acc, exp) => acc + exp.amount, 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
context.newExperiences = Object.keys(currentLevel.achievements.experiences).map(key => {
|
||||||
|
const experience = currentLevel.achievements.experiences[key];
|
||||||
|
return {
|
||||||
|
...experience,
|
||||||
|
level: this.levelup.currentLevel,
|
||||||
|
key: key
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
context.vicious = advancementChoices.vicious ? Object.values(advancementChoices.vicious) : null;
|
||||||
|
context.viciousChoices = {
|
||||||
|
damage: game.i18n.localize('DAGGERHEART.Application.LevelUp.Selections.viciousDamage'),
|
||||||
|
range: game.i18n.localize('DAGGERHEART.Application.LevelUp.Selections.viciousRange')
|
||||||
|
};
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'summary':
|
||||||
|
const { current: currentActorLevel, changed: changedActorLevel } = this.actor.system.levelData.level;
|
||||||
|
const levelKeys = Object.keys(this.levelup.levels);
|
||||||
|
let achievementExperiences = [];
|
||||||
|
for (var levelKey of levelKeys) {
|
||||||
|
const level = this.levelup.levels[levelKey];
|
||||||
|
if (Number(levelKey) < this.levelup.startLevel) continue;
|
||||||
|
|
||||||
|
achievementExperiences = level.achievements.experiences
|
||||||
|
? Object.values(level.achievements.experiences).reduce((acc, experience) => {
|
||||||
|
if (experience.name) acc.push(experience);
|
||||||
|
return acc;
|
||||||
|
}, [])
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
context.achievements = {};
|
||||||
|
|
||||||
|
const actorDamageDice = this.actor.system.attack.damage.parts[0].value.dice;
|
||||||
|
const actorRange = this.actor.system.attack.range;
|
||||||
|
const advancement = {};
|
||||||
|
for (var levelKey of levelKeys) {
|
||||||
|
const level = this.levelup.levels[levelKey];
|
||||||
|
if (Number(levelKey) < this.levelup.startLevel) continue;
|
||||||
|
|
||||||
|
for (var choiceKey of Object.keys(level.choices)) {
|
||||||
|
const choice = level.choices[choiceKey];
|
||||||
|
for (var checkbox of Object.values(choice)) {
|
||||||
|
switch (choiceKey) {
|
||||||
|
case 'resilient':
|
||||||
|
case 'aware':
|
||||||
|
advancement[choiceKey] = advancement[choiceKey]
|
||||||
|
? advancement[choiceKey] + Number(checkbox.value)
|
||||||
|
: Number(checkbox.value);
|
||||||
|
break;
|
||||||
|
case 'intelligent':
|
||||||
|
if (!advancement[choiceKey]) advancement[choiceKey] = [];
|
||||||
|
const data = checkbox.data.map(data => {
|
||||||
|
const experience = Object.keys(this.actor.system.experiences).find(
|
||||||
|
x => x === data
|
||||||
|
);
|
||||||
|
return this.actor.system.experiences[experience]?.name ?? '';
|
||||||
|
});
|
||||||
|
advancement[choiceKey].push({ data: data, value: checkbox.value });
|
||||||
|
break;
|
||||||
|
case 'vicious':
|
||||||
|
if (!advancement[choiceKey]) advancement[choiceKey] = { damage: null, range: null };
|
||||||
|
const isDamage = checkbox.data[0] === 'damage';
|
||||||
|
const options = isDamage ? diceTypes : range;
|
||||||
|
const keys = Object.keys(options);
|
||||||
|
const actorKey = keys.indexOf(isDamage ? actorDamageDice : actorRange);
|
||||||
|
const currentIndex = advancement[choiceKey][checkbox.data[0]]
|
||||||
|
? keys.indexOf(advancement[choiceKey][checkbox.data[0]])
|
||||||
|
: actorKey;
|
||||||
|
advancement[choiceKey][checkbox.data[0]] =
|
||||||
|
options[keys[Math.min(currentIndex + 1, keys.length - 1)]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.advancements = {
|
||||||
|
statistics: {
|
||||||
|
stress: {
|
||||||
|
old: this.actor.system.resources.stress.maxTotal,
|
||||||
|
new: this.actor.system.resources.stress.maxTotal + (advancement.stress ?? 0)
|
||||||
|
},
|
||||||
|
evasion: {
|
||||||
|
old: this.actor.system.evasion.total,
|
||||||
|
new: this.actor.system.evasion.total + (advancement.evasion ?? 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
experiences:
|
||||||
|
advancement.experience?.flatMap(x => x.data.map(data => ({ name: data, modifier: x.value }))) ??
|
||||||
|
[],
|
||||||
|
vicious: {
|
||||||
|
damage: advancement.vicious?.damage
|
||||||
|
? {
|
||||||
|
old: actorDamageDice,
|
||||||
|
new: advancement.vicious.damage
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
range: advancement.vicious?.range
|
||||||
|
? {
|
||||||
|
old: game.i18n.localize(`DAGGERHEART.Range.${actorRange}.name`),
|
||||||
|
new: game.i18n.localize(advancement.vicious.range.label)
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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.stress.shown || context.advancements.statistics.evasion.shown;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { abilities, subclassFeatureLabels } from '../config/actorConfig.mjs';
|
import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs';
|
||||||
import { domains } from '../config/domainConfig.mjs';
|
import { domains } from '../../config/domainConfig.mjs';
|
||||||
import { DhLevelup } from '../data/levelup.mjs';
|
import { getDeleteKeys, tagifyElement } from '../../helpers/utils.mjs';
|
||||||
import { getDeleteKeys, tagifyElement } from '../helpers/utils.mjs';
|
|
||||||
|
|
||||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
|
@ -10,10 +9,6 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
||||||
super({});
|
super({});
|
||||||
|
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.levelTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers);
|
|
||||||
|
|
||||||
const playerLevelupData = actor.system.levelData;
|
|
||||||
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData, actor.system.level));
|
|
||||||
|
|
||||||
this._dragDrop = this._createDragDropHandlers();
|
this._dragDrop = this._createDragDropHandlers();
|
||||||
this.tabGroups.primary = 'advancements';
|
this.tabGroups.primary = 'advancements';
|
||||||
|
|
@ -118,181 +113,6 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
||||||
context.tabs.advancements.progress = { selected: selections, max: currentLevel.maxSelections };
|
context.tabs.advancements.progress = { selected: selections, max: currentLevel.maxSelections };
|
||||||
context.showTabs = this.tabGroups.primary !== 'summary';
|
context.showTabs = this.tabGroups.primary !== 'summary';
|
||||||
break;
|
break;
|
||||||
case 'selections':
|
|
||||||
const advancementChoices = Object.keys(currentLevel.choices).reduce((acc, choiceKey) => {
|
|
||||||
Object.keys(currentLevel.choices[choiceKey]).forEach(checkboxNr => {
|
|
||||||
const checkbox = currentLevel.choices[choiceKey][checkboxNr];
|
|
||||||
const data = {
|
|
||||||
...checkbox,
|
|
||||||
path: `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}`,
|
|
||||||
level: this.levelup.currentLevel
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!acc[choiceKey]) acc[choiceKey] = [];
|
|
||||||
acc[choiceKey].push(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const traits = Object.values(advancementChoices.trait ?? {});
|
|
||||||
const traitValues = traits.filter(trait => trait.data.length > 0).flatMap(trait => trait.data);
|
|
||||||
context.traits = {
|
|
||||||
values: traitValues,
|
|
||||||
active: traits.length > 0,
|
|
||||||
progress: {
|
|
||||||
selected: traitValues.length,
|
|
||||||
max: traits.reduce((acc, exp) => acc + exp.amount, 0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const experienceIncreases = Object.values(advancementChoices.experience ?? {});
|
|
||||||
const experienceIncreaseValues = experienceIncreases
|
|
||||||
.filter(exp => exp.data.length > 0)
|
|
||||||
.flatMap(exp =>
|
|
||||||
exp.data.map(data => {
|
|
||||||
const experience = Object.keys(this.actor.system.experiences).find(x => x === data);
|
|
||||||
return this.actor.system.experiences[experience].description;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
context.experienceIncreases = {
|
|
||||||
values: experienceIncreaseValues,
|
|
||||||
active: experienceIncreases.length > 0,
|
|
||||||
progress: {
|
|
||||||
selected: experienceIncreaseValues.length,
|
|
||||||
max: experienceIncreases.reduce((acc, exp) => acc + exp.amount, 0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
context.newExperiences = Object.keys(currentLevel.achievements.experiences).map(key => {
|
|
||||||
const experience = currentLevel.achievements.experiences[key];
|
|
||||||
return {
|
|
||||||
...experience,
|
|
||||||
level: this.levelup.currentLevel,
|
|
||||||
key: key
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const allDomainCards = {
|
|
||||||
...advancementChoices.domainCard,
|
|
||||||
...currentLevel.achievements.domainCards
|
|
||||||
};
|
|
||||||
const allDomainCardKeys = Object.keys(allDomainCards);
|
|
||||||
|
|
||||||
const classDomainsData = this.actor.system.class.value.system.domains.map(domain => ({
|
|
||||||
domain,
|
|
||||||
multiclass: false
|
|
||||||
}));
|
|
||||||
const multiclassDomainsData = (this.actor.system.multiclass?.value?.system?.domains ?? []).map(
|
|
||||||
domain => ({ domain, multiclass: true })
|
|
||||||
);
|
|
||||||
const domainsData = [...classDomainsData, ...multiclassDomainsData];
|
|
||||||
const multiclassDomain = this.levelup.classUpgradeChoices?.multiclass?.domain;
|
|
||||||
if (multiclassDomain) {
|
|
||||||
if (!domainsData.some(x => x.domain === multiclassDomain))
|
|
||||||
domainsData.push({ domain: multiclassDomain, multiclass: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
context.domainCards = [];
|
|
||||||
for (var key of allDomainCardKeys) {
|
|
||||||
const domainCard = allDomainCards[key];
|
|
||||||
if (domainCard.level > this.levelup.endLevel) continue;
|
|
||||||
|
|
||||||
const uuid = domainCard.data?.length > 0 ? domainCard.data[0] : domainCard.uuid;
|
|
||||||
const card = uuid ? await foundry.utils.fromUuid(uuid) : {};
|
|
||||||
|
|
||||||
context.domainCards.push({
|
|
||||||
...(card.toObject?.() ?? card),
|
|
||||||
emptySubtexts: domainsData.map(domain => {
|
|
||||||
const levelBase = domain.multiclass
|
|
||||||
? Math.ceil(this.levelup.currentLevel / 2)
|
|
||||||
: this.levelup.currentLevel;
|
|
||||||
const levelMax = domainCard.secondaryData?.limit
|
|
||||||
? Math.min(domainCard.secondaryData.limit, levelBase)
|
|
||||||
: levelBase;
|
|
||||||
|
|
||||||
return game.i18n.format('DAGGERHEART.Application.LevelUp.Selections.emptyDomainCardHint', {
|
|
||||||
domain: game.i18n.localize(domains[domain.domain].label),
|
|
||||||
level: levelMax
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
path: domainCard.data
|
|
||||||
? `${domainCard.path}.data`
|
|
||||||
: `levels.${domainCard.level}.achievements.domainCards.${key}.uuid`,
|
|
||||||
limit: domainCard.secondaryData?.limit ?? null,
|
|
||||||
compendium: 'domains'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subclassSelections = advancementChoices.subclass?.flatMap(x => x.data) ?? [];
|
|
||||||
const possibleSubclasses = [this.actor.system.class.subclass];
|
|
||||||
if (this.actor.system.multiclass?.subclass) {
|
|
||||||
possibleSubclasses.push(this.actor.system.multiclass.subclass);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.subclassCards = [];
|
|
||||||
if (advancementChoices.subclass?.length > 0) {
|
|
||||||
const featureStateIncrease = Object.values(this.levelup.levels).reduce((acc, level) => {
|
|
||||||
acc += Object.values(level.choices).filter(choice => {
|
|
||||||
return Object.values(choice).every(checkbox => checkbox.type === 'subclass');
|
|
||||||
}).length;
|
|
||||||
return acc;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
for (var subclass of possibleSubclasses) {
|
|
||||||
const choice =
|
|
||||||
advancementChoices.subclass.find(x => x.data[0] === subclass.uuid) ??
|
|
||||||
advancementChoices.subclass.find(x => x.data.length === 0);
|
|
||||||
const featureState = subclass.system.featureState + featureStateIncrease;
|
|
||||||
const data = await foundry.utils.fromUuid(subclass.uuid);
|
|
||||||
context.subclassCards.push({
|
|
||||||
...data.toObject(),
|
|
||||||
path: choice?.path,
|
|
||||||
uuid: data.uuid,
|
|
||||||
selected: subclassSelections.includes(subclass.uuid),
|
|
||||||
featureState: featureState,
|
|
||||||
featureLabel: game.i18n.localize(subclassFeatureLabels[featureState]),
|
|
||||||
isMulticlass: subclass.system.isMulticlass ? 'true' : 'false'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const multiclasses = Object.values(advancementChoices.multiclass ?? {});
|
|
||||||
if (multiclasses?.[0]) {
|
|
||||||
const data = multiclasses[0];
|
|
||||||
const multiclass = data.data.length > 0 ? await foundry.utils.fromUuid(data.data[0]) : {};
|
|
||||||
|
|
||||||
context.multiclass = {
|
|
||||||
...data,
|
|
||||||
...(multiclass.toObject?.() ?? multiclass),
|
|
||||||
uuid: multiclass.uuid,
|
|
||||||
domains:
|
|
||||||
multiclass?.system?.domains.map(key => {
|
|
||||||
const domain = domains[key];
|
|
||||||
const alreadySelected = this.actor.system.class.value.system.domains.includes(key);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...domain,
|
|
||||||
selected: key === data.secondaryData.domain,
|
|
||||||
disabled:
|
|
||||||
(data.secondaryData.domain && key !== data.secondaryData.domain) ||
|
|
||||||
alreadySelected
|
|
||||||
};
|
|
||||||
}) ?? [],
|
|
||||||
subclasses:
|
|
||||||
multiclass?.system?.subclasses.map(subclass => ({
|
|
||||||
...subclass,
|
|
||||||
uuid: subclass.uuid,
|
|
||||||
selected: data.secondaryData.subclass === subclass.uuid,
|
|
||||||
disabled: data.secondaryData.subclass && data.secondaryData.subclass !== subclass.uuid
|
|
||||||
})) ?? [],
|
|
||||||
compendium: 'classes',
|
|
||||||
limit: 1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'summary':
|
|
||||||
const { current: currentActorLevel, changed: changedActorLevel } = this.actor.system.levelData.level;
|
const { current: currentActorLevel, changed: changedActorLevel } = this.actor.system.levelData.level;
|
||||||
const actorArmor = this.actor.system.armor;
|
const actorArmor = this.actor.system.armor;
|
||||||
const levelKeys = Object.keys(this.levelup.levels);
|
const levelKeys = Object.keys(this.levelup.levels);
|
||||||
|
|
@ -4,7 +4,7 @@ import DhpDowntime from '../downtime.mjs';
|
||||||
import AncestrySelectionDialog from '../ancestrySelectionDialog.mjs';
|
import AncestrySelectionDialog from '../ancestrySelectionDialog.mjs';
|
||||||
import DaggerheartSheet from './daggerheart-sheet.mjs';
|
import DaggerheartSheet from './daggerheart-sheet.mjs';
|
||||||
import { abilities } from '../../config/actorConfig.mjs';
|
import { abilities } from '../../config/actorConfig.mjs';
|
||||||
import DhlevelUp from '../levelup.mjs';
|
import DhCharacterlevelUp from '../levelup/characterLevelup.mjs';
|
||||||
import DhCharacterCreation from '../characterCreation.mjs';
|
import DhCharacterCreation from '../characterCreation.mjs';
|
||||||
|
|
||||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
@ -425,7 +425,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new DhlevelUp(this.document).render(true);
|
new DhCharacterlevelUp(this.document).render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async useDomainCard(event, button) {
|
static async useDomainCard(event, button) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import DhCompanionlevelUp from '../levelup/companionLevelup.mjs';
|
||||||
import DaggerheartSheet from './daggerheart-sheet.mjs';
|
import DaggerheartSheet from './daggerheart-sheet.mjs';
|
||||||
|
|
||||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
@ -7,7 +8,8 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||||
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'companion'],
|
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'companion'],
|
||||||
position: { width: 700, height: 1000 },
|
position: { width: 700, height: 1000 },
|
||||||
actions: {
|
actions: {
|
||||||
attackRoll: this.attackRoll
|
attackRoll: this.attackRoll,
|
||||||
|
levelUp: this.levelUp
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
handler: this.updateForm,
|
handler: this.updateForm,
|
||||||
|
|
@ -20,6 +22,12 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||||
sidebar: { template: 'systems/daggerheart/templates/sheets/actors/companion/tempMain.hbs' }
|
sidebar: { template: 'systems/daggerheart/templates/sheets/actors/companion/tempMain.hbs' }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
htmlElement.querySelector('.partner-value')?.addEventListener('change', this.onPartnerChange.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
context.document = this.document;
|
context.document = this.document;
|
||||||
|
|
@ -35,7 +43,22 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onPartnerChange(event) {
|
||||||
|
if (event.target.value) {
|
||||||
|
const partner = game.actors.find(a => a.uuid === event.target.value);
|
||||||
|
await partner.update({ 'system.companion': this.document.uuid });
|
||||||
|
} else {
|
||||||
|
await this.document.system.partner.update({ 'system.companion': null });
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.document.update({ 'system.partner': event.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
static async attackRoll(event) {
|
static async attackRoll(event) {
|
||||||
this.actor.system.attack.use(event);
|
this.actor.system.attack.use(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async levelUp() {
|
||||||
|
new DhCompanionlevelUp(this.document).render(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
magic: new fields.NumberField({ integer: true, initial: 0 })
|
magic: new fields.NumberField({ integer: true, initial: 0 })
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
companion: new ForeignDocumentUUIDField({ type: 'actor', nullable: true, initial: null }),
|
||||||
rules: new fields.SchemaField({
|
rules: new fields.SchemaField({
|
||||||
maxArmorMarked: new fields.SchemaField({
|
maxArmorMarked: new fields.SchemaField({
|
||||||
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import BaseDataActor from './base.mjs';
|
||||||
import DhLevelData from '../levelData.mjs';
|
import DhLevelData from '../levelData.mjs';
|
||||||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import ActionField from '../fields/actionField.mjs';
|
||||||
|
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
export default class DhCompanion extends BaseDataActor {
|
export default class DhCompanion extends BaseDataActor {
|
||||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Companion'];
|
static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Companion'];
|
||||||
|
|
@ -9,7 +10,7 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
static get metadata() {
|
static get metadata() {
|
||||||
return foundry.utils.mergeObject(super.metadata, {
|
return foundry.utils.mergeObject(super.metadata, {
|
||||||
label: 'TYPES.Actor.companion',
|
label: 'TYPES.Actor.companion',
|
||||||
type: 'character'
|
type: 'companion'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,7 +24,8 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
max: new fields.NumberField({ initial: 3, integer: true })
|
max: new fields.NumberField({ initial: 3, integer: true })
|
||||||
})
|
}),
|
||||||
|
hope: new fields.NumberField({ initial: 0, integer: true })
|
||||||
}),
|
}),
|
||||||
evasion: new fields.SchemaField({
|
evasion: new fields.SchemaField({
|
||||||
value: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }),
|
value: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }),
|
||||||
|
|
@ -31,7 +33,7 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
}),
|
}),
|
||||||
experiences: new fields.TypedObjectField(
|
experiences: new fields.TypedObjectField(
|
||||||
new fields.SchemaField({
|
new fields.SchemaField({
|
||||||
description: new fields.StringField({}),
|
name: new fields.StringField({}),
|
||||||
value: new fields.NumberField({ integer: true, initial: 0 }),
|
value: new fields.NumberField({ integer: true, initial: 0 }),
|
||||||
bonus: new fields.NumberField({ integer: true, initial: 0 })
|
bonus: new fields.NumberField({ integer: true, initial: 0 })
|
||||||
}),
|
}),
|
||||||
|
|
@ -43,7 +45,7 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
attack: new ActionField({
|
attack: new ActionField({
|
||||||
base: {
|
initial: {
|
||||||
name: 'Attack',
|
name: 'Attack',
|
||||||
_id: foundry.utils.randomID(),
|
_id: foundry.utils.randomID(),
|
||||||
systemPath: 'attack',
|
systemPath: 'attack',
|
||||||
|
|
@ -60,7 +62,11 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
damage: {
|
damage: {
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
multiplier: 'flat'
|
multiplier: 'flat',
|
||||||
|
value: {
|
||||||
|
dice: 'd6',
|
||||||
|
multiplier: 'flat'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +80,36 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main;
|
const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main;
|
||||||
const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.total;
|
const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.total;
|
||||||
this.attack.roll.bonus = spellcastingModifier ?? 0; // Needs to expand on which modifier it is that should be used because of multiclassing;
|
this.attack.roll.bonus = spellcastingModifier ?? 0; // Needs to expand on which modifier it is that should be used because of multiclassing;
|
||||||
|
|
||||||
|
for (let levelKey in this.levelData.levelups) {
|
||||||
|
const level = this.levelData.levelups[levelKey];
|
||||||
|
for (let selection of level.selections) {
|
||||||
|
switch (selection.type) {
|
||||||
|
case 'lightInTheDark':
|
||||||
|
this.resources.hope += selection.value;
|
||||||
|
break;
|
||||||
|
case 'vicious':
|
||||||
|
if (selection.data === 'damage') {
|
||||||
|
this.attack.damage.parts[0].value.dice = adjustDice(this.attack.damage.parts[0].value.dice);
|
||||||
|
} else {
|
||||||
|
this.attack.range = adjustRange(this.attack.range);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'resilient':
|
||||||
|
this.resources.stress.bonus += selection.value;
|
||||||
|
break;
|
||||||
|
case 'aware':
|
||||||
|
this.evasion.bonus += selection.value;
|
||||||
|
break;
|
||||||
|
case 'intelligent':
|
||||||
|
Object.keys(this.experiences).forEach(key => {
|
||||||
|
const experience = this.experiences[key];
|
||||||
|
experience.bonus += selection.value;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
|
|
@ -92,4 +128,8 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
...data
|
...data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_preDelete() {
|
||||||
|
/* Null Character Companion field */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,37 @@ class DhLevelOption extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CompanionLevelOptionType = {
|
||||||
|
lightInTheDark: {
|
||||||
|
id: 'lightInTheDark',
|
||||||
|
label: 'Light In The Dark'
|
||||||
|
},
|
||||||
|
createComfort: {
|
||||||
|
id: 'createComfort',
|
||||||
|
label: 'Create Comfort'
|
||||||
|
},
|
||||||
|
armored: {
|
||||||
|
id: 'armored',
|
||||||
|
label: 'Armored'
|
||||||
|
},
|
||||||
|
vicious: {
|
||||||
|
id: 'vicious',
|
||||||
|
label: 'Viscious'
|
||||||
|
},
|
||||||
|
resilient: {
|
||||||
|
id: 'resilient',
|
||||||
|
label: 'Resilient'
|
||||||
|
},
|
||||||
|
bonded: {
|
||||||
|
id: 'bonded',
|
||||||
|
label: 'Bonded'
|
||||||
|
},
|
||||||
|
aware: {
|
||||||
|
id: 'aware',
|
||||||
|
label: 'Aware'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const LevelOptionType = {
|
export const LevelOptionType = {
|
||||||
trait: {
|
trait: {
|
||||||
id: 'trait',
|
id: 'trait',
|
||||||
|
|
@ -106,7 +137,8 @@ export const LevelOptionType = {
|
||||||
multiclass: {
|
multiclass: {
|
||||||
id: 'multiclass',
|
id: 'multiclass',
|
||||||
label: 'Multiclass'
|
label: 'Multiclass'
|
||||||
}
|
},
|
||||||
|
...CompanionLevelOptionType
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultLevelTiers = {
|
export const defaultLevelTiers = {
|
||||||
|
|
@ -338,3 +370,80 @@ export const defaultLevelTiers = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defaultCompanionTier = {
|
||||||
|
tiers: {
|
||||||
|
2: {
|
||||||
|
tier: 2,
|
||||||
|
name: 'Companion Choices',
|
||||||
|
levels: {
|
||||||
|
start: 2,
|
||||||
|
end: 10
|
||||||
|
},
|
||||||
|
initialAchievements: {},
|
||||||
|
availableOptions: 1,
|
||||||
|
domainCardByLevel: 0,
|
||||||
|
options: {
|
||||||
|
experience: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.intelligent',
|
||||||
|
checkboxSelections: 3,
|
||||||
|
minCost: 1,
|
||||||
|
type: LevelOptionType.experience.id,
|
||||||
|
value: 1,
|
||||||
|
amount: 2
|
||||||
|
},
|
||||||
|
lightInTheDark: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.lightInTheDark',
|
||||||
|
checkboxSelections: 1,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.lightInTheDark.id,
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
creatureComfort: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.creatureComfort',
|
||||||
|
checkboxSelections: 1,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.createComfort.id,
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
armored: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.armored',
|
||||||
|
checkboxSelections: 1,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.armored.id,
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
vicious: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.vicious',
|
||||||
|
checkboxSelections: 3,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.vicious.id,
|
||||||
|
value: 1,
|
||||||
|
amount: 1
|
||||||
|
},
|
||||||
|
resilient: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.resilient',
|
||||||
|
checkboxSelections: 3,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.resilient.id,
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
bonded: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.bonded',
|
||||||
|
checkboxSelections: 1,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.bonded.id,
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
aware: {
|
||||||
|
label: 'DAGGERHEART.LevelUp.Options.aware',
|
||||||
|
checkboxSelections: 3,
|
||||||
|
minCost: 1,
|
||||||
|
type: CompanionLevelOptionType.aware.id,
|
||||||
|
value: 2,
|
||||||
|
amount: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
||||||
name: tier.name,
|
name: tier.name,
|
||||||
belongingLevels: belongingLevels,
|
belongingLevels: belongingLevels,
|
||||||
options: Object.keys(tier.options).reduce((acc, key) => {
|
options: Object.keys(tier.options).reduce((acc, key) => {
|
||||||
acc[key] = tier.options[key].toObject();
|
acc[key] = tier.options[key].toObject?.() ?? tier.options[key];
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
};
|
};
|
||||||
|
|
@ -98,6 +98,8 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
||||||
case 'experience':
|
case 'experience':
|
||||||
case 'domainCard':
|
case 'domainCard':
|
||||||
case 'subclass':
|
case 'subclass':
|
||||||
|
case 'vicious':
|
||||||
|
case 'intelligent':
|
||||||
return checkbox.data.length === (checkbox.amount ?? 1);
|
return checkbox.data.length === (checkbox.amount ?? 1);
|
||||||
case 'multiclass':
|
case 'multiclass':
|
||||||
const classSelected = checkbox.data.length === 1;
|
const classSelected = checkbox.data.length === 1;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getDiceSoNicePresets } from '../config/generalConfig.mjs';
|
import { diceTypes, getDiceSoNicePresets, range } from '../config/generalConfig.mjs';
|
||||||
import Tagify from '@yaireo/tagify';
|
import Tagify from '@yaireo/tagify';
|
||||||
|
|
||||||
export const loadCompendiumOptions = async compendiums => {
|
export const loadCompendiumOptions = async compendiums => {
|
||||||
|
|
@ -259,3 +259,17 @@ export const damageKeyToNumber = key => {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const adjustDice = (dice, decrease) => {
|
||||||
|
const diceKeys = Object.keys(diceTypes);
|
||||||
|
const index = diceKeys.indexOf(dice);
|
||||||
|
const newIndex = decrease ? Math.max(index - 1, 0) : Math.min(index + 1, diceKeys.length - 1);
|
||||||
|
return diceTypes[diceKeys[newIndex]];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const adjustRange = (rangeVal, decrease) => {
|
||||||
|
const rangeKeys = Object.keys(range);
|
||||||
|
const index = rangeKeys.indexOf(rangeVal);
|
||||||
|
const newIndex = decrease ? Math.max(index - 1, 0) : Math.min(index + 1, rangeKeys.length - 1);
|
||||||
|
return range[rangeKeys[newIndex]];
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -2933,6 +2933,7 @@ div.daggerheart.views.multiclass {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.daggerheart.levelup .levelup-navigation-container {
|
.daggerheart.levelup .levelup-navigation-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -3094,6 +3095,13 @@ div.daggerheart.views.multiclass {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
.daggerheart.levelup .levelup-selections-container .levelup-radio-choices {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.daggerheart.levelup .levelup-selections-container .levelup-radio-choices label {
|
||||||
|
flex: 0;
|
||||||
|
}
|
||||||
.daggerheart.levelup .levelup-summary-container .level-achievements-container,
|
.daggerheart.levelup .levelup-summary-container .level-achievements-container,
|
||||||
.daggerheart.levelup .levelup-summary-container .level-advancements-container {
|
.daggerheart.levelup .levelup-summary-container .level-advancements-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,6 +218,15 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.levelup-radio-choices {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
flex: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.levelup-summary-container {
|
.levelup-summary-container {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-fields">
|
<div class="form-fields">
|
||||||
<label>{{localize "DAGGERHEART.Sheets.Companion.FIELDS.partner.label"}}</label>
|
<label>{{localize "DAGGERHEART.Sheets.Companion.FIELDS.partner.label"}}</label>
|
||||||
<select name="system.partner">
|
<select class="partner-value">
|
||||||
{{selectOptions playerCharacters selected=source.system.partner.uuid labelAttr="name" valueAttr="key" blank=""}}
|
{{selectOptions playerCharacters selected=source.system.partner.uuid labelAttr="name" valueAttr="key" blank=""}}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
<div class="flexcol">
|
<div class="flexcol">
|
||||||
{{#each source.system.experiences as |experience key|}}
|
{{#each source.system.experiences as |experience key|}}
|
||||||
<div class="flexrow">
|
<div class="flexrow">
|
||||||
<input type="text" name="{{concat "system.experiences." key ".description"}}" value="{{experience.description}}" />
|
<input type="text" name="{{concat "system.experiences." key ".name"}}" value="{{experience.name}}" />
|
||||||
<input type="text" data-dtype="Number" name="{{concat "system.experiences." key ".value"}}" value="{{experience.value}}" />
|
<input type="text" data-dtype="Number" name="{{concat "system.experiences." key ".value"}}" value="{{experience.value}}" />
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
@ -30,4 +30,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flexrow">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize "DAGGERHEART.Sheets.Companion.Level"}}</label>
|
||||||
|
<input type="text" name="system.levelData.level.changed" value="{{source.system.levelData.level.changed}}" />
|
||||||
|
<button data-action="levelUp" {{#if (not source.system.levelData.canLevelUp)}}disabled{{/if}}>Level Up</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -111,5 +111,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.vicious}}
|
||||||
|
<div>
|
||||||
|
<h3>{{localize "DAGGERHEART.Application.LevelUp.summary.vicious"}}</h3>
|
||||||
|
{{#each this.vicious}}
|
||||||
|
<div class="levelup-radio-choices">
|
||||||
|
{{radioBoxes (concat "levelup." this.path ".data") @root.viciousChoices checked=this.data}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -17,19 +17,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div>
|
{{#if this.achievements.damageThresholds}}
|
||||||
<h5 class="summary-section">{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholds"}}{{#if this.levelAchievements.damageThresholds.unarmored}}({{localize "DAGGERHEART.General.unarmored"}}){{/if}}</h5>
|
<div>
|
||||||
<div class="increase-container">
|
<h5 class="summary-section">{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholds"}}{{#if this.levelAchievements.damageThresholds.unarmored}}({{localize "DAGGERHEART.General.unarmored"}}){{/if}}</h5>
|
||||||
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdMajorIncrease" threshold=this.achievements.damageThresholds.major.old }}
|
<div class="increase-container">
|
||||||
<i class="fa-solid fa-arrow-right-long"></i>
|
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdMajorIncrease" threshold=this.achievements.damageThresholds.major.old }}
|
||||||
{{this.achievements.damageThresholds.major.new}}
|
<i class="fa-solid fa-arrow-right-long"></i>
|
||||||
|
{{this.achievements.damageThresholds.major.new}}
|
||||||
|
</div>
|
||||||
|
<div class="increase-container">
|
||||||
|
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdSevereIncrease" threshold=this.achievements.damageThresholds.severe.old }}
|
||||||
|
<i class="fa-solid fa-arrow-right-long"></i>
|
||||||
|
{{this.achievements.damageThresholds.severe.new}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="increase-container">
|
{{/if}}
|
||||||
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdSevereIncrease" threshold=this.achievements.damageThresholds.severe.old }}
|
|
||||||
<i class="fa-solid fa-arrow-right-long"></i>
|
|
||||||
{{this.achievements.damageThresholds.severe.new}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{#if this.achievements.domainCards.shown}}
|
{{#if this.achievements.domainCards.shown}}
|
||||||
<div>
|
<div>
|
||||||
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.domainCards"}}</h5>
|
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.domainCards"}}</h5>
|
||||||
|
|
@ -151,6 +153,21 @@
|
||||||
</div>
|
</div>
|
||||||
{{/with}}
|
{{/with}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.advancements.vicious.damage}}
|
||||||
|
<div class="increase-container">
|
||||||
|
{{localize "DAGGERHEART.Application.LevelUp.summary.damageIncreased" damage=this.advancements.vicious.damage.old }}
|
||||||
|
<i class="fa-solid fa-arrow-right-long"></i>
|
||||||
|
{{this.advancements.vicious.damage.new}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if this.advancements.vicious.range}}
|
||||||
|
<div class="increase-container">
|
||||||
|
{{localize "DAGGERHEART.Application.LevelUp.summary.rangeIncreased" range=this.advancements.vicious.range.old }}
|
||||||
|
<i class="fa-solid fa-arrow-right-long"></i>
|
||||||
|
{{this.advancements.vicious.range.new}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue