Willem van den Ende ba0903714c refactor: replace number health with Health value object in MagicalObject
- MagicalObject: internal #health and #maxHealth now Health type
- HealingObject: constructor, create, and heal use Health value object
- MagicalWeapon: constructor, create, and use use Health value object
- DamageDealer and Healer interfaces: health: number -> health: Health
- magical-objects.spec.ts: all assertions use .health.value
- Run npm run checks: 0 errors, 70 tests passing
2026-06-14 13:35:44 +01:00

88 lines
2.4 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 { 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,
};
}
}