/** * Magical Weapon — a Magical Object that deals fixed damage. * * Inherits health/status management from MagicalObject. * Invariants enforced at construction: * - Damage is non-negative */ import { Character } from '../characters/Character.ts'; import { Health } from '../value-objects/Health.ts'; import { MagicalObject } from './MagicalObject.ts'; import type { DamageDealer } from './magical-object-types.ts'; export class MagicalWeapon extends MagicalObject implements DamageDealer { readonly #damage: number; readonly #owner: Character; private constructor( health: Health, maxHealth: Health, status: { readonly kind: 'alive' } | { readonly kind: 'destroyed' }, damage: number, owner: Character, ) { super(health, maxHealth, status); this.#damage = damage; this.#owner = owner; } static create({ maxHealth, damage, owner, }: { maxHealth: number; damage: number; owner: Character; }): MagicalWeapon { if (maxHealth < 0) throw new Error('MaxHealth cannot be negative'); if (damage < 0) throw new Error('Damage cannot be negative'); return new MagicalWeapon( Health.create(maxHealth), Health.create(maxHealth), { kind: 'alive' }, damage, owner, ); } get damage(): number { return this.#damage; } get owner(): Character { return this.#owner; } /** Use this weapon to deal damage. Returns updated weapon and target. */ use(target: Character): { weapon: MagicalWeapon; target: Character } { // Destroyed weapons can't be used if (this.status.kind === 'destroyed') { return { weapon: this, target }; } // Deal fixed damage const newTargetHealth = Math.max(0, target.health.value - this.#damage); const newTargetStatus = newTargetHealth === 0 ? { kind: 'dead' as const } : target.status; const newTarget = Character.createWithHealthAndStatus({ name: target.name, level: target.level, health: newTargetHealth, status: newTargetStatus, }); // Reduce weapon health by 1 const newWeaponHealth = this.health.value - 1; const newWeaponStatus = newWeaponHealth === 0 ? { kind: 'destroyed' as const } : { kind: 'alive' as const }; return { weapon: new MagicalWeapon( Health.create(newWeaponHealth), this.maxHealth, newWeaponStatus, this.#damage, this.#owner, ), target: newTarget, }; } }