81 lines
2.3 KiB
TypeScript

/**
* 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 { 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: number,
maxHealth: number,
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(maxHealth, 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 - 1;
const newWeaponStatus =
newWeaponHealth === 0 ? { kind: 'destroyed' as const } : { kind: 'alive' as const };
return {
weapon: new MagicalWeapon(
newWeaponHealth,
this.maxHealth,
newWeaponStatus,
this.#damage,
this.#owner,
),
target: newTarget,
};
}
}