Merge branch 'main' into rework/chat-message-damage

This commit is contained in:
WBHarry 2026-07-12 00:49:04 +02:00
commit e9e061284c
251 changed files with 872 additions and 688 deletions

View file

@ -315,15 +315,15 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
const beastformEffect = selected.effects.find(x => x.type === 'beastform');
for (const traitBonus of app.modifications.traitBonuses) {
const existingChange = beastformEffect.changes.find(
const existingChange = beastformEffect.system.changes.find(
x => x.key === `system.traits.${traitBonus.trait}.value`
);
if (existingChange) {
existingChange.value = Number.parseInt(existingChange.value) + traitBonus.bonus;
} else {
beastformEffect.changes.push({
beastformEffect.system.changes.push({
key: `system.traits.${traitBonus.trait}.value`,
mode: 2,
type: 'add',
priority: null,
value: traitBonus.bonus
});

View file

@ -139,13 +139,15 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
name: game.i18n.localize('DAGGERHEART.CONFIG.DeathMoves.blazeOfGlory.name'),
description: game.i18n.localize('DAGGERHEART.CONFIG.DeathMoves.blazeOfGlory.description'),
img: CONFIG.DH.GENERAL.deathMoves.blazeOfGlory.img,
changes: [
{
key: 'system.rules.roll.guaranteedCritical',
mode: 2,
value: 'true'
}
]
system: {
changes: [
{
key: 'system.rules.roll.guaranteedCritical',
type: 'add',
value: 'true'
}
]
}
}
]);

View file

@ -90,18 +90,20 @@ export const BPModifiers = {
name: 'DAGGERHEART.CONFIG.BPModifiers.increaseDamage.effect.name',
description: 'DAGGERHEART.CONFIG.BPModifiers.increaseDamage.effect.description',
img: 'icons/magic/control/buff-flight-wings-red.webp',
changes: [
{
key: 'system.bonuses.damage.physical.dice',
mode: 2,
value: '1d4'
},
{
key: 'system.bonuses.damage.magical.dice',
mode: 2,
value: '1d4'
}
]
system: {
changes: [
{
key: 'system.bonuses.damage.physical.dice',
type: 'add',
value: '1d4'
},
{
key: 'system.bonuses.damage.magical.dice',
type: 'add',
value: '1d4'
}
]
}
}
]
}

View file

@ -37,13 +37,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.channeling.effects.channeling.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.channeling.effects.channeling.description',
img: 'icons/magic/symbols/rune-sigil-horned-blue.webp',
changes: [
{
key: 'system.bonuses.roll.spellcast',
mode: 2,
value: '1'
}
]
system: {
changes: [
{
key: 'system.bonuses.roll.spellcast',
type: 'add',
value: '1'
}
]
}
}
]
},
@ -55,43 +57,45 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.difficult.effects.difficult.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.difficult.effects.difficult.description',
img: 'icons/magic/control/buff-flight-wings-red.webp',
changes: [
{
key: 'system.traits.agility.value',
mode: 2,
value: '-1'
},
{
key: 'system.traits.strength.value',
mode: 2,
value: '-1'
},
{
key: 'system.traits.finesse.value',
mode: 2,
value: '-1'
},
{
key: 'system.traits.instinct.value',
mode: 2,
value: '-1'
},
{
key: 'system.traits.presence.value',
mode: 2,
value: '-1'
},
{
key: 'system.traits.knowledge.value',
mode: 2,
value: '-1'
},
{
key: 'system.evasion',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.traits.agility.value',
type: 'add',
value: '-1'
},
{
key: 'system.traits.strength.value',
type: 'add',
value: '-1'
},
{
key: 'system.traits.finesse.value',
type: 'add',
value: '-1'
},
{
key: 'system.traits.instinct.value',
type: 'add',
value: '-1'
},
{
key: 'system.traits.presence.value',
type: 'add',
value: '-1'
},
{
key: 'system.traits.knowledge.value',
type: 'add',
value: '-1'
},
{
key: 'system.evasion',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -103,13 +107,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.flexible.effects.flexible.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.flexible.effects.flexible.description',
img: 'icons/magic/movement/abstract-ribbons-red-orange.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '1'
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '1'
}
]
}
}
]
},
@ -121,13 +127,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.fortified.effects.fortified.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.fortified.effects.fortified.description',
img: 'icons/magic/defensive/shield-barrier-glowing-blue.webp',
changes: [
{
key: 'system.rules.damageReduction.increasePerArmorMark',
mode: 5,
value: '2'
}
]
system: {
changes: [
{
key: 'system.rules.damageReduction.increasePerArmorMark',
type: 'override',
value: '2'
}
]
}
}
]
},
@ -139,13 +147,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.gilded.effects.gilded.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.gilded.effects.gilded.description',
img: 'icons/magic/control/control-influence-crown-gold.webp',
changes: [
{
key: 'system.traits.presence.value',
mode: 2,
value: '1'
}
]
system: {
changes: [
{
key: 'system.traits.presence.value',
type: 'add',
value: '1'
}
]
}
}
]
},
@ -157,13 +167,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.heavy.effects.heavy.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.heavy.effects.heavy.description',
img: 'icons/commodities/metal/ingot-worn-iron.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -212,13 +224,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.magical.effects.magical.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.magical.effects.magical.description',
img: 'icons/magic/defensive/barrier-shield-dome-blue-purple.webp',
changes: [
{
key: 'system.rules.damageReduction.magical',
mode: 5,
value: 1
}
]
system: {
changes: [
{
key: 'system.rules.damageReduction.magical',
type: 'override',
value: 1
}
]
}
}
]
},
@ -249,13 +263,15 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.physical.effects.physical.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.physical.effects.physical.description',
img: 'icons/commodities/stone/ore-pile-tan.webp',
changes: [
{
key: 'system.rules.damageReduction.physical',
mode: 5,
value: 1
}
]
system: {
changes: [
{
key: 'system.rules.damageReduction.physical',
type: 'override',
value: 1
}
]
}
}
]
},
@ -280,18 +296,20 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.reinforced.effects.reinforced.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.reinforced.effects.reinforced.description',
img: 'icons/magic/defensive/shield-barrier-glowing-triangle-green.webp',
changes: [
{
key: 'system.bunuses.damageThresholds.major',
mode: 2,
value: '2'
},
{
key: 'system.bunuses.damageThresholds.severe',
mode: 2,
value: '2'
}
]
system: {
changes: [
{
key: 'system.bunuses.damageThresholds.major',
type: 'add',
value: '2'
},
{
key: 'system.bunuses.damageThresholds.severe',
type: 'add',
value: '2'
}
]
}
}
]
},
@ -326,18 +344,20 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.sharp.effects.sharp.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.sharp.effects.sharp.description',
img: 'icons/magic/defensive/shield-barrier-glowing-triangle-green.webp',
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.dice',
mode: 2,
value: '1d4'
},
{
key: 'system.bonuses.damage.secondaryWeapon.dice',
mode: 2,
value: '1d4'
}
]
system: {
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.dice',
type: 'add',
value: '1d4'
},
{
key: 'system.bonuses.damage.secondaryWeapon.dice',
type: 'add',
value: '1d4'
}
]
}
}
]
},
@ -408,18 +428,20 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.veryHeavy.effects.veryHeavy.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.veryHeavy.effects.veryHeavy.description',
img: 'icons/commodities/metal/ingot-stamped-steel.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '-2'
},
{
key: 'system.traits.agility.value',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '-2'
},
{
key: 'system.traits.agility.value',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -431,14 +453,16 @@ export const armorFeatures = {
name: 'DAGGERHEART.CONFIG.ArmorFeature.warded.effects.warded.name',
description: 'DAGGERHEART.CONFIG.ArmorFeature.warded.effects.warded.description',
img: 'icons/magic/defensive/barrier-shield-dome-pink.webp',
changes: [
{
key: 'system.resistance.magical.reduction',
mode: 2,
value: '@system.armorScore',
priority: 21
}
]
system: {
changes: [
{
key: 'system.resistance.magical.reduction',
type: 'add',
value: '@system.armorScore',
priority: 21
}
]
}
}
]
}
@ -488,21 +512,23 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.barrier.effects.barrier.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.barrier.effects.barrier.description',
img: 'icons/skills/melee/shield-block-bash-blue.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '-1'
},
{
key: 'Armor',
type: 'armor',
typeData: {
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '-1'
},
{
key: 'Armor',
type: 'armor',
max: 'ITEM.@system.tier + 1'
typeData: {
type: 'armor',
max: 'ITEM.@system.tier + 1'
}
}
}
]
]
}
}
]
},
@ -514,13 +540,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.bonded.effects.damage.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.bonded.effects.damage.description',
img: 'icons/magic/symbols/chevron-elipse-circle-blue.webp',
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.bonus',
mode: 2,
value: '@system.levelData.level.current'
}
]
system: {
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.bonus',
type: 'add',
value: '@system.levelData.level.current'
}
]
}
}
]
},
@ -553,18 +581,20 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.brave.effects.brave.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.brave.effects.brave.description',
img: 'icons/magic/life/heart-cross-strong-flame-purple-orange.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '-1'
},
{
key: 'system.damageThresholds.severe',
mode: 2,
value: 'ITEM.@system.tier'
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '-1'
},
{
key: 'system.damageThresholds.severe',
type: 'add',
value: 'ITEM.@system.tier'
}
]
}
}
]
},
@ -618,13 +648,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.charged.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.charged.description',
img: 'icons/magic/lightning/claws-unarmed-strike-teal.webp',
changes: [
{
key: 'system.proficiency',
mode: 2,
value: '1'
}
]
system: {
changes: [
{
key: 'system.proficiency',
type: 'add',
value: '1'
}
]
}
}
]
}
@ -660,13 +692,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.cumbersome.effects.cumbersome.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.cumbersome.effects.cumbersome.description',
img: 'icons/commodities/metal/mail-plate-steel.webp',
changes: [
{
key: 'system.traits.finesse.value',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.traits.finesse.value',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -707,14 +741,16 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.deflecting.effects.deflecting.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.deflecting.effects.deflecting.description',
img: 'icons/skills/melee/hand-grip-sword-strike-orange.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '@system.armorScore',
priority: 21
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '@system.armorScore',
priority: 21
}
]
}
}
]
}
@ -754,13 +790,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.destructive.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.destructive.effects.agility',
img: 'icons/skills/melee/strike-flail-spiked-pink.webp',
changes: [
{
key: 'system.traits.agility.value',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.traits.agility.value',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -795,7 +833,7 @@ export const weaponFeatures = {
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.bonus',
mode: 2,
type: 'add',
value: '1'
}
],
@ -902,13 +940,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.greedy.actions.greed.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.greedy.actions.greed.description',
img: 'icons/commodities/currency/coins-crown-stack-gold.webp',
changes: [
{
key: 'system.proficiency',
mode: 2,
value: '1'
}
]
system: {
changes: [
{
key: 'system.proficiency',
type: 'add',
value: '1'
}
]
}
}
]
}
@ -951,13 +991,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.heavy.effects.heavy.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.heavy.effects.heavy.description',
img: 'icons/commodities/metal/ingot-worn-iron.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -1066,13 +1108,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.massive.effects.massive.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.massive.effects.massive.description',
img: 'icons/skills/melee/strike-flail-destructive-yellow.webp',
changes: [
{
key: 'system.evasion',
mode: 2,
value: '-1'
}
]
system: {
changes: [
{
key: 'system.evasion',
type: 'add',
value: '-1'
}
]
}
}
]
},
@ -1107,7 +1151,7 @@ export const weaponFeatures = {
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.bonus',
mode: 2,
type: 'add',
value: 'ITEM.@system.tier + 1'
}
],
@ -1158,13 +1202,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.persuasive.effects.persuasive.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.persuasive.effects.persuasive.description',
img: 'icons/magic/control/hypnosis-mesmerism-eye.webp',
changes: [
{
key: 'system.traits.presence.value',
mode: 2,
value: '2'
}
]
system: {
changes: [
{
key: 'system.traits.presence.value',
type: 'add',
value: '2'
}
]
}
}
]
}
@ -1203,17 +1249,20 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.protective.effects.protective.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.protective.effects.protective.description',
img: 'icons/skills/melee/shield-block-gray-orange.webp',
changes: [
{
key: 'Armor',
type: 'armor',
value: 0,
typeData: {
system: {
changes: [
{
key: 'Armor',
type: 'armor',
max: 'ITEM.@system.tier'
value: 0,
typeData: {
type: 'armor',
max: 'ITEM.@system.tier'
}
}
}
]
]
}
}
]
},
@ -1244,13 +1293,15 @@ export const weaponFeatures = {
name: 'DAGGERHEART.CONFIG.WeaponFeature.reliable.effects.reliable.name',
description: 'DAGGERHEART.CONFIG.WeaponFeature.reliable.effects.reliable.description',
img: 'icons/skills/melee/strike-sword-slashing-red.webp',
changes: [
{
key: 'system.bonuses.roll.primaryWeapon.bonus',
mode: 2,
value: 1
}
]
system: {
changes: [
{
key: 'system.bonuses.roll.primaryWeapon.bonus',
type: 'add',
value: 1
}
]
}
}
]
},
@ -1341,7 +1392,7 @@ export const weaponFeatures = {
changes: [
{
key: 'system.bonuses.damage.primaryWeapon.bonus',
mode: 2,
type: 'add',
value: '@system.traits.agility.value',
priority: 21
}

View file

@ -58,7 +58,7 @@ export const renderMeasuredTemplate = async event => {
if (!type || !range || !game.canvas.scene) return;
const shapeData = CONFIG.Canvas.layers.regions.layerClass.getTemplateShape({
shapetype: type,
shapeType: type,
angle,
range,
direction,

View file

@ -35,23 +35,24 @@ export const enricherConfig = [
];
export const enricherRenderSetup = element => {
const clickWrapper = func => event => {
event.stopPropagation();
func(event);
};
element
.querySelectorAll('.enriched-damage-button')
.forEach(element => element.addEventListener('click', renderDamageButton));
.forEach(element => element.addEventListener('click', clickWrapper(renderDamageButton)));
element
.querySelectorAll('.duality-roll-button')
.forEach(element => element.addEventListener('click', renderDualityButton));
.forEach(element => element.addEventListener('click', clickWrapper(renderDualityButton)));
element
.querySelectorAll('.fate-roll-button')
.forEach(element => element.addEventListener('click', renderFateButton));
.forEach(element => element.addEventListener('click', clickWrapper(renderFateButton)));
element
.querySelectorAll('.measured-template-button')
.forEach(element => element.addEventListener('click', renderMeasuredTemplate));
// element
// .querySelectorAll('.enriched-effect')
// .forEach(element => element.addEventListener('dragstart', dragEnrichedEffect));
.forEach(element => element.addEventListener('click', clickWrapper(renderMeasuredTemplate)));
};

View file

@ -0,0 +1,38 @@
import { MigrationHandlerBase } from './base.mjs';
export class Migration_2_5_2 extends MigrationHandlerBase {
version = '2.5.2';
/** @inheritdoc */
async updateActiveEffectSource(effectSource, item) {
let shouldUpdate = false;
const newChanges = [];
const srdItem = item?._stats.compendiumSource ?
await foundry.utils.fromUuid(item?._stats.compendiumSource) :
null;
for (let i = 0; i < effectSource.system.changes.length; i++) {
const change = effectSource.system.changes[i];
const srdEffect = srdItem?.effects.find(x => x.name === effectSource.name);
if (change.type === 'custom') {
const srdChange = srdEffect ? srdEffect.system.changes[i] : null;
if (
change.key === srdChange.key &&
change.value === srdChange.value &&
change.type !== srdChange.type
) {
shouldUpdate = true;
newChanges.push(srdChange);
}
} else {
newChanges.push(change);
}
}
if (shouldUpdate) {
return {
_id: effectSource._id,
system: { changes: newChanges }
}
}
}
}

View file

@ -0,0 +1,77 @@
/**
* @import DHItem from "../../documents/item.mjs";
*/
/**
* The base class of an async migration.
* These are generally run between versions for things that require compendiums or must be done in post.
* The migrate() functions calls the various updateXSource() functions.
* Generally a subclass will override the version and the updateXSource() functions.
*/
export class MigrationHandlerBase {
version = null;
/**
* Gets change data for an active effect's source, or null if no changes
* @param {object} effectSource
* @param {DHItem} item
* @returns {Promise<object>}
* @protected
*/
async updateActiveEffectSource(effectSource, item) {
return null;
}
async migrate() {
// todo: handle more than just migrating effects. Right now this can only migrate effects
// NOTE: the preload is hardcoded, we should not hardcode it
const numActors = game.actors.size;
const numItems = game.items.size;
const finalUpdateProgress = 5;
const DhProgress = game.system.api.applications.ui.DhProgress;
const preRunProgress = game.packs.size;
const progress = DhProgress.createMigrationProgress(
preRunProgress + numActors + numItems + finalUpdateProgress
);
// Preload. Avoid hardcoding in the future
for (const pack of game.packs) {
await pack.getDocuments();
progress.advance();
}
const batch = [];
const updateItem = async item => {
const itemUpdates = [];
for (const effect of item.effects) {
const changes = await this.updateActiveEffectSource(effect.toObject(), item);
if (changes) itemUpdates.push(changes);
}
if (itemUpdates.length) {
batch.push({
action: 'update',
documentName: 'ActiveEffect',
updates: itemUpdates,
parent: item
});
}
};
for (const actor of game.actors) {
for (const item of actor.items) {
await updateItem(item);
}
progress.advance();
}
for (const item of game.items) {
await updateItem(item);
progress.advance();
}
await foundry.documents.modifyBatch(batch);
progress.advance({ by: finalUpdateProgress });
}
}

View file

@ -1,4 +1,5 @@
import { defaultRestOptions } from '../config/generalConfig.mjs';
import { Migration_2_5_2 } from './migration-handlers/2_5_2.mjs';
export async function runMigrations() {
let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion);
@ -320,7 +321,19 @@ export async function runMigrations() {
lastMigrationVersion = '2.1.0';
}
//#endregion
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion);
/* -------------------------------------------- */
/* New Style migrations below this point */
/* -------------------------------------------- */
const migrations = [
new Migration_2_5_2()
].filter(m => m.version && foundry.utils.isNewerVersion(m.version, lastMigrationVersion));
for (const handler of migrations) {
await handler.migrate();
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, handler.version);
}
}