52 lines
1.9 KiB
TypeScript
52 lines
1.9 KiB
TypeScript
import { AttackType } from '../data/Interfaces';
|
||
import { PlayerStateMachine, DamageOutcome } from './PlayerStateMachine';
|
||
|
||
/**
|
||
* DamageSystem — the single funnel through which **every** player-facing
|
||
* damage event must flow (req 10.1-10.6).
|
||
*
|
||
* Decision precedence (req 10.3):
|
||
* 1. i-frames → no effect
|
||
* 2. sword parry → no effect (only vs. shuriken/sword; see PSM)
|
||
* 3. attack type × distance → dispatch to PlayerStateMachine.takeHit
|
||
*
|
||
* Distance thresholds:
|
||
* - fireball: lethal within 100px (req 10.4)
|
||
* - smoke bomb: lethal within 80px (req 10.5)
|
||
* - shuriken / sword: any contact is eligible
|
||
*
|
||
* Enemy-facing damage is a separate, simpler `applyToEnemy` helper.
|
||
*/
|
||
|
||
export interface IDamageContext {
|
||
attackType: AttackType;
|
||
attackerX: number;
|
||
attackerY: number;
|
||
victimX: number;
|
||
victimY: number;
|
||
}
|
||
|
||
export const FIREBALL_KILL_RADIUS = 100;
|
||
export const SMOKE_KILL_RADIUS = 80;
|
||
|
||
export class DamageSystem {
|
||
constructor(private readonly psm: PlayerStateMachine) {}
|
||
|
||
/** Try to damage the player. Returns `null` if the attack missed by distance. */
|
||
public applyToPlayer(ctx: IDamageContext): DamageOutcome | null {
|
||
const distance = Math.hypot(ctx.attackerX - ctx.victimX, ctx.attackerY - ctx.victimY);
|
||
if (ctx.attackType === 'fireball' && distance > FIREBALL_KILL_RADIUS) return null;
|
||
if (ctx.attackType === 'smoke_bomb' && distance > SMOKE_KILL_RADIUS) return null;
|
||
// shuriken / sword rely on caller-side hitbox; reaching here means "hit".
|
||
return this.psm.takeHit(ctx.attackType);
|
||
}
|
||
|
||
/**
|
||
* Apply flat damage to an enemy HP bucket. The damage number comes from
|
||
* the active weapon config. Returns the remaining HP (0 means killed).
|
||
*/
|
||
public applyToEnemy(currentHp: number, damage: number): number {
|
||
return Math.max(0, currentHp - damage);
|
||
}
|
||
}
|