[Feature] ActiveEffect Improvements (#439)

* Fixed so genericStatuses aren't shown in activeEffectConfig if turned off. Fixed localization of genericStatuses in Inventory-ItemV2.

* Effects with statuses on them will now add them as full additional effects so they show up on the token.

* Revert "Effects with statuses on them will now add them as full additional effects so they show up on the token."

This reverts commit 5afd7ae686.

* Redid it a better way

* Fixed so multiple statuses on an effect are still treated as active
This commit is contained in:
WBHarry 2025-07-28 15:32:19 +02:00 committed by GitHub
parent 0a944eb3d4
commit 2fbbf98f88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 83 additions and 13 deletions

View file

@ -66,12 +66,9 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
if (!status) continue;
if (status._id) {
if (status._id !== effect.id) continue;
} else {
if (effect.statuses.size !== 1) continue;
}
status.isActive = true;
if (effect.getFlag('core', 'overlay')) status.isOverlay = true;
break;
}
}

View file

@ -99,7 +99,17 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
async _preparePartContext(partId, context) {
const partContext = await super._preparePartContext(partId, context);
switch (partId) {
case 'changes':
case 'details':
const useGeneric = game.settings.get(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.appearance
).showGenericStatusEffects;
if (!useGeneric) {
partContext.statuses = Object.values(CONFIG.DH.GENERAL.conditions).map(status => ({
value: status.id,
label: game.i18n.localize(status.name)
}));
}
break;
}

View file

@ -10,8 +10,28 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
this.effects.overlay = null;
// Categorize effects
const activeEffects = this.actor ? Array.from(this.actor.effects).filter(x => !x.disabled) : [];
const overlayEffect = activeEffects.findLast(e => e.img && e.getFlag('core', 'overlay'));
const statusMap = new Map(foundry.CONFIG.statusEffects.map(status => [status.id, status]));
const activeEffects = (this.actor ? this.actor.effects.filter(x => !x.disabled) : []).reduce((acc, effect) => {
acc.push(effect);
const currentStatusActiveEffects = acc.filter(
x => x.statuses.size === 1 && x.name === game.i18n.localize(statusMap.get(x.statuses.first()).name)
);
for (var status of effect.statuses) {
if (!currentStatusActiveEffects.find(x => x.statuses.includes(status))) {
const statusData = statusMap.get(status);
acc.push({
name: game.i18n.localize(statusData.name),
statuses: [status],
img: statusData.icon,
tint: effect.tint
});
}
}
return acc;
}, []);
const overlayEffect = activeEffects.findLast(e => e.img && e.getFlag?.('core', 'overlay'));
// Draw effects
const promises = [];

View file

@ -41,6 +41,14 @@ export default class DhActiveEffect extends ActiveEffect {
});
}
get localizedStatuses() {
const statusMap = new Map(foundry.CONFIG.statusEffects.map(status => [status.id, status.name]));
return this.statuses.map(x => ({
key: x,
name: game.i18n.localize(statusMap.get(x))
}));
}
async _preCreate(data, options, user) {
const update = {};
if (!data.img) {

View file

@ -389,6 +389,41 @@ export default class DhpActor extends Actor {
return this.system.difficulty ?? 10;
}
/** @inheritDoc */
async toggleStatusEffect(statusId, { active, overlay = false } = {}) {
const status = CONFIG.statusEffects.find(e => e.id === statusId);
if (!status) throw new Error(`Invalid status ID "${statusId}" provided to Actor#toggleStatusEffect`);
const existing = [];
// Find the effect with the static _id of the status effect
if (status._id) {
const effect = this.effects.get(status._id);
if (effect) existing.push(effect.id);
}
// If no static _id, find all effects that have this status
else {
for (const effect of this.effects) {
if (effect.statuses.has(status.id)) existing.push(effect.id);
}
}
// Remove the existing effects unless the status effect is forced active
if (existing.length) {
if (active) return true;
await this.deleteEmbeddedDocuments('ActiveEffect', existing);
return false;
}
// Create a new effect unless the status effect is forced inactive
if (!active && active !== undefined) return;
const ActiveEffect = getDocumentClass('ActiveEffect');
const effect = await ActiveEffect.fromStatusEffect(statusId);
if (overlay) effect.updateSource({ 'flags.core.overlay': true });
return ActiveEffect.implementation.create(effect, { parent: this, keepId: true });
}
getRollData() {
const rollData = super.getRollData();
rollData.system = this.system.getRollData();
@ -505,16 +540,16 @@ export default class DhpActor extends Actor {
Object.entries(healings).forEach(([key, healing]) => {
healing.parts.forEach(part => {
const update = updates.find(u => u.key === key);
if (update)
update.value += part.total;
if (update) update.value += part.total;
else updates.push({ value: part.total, key });
});
});
updates.forEach(
u =>
(u.value =
!(u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false) ? u.value * -1 : u.value)
(u.value = !(u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false)
? u.value * -1
: u.value)
);
await this.modifyResource(updates);
@ -561,7 +596,7 @@ export default class DhpActor extends Actor {
}
}
});
Object.keys(updates).forEach(async key => {
const u = updates[key];
if (key === 'items') {