/** * MagicalObject — shared base for all magical items in the game. * * Invariants enforced at construction: * - Health is non-negative * - Health never exceeds maxHealth * - Status derived from health (0 = destroyed, > 0 = alive) */ export type MagicalObjectStatus = { readonly kind: 'alive' } | { readonly kind: 'destroyed' }; export class MagicalObject { readonly #health: number; readonly #maxHealth: number; readonly #status: MagicalObjectStatus; protected constructor(health: number, maxHealth: number, status: MagicalObjectStatus) { this.#health = health; this.#maxHealth = maxHealth; this.#status = status; } get health(): number { return this.#health; } get maxHealth(): number { return this.#maxHealth; } get status(): MagicalObjectStatus { return this.#status; } /** Create a destroyed object (health = 0). */ static createDestroyed(maxHealth: number): MagicalObject { if (maxHealth < 0) throw new Error('MaxHealth cannot be negative'); return new MagicalObject(0, maxHealth, { kind: 'destroyed' }); } /** Check if this object is alive. */ isAlive(): boolean { return this.#status.kind === 'alive'; } }