import type { RPGAction, RPGActions, RPGVariables } from "../types"; import type { EvalContext, Entity } from "../core/world"; export function resolveVariables(entity: Entity): RPGVariables { const result: RPGVariables = {}; for (const [key, component] of entity) { for (const [varKey, value] of Object.entries(component.getVariables())) { if (value != null) { if (varKey && varKey !== '.') { result[`${key}.${varKey}`] = value; } else { result[key] = value; } } } } return result; } export function resolveVariable(name: string, ctx: EvalContext): RPGVariables[string] { // $. prefix → world globals if (name.startsWith('$.')) { return ctx.world.globals[name.slice(2)]; } // @entityId.component.variable → another entity if (name.startsWith('@')) { const dotIdx = name.indexOf('.', 1); if (dotIdx === -1) return undefined; const entityId = name.slice(1, dotIdx); const varName = name.slice(dotIdx + 1); const entity = ctx.world.getEntity(entityId); if (!entity) return undefined; return resolveVariables(entity)[varName]; } // bare name → self entity return resolveVariables(ctx.self)[name]; } export function resolveActions(entity: Entity): RPGActions { const result: RPGActions = {}; for (const [key, component] of entity) { for (const [actionKey, fn] of Object.entries(component.getActions())) { result[`${key}.${actionKey}`] = fn; } } return result; } export async function executeAction(action: RPGAction, ctx: EvalContext): Promise { let entity = ctx.self; let actionType = action.type; // @entityId.component.action → dispatch to another entity if (action.type.startsWith('@')) { const dotIdx = action.type.indexOf('.', 1); if (dotIdx === -1) return; const entityId = action.type.slice(1, dotIdx); const found = ctx.world.getEntity(entityId); if (!found) return; entity = found; actionType = action.type.slice(dotIdx + 1); } const actions = resolveActions(entity); return actions[actionType]?.(action.arg); }