mirror of
https://github.com/fzumpe/foundry-dnd5e-adaptive-resistances.git
synced 2026-06-06 21:10:02 +02:00
136 lines
3.1 KiB
JavaScript
136 lines
3.1 KiB
JavaScript
import {
|
|
MODULE_ID,
|
|
EFFECT_FLAG,
|
|
ADAPTATION_CONFIG,
|
|
ADAPTATION_TYPES,
|
|
PROFANE_DAMAGE_TYPES,
|
|
PROFANE_BYPASSES
|
|
} from "./constants.js";
|
|
|
|
import {
|
|
getAdaptiveTriggerEffects,
|
|
getDamageTypeLabel
|
|
} from "./utils.js";
|
|
|
|
/**
|
|
* Entfernt sämtliche dynamisch erzeugten adaptiven Schutzwirkungen.
|
|
* Eine neu ausgelöste Anpassung ersetzt damit immer die vorherige.
|
|
*/
|
|
export async function removeOldAdaptiveEffects(actor) {
|
|
const oldEffects = actor.effects.filter(
|
|
effect => effect.getFlag(MODULE_ID, EFFECT_FLAG)
|
|
);
|
|
|
|
if (!oldEffects.length) return;
|
|
|
|
await actor.deleteEmbeddedDocuments(
|
|
"ActiveEffect",
|
|
oldEffects.map(effect => effect.id)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Entfernt adaptive Schutzwirkungen, deren auslösende Quelle nicht mehr
|
|
* auf dem Actor angewendet wird.
|
|
*
|
|
* Beispiel:
|
|
* Ein getragenes Amulett verleiht adaptive Feuerresistenz. Wird das Amulett
|
|
* abgelegt, verschwindet sein Marker-Effect aus actor.appliedEffects und die
|
|
* zuvor erzeugte Feuerresistenz wird ebenfalls entfernt.
|
|
*/
|
|
export async function removeOrphanedAdaptiveEffects(actor) {
|
|
if (!actor) return;
|
|
|
|
const appliedSourceUuids = new Set(
|
|
getAdaptiveTriggerEffects(actor).map(effect => effect.uuid)
|
|
);
|
|
|
|
const orphanedEffects = actor.effects.filter(effect => {
|
|
const data = effect.getFlag(MODULE_ID, EFFECT_FLAG);
|
|
|
|
return data?.sourceEffectUuid
|
|
&& !appliedSourceUuids.has(data.sourceEffectUuid);
|
|
});
|
|
|
|
if (!orphanedEffects.length) return;
|
|
|
|
await actor.deleteEmbeddedDocuments(
|
|
"ActiveEffect",
|
|
orphanedEffects.map(effect => effect.id)
|
|
);
|
|
}
|
|
|
|
function getAdaptiveChanges(config, damageType) {
|
|
const changes = [
|
|
{
|
|
key: config.traitKey,
|
|
mode: CONST.ACTIVE_EFFECT_MODES.ADD,
|
|
value: damageType,
|
|
priority: 20
|
|
}
|
|
];
|
|
|
|
if (PROFANE_DAMAGE_TYPES.includes(damageType)) {
|
|
const bypassKey = config.traitKey.replace(/\.value$/, ".bypasses");
|
|
|
|
for (const bypass of PROFANE_BYPASSES) {
|
|
changes.push({
|
|
key: bypassKey,
|
|
mode: CONST.ACTIVE_EFFECT_MODES.ADD,
|
|
value: bypass,
|
|
priority: 20
|
|
});
|
|
}
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
/**
|
|
* Erzeugt die konkrete adaptive Resistenz oder Immunität auf dem Actor.
|
|
*/
|
|
export async function createAdaptiveEffect(
|
|
actor,
|
|
damageType,
|
|
adaptationType = ADAPTATION_TYPES.RESISTANCE,
|
|
sourceEffectUuid = null
|
|
) {
|
|
const config = ADAPTATION_CONFIG[adaptationType]
|
|
?? ADAPTATION_CONFIG[ADAPTATION_TYPES.RESISTANCE];
|
|
|
|
const label = getDamageTypeLabel(damageType);
|
|
|
|
await actor.createEmbeddedDocuments("ActiveEffect", [
|
|
{
|
|
name: game.i18n.format(config.effectNameKey, { type: label }),
|
|
img: config.icon,
|
|
disabled: false,
|
|
transfer: false,
|
|
|
|
flags: {
|
|
[MODULE_ID]: {
|
|
[EFFECT_FLAG]: {
|
|
adaptationType: config.id,
|
|
damageType,
|
|
sourceEffectUuid
|
|
}
|
|
}
|
|
},
|
|
|
|
changes: getAdaptiveChanges(config, damageType)
|
|
}
|
|
]);
|
|
}
|
|
|
|
export async function createAdaptiveResistanceEffect(
|
|
actor,
|
|
damageType,
|
|
sourceEffectUuid = null
|
|
) {
|
|
return createAdaptiveEffect(
|
|
actor,
|
|
damageType,
|
|
ADAPTATION_TYPES.RESISTANCE,
|
|
sourceEffectUuid
|
|
);
|
|
} |