Implemented Active Effects.

Used AE to implement exhaustion, stimulants, and rest.
This commit is contained in:
Aaron Lutomski
2026-05-29 21:07:33 -07:00
parent 67b70268b6
commit bf4ca9bf88
65 changed files with 5830 additions and 3480 deletions
+97
View File
@@ -0,0 +1,97 @@
import {
applyAgentResourceMaxBonuses,
calculateHealthMax,
setSkillTargetProficiencies,
calculateMeleeDamageBonusFormula,
clampSanityRitualValue,
prepareAgentSkillFlags,
prepareBreakingPointHit,
prepareStatisticsX5,
} from "./derived-actor-data.js";
/**
* @param {number} current
* @param {number} base
* @returns {string}
*/
function getActiveEffectModificationClass(current, base) {
if (current == null || base == null || current === base) return "";
return current > base ? "ae-mod-increase" : "ae-mod-decrease";
}
/**
* Attach sheet display classes comparing prepared data to persisted source (pre–AE).
* @param {Actor} actor
* @returns {void}
*/
export function prepareAgentActiveEffectDisplay(actor) {
if (actor.type !== "agent") return;
const system = actor.system;
const source = actor._source?.system;
if (!source) return;
for (const [key, stat] of Object.entries(system.statistics ?? {})) {
const baseValue = source.statistics?.[key]?.value;
const effective = stat.effectiveValue ?? stat.value;
stat.valueDisplayClass = getActiveEffectModificationClass(
effective,
baseValue,
);
stat.statisticAeModifier = stat.valueDisplayClass
? effective - (baseValue ?? 0)
: 0;
}
const persistedStats = source.statistics ?? system.statistics;
const healthFormulaMax = calculateHealthMax(persistedStats, persistedStats);
const wpFormulaMax = persistedStats.pow?.value ?? 0;
const persistedUnnatural =
source.skills?.unnatural?.proficiency ?? system.skills?.unnatural?.proficiency ?? 0;
const sanityFormulaMax = 99 - persistedUnnatural;
const healthBaseMax = healthFormulaMax + (source.health?.maxBonus ?? 0);
system.health.maxDisplayClass = getActiveEffectModificationClass(
system.health.max,
healthBaseMax,
);
const wpBaseMax = wpFormulaMax + (source.wp?.maxBonus ?? 0);
system.wp.maxDisplayClass = getActiveEffectModificationClass(
system.wp.max,
wpBaseMax,
);
const sanityBaseMax = sanityFormulaMax + (source.sanity?.maxBonus ?? 0);
system.sanity.maxDisplayClass = getActiveEffectModificationClass(
system.sanity.max,
sanityBaseMax,
);
}
/**
* Recompute agent fields that depend on Active Effects (final phase) and refresh sheet display.
* Single post-AE pass for agents — do not mirror this logic in AgentData.prepareDerivedData.
* @param {Actor} actor
* @returns {void}
*/
export function refreshDerivedAfterActiveEffects(actor) {
if (actor.type !== "agent") return;
const system = actor.system;
const sourceStatistics = actor._source?.system?.statistics;
prepareStatisticsX5(system.statistics, sourceStatistics);
applyAgentResourceMaxBonuses(system, sourceStatistics);
setSkillTargetProficiencies(system.skills);
setSkillTargetProficiencies(system.typedSkills);
prepareAgentSkillFlags(system.skills);
clampSanityRitualValue(system.sanity);
prepareBreakingPointHit(system.sanity);
system.statistics.str.meleeDamageBonusFormula =
calculateMeleeDamageBonusFormula(
system.statistics.str.effectiveValue ?? system.statistics.str.value,
);
prepareAgentActiveEffectDisplay(actor);
}