Merge branch 'hotfix' into fix/877-hope-update-order

This commit is contained in:
Dapoolp 2025-08-13 13:41:45 +02:00
commit a22b4c8209
23 changed files with 267 additions and 80 deletions

View file

@ -67,6 +67,28 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
const levelKeys = Object.keys(this.levelup.levels);
const actorDamageDice = this.actor.system.attack.damage.parts[0].value.dice;
const actorRange = this.actor.system.attack.range;
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 = {
experiences: {
values: achievementExperiences,
shown: achievementExperiences.length > 0
}
};
context.achievements = context.achievements.experiences.shown ? context.achievements : undefined;
const advancement = {};
for (var levelKey of levelKeys) {
const level = this.levelup.levels[levelKey];

View file

@ -1,5 +1,4 @@
import { GMUpdateEvent, socketEvent } from '../../systemRegistration/socket.mjs';
import DhCompanionlevelUp from '../levelup/companionLevelup.mjs';
import DHBaseActorSettings from '../sheets/api/actor-setting.mjs';
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
@ -11,8 +10,7 @@ export default class DHCompanionSettings extends DHBaseActorSettings {
position: { width: 455, height: 'auto' },
actions: {
addExperience: DHCompanionSettings.#addExperience,
removeExperience: DHCompanionSettings.#removeExperience,
levelUp: DHCompanionSettings.#levelUp
removeExperience: DHCompanionSettings.#removeExperience
}
};
@ -121,12 +119,4 @@ export default class DHCompanionSettings extends DHBaseActorSettings {
await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null });
}
/**
* Opens the companion level-up dialog for the associated actor.
* @type {ApplicationClickAction}
*/
static async #levelUp() {
new DhCompanionlevelUp(this.actor).render({ force: true });
}
}

View file

@ -1,3 +1,4 @@
import DhCompanionLevelUp from '../../levelup/companionLevelup.mjs';
import DHBaseActorSheet from '../api/base-actor.mjs';
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
@ -6,7 +7,9 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
static DEFAULT_OPTIONS = {
classes: ['actor', 'companion'],
position: { width: 300 },
actions: {}
actions: {
levelManagement: DhCompanionSheet.#levelManagement
}
};
static PARTS = {
@ -25,4 +28,25 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
}
};
/** @inheritDoc */
async _onRender(context, options) {
await super._onRender(context, options);
this.element
.querySelector('.level-value')
?.addEventListener('change', event => this.document.updateLevel(Number(event.currentTarget.value)));
}
/* -------------------------------------------- */
/* Application Clicks Actions */
/* -------------------------------------------- */
/**
* Opens the companions level management window.
* @type {ApplicationClickAction}
*/
static #levelManagement() {
new DhCompanionLevelUp(this.document).render({ force: true });
}
}

View file

@ -24,7 +24,7 @@ export default function ItemAttachmentSheet(Base) {
...super.TABS,
primary: {
...super.TABS?.primary,
tabs: [...(super.TABS?.primary?.tabs || []), { id: 'attachments' }],
tabs: [...(super.TABS?.primary?.tabs || []) /*{ id: 'attachments' }*/], // Disabled until fixed
initial: super.TABS?.primary?.initial || 'description',
labelPrefix: super.TABS?.primary?.labelPrefix || 'DAGGERHEART.GENERAL.Tabs'
}

View file

@ -602,7 +602,20 @@ export default class DhCharacter extends BaseDataActor {
}
prepareDerivedData() {
const baseHope = this.resources.hope.value + (this.companion?.system?.resources?.hope ?? 0);
let baseHope = this.resources.hope.value;
if (this.companion) {
for (let levelKey in this.companion.system.levelData.levelups) {
const level = this.companion.system.levelData.levelups[levelKey];
for (let selection of level.selections) {
switch (selection.type) {
case 'hope':
this.resources.hope.max += selection.value;
break;
}
}
}
}
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;

View file

@ -40,12 +40,14 @@ export default class DhCompanion extends BaseDataActor {
experiences: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField({}),
value: new fields.NumberField({ integer: true, initial: 0 })
value: new fields.NumberField({ integer: true, initial: 0 }),
description: new fields.StringField(),
core: new fields.BooleanField({ initial: false })
}),
{
initial: {
experience1: { value: 2 },
experience2: { value: 2 }
experience1: { value: 2, core: true },
experience2: { value: 2, core: true }
}
}
),
@ -134,6 +136,23 @@ export default class DhCompanion extends BaseDataActor {
}
}
async _preUpdate(changes, options, userId) {
const allowed = await super._preUpdate(changes, options, userId);
if (allowed === false) return;
/* The first two experiences are always marked as core */
if (changes.system?.experiences && Object.keys(this.experiences).length < 2) {
const experiences = new Set(Object.keys(this.experiences));
const changeExperiences = new Set(Object.keys(changes.system.experiences));
const newExperiences = Array.from(changeExperiences.difference(experiences));
for (var i = 0; i < Math.min(newExperiences.length, 2 - experiences.size); i++) {
const experience = newExperiences[i];
changes.system.experiences[experience].core = true;
}
}
}
async _preDelete() {
if (this.partner) {
await this.partner.update({ 'system.companion': null });

View file

@ -1,5 +1,5 @@
import AttachableItem from './attachableItem.mjs';
import { ActionsField, ActionField } from '../fields/actionField.mjs';
import { ActionField } from '../fields/actionField.mjs';
export default class DHWeapon extends AttachableItem {
/** @inheritDoc */
@ -18,12 +18,23 @@ export default class DHWeapon extends AttachableItem {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1, label: "DAGGERHEART.GENERAL.Tiers.singular" }),
tier: new fields.NumberField({
required: true,
integer: true,
initial: 1,
min: 1,
label: 'DAGGERHEART.GENERAL.Tiers.singular'
}),
equipped: new fields.BooleanField({ initial: false }),
//SETTINGS
secondary: new fields.BooleanField({ initial: false, label: "DAGGERHEART.ITEMS.Weapon.secondaryWeapon" }),
burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, initial: 'oneHanded', label: "DAGGERHEART.GENERAL.burden" }),
secondary: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon' }),
burden: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.burden,
initial: 'oneHanded',
label: 'DAGGERHEART.GENERAL.burden'
}),
weaponFeatures: new fields.ArrayField(
new fields.SchemaField({
value: new fields.StringField({
@ -212,7 +223,7 @@ export default class DHWeapon extends AttachableItem {
const labels = [];
const { roll, range, damage } = this.attack;
if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`))
if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`));
if (range) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`));
for (const { value, type } of damage.parts) {

View file

@ -404,7 +404,27 @@ export const defaultCompanionTier = {
start: 2,
end: 10
},
initialAchievements: {},
initialAchievements: {
experience: {
nr: 1,
modifier: 2
}
},
/* Improved this. Quick solution for companions */
extraAchievements: {
5: {
experience: {
nr: 1,
modifier: 2
}
},
8: {
experience: {
nr: 1,
modifier: 2
}
}
},
availableOptions: 1,
domainCardByLevel: 0,
options: {

View file

@ -26,6 +26,7 @@ export class DhLevelup extends foundry.abstract.DataModel {
return acc;
}, {})
: {};
const domainCards = [...Array(tier.domainCardByLevel).keys()].reduce((acc, _) => {
const id = foundry.utils.randomID();
acc[id] = { uuid: null, itemUuid: null, level: i };
@ -42,6 +43,20 @@ export class DhLevelup extends foundry.abstract.DataModel {
belongingLevels.push(i);
}
/* Improve. Temporary handling for Companion new experiences */
Object.keys(tier.extraAchievements ?? {}).forEach(key => {
const level = Number(key);
if (level >= startLevel && level <= endLevel) {
const levelExtras = tier.extraAchievements[level];
if (levelExtras.experience) {
levels[level].achievements.experiences[foundry.utils.randomID()] = {
name: '',
modifier: levelExtras.experience.modifier
};
}
}
});
tiers[key] = {
name: tier.name,
belongingLevels: belongingLevels,

View file

@ -137,9 +137,10 @@ export default class DamageRoll extends DHRoll {
}
if (config.isCritical && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
const tmpRoll = Roll.fromTerms(part.roll.terms)._evaluateSync({ maximize: true }),
criticalBonus = tmpRoll.total - this.constructor.calculateTotalModifiers(tmpRoll);
part.roll.terms.push(...this.formatModifier(criticalBonus));
const total = part.roll.dice.reduce((acc, term) => acc + term._faces*term._number, 0);
if (total > 0) {
part.roll.terms.push(...this.formatModifier(total));
}
}
/* To Remove When Reaction System */

View file

@ -2,6 +2,7 @@ import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
import { LevelOptionType } from '../data/levelTier.mjs';
import DHFeature from '../data/item/feature.mjs';
import { damageKeyToNumber } from '../helpers/utils.mjs';
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
export default class DhpActor extends Actor {
/**
@ -142,9 +143,6 @@ export default class DhpActor extends Actor {
}, {})
});
this.update(getUpdate());
if (this.system.companion) {
this.system.companion.update(getUpdate());
}
}
if (subclassFeatureState.class) {
@ -195,10 +193,6 @@ export default class DhpActor extends Actor {
}
});
this.sheet.render();
if (this.system.companion) {
this.system.companion.updateLevel(newLevel);
}
}
}
@ -219,16 +213,6 @@ export default class DhpActor extends Actor {
core: true
}
});
if (this.system.companion) {
await this.system.companion.update({
[`system.experiences.${experienceKey}`]: {
name: '',
value: experience.modifier,
core: true
}
});
}
}
}
@ -405,6 +389,7 @@ export default class DhpActor extends Actor {
};
}
const levelChange = this.system.levelData.level.changed - this.system.levelData.level.current;
await this.update({
system: {
levelData: {
@ -417,8 +402,21 @@ export default class DhpActor extends Actor {
});
this.sheet.render();
if (this.system.companion) {
this.system.companion.updateLevel(this.system.levelData.level.changed);
if (this.system.companion && !this.system.companion.system.levelData.canLevelUp) {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.localize('DAGGERHEART.ACTORS.Character.companionLevelup.confirmTitle')
},
content: game.i18n.format('DAGGERHEART.ACTORS.Character.companionLevelup.confirmText', {
name: this.system.companion.name,
levelChange: levelChange
})
});
if (!confirmed) return;
await this.system.companion.updateLevel(this.system.companion.system.levelData.level.current + levelChange);
new DhCompanionLevelUp(this.system.companion).render({ force: true });
}
}

View file

@ -72,4 +72,8 @@ export default class DHToken extends TokenDocument {
}
return attributes;
}
_shouldRecordMovementHistory() {
return false;
}
}

View file

@ -49,11 +49,11 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
const longRest = element.dataset.tooltip?.startsWith('#longRest#');
if (shortRest || longRest) {
const key = element.dataset.tooltip.slice(shortRest ? 11 : 10);
const downtimeOptions = shortRest
? CONFIG.DH.GENERAL.defaultRestOptions.shortRest()
: CONFIG.DH.GENERAL.defaultRestOptions.longRest();
const move = downtimeOptions[key];
const moves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves[
element.dataset.restType
].moves;
const move = moves[key];
const description = await TextEditor.enrichHTML(move.description);
html = await foundry.applications.handlebars.renderTemplate(
`systems/daggerheart/templates/ui/tooltip/downtime.hbs`,

View file

@ -251,13 +251,15 @@ export const adjustRange = (rangeVal, decrease) => {
};
export const updateActorTokens = async (actor, update) => {
await actor.prototypeToken.update(update);
await actor.prototypeToken.update({ ...update });
/* Update the tokens in all scenes belonging to Actor */
for (let token of actor.getDependentTokens()) {
const tokenActor = token.baseActor ?? token.actor;
if (tokenActor?.id === actor.id) {
await token.update(update);
await token.update({
...update
});
}
}
};
@ -341,7 +343,7 @@ export const itemAbleRollParse = (value, actor, item) => {
const model = isItemTarget ? item : actor;
try {
return Roll.replaceFormulaData(slicedValue, model?.getRollData?.() ?? model);
return Roll.replaceFormulaData(slicedValue, isItemTarget || !model?.getRollData ? model : model.getRollData());
} catch (_) {
return '';
}
@ -370,7 +372,7 @@ export function getScrollTextData(resources, resource, key) {
export function createScrollText(actor, optionsData) {
if (actor && optionsData?.length) {
actor.getDependentTokens().forEach(token => {
actor.getActiveTokens().forEach(token => {
optionsData.forEach(data => {
const { text, ...options } = data;
canvas.interface.createScrollingText(token.getCenterPoint(), data.text, {