Changed task triggers to be stored differently so that attribute check and damage triggers don't overlap

This commit is contained in:
Thaum Rystra
2024-05-21 17:41:20 +02:00
parent 8eb702cde3
commit 772e55ece5
9 changed files with 154 additions and 173 deletions

View File

@@ -131,7 +131,7 @@ export async function applyAfterPropTasksForSomeChildren(
export async function applyTriggers(
action: EngineAction, prop, targetIds: string[], triggerPath: string, inputProvider: InputProvider
) {
const triggerIds = get(prop?.triggerIds, triggerPath);
const triggerIds = get(prop, triggerPath);
if (!triggerIds) return;
for (const triggerId of triggerIds) {
const trigger = await getSingleProperty(action.creatureId, triggerId);

View File

@@ -7,7 +7,6 @@ import {
} from '/imports/api/engine/loadCreatures';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions';
import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty';
// TODO Migrate this to the new action engine

View File

@@ -1,10 +1,10 @@
import { applyDefaultAfterPropTasks } from '/imports/api/engine/action/functions/applyTaskGroups';
import { applyTriggers } from '/imports/api/engine/action/functions/applyTaskGroups';
import { CheckTask } from '/imports/api/engine/action/tasks/Task';
import { EngineAction } from '/imports/api/engine/action/EngineActions';
import { getEffectiveActionScope } from '/imports/api/engine/action/functions/getEffectiveActionScope';
import { getFromScope } from '/imports/api/creature/creatures/CreatureVariables';
import { getVariables } from '/imports/api/engine/loadCreatures';
import InputProvider, { CheckParams } from '/imports/api/engine/action/functions/userInput/InputProvider';
import InputProvider from '/imports/api/engine/action/functions/userInput/InputProvider';
import numberToSignedString from '/imports/api/utility/numberToSignedString';
import TaskResult from '/imports/api/engine/action/tasks/TaskResult';
@@ -38,6 +38,17 @@ export default async function applyCheckTask(
const ability = checkParams.abilityVariableName && getFromScope(checkParams.abilityVariableName, scope) || null;
const abilityModifier = ability?.modifier || 0;
// Run the before triggers which may change scope properties
if (skill) await applyTriggers(action, skill, [targetId], 'checkTriggerIds.before', userInput);
if (ability) await applyTriggers(action, ability, [targetId], 'checkTriggerIds.before', userInput);
if (skill || ability) {
// Create a new result after before triggers have run
result = new TaskResult(task.prop._id, task.targetIds);
action.results.push(result);
}
const totalModifier = skillBonus + abilityModifier;
const rollModifierText = numberToSignedString(totalModifier);
@@ -100,9 +111,15 @@ export default async function applyCheckTask(
inline: true,
...prop?.silent && { silenced: prop.silent }
}, [targetId]);
}
return applyDefaultAfterPropTasks(action, prop, targetIds, userInput);
// After check triggers
if (skill) await applyTriggers(action, skill, [targetId], 'checkTriggerIds.after', userInput);
if (ability) await applyTriggers(action, ability, [targetId], 'checkTriggerIds.after', userInput);
// After children check triggers
if (skill) await applyTriggers(action, skill, [targetId], 'checkTriggerIds.afterChildren', userInput);
if (ability) await applyTriggers(action, ability, [targetId], 'checkTriggerIds.afterChildren', userInput);
}
}
// TODO set these and potentially read them again if triggers can change them

View File

@@ -42,7 +42,7 @@ export default async function applyDamagePropTask(
}
// Run the before triggers which may change scope properties
await applyTriggers(action, targetProp, [action.creatureId], 'before', userInput);
await applyTriggers(action, targetProp, [targetId], 'damageTriggerIds.before', userInput);
// Create a new result after triggers have run
result = new TaskResult(task.prop._id, task.targetIds);
@@ -136,8 +136,8 @@ export default async function applyDamagePropTask(
});
setScope(result, targetProp, newValue, damage);
}
await applyTriggers(action, targetProp, [action.creatureId], 'after', userInput);
await applyTriggers(action, targetProp, [action.creatureId], 'afterChildren', userInput);
await applyTriggers(action, targetProp, [targetId], 'damageTriggerIds.after', userInput);
await applyTriggers(action, targetProp, [targetId], 'damageTriggerIds.afterChildren', userInput);
return increment;
}

View File

@@ -22,7 +22,11 @@ export default async function applyItemAsAmmoTask(task: ItemAsAmmoTask, action:
result.pushScope = { ['~ammoConsumed']: { value } };
// Apply the before triggers
await applyTriggers(action, item, [action.creatureId], 'ammo.before', userInput);
await applyTriggers(action, item, task.targetIds, 'ammoTriggerIds.before', userInput);
// Create a new result after before triggers have run
result = new TaskResult(task.prop._id, task.targetIds);
action.results.push(result);
// Refetch the scope properties
const scope = await getEffectiveActionScope(action);
@@ -52,11 +56,12 @@ export default async function applyItemAsAmmoTask(task: ItemAsAmmoTask, action:
},
});
await applyTriggers(action, item, [action.creatureId], 'ammo.after', userInput);
await applyTriggers(action, item, task.targetIds, 'ammoTriggerIds.after', userInput);
if (task.params.skipChildren) {
return applyAfterTasksSkipChildren(action, item, task.targetIds, userInput);
await applyAfterTasksSkipChildren(action, item, task.targetIds, userInput);
} else {
return applyDefaultAfterPropTasks(action, item, task.targetIds, userInput);
await applyDefaultAfterPropTasks(action, item, task.targetIds, userInput);
}
return applyTriggers(action, item, task.targetIds, 'ammoTriggerIds.afterChildren', userInput);
}

View File

@@ -9,31 +9,40 @@ export default function computeTrigger(computation, node) {
// Link triggers to all the properties that would fire them when applied
const tagTargets = getEffectTagTargets(prop, computation);
switch (prop.event) {
case 'doActionProperty':
tagTargets.forEach(targetId => {
const targetProp = computation.propsById[targetId];
for (const targetId of tagTargets) {
const targetProp = computation.propsById[targetId];
switch (prop.event) {
case 'doActionProperty':
// Only apply if the trigger matches this property type
if (targetProp.type !== prop.actionPropertyType) return;
setTrigger(prop, targetProp);
});
break;
case 'damageProperty':
tagTargets.forEach(targetId => {
const targetProp = computation.propsById[targetId];
if (targetProp.type === prop.actionPropertyType) {
setTrigger(prop, targetProp, 'triggerIds');
}
// Or on an item used as ammo
else if (prop.actionPropertyType === 'ammo' && targetProp.type === 'item') {
setTrigger(prop, targetProp, 'ammoTriggerIds');
}
break;
case 'damageProperty':
// Only apply to attributes
if (targetProp.type !== 'attribute') return;
setTrigger(prop, targetProp);
});
break;
if (targetProp.type === 'attribute') {
setTrigger(prop, targetProp, 'damageTriggerIds');
}
break;
case 'check':
// Only apply to attributes and skills
if (targetProp.type === 'attribute' || targetProp.type === 'skill') {
setTrigger(prop, targetProp, 'checkTriggerIds');
}
break;
}
}
}
function setTrigger(prop, targetProp) {
let triggerIdArray = get(targetProp, `triggerIds.${prop.timing}`);
function setTrigger(prop, targetProp, field = 'triggerIds') {
let triggerIdArray = get(targetProp, `${field}.${prop.timing}`);
if (!triggerIdArray) {
triggerIdArray = [];
set(targetProp, `triggerIds.${prop.timing}`, triggerIdArray);
set(targetProp, `${field}.${prop.timing}`, triggerIdArray);
}
triggerIdArray.push(prop._id);
}