Operations API
The operations module provides built-in operations and utilities for creating custom operations that modify item metrics.
Built-in Operations
sumOperation
Adds a value to the current metric.
function sumOperation<C extends ConfigSpec>(
current: number,
value: number,
context: EvalContext<C>
): number;
Formula: current + value
subtractOperation
Subtracts a value from the current metric.
function subtractOperation<C extends ConfigSpec>(
current: number,
value: number,
context: EvalContext<C>
): number;
Formula: current - value
multiplyOperation
Multiplies the current metric by a value.
function multiplyOperation<C extends ConfigSpec>(
current: number,
value: number,
context: EvalContext<C>
): number;
Formula: current * value
Operation Utilities
builtinOps
Type-safe helper for declaring built-in operations in configuration.
function builtinOps<T extends BuiltinOperation>(...ops: T[]): readonly T[];
Example
import { defineConfig, builtinOps } from "mod-engine";
const config = defineConfig({
metrics: ["Health", "Damage"] as const,
operations: builtinOps("sum", "multiply"), // Type-safe
attributes: [] as const,
});
createBuiltInOperations
Creates a map of built-in operations along with precedence values.
function createBuiltInOperations<C extends ConfigSpec>(): Map<
string,
OperationInfo<C>
>;
validateNumericResult
Validates that an operation result is a valid number.
function validateNumericResult(value: number, operationName: string): number;
Throws
OperationError if the value is NaN or Infinity.
Custom Operations
OperationImpl Type
Interface for implementing custom operations.
type OperationImpl<C extends ConfigSpec> = (
currentValue: number,
modifierValue: number,
context: EvalContext<C>
) => number;
Parameters
currentValue- Current metric valuemodifierValue- Value from the modifiercontext- Evaluation context with attributes and item
Example Custom Operations
Power Operation
const powOperation: OperationImpl<Config> = (current, value) => {
return Math.pow(current, value);
};
engine.registerOperation("pow", powOperation);
Clamp Operation
const clampOperation: OperationImpl<Config> = (current, value) => {
return Math.min(Math.max(current, 0), value);
};
engine.registerOperation("clamp", clampOperation);
Context-Aware Operation
const levelScaledAdd: OperationImpl<Config> = (current, value, context) => {
const level = context.attributes.Level ?? 1;
const scaledValue = value * (1 + level / 100);
return current + scaledValue;
};
engine.registerOperation("levelAdd", levelScaledAdd);
OperationInfo Structure
Operations are stored with metadata:
interface OperationInfo<C extends ConfigSpec> {
impl: OperationImpl<C>;
precedence: number;
}
Precedence System
Operations with higher precedence are applied later:
// Applied in order: sum (0), multiply (0), pow (100)
engine.registerOperation("pow", powOp, { precedence: 100 });
Default precedence for built-ins:
sum: 10subtract: 10multiply: 20
Registration Methods
Engine Registration
engine.registerOperation("customOp", impl, { precedence: 50 });
Engine Builder Registration
const engine = createEngineBuilder(config)
.withOperation("pow", powOperation)
.withOperations({
min: { impl: minOperation, precedence: 10 },
max: { impl: maxOperation, precedence: 10 },
})
.build();
Advanced Patterns
Mathematical Operations
const mathOperations = {
pow: (current, value) => Math.pow(current, value),
sqrt: (current, value) => Math.sqrt(current + value),
log: (current, value) => Math.log(Math.max(current + value, 1)),
abs: (current, value) => Math.abs(current + value),
round: (current, value) => Math.round(current + value),
};
// Register all at once
Object.entries(mathOperations).forEach(([name, impl]) => {
engine.registerOperation(name, impl);
});
Conditional Operations
const conditionalBonus: OperationImpl<Config> = (current, value, context) => {
const isEnchanted = context.attributes.Enchanted;
const isRare = ["Rare", "Epic", "Legendary"].includes(
context.attributes.Rarity
);
let bonus = value;
if (isEnchanted) bonus *= 1.5;
if (isRare) bonus *= 1.2;
return current + bonus;
};
Bounded Operations
const boundedAdd: OperationImpl<Config> = (current, value, context) => {
const maxValue = context.attributes.MaxHealth ?? 1000;
return Math.min(current + value, maxValue);
};
const boundedMultiply: OperationImpl<Config> = (current, value, context) => {
const result = current * value;
const cap = context.attributes.CapMultiplier ?? 10;
return Math.min(result, current * cap);
};
Percentage Operations
const percentageIncrease: OperationImpl<Config> = (current, percentage) => {
return current * (1 + percentage / 100);
};
const percentageDecrease: OperationImpl<Config> = (current, percentage) => {
return current * (1 - percentage / 100);
};
Error Handling
OperationError
Thrown when operations produce invalid results:
import { OperationError } from "mod-engine";
const safeOperation: OperationImpl<Config> = (current, value) => {
const result = current / value;
if (!isFinite(result)) {
throw new OperationError(`Division by ${value} produced invalid result`);
}
return result;
};
Validation
const validatedOperation: OperationImpl<Config> = (current, value) => {
if (value < 0) {
throw new OperationError("Negative values not allowed");
}
const result = current + value;
return validateNumericResult(result, "customAdd");
};
Type Safety
Operations are fully type-safe:
// ✅ Valid - operation in config
engine.registerOperation("declaredOp", impl);
// ❌ TypeScript error - operation not declared
engine.registerOperation("undeclaredOp", impl);
// ✅ Type-safe context access
const contextOp: OperationImpl<Config> = (current, value, context) => {
// context.attributes is fully typed
const level: number = context.attributes.Level;
return current + value * level;
};
Performance Tips
Efficient Operations
// ✅ Fast - simple arithmetic
const fastOp = (current, value) => current * value;
// ❌ Slow - complex calculations
const slowOp = (current, value, context) => {
return Math.pow(Math.sin(current), Math.cos(value));
};
Caching Context Values
const cachedOp: OperationImpl<Config> = (current, value, context) => {
// Cache expensive lookups
const multiplier =
context.cache?.multiplier ??
(context.cache = { multiplier: calculateMultiplier(context) }).multiplier;
return current + value * multiplier;
};
Context added by Giga metric-operations - using core operation types, operation registration, and stacking behavior information.