import { Component, type EvalContext, type World } from "../core/world"; import type { RPGAction } from "../types"; import { action, variable } from "../utils/decorators"; import { executeAction } from "../utils/variables"; export class Item extends Component { constructor( readonly name: string, readonly description: string = '', ) { super(); } } export class Stackable extends Component { @variable readonly maxStack: number; constructor(maxStack: number) { super(); this.maxStack = maxStack; } } export class Usable extends Component { @variable readonly consumeOnUse: boolean; constructor(private readonly actions: RPGAction[], consumeOnUse = true) { super(); this.consumeOnUse = consumeOnUse; } @action async use(arg?: EvalContext, ctx?: EvalContext): Promise { ctx = arg ?? ctx ?? this.context; if (!ctx) return; for (const action of this.actions) { await executeAction(action, ctx); } } } export namespace Items { export interface RegisterOptions { maxStack?: number; description?: string; usable?: { actions: RPGAction[]; consumeOnUse?: boolean }; } export function register(world: World, id: string, name: string, options?: RegisterOptions) { const entity = world.createEntity(id); entity.add('item', new Item(name, options?.description)); if (options?.maxStack !== undefined) entity.add('stackable', new Stackable(options.maxStack)); if (options?.usable) entity.add('usable', new Usable(options.usable.actions, options.usable.consumeOnUse)); return entity; } }