Triggers needed action context to function outside of the action engine proper, so now it's been abstracted into its own class
126 lines
4.0 KiB
JavaScript
126 lines
4.0 KiB
JavaScript
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
|
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
|
import SimpleSchema from 'simpl-schema';
|
|
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
|
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
|
import { applyTriggers } from '/imports/api/engine/actions/applyTriggers.js';
|
|
import ActionContext from '/imports/api/engine/actions/ActionContext.js';
|
|
|
|
const damageProperty = new ValidatedMethod({
|
|
name: 'creatureProperties.damage',
|
|
validate: new SimpleSchema({
|
|
_id: SimpleSchema.RegEx.Id,
|
|
operation: {
|
|
type: String,
|
|
allowedValues: ['set', 'increment']
|
|
},
|
|
value: Number,
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 20,
|
|
timeInterval: 5000,
|
|
},
|
|
run({ _id, operation, value }) {
|
|
|
|
// Get action context
|
|
const prop = CreatureProperties.findOne(_id);
|
|
if (!prop) throw new Meteor.Error(
|
|
'Damage property failed', 'Property doesn\'t exist'
|
|
);
|
|
const creatureId = prop.ancestors[0].id;
|
|
const actionContext = new ActionContext(creatureId, [creatureId], this);
|
|
|
|
// Check permissions
|
|
assertEditPermission(actionContext.creature, this.userId);
|
|
|
|
// Check if property can take damage
|
|
let schema = CreatureProperties.simpleSchema(prop);
|
|
if (!schema.allowsKey('damage')){
|
|
throw new Meteor.Error(
|
|
'Damage property failed',
|
|
`Property of type "${prop.type}" can't be damaged`
|
|
);
|
|
}
|
|
|
|
const result = damagePropertyWork({ prop, operation, value, actionContext });
|
|
|
|
// Insert the log
|
|
actionContext.writeLog();
|
|
return result;
|
|
},
|
|
});
|
|
|
|
export function damagePropertyWork({ prop, operation, value, actionContext }) {
|
|
|
|
// Save the value to the scope before applying the before triggers
|
|
if (operation === 'increment') {
|
|
if (value >= 0) {
|
|
actionContext.scope['$damage'] = value;
|
|
} else {
|
|
actionContext.scope['$healing'] = -value;
|
|
}
|
|
} else {
|
|
actionContext.scope['$set'] = value;
|
|
}
|
|
|
|
applyTriggers(actionContext.triggers?.damageProperty?.before, prop, actionContext);
|
|
|
|
// fetch the value from the scope after the before triggers, in case they changed them
|
|
if (operation === 'increment') {
|
|
if (value >= 0) {
|
|
value = actionContext.scope['$damage'];
|
|
} else {
|
|
value = -actionContext.scope['$healing'];
|
|
}
|
|
} else {
|
|
value = actionContext.scope['$set'];
|
|
}
|
|
|
|
let damage, newValue, increment;
|
|
if (operation === 'set'){
|
|
const total = prop.total || 0;
|
|
// Set represents what we want the value to be after damage
|
|
// So we need the actual damage to get to that value
|
|
damage = total - value;
|
|
// Damage can't exceed total value
|
|
if (damage > total && !prop.ignoreLowerLimit) damage = total;
|
|
// Damage must be positive
|
|
if (damage < 0 && !prop.ignoreUpperLimit) damage = 0;
|
|
newValue = prop.total - damage;
|
|
// Write the results
|
|
CreatureProperties.update(prop._id, {
|
|
$set: { damage, value: newValue, dirty: true }
|
|
}, {
|
|
selector: prop
|
|
});
|
|
} else if (operation === 'increment'){
|
|
let currentValue = prop.value || 0;
|
|
let currentDamage = prop.damage || 0;
|
|
increment = value;
|
|
// Can't increase damage above the remaining value
|
|
if (increment > currentValue && !prop.ignoreLowerLimit) increment = currentValue;
|
|
// Can't decrease damage below zero
|
|
if (-increment > currentDamage && !prop.ignoreUpperLimit) increment = -currentDamage;
|
|
damage = currentDamage + increment;
|
|
newValue = prop.total - damage;
|
|
// Write the results
|
|
CreatureProperties.update(prop._id, {
|
|
$inc: { damage: increment, value: -increment },
|
|
$set: { dirty: true },
|
|
}, {
|
|
selector: prop
|
|
});
|
|
}
|
|
|
|
applyTriggers(actionContext.triggers?.damageProperty?.after, prop, actionContext);
|
|
|
|
if (operation === 'set') {
|
|
return damage;
|
|
} else if (operation === 'increment') {
|
|
return increment;
|
|
}
|
|
}
|
|
|
|
export default damageProperty;
|