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