1
0
Fork 0
tsgames/src/common/rpg/conditions.ts

66 lines
2.3 KiB
TypeScript

import type { RPGCondition, RPGVariables } from "./types";
type ConditionOperator = '==' | '!=' | '>' | '<' | '>=' | '<=' | 'null' | '~null';
type ConditionValue = string | number | boolean | null;
export interface ParsedCondition {
variable: string;
negate: boolean;
operator?: ConditionOperator;
value?: ConditionValue;
}
export function parseCondition(s: RPGCondition): ParsedCondition {
// ~variable — falsy check, nothing else allowed
if (s.startsWith('~') && !s.includes(' '))
return { variable: s.slice(1), negate: true };
const spaceIdx = s.indexOf(' ');
if (spaceIdx === -1)
return { variable: s, negate: false };
const variable = s.slice(0, spaceIdx);
const rest = s.slice(spaceIdx + 1).trim();
if (rest === 'null') return { variable, negate: false, operator: 'null' };
if (rest === '~null') return { variable, negate: false, operator: '~null' };
const opMatch = rest.match(/^(==|!=|>=|<=|>|<)\s*(.+)$/);
if (!opMatch) throw new Error(`Invalid condition: "${s}"`);
const [, operator, rawValue] = opMatch;
let value: ConditionValue;
if (rawValue === 'null') value = null;
else if (rawValue === 'true') value = true;
else if (rawValue === 'false') value = false;
else if (!isNaN(Number(rawValue))) value = Number(rawValue);
else value = rawValue.replace(/^['"]|['"]$/g, '');
return { variable, negate: false, operator: operator as ConditionOperator, value };
}
export function evaluateCondition({ variable, negate, operator, value }: ParsedCondition, variables: RPGVariables): boolean {
const val = variables[variable];
if (operator === 'null') return val == null;
if (operator === '~null') return val != null;
if (operator === undefined)
return negate ? !Boolean(val) : Boolean(val);
if (operator === '==') return val === value;
if (operator === '!=') return val !== value;
if (typeof val !== 'number' || typeof value !== 'number') return false;
if (operator === '<') return val < value;
if (operator === '>') return val > value;
if (operator === '<=') return val <= value;
if (operator === '>=') return val >= value;
return false;
}
export function evaluateConditions(conditions: RPGCondition[], variables: RPGVariables): boolean {
return conditions.every(c => evaluateCondition(parseCondition(c), variables));
}