first commmit

This commit is contained in:
jakciehan
2026-05-06 08:17:32 +08:00
commit 427a33c55b
269 changed files with 20906 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
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);
}
}