import { System } from '../core/System.ts'; import { SystemName, ComponentType } from '../core/Constants.ts'; import type { Entity } from '../core/Entity.ts'; import type { Stealth } from '../components/Stealth.ts'; import type { Velocity } from '../components/Velocity.ts'; import type { Combat } from '../components/Combat.ts'; import type { Evolution } from '../components/Evolution.ts'; import type { InputSystem } from './InputSystem.ts'; import type { PlayerControllerSystem } from './PlayerControllerSystem.ts'; /** * System responsible for managing stealth mechanics, including visibility updates based on form, movement, and combat. */ export class StealthSystem extends System { constructor() { super(SystemName.STEALTH); this.requiredComponents = [ComponentType.STEALTH]; this.priority = 12; } /** * Update stealth state for entities, handling toggle input and form-specific visibility changes. * @param deltaTime - Time elapsed since last frame in seconds * @param entities - Entities matching active required components */ process(deltaTime: number, entities: Entity[]): void { const inputSystem = this.engine.systems.find((s) => s.name === SystemName.INPUT) as | InputSystem | undefined; const playerController = this.engine.systems.find( (s) => s.name === SystemName.PLAYER_CONTROLLER ) as PlayerControllerSystem | undefined; const player = playerController ? playerController.getPlayerEntity() : null; entities.forEach((entity) => { const stealth = entity.getComponent(ComponentType.STEALTH); const velocity = entity.getComponent(ComponentType.VELOCITY); const combat = entity.getComponent(ComponentType.COMBAT); const evolution = entity.getComponent(ComponentType.EVOLUTION); if (!stealth) return; if (evolution) { const form = evolution.getDominantForm(); stealth.stealthType = form; } if (entity === player && inputSystem) { const shiftPress = inputSystem.isKeyJustPressed('shift'); if (shiftPress) { if (stealth.isStealthed) { stealth.exitStealth(); } else { stealth.enterStealth(stealth.stealthType); } } } const isMoving = velocity && (Math.abs(velocity.vx) > 1 || Math.abs(velocity.vy) > 1); const isInCombat = combat && combat.isAttacking; stealth.updateStealth(isMoving || false, isInCombat || false); if (stealth.isStealthed) { switch (stealth.stealthType) { case 'slime': if (!isMoving) { stealth.visibility = Math.max(0.05, stealth.visibility - deltaTime * 0.2); } break; case 'beast': if (isMoving && velocity) { const speed = Math.sqrt(velocity.vx * velocity.vx + velocity.vy * velocity.vy); if (speed < 50) { stealth.visibility = Math.max(0.1, stealth.visibility - deltaTime * 0.1); } } break; case 'human': stealth.visibility = Math.max(0.2, stealth.visibility - deltaTime * 0.05); break; } } }); } }