81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
import { Component, type EvalContext, type World } from "../core/world";
|
|
import type { RPGAction } from "../types";
|
|
import { action, component, variable } from "../utils/decorators";
|
|
import { executeAction } from "../utils/variables";
|
|
import { Equippable } from "./equipment";
|
|
|
|
interface ItemState {
|
|
name: string;
|
|
description: string;
|
|
}
|
|
|
|
@component
|
|
export class Item extends Component<ItemState> {
|
|
constructor(name: string, description = '') {
|
|
super({ name, description });
|
|
}
|
|
|
|
get name(): string { return this.state.name; }
|
|
get description(): string { return this.state.description; }
|
|
}
|
|
|
|
interface StackableState {
|
|
maxStack: number;
|
|
}
|
|
|
|
@component
|
|
export class Stackable extends Component<StackableState> {
|
|
constructor(maxStack: number) {
|
|
super({ maxStack });
|
|
}
|
|
|
|
@variable get maxStack(): number { return this.state.maxStack; }
|
|
}
|
|
|
|
interface UsableState {
|
|
actions: RPGAction[];
|
|
consumeOnUse: boolean;
|
|
}
|
|
|
|
@component
|
|
export class Usable extends Component<UsableState> {
|
|
constructor(actions: RPGAction[], consumeOnUse = true) {
|
|
super({ actions, consumeOnUse });
|
|
}
|
|
|
|
@variable get consumeOnUse(): boolean { return this.state.consumeOnUse; }
|
|
|
|
@action
|
|
use(arg?: EvalContext, ctx?: EvalContext): void {
|
|
ctx = arg ?? ctx ?? this.context;
|
|
if (!ctx) return;
|
|
for (const action of this.state.actions) {
|
|
executeAction(action, ctx);
|
|
}
|
|
}
|
|
}
|
|
|
|
export namespace Items {
|
|
export interface RegisterOptions {
|
|
maxStack?: number;
|
|
description?: string;
|
|
usable?: { actions: RPGAction[]; consumeOnUse?: boolean };
|
|
equippable?: { slotType: string };
|
|
}
|
|
|
|
export function register(world: World, id: string, name: string, options?: RegisterOptions) {
|
|
const entity = world.createEntity(id);
|
|
entity.add(new Item(name, options?.description));
|
|
if (options?.maxStack !== undefined) {
|
|
entity.add(new Stackable(options.maxStack));
|
|
}
|
|
if (options?.usable) {
|
|
entity.add(new Usable(options.usable.actions, options.usable.consumeOnUse));
|
|
}
|
|
if (options?.equippable) {
|
|
entity.add(new Equippable(options.equippable.slotType));
|
|
}
|
|
return entity;
|
|
}
|
|
}
|