Files
DiceCloud/app/imports/api/engine/action/applyProperties/applyBuffRemoverProperty.ts
2025-05-02 15:38:18 +02:00

124 lines
3.9 KiB
TypeScript

import { PropTask } from '/imports/api/engine/action/tasks/Task';
import TaskResult from '/imports/api/engine/action/tasks/TaskResult';
import getPropertyTitle from '/imports/api/utility/getPropertyTitle';
import { findLast, filter, difference, intersection } from 'lodash';
import { getPropertiesOfType, getPropertyAncestors } from '/imports/api/engine/loadCreatures';
import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags';
import { applyDefaultAfterPropTasks, applyTaskToEachTarget } from '/imports/api/engine/action/functions/applyTaskGroups';
import { EngineAction } from '/imports/api/engine/action/EngineActions';
import InputProvider from '/imports/api/engine/action/functions/userInput/InputProvider';
import { CreaturePropertyTypes } from '/imports/api/creature/creatureProperties/CreatureProperties';
export default async function applyBuffRemoverProperty(
task: PropTask, action: EngineAction, result: TaskResult, userInput: InputProvider
) {
const prop = task.prop as CreaturePropertyTypes['buffRemover'];
const targetIds = prop.target === 'self' ? [action.creatureId] : task.targetIds;
if (prop.name) {
// Log Name
result.appendLog({
name: getPropertyTitle(prop),
silenced: prop.silent,
}, task.targetIds)
}
if (targetIds.length > 1) {
return applyTaskToEachTarget(action, task, targetIds, userInput);
}
if (!targetIds.length) {
return applyDefaultAfterPropTasks(action, prop, task.targetIds, userInput);
}
if (targetIds.length !== 1) {
throw 'At this step, only a single target is supported'
}
const targetId = targetIds[0];
// Remove buffs
if (prop.targetParentBuff) {
// Remove nearest ancestor buff
const ancestors = getPropertyAncestors(action.creatureId, prop._id);
const nearestBuff = findLast(ancestors, ancestor => ancestor.type === 'buff');
if (!nearestBuff) {
result.appendLog({
name: 'Error',
value: 'Buff remover does not have a parent buff to remove',
silenced: prop.silent,
}, [targetId]);
return;
}
removeBuff(nearestBuff, prop, result);
} else {
// Get all the buffs targeted by tags
const allBuffs = getPropertiesOfType(targetId, 'buff');
const targetedBuffs = filter(allBuffs, (buff): boolean => {
if (buff.inactive) return false;
if (buffRemoverMatchTags(prop, buff)) return true;
return false;
});
// Remove the buffs
if (prop.removeAll) {
// Remove all matching buffs
targetedBuffs.forEach(buff => {
removeBuff(buff, prop, result);
});
} else {
// Sort in reverse order
targetedBuffs.sort((a, b) => b.left - a.left);
// Remove the one with the highest order
const buff = targetedBuffs[0];
if (buff) {
removeBuff(buff, prop, result);
}
}
}
return applyDefaultAfterPropTasks(action, prop, task.targetIds, userInput);
}
function removeBuff(buff: any, prop, result: TaskResult) {
result.mutations.push({
targetIds: result.targetIds,
removals: [{ propId: buff._id }],
contents: [{
name: 'Removed',
value: `${buff.name || 'Buff'}`,
...prop.silent && { silenced: true },
}],
});
}
function buffRemoverMatchTags(buffRemover, prop) {
let matched = false;
const propTags = getEffectivePropTags(prop);
// Check the target tags
if (
!buffRemover.targetTags?.length ||
difference(buffRemover.targetTags, propTags).length === 0
) {
matched = true;
}
// Check the extra tags
buffRemover.extraTags?.forEach(extra => {
if (extra.operation === 'OR') {
if (matched) return;
if (
!extra.tags.length ||
difference(extra.tags, propTags).length === 0
) {
matched = true;
}
} else if (extra.operation === 'NOT') {
if (
extra.tags.length &&
intersection(extra.tags, propTags)
) {
return false;
}
}
});
return matched;
}