blacktrigram 0.7.48 → 0.7.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.js +7 -14
- package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js +2 -2
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js +2 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.js +11 -5
- package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.js +1 -1
- package/lib/components/screens/intro/IntroScreen3D.js +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.js +1 -1
- package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.js +2 -11
- package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js +2 -2
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.js +11 -5
- package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
- package/lib/components/shared/ui/SplashScreen.js +2 -2
- package/lib/hooks/useHUDLayout.d.ts.map +1 -1
- package/lib/hooks/useHUDLayout.js +3 -2
- package/lib/hooks/useHUDLayout.js.map +1 -1
- package/lib/types/constants/layout.d.ts +21 -0
- package/lib/types/constants/layout.d.ts.map +1 -1
- package/lib/types/constants/layout.js +22 -1
- package/lib/types/constants/layout.js.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.d.ts +7 -0
- package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.js +16 -2
- package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CombatScreen3D.js","names":[],"sources":["../../../../src/components/screens/combat/CombatScreen3D.tsx"],"sourcesContent":["/**\n * CombatScreen3D - Three.js-based combat screen (Black Trigram 흑괘)\n *\n * Maintains all existing combat logic and state management\n * Uses Html overlays for UI and 3D meshes for game objects\n */\n\nimport { Canvas } from \"@react-three/fiber\";\nimport { Html } from \"@react-three/drei\";\nimport {\n Bloom,\n EffectComposer,\n Noise,\n Vignette,\n} from \"@react-three/postprocessing\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useAudio } from \"../../../audio/AudioProvider\";\nimport { useActionFeedback } from \"../../../hooks/useActionFeedback\";\nimport { useCombatTimer } from \"../../../hooks/useCombatTimer\";\nimport { useKeyboardControls } from \"../../../hooks/useKeyboardControls\";\nimport { usePlayerAnimation } from \"../../../hooks/usePlayerAnimation\";\nimport { useRoundTransition } from \"../../../hooks/useRoundTransition\";\nimport { useTechniqueSelection } from \"../../../hooks/useTechniqueSelection\";\nimport { useWebGLContextLossHandler } from \"../../../hooks/useWebGLContextLossHandler\";\nimport { useCombatAttackMovement } from \"./hooks/useCombatAttackMovement\";\nimport { HitEffect, PlayerState } from \"../../../systems\";\nimport { CombatSystem } from \"../../../systems/CombatSystem\";\nimport {\n AdaptiveDifficulty,\n getPersonalityByArchetype,\n} from \"../../../systems/ai\";\nimport {\n AnimationEvents,\n AnimationState,\n AnimationType,\n determineRecoveryType,\n getAnimation,\n getAnimationDurationOrFallback,\n getRecoveryAnimationState,\n resolveTechniqueAnimation,\n TARGET_ANIMATION_FPS,\n} from \"../../../systems/animation\";\nimport { BalanceSystem } from \"../../../systems/combat/BalanceSystem\";\nimport type { BalancePlayerState } from \"../../../systems/combat/BalanceSystem\";\nimport { HitEffectType } from \"../../../systems/effects\";\nimport { injuryMovementModifier } from \"../../../systems/movement/InjuryMovementModifier\";\nimport { TRIGRAM_STANCES_ORDER } from \"../../../systems/trigram/types\";\nimport { TRIGRAM_TECHNIQUES } from \"../../../systems/trigram/techniques\";\nimport type { KoreanTechnique } from \"../../../systems/vitalpoint/types\";\nimport {\n CombatState,\n GameMode,\n PlayerArchetype,\n Position,\n TrigramStance,\n} from \"../../../types\";\nimport { Injury, InjuryType } from \"../../../types/injury\";\nimport { Z_INDEX } from \"../../../types/LayoutTypes\";\nimport { getMobileControlsBottom } from \"../../../types/constants/layout\";\nimport {\n FONT_FAMILY,\n getPerformanceSettings,\n KOREAN_COLORS,\n ROUND_ANNOUNCEMENT_TIMINGS,\n} from \"@/types/constants\";\nimport { getAnimationTypeForTechnique } from \"../../../data/techniqueMappings\";\nimport { toHexColor } from \"../../../utils/colorHelpers\";\nimport { usePlayerMovement } from \"../../../utils/inputSystem\";\nimport { PerformanceOverlay3D } from \"../../../utils/performance\";\nimport { createPlayerFromArchetype } from \"../../../utils/playerUtils\";\nimport { createCameraConfig } from \"../../../utils/sharedPhysicsConfig\";\nimport { useAdaptiveQuality } from \"../../shared/three/optimization\";\nimport { useKoreanTheme } from \"../../shared/base/useKoreanTheme\";\nimport {\n ActionFeedback,\n TechniqueName,\n} from \"../../shared/three/effects/ActionFeedback\";\nimport { DamageNumbers } from \"../../shared/three/effects/DamageNumbers\";\nimport HitEffects3D from \"../../shared/three/effects/HitEffects3D\";\nimport { VitalPointMarkers3D } from \"../../shared/three/effects/VitalPointMarkers3D\";\nimport { StanceChangeIndicator } from \"../../shared/three/indicators/StanceChangeIndicator\";\nimport { CombatArena3D } from \"../../shared/three/scene/CombatArena3D\";\nimport { BreathingIndicator } from \"../../shared/three/ui/BreathingIndicator\";\nimport { ComboCounter } from \"../../shared/three/ui/ComboCounter\";\nimport { VitalPointOverlayControlsHtml } from \"../../shared/three/ui/VitalPointOverlayControlsHtml\";\nimport { KeyboardHints } from \"./components/controls/KeyboardHints\";\nimport { MatchCountdown } from \"./components/feedback/MatchCountdown\";\nimport { RoundAnnouncement } from \"./components/feedback/RoundAnnouncementOverlayHtml\";\nimport { RoundDisplayStatus } from \"./components/feedback/RoundDisplayStatus\";\nimport { RoundStartAnnouncement } from \"./components/feedback/RoundStartAnnouncementOverlayHtml\";\nimport { InputBufferDisplay } from \"./components/indicators/InputBufferDisplay\";\nimport { GestureEvent } from \"../../../hooks/useTouchControls\";\nimport {\n MovementType,\n SpeedModifierSystem,\n} from \"../../../systems/physics/SpeedModifierSystem\";\nimport { Technique } from \"../../../types\";\nimport {\n animationStateToPlayerAnimation,\n convertPlayerStateToProps,\n getBalanceState,\n} from \"../../../utils/player3DHelpers\";\nimport {\n GestureRecognizerPure,\n MobileControlsOverlay,\n StanceWheelPure,\n} from \"../../shared/mobile\";\nimport { ButtonEventType } from \"../../shared/mobile/ActionButtons\";\nimport { Direction, DPadEventType } from \"../../shared/mobile/VirtualDPad\";\nimport { Player3DWithTransitions } from \"../../shared/three/models/Player3DWithTransitions\";\nimport { PauseMenu } from \"./components/controls/PauseMenu\";\nimport { TraumaOverlay3D } from \"./components/effects/TraumaOverlay3D\";\nimport { CombatParticleEffects3D } from \"./components/effects/CombatParticleEffects3D\";\nimport {\n CombatBottomHUD,\n CombatLeftHUD,\n CombatPortraitStatusStrip,\n CombatRightHUD,\n CombatTopHUD,\n} from \"./components/hud\";\nimport { FPSMonitor } from \"./components/hud/FPSMonitor\";\nimport { PlayerStateOverlayHtml } from \"./components/hud/PlayerStateOverlayHtml\";\nimport { BalanceIndicatorOverlayHtml } from \"../../ui/combat/BalanceIndicatorOverlayHtml\";\nimport {\n ANNOUNCEMENT_FADE_OUT_DELAY,\n calculateAccuracy,\n STANCE_INDEX_MAP,\n} from \"./helpers\";\nimport { AnimationUpdater } from \"./helpers/AnimationUpdater\";\nimport { AccelerationUpdater } from \"../../../systems/movement/helpers/AccelerationUpdater\";\nimport { isRunningSpeed } from \"../../../systems/movement/helpers/accelerationUtils\";\nimport { useAICombat } from \"./hooks/useAICombat\";\nimport { useCombatActions } from \"./hooks/useCombatActions\";\nimport { useCombatAudio } from \"./hooks/useCombatAudio\";\nimport { useCombatLayout } from \"./hooks/useCombatLayout\";\nimport { useCombatState } from \"./hooks/useCombatState\";\n\nconst PLAYER_ONE_INDEX = 0;\n\n/**\n * Props for the CombatScreen3D component.\n * Provides all state and callbacks required for the 3D combat screen.\n */\nexport interface CombatScreen3DProps {\n /**\n * Array of player states (expects exactly 2 players).\n * Each PlayerState contains all combat and status information for a player.\n */\n readonly players: readonly PlayerState[];\n /**\n * Callback to update a player's state by index.\n * @param playerIndex - Index of the player to update (0 or 1).\n * @param updates - Partial PlayerState with updated fields.\n */\n readonly onPlayerUpdate: (\n playerIndex: number,\n updates: Partial<PlayerState>,\n ) => void;\n /**\n * Current round number (1-based).\n */\n readonly currentRound: number;\n /**\n * Remaining time in seconds for the current round.\n */\n readonly timeRemaining: number;\n /**\n * Whether combat is currently paused.\n */\n readonly isPaused: boolean;\n /**\n * Callback when the user exits to the menu.\n */\n readonly onReturnToMenu: () => void;\n /**\n * Callback when the match ends, with the winner's index (0 or 1).\n * @param winner - Index of the winning player.\n */\n readonly onGameEnd: (winner: number) => void;\n /**\n * Optional game mode (affects rules/behavior).\n */\n readonly gameMode?: GameMode;\n /**\n * Canvas width in pixels. Defaults to 1200.\n */\n readonly width?: number;\n /**\n * Canvas height in pixels. Defaults to 800.\n */\n readonly height?: number;\n /**\n * Enable adaptive quality adjustment (default: true on mobile)\n */\n readonly enableAdaptiveQuality?: boolean;\n /**\n * Show performance overlay in dev mode (default: import.meta.env.DEV)\n */\n readonly showPerformanceOverlay?: boolean;\n}\n\n/**\n * CombatScreen3D Component\n * Three.js-based combat screen with 3D characters and effects\n */\n\n/**\n * AdaptiveQualityWrapper - Internal component to use adaptive quality hook\n * Must be inside Canvas to use useFrame from @react-three/fiber\n *\n * Hoisted outside CombatScreen3D to avoid \"Cannot create components during render\"\n * warnings from react-hooks/component-creation. Keeps the component type stable\n * across renders of the parent.\n */\nconst AdaptiveQualityWrapper: React.FC<{\n readonly enabled: boolean;\n readonly isMobile: boolean;\n readonly children: React.ReactNode;\n}> = ({ enabled, isMobile, children }) => {\n useAdaptiveQuality(enabled, isMobile, (newQuality) => {\n if (import.meta.env.DEV) {\n console.log(`[CombatScreen3D] Quality adjusted to: ${newQuality}`);\n }\n });\n\n return <>{children}</>;\n};\n\nexport const CombatScreen3D: React.FC<CombatScreen3DProps> = ({\n players,\n onPlayerUpdate,\n currentRound,\n timeRemaining,\n isPaused,\n onReturnToMenu,\n onGameEnd,\n width = 1200,\n height = 800,\n enableAdaptiveQuality,\n showPerformanceOverlay = import.meta.env.DEV,\n}) => {\n const [contentReady, setContentReady] = useState(false);\n\n const contextLossCountRef = useRef(0);\n\n useWebGLContextLossHandler({\n onContextLost: () => {\n console.warn(\"⚠️ WebGL context lost in CombatScreen\");\n contextLossCountRef.current += 1;\n setContentReady(false);\n },\n onContextRestored: () => {\n setTimeout(() => setContentReady(true), 100);\n },\n autoRestore: true,\n });\n\n useEffect(() => {\n const timer = setTimeout(() => setContentReady(true), 50);\n return () => clearTimeout(timer);\n }, []);\n\n const audio = useAudio();\n\n useEffect(() => {\n if (import.meta.env.DEV) {\n performance.mark(\"combat-3d-render-start\");\n return () => {\n performance.mark(\"combat-3d-render-end\");\n performance.measure(\n \"combat-3d-render\",\n \"combat-3d-render-start\",\n \"combat-3d-render-end\",\n );\n };\n }\n }, []);\n\n const { arenaBounds, isMobile, isPortrait, screenSize, layoutConstants } =\n useCombatLayout(width, height);\n\n const theme = useKoreanTheme({\n variant: \"primary\",\n size: \"md\",\n isMobile,\n });\n\n const positionScale = useMemo(() => {\n if (isMobile) {\n return 1.0;\n }\n\n switch (screenSize) {\n case \"mobile\":\n return 1.0; // Mobile already has special handling\n case \"tablet\":\n return 1.0;\n case \"desktop\":\n return 1.0;\n case \"large\":\n return 1.25;\n case \"xlarge\":\n return 1.5; // 4K displays need 1.5x offsets\n default:\n return 1.0;\n }\n }, [isMobile, screenSize]);\n\n const cameraConfig = useMemo(() => {\n const base = createCameraConfig(isMobile);\n if (!isPortrait) return base;\n return {\n ...base,\n fov: Math.min(80, base.fov + 15),\n position: [base.position[0], base.position[1], base.position[2] + 4] as [\n number,\n number,\n number,\n ],\n };\n }, [isMobile, isPortrait]);\n\n const renderConfig = useMemo(() => {\n const performanceSettings = getPerformanceSettings(width, isMobile);\n\n return {\n shadowMapSize: performanceSettings.shadowMapSize,\n dpr: performanceSettings.dpr,\n antialias: performanceSettings.antialias,\n maxParticles: performanceSettings.maxParticles,\n postProcessing: performanceSettings.postProcessing,\n };\n }, [isMobile, width]);\n\n const shouldEnableAdaptiveQuality = enableAdaptiveQuality ?? isMobile;\n\n const { state: combatState, actions: combatActions } = useCombatState();\n\n\n const [overlayVisible, setOverlayVisible] = useState(false);\n const [severityFilters, setSeverityFilters] = useState<\n import(\"../../../types/common\").VitalPointSeverity[]\n >([]);\n const [regionFilter, setRegionFilter] =\n useState<\n import(\"../../shared/three/ui/VitalPointOverlayControlsHtml\").BodyRegionFilter\n >(\"all\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [showLabels, setShowLabels] = useState(true);\n const [animated, setAnimated] = useState(true);\n const [scale, setScale] = useState(1.2); // Larger scale for better visibility in combat\n const [showPerformanceMonitor, setShowPerformanceMonitor] = useState(false);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"v\" || e.key === \"V\") {\n setOverlayVisible((prev) => !prev);\n audio.playSFX(\"menu_select\");\n }\n if (e.key === \"F9\" && import.meta.env.DEV) {\n e.preventDefault();\n setShowPerformanceMonitor((prev) => !prev);\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [audio]);\n\n const { state: feedbackState, actions: feedbackActions } = useActionFeedback({\n damageNumberDuration: 1500,\n actionFeedbackDuration: 1200,\n techniqueDuration: 2000,\n comboResetTime: 2000,\n });\n\n const combatAudio = useCombatAudio();\n const { playStanceChangeSound } = combatAudio;\n\n const [matchScore, setMatchScore] = useState({ player1: 0, player2: 0 });\n const matchScoreRef = useRef(matchScore);\n\n const updateMatchScore = useCallback((winner: 0 | 1) => {\n const newScore = {\n player1:\n winner === 0\n ? matchScoreRef.current.player1 + 1\n : matchScoreRef.current.player1,\n player2:\n winner === 1\n ? matchScoreRef.current.player2 + 1\n : matchScoreRef.current.player2,\n };\n matchScoreRef.current = newScore;\n setTimeout(() => setMatchScore(newScore), 0);\n }, []);\n\n const [internalRound, setInternalRound] = useState(currentRound);\n\n const [currentTime, setCurrentTime] = useState(() => Date.now());\n\n const [hasShownMatchCountdown, setHasShownMatchCountdown] = useState(true); // Already shown (skipped)\n const [showMatchCountdown, setShowMatchCountdown] = useState(false); // Don't show\n const [showRoundStart, setShowRoundStart] = useState(false);\n const [matchCountdownComplete, setMatchCountdownComplete] = useState(true); // Already complete (skipped)\n\n const [player1Position, setPlayer1Position] = useState<Position>({\n x: arenaBounds.worldWidthMeters * -0.1, // 10% left of center (~0.8m for 8m arena)\n y: 0, // Centered\n });\n\n const [showPauseMenu, setShowPauseMenu] = useState(false);\n\n const handlePause = useCallback(() => {\n setShowPauseMenu(true);\n audio.playSFX(\"menu_select\");\n }, [audio]);\n\n const handleResume = useCallback(() => {\n setShowPauseMenu(false);\n audio.playSFX(\"menu_select\");\n }, [audio]);\n\n const handleRestart = useCallback(() => {\n\n setInternalRound(1);\n setMatchScore({ player1: 0, player2: 0 });\n matchScoreRef.current = { player1: 0, player2: 0 };\n\n combatActions.setRoundEnded(false);\n combatActions.setRoundStarted(false);\n combatActions.setRoundDisplayStatus(null);\n\n onPlayerUpdate(0, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n onPlayerUpdate(1, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n\n setPlayer1Position({\n x: arenaBounds.worldWidthMeters * -0.1, // 10% left of center in meters\n y: 0, // Centered\n });\n onPlayerUpdate(1, {\n position: {\n x: arenaBounds.worldWidthMeters * 0.1, // 10% right of center in meters\n y: 0, // Centered\n },\n });\n\n setShowPauseMenu(false);\n setShowRoundStart(true);\n\n audio.playSFX(\"menu_select\");\n }, [audio, combatActions, onPlayerUpdate, arenaBounds, setPlayer1Position]);\n\n const handleRoundTransitionComplete = useCallback(() => {\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Round transition complete, checking match status\");\n }\n const currentScore = matchScoreRef.current;\n if (currentScore.player1 >= 2 || currentScore.player2 >= 2) {\n const matchWinner = currentScore.player1 >= 2 ? 0 : 1;\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Match over, winner:\", matchWinner);\n }\n onGameEnd(matchWinner);\n return; // Don't start next round\n }\n\n combatActions.resetRoundState();\n\n setInternalRound((prev) => {\n const nextRound = prev + 1;\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Incrementing round from\", prev, \"to\", nextRound);\n }\n setTimeout(() => {\n if (import.meta.env.DEV) {\n console.log(\n \"[DEV] Showing round start announcement for round\",\n nextRound,\n );\n }\n setShowRoundStart(true);\n }, ANNOUNCEMENT_FADE_OUT_DELAY);\n return nextRound;\n });\n\n onPlayerUpdate(0, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n onPlayerUpdate(1, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n\n setPlayer1Position({\n x: arenaBounds.worldWidthMeters * -0.1, // 10% left of center in meters\n y: 0, // Centered\n });\n onPlayerUpdate(1, {\n position: {\n x: arenaBounds.worldWidthMeters * 0.1, // 10% right of center in meters\n y: 0, // Centered\n },\n });\n }, [\n combatActions,\n onGameEnd,\n onPlayerUpdate,\n arenaBounds,\n setPlayer1Position,\n ]);\n\n const {\n showAnnouncement,\n roundWinner,\n currentRoundNumber: transitionRoundNumber,\n skipCountdown,\n startTransition,\n } = useRoundTransition(\n {\n announcementDuration: ROUND_ANNOUNCEMENT_TIMINGS.ANNOUNCEMENT_DURATION,\n countdownDuration: ROUND_ANNOUNCEMENT_TIMINGS.COUNTDOWN_DURATION,\n transitionDuration: ROUND_ANNOUNCEMENT_TIMINGS.TRANSITION_DURATION,\n },\n handleRoundTransitionComplete,\n );\n\n const player2Position = useMemo<Position>(() => {\n if (players.length >= 2 && players[1].position) {\n return players[1].position;\n }\n return {\n x: arenaBounds.worldWidthMeters * 0.1, // 10% right of center (~0.8m for 8m arena)\n y: 0, // Centered\n };\n }, [players, arenaBounds]);\n\n const playerPositions = useMemo<Position[]>(() => {\n return [player1Position, player2Position];\n }, [player1Position, player2Position]);\n\n const player1Position3D: [number, number, number] = useMemo(() => {\n return [playerPositions[0].x, 0, playerPositions[0].y];\n }, [playerPositions]);\n\n const player2Position3D: [number, number, number] = useMemo(() => {\n return [playerPositions[1].x, 0, playerPositions[1].y];\n }, [playerPositions]);\n\n\n const player2Rotation = useMemo(() => {\n const dx = player1Position3D[0] - player2Position3D[0];\n const dz = player1Position3D[2] - player2Position3D[2];\n return Math.atan2(dx, dz);\n }, [player1Position3D, player2Position3D]);\n\n const combatSystem = useMemo(() => new CombatSystem(), []);\n\n const balanceSystem = useMemo(() => new BalanceSystem(), []);\n\n const speedModifierSystem = useMemo(() => new SpeedModifierSystem(), []);\n\n const [player1SpeedModifiers, setPlayer1SpeedModifiers] = useState({\n finalSpeed: 6.0, // BASE_WALK_SPEED (6.0 m/s)\n baseSpeed: 6.0,\n finalAcceleration: 12.0, // BASE_ACCELERATION (12.0 m/s²)\n });\n const [player2SpeedModifiers, setPlayer2SpeedModifiers] = useState({\n finalSpeed: 6.0, // BASE_WALK_SPEED (6.0 m/s)\n baseSpeed: 6.0,\n finalAcceleration: 12.0, // BASE_ACCELERATION (12.0 m/s²)\n });\n\n const [player1WalkRunSpeeds, setPlayer1WalkRunSpeeds] = useState({\n walkSpeed: 6.0,\n runSpeed: 10.0,\n });\n\n useEffect(() => {\n const updateSpeedModifiers = () => {\n if (players.length >= 2) {\n const player1WalkModifiers =\n speedModifierSystem.calculateSpeedModifiers(\n players[0],\n MovementType.WALKING,\n false, // isCrouching\n );\n const player1RunModifiers = speedModifierSystem.calculateSpeedModifiers(\n players[0],\n MovementType.RUNNING,\n false, // isCrouching\n );\n\n setPlayer1SpeedModifiers({\n finalSpeed: player1WalkModifiers.finalSpeed,\n baseSpeed: player1WalkModifiers.baseSpeed,\n finalAcceleration: player1WalkModifiers.finalAcceleration,\n });\n\n setPlayer1WalkRunSpeeds({\n walkSpeed: player1WalkModifiers.finalSpeed,\n runSpeed: player1RunModifiers.finalSpeed,\n });\n\n const player2Modifiers = speedModifierSystem.calculateSpeedModifiers(\n players[1],\n MovementType.WALKING,\n false,\n );\n setPlayer2SpeedModifiers({\n finalSpeed: player2Modifiers.finalSpeed,\n baseSpeed: player2Modifiers.baseSpeed,\n finalAcceleration: player2Modifiers.finalAcceleration,\n });\n }\n };\n\n updateSpeedModifiers();\n\n const intervalId = setInterval(updateSpeedModifiers, 200);\n\n return () => clearInterval(intervalId);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [players]); // speedModifierSystem is memoized and never changes\n\n useEffect(() => {\n const updateTime = () => {\n setCurrentTime(Date.now());\n };\n\n const intervalId = setInterval(updateTime, 200);\n\n return () => clearInterval(intervalId);\n }, []);\n\n const calculateLegInjuryFactor = useCallback(\n (player: PlayerState): number => {\n if (!player.bodyPartHealth) return 0;\n\n const leftLeg = player.bodyPartHealth.legLeft ?? player.maxHealth;\n const rightLeg = player.bodyPartHealth.legRight ?? player.maxHealth;\n const maxHealth = player.maxHealth;\n\n const averageLegHealth = (leftLeg + rightLeg) / (2 * maxHealth);\n return Math.max(0, Math.min(1, 1.0 - averageLegHealth)); // 0 = healthy, 1 = critical\n },\n [],\n );\n\n const player1 = players.length > 0 ? players[0] : undefined;\n const player1Data = useMemo(() => {\n const p1 = player1 ?? createPlayerFromArchetype(PlayerArchetype.MUSA, 0);\n return {\n currentStance: p1.currentStance,\n legInjuryFactor: calculateLegInjuryFactor(p1),\n };\n }, [player1, calculateLegInjuryFactor]);\n\n const [player1AttackAnimation, setPlayer1AttackAnimation] = useState<\n string | undefined\n >(undefined);\n const [player2AttackAnimation, setPlayer2AttackAnimation] = useState<\n string | undefined\n >(undefined);\n\n const [player1TechniqueId, setPlayer1TechniqueId] = useState<\n string | undefined\n >(undefined);\n const [player2TechniqueId, setPlayer2TechniqueId] = useState<\n string | undefined\n >(undefined);\n\n const [player1Injuries, setPlayer1Injuries] = useState<readonly Injury[]>([]);\n const [player2Injuries, setPlayer2Injuries] = useState<readonly Injury[]>([]);\n\n useEffect(() => {\n return () => {\n setPlayer1Injuries([]);\n setPlayer2Injuries([]);\n };\n }, []);\n\n useEffect(() => {\n if (players.length >= 2) {\n const player1 = players[0];\n const player2 = players[1];\n\n if (\n player1?.health === player1?.maxHealth &&\n player2?.health === player2?.maxHealth\n ) {\n setPlayer1Injuries([]);\n setPlayer2Injuries([]);\n }\n }\n }, [players]);\n\n const handlePlayer1PositionChange = useCallback(\n (newPosition: Position) => {\n setPlayer1Position(newPosition);\n onPlayerUpdate(0, { position: newPosition });\n },\n [onPlayerUpdate],\n );\n\n const movementBounds = useMemo(\n () => ({\n worldWidthMeters: arenaBounds.worldWidthMeters,\n worldDepthMeters: arenaBounds.worldDepthMeters,\n }),\n [arenaBounds.worldWidthMeters, arenaBounds.worldDepthMeters],\n );\n\n\n const player1MovementTimeRef = useRef(0);\n const player1LastDirectionRef = useRef<{ x: number; y: number }>({\n x: 0,\n y: 0,\n });\n\n const [player1AccelerationBasedSpeed, setPlayer1AccelerationBasedSpeed] =\n useState(player1WalkRunSpeeds.walkSpeed);\n\n const player1IsRunning = isRunningSpeed(\n player1AccelerationBasedSpeed,\n player1WalkRunSpeeds.runSpeed,\n );\n\n const { isMoving: player1IsMoving, velocity: player1Velocity } =\n usePlayerMovement({\n enabled:\n !isPaused &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart,\n bounds: movementBounds, // Use memoized bounds object\n onPositionChange: handlePlayer1PositionChange, // Use memoized callback\n initialPositionMeters: player1Position,\n currentStance: player1Data.currentStance,\n legInjuryFactor: player1Data.legInjuryFactor,\n isRunning: player1IsRunning, // Use computed acceleration-based running state\n useTacticalSteps: false,\n maxSpeedOverride: player1AccelerationBasedSpeed,\n accelerationOverride: player1SpeedModifiers.finalAcceleration,\n });\n\n const player1Rotation = useMemo(() => {\n if (\n player1IsMoving &&\n player1Velocity &&\n (player1Velocity.x !== 0 || player1Velocity.y !== 0)\n ) {\n const movementRotation = Math.atan2(player1Velocity.x, player1Velocity.y);\n return movementRotation;\n } else {\n const dx = player2Position3D[0] - player1Position3D[0];\n const dz = player2Position3D[2] - player1Position3D[2];\n const targetRotation = Math.atan2(dx, dz);\n return targetRotation;\n }\n }, [player1IsMoving, player1Velocity, player1Position3D, player2Position3D]);\n\n const handleAttackRef = useRef<(() => void) | null>(null);\n\n const player1AnimationRef = useRef<ReturnType<\n typeof usePlayerAnimation\n > | null>(null);\n\n const validPlayersRefForAnimation = useRef<[PlayerState, PlayerState] | null>(\n null,\n );\n\n const player1HitTriggerFrameRef = useRef<number>(6);\n const player1AttackHitFiredRef = useRef<boolean>(false);\n\n const [player1AttackDuration, setPlayer1AttackDuration] =\n useState<number>(0.55);\n const [player2AttackDuration, setPlayer2AttackDuration] =\n useState<number>(0.55);\n\n const clearPlayer1AttackAnimation = useRef<() => void>(() => {\n setPlayer1AttackAnimation(undefined);\n setPlayer1TechniqueId(undefined);\n });\n const clearPlayer2AttackAnimation = useRef<() => void>(() => {\n setPlayer2AttackAnimation(undefined);\n setPlayer2TechniqueId(undefined);\n });\n\n const preparePlayer1AttackTiming = useCallback((animationName: string) => {\n const attackDuration = getAnimationDurationOrFallback(animationName);\n const attackFrames = Math.max(\n 1,\n Math.round(attackDuration * TARGET_ANIMATION_FPS),\n );\n player1HitTriggerFrameRef.current = Math.round(attackFrames * 0.4);\n player1AttackHitFiredRef.current = false;\n setPlayer1AttackDuration(attackDuration);\n return attackDuration;\n }, []);\n\n const player1AnimationEvents = useMemo<AnimationEvents>(\n () => ({\n onFrame: (frame, state) => {\n if (\n state === AnimationState.ATTACK &&\n frame >= player1HitTriggerFrameRef.current &&\n !player1AttackHitFiredRef.current\n ) {\n player1AttackHitFiredRef.current = true;\n handleAttackRef.current?.();\n }\n },\n onAnimationComplete: (state) => {\n if (\n state === AnimationState.ATTACK ||\n state === AnimationState.DEFEND\n ) {\n combatActions.setExecutingTechnique(false);\n if (state === AnimationState.ATTACK) {\n clearPlayer1AttackAnimation.current();\n }\n } else if (state === AnimationState.STANCE_CHANGE) {\n audio.playSFX(\"menu_select\");\n const players = validPlayersRefForAnimation.current;\n const currentStance = players?.[0]?.currentStance;\n if (currentStance && player1AnimationRef.current) {\n player1AnimationRef.current.transitionToStanceGuard(currentStance);\n }\n }\n },\n }),\n [combatActions, audio],\n );\n\n const player1Animation = usePlayerAnimation({\n events: player1AnimationEvents,\n });\n\n useEffect(() => {\n player1AnimationRef.current = player1Animation;\n }, [player1Animation]);\n\n const player2Animation = usePlayerAnimation({\n events: {\n onFrame: (frame, state) => {\n if (state === AnimationState.ATTACK && frame === 6) { /* attack frame hook */ }\n },\n onAnimationComplete: (state) => {\n if (state === AnimationState.ATTACK) {\n clearPlayer2AttackAnimation.current();\n }\n },\n },\n });\n\n const prevPlayer1IsMovingRef = useRef<boolean>(player1IsMoving);\n const prevPlayer1IsRunningRef = useRef<boolean>(player1IsRunning);\n useEffect(() => {\n const movementChanged = prevPlayer1IsMovingRef.current !== player1IsMoving;\n const runningChanged = prevPlayer1IsRunningRef.current !== player1IsRunning;\n\n if (movementChanged || runningChanged) {\n if (player1IsMoving) {\n const targetState = player1IsRunning\n ? AnimationState.RUN\n : AnimationState.WALK;\n if (player1Animation.currentState !== targetState) {\n player1Animation.transitionTo(targetState);\n }\n } else if (\n player1Animation.currentState === AnimationState.WALK ||\n player1Animation.currentState === AnimationState.RUN\n ) {\n player1Animation.transitionToStanceGuard(player1Data.currentStance);\n }\n prevPlayer1IsMovingRef.current = player1IsMoving;\n prevPlayer1IsRunningRef.current = player1IsRunning;\n }\n }, [\n player1IsMoving,\n player1IsRunning,\n player1Animation,\n player1Data.currentStance,\n ]);\n\n const MOVEMENT_DETECTION_THRESHOLD = 0.5;\n\n const player2Stance = useMemo(() => {\n return players[1]?.currentStance ?? TrigramStance.GEON;\n }, [players]);\n\n const prevPlayer2PositionRef = useRef(player2Position);\n useEffect(() => {\n const currentPos = playerPositions[1];\n const prevPos = prevPlayer2PositionRef.current;\n\n const isMoving =\n Math.abs(currentPos.x - prevPos.x) > MOVEMENT_DETECTION_THRESHOLD ||\n Math.abs(currentPos.y - prevPos.y) > MOVEMENT_DETECTION_THRESHOLD;\n\n if (isMoving) {\n if (\n player2Animation.currentState !== AnimationState.WALK &&\n player2Animation.currentState !== AnimationState.ATTACK\n ) {\n player2Animation.transitionTo(AnimationState.WALK);\n }\n } else {\n if (player2Animation.currentState === AnimationState.WALK) {\n player2Animation.transitionToStanceGuard(player2Stance);\n }\n }\n\n prevPlayer2PositionRef.current = currentPos;\n }, [playerPositions, player2Animation, player2Stance]);\n\n const validPlayers = useMemo((): [PlayerState, PlayerState] => {\n if (players.length === 0) {\n const player1 = createPlayerFromArchetype(PlayerArchetype.MUSA, 0);\n const player2 = createPlayerFromArchetype(PlayerArchetype.AMSALJA, 1);\n\n return [\n { ...player1, position: playerPositions[0] },\n { ...player2, position: playerPositions[1] },\n ];\n }\n\n const player1 = players[0];\n const player2 =\n players[1] ?? createPlayerFromArchetype(PlayerArchetype.AMSALJA, 1);\n\n return [\n { ...player1, position: playerPositions[0] },\n { ...player2, position: playerPositions[1] },\n ];\n }, [players, playerPositions]);\n\n const validPlayersRef = useRef<[PlayerState, PlayerState]>(validPlayers);\n useEffect(() => {\n validPlayersRef.current = validPlayers;\n validPlayersRefForAnimation.current = validPlayers;\n }, [validPlayers]);\n\n const getTechniqueAnimationType = useCallback(\n (techniqueId: string | undefined): AnimationType | undefined => {\n if (!techniqueId) return undefined;\n\n return getAnimationTypeForTechnique(techniqueId);\n },\n [],\n );\n\n const {\n player1Position: player1PositionWithAttackMovement,\n player2Position: player2PositionWithAttackMovement,\n } = useCombatAttackMovement({\n player1Attacking: player1Animation.currentState === AnimationState.ATTACK,\n player1AnimationType: getTechniqueAnimationType(player1TechniqueId),\n player1Stance: player1Data.currentStance,\n player1BasePosition: player1Position3D,\n player1AnimationDuration: player1AttackDuration,\n player2Attacking: player2Animation.currentState === AnimationState.ATTACK,\n player2AnimationType: getTechniqueAnimationType(player2TechniqueId),\n player2Stance: validPlayers[1].currentStance,\n player2BasePosition: player2Position3D,\n player2AnimationDuration: player2AttackDuration,\n });\n\n const [player1LocalStance, setPlayer1LocalStance] = useState<TrigramStance>(\n validPlayers[0].currentStance,\n );\n\n useEffect(() => {\n setPlayer1LocalStance(validPlayers[0].currentStance);\n }, [validPlayers]);\n\n const player1WithLocalStance = useMemo(\n (): PlayerState => ({\n ...validPlayers[0],\n currentStance: player1LocalStance,\n }),\n [validPlayers, player1LocalStance],\n );\n\n const startTransitionRef = useRef(startTransition);\n const internalRoundRef = useRef(internalRound);\n useEffect(() => {\n startTransitionRef.current = startTransition;\n internalRoundRef.current = internalRound;\n }, [startTransition, internalRound]);\n\n const addCombatMessage = useCallback(\n (korean: string, english: string) => {\n const message = `${korean} | ${english}`;\n combatActions.addCombatMessage(message);\n },\n [combatActions],\n );\n\n const handleTimeUp = useCallback(() => {\n if (!combatState.roundEnded) {\n combatActions.setRoundEnded(true);\n addCombatMessage(\"시간 종료!\", \"Time's Up!\");\n\n const currentPlayers = validPlayersRef.current;\n const player1Health = currentPlayers[0].health;\n const player2Health = currentPlayers[1].health;\n\n if (player1Health > player2Health) {\n updateMatchScore(0);\n startTransitionRef.current(currentPlayers[0], internalRoundRef.current); // Player 1 wins round\n } else if (player2Health > player1Health) {\n updateMatchScore(1);\n startTransitionRef.current(currentPlayers[1], internalRoundRef.current); // Player 2 wins round\n } else {\n startTransitionRef.current(null, internalRoundRef.current);\n }\n }\n }, [\n combatState.roundEnded,\n combatActions,\n addCombatMessage,\n updateMatchScore,\n ]);\n\n const handleTimeUpRef = useRef(handleTimeUp);\n useEffect(() => {\n handleTimeUpRef.current = handleTimeUp;\n }, [handleTimeUp]);\n\n const timerResetKey = `round-${internalRound}`;\n\n const timerState = useCombatTimer({\n initialTime: Math.max(0, timeRemaining),\n isPaused:\n isPaused ||\n !combatState.roundStarted ||\n combatState.roundEnded ||\n !matchCountdownComplete ||\n showRoundStart,\n onTimeUp: useCallback(() => handleTimeUpRef.current(), []),\n warningThreshold: 10,\n urgentThreshold: 5,\n resetKey: timerResetKey,\n });\n\n const startRound = useCallback(() => {\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Starting round, setting roundStarted=true\");\n }\n combatActions.setRoundStarted(true);\n combatActions.setRoundEnded(false); // Ensure roundEnded is false\n addCombatMessage(\"라운드 시작!\", \"Round Start!\");\n\n const player = validPlayers[0];\n if (player?.archetype) {\n const playerArchetype = player.archetype.toLowerCase();\n combatAudio.playArchetypeMusic(playerArchetype, 2000);\n } else {\n combatAudio.playCombatMusic(2000);\n }\n }, [combatActions, addCombatMessage, validPlayers, combatAudio]);\n\n const hasAutoStartedRef = useRef(false);\n\n useEffect(() => {\n if (matchCountdownComplete && !hasAutoStartedRef.current) {\n hasAutoStartedRef.current = true;\n combatActions.setRoundStarted(true);\n addCombatMessage(\"라운드 시작!\", \"Round Start!\");\n\n const player = validPlayers[0];\n if (player?.archetype) {\n const playerArchetype = player.archetype.toLowerCase();\n combatAudio.playArchetypeMusic(playerArchetype, 2000);\n } else {\n combatAudio.playCombatMusic(2000);\n }\n }\n }, [\n matchCountdownComplete,\n combatActions,\n addCombatMessage,\n validPlayers,\n combatAudio,\n ]);\n\n const adaptiveDifficulty = useMemo(() => new AdaptiveDifficulty(), []);\n\n useEffect(() => {\n try {\n const savedMetrics = localStorage.getItem(\"ai_difficulty_metrics\");\n if (savedMetrics) {\n adaptiveDifficulty.importMetrics(savedMetrics);\n }\n } catch (err) {\n console.warn(\"Failed to load AI difficulty metrics:\", err);\n }\n\n return () => {\n try {\n const metrics = adaptiveDifficulty.exportMetrics();\n localStorage.setItem(\"ai_difficulty_metrics\", metrics);\n } catch (err) {\n console.warn(\"Failed to save AI difficulty metrics:\", err);\n }\n };\n }, [adaptiveDifficulty]);\n\n const aiPersonality = useMemo(\n () => getPersonalityByArchetype(validPlayers[1].archetype),\n [validPlayers],\n );\n\n const handleAIStanceChange = useCallback(\n (stance: TrigramStance) => {\n const currentStance = validPlayers[1].currentStance;\n\n player2Animation.transitionToStanceChange(currentStance, stance);\n\n onPlayerUpdate(1, { currentStance: stance });\n addCombatMessage(\n `AI 자세 변경: ${stance}`,\n `AI Stance Change: ${stance}`,\n );\n },\n [validPlayers, player2Animation, onPlayerUpdate, addCombatMessage],\n );\n\n const handleEffectComplete = useCallback(\n (effectId: string) => {\n combatActions.removeHitEffect(effectId);\n },\n [combatActions],\n );\n\n const createHitEffect = useCallback(\n (\n id: string,\n type: HitEffectType,\n position: Position,\n intensity: number,\n ): HitEffect => ({\n id,\n type,\n attackerId: \"player1\",\n defenderId: \"player2\",\n timestamp: Date.now(),\n duration: 1000,\n position,\n intensity,\n startTime: Date.now(),\n }),\n [],\n );\n\n const addHitEffect = useCallback(\n (type: HitEffectType, position: Position, intensity: number = 1) => {\n const effect = createHitEffect(\n `effect_${Date.now()}`,\n type,\n position,\n intensity,\n );\n combatActions.addHitEffect(effect);\n },\n [createHitEffect, combatActions],\n );\n\n const handlePlayerPositionUpdate = useCallback(\n (playerIndex: number, position: Position) => {\n if (playerIndex === 0) {\n setPlayer1Position(position);\n onPlayerUpdate(0, { position });\n } else if (playerIndex === 1) {\n onPlayerUpdate(1, { position });\n }\n },\n [onPlayerUpdate, setPlayer1Position],\n );\n\n const handleInjuryCreated = useCallback(\n (injury: Injury, targetPlayerIndex: number) => {\n const updateInjuries = (prev: readonly Injury[]): readonly Injury[] => {\n const recentHitTime = 5000; // 5 seconds\n const now = Date.now();\n\n const recentHit = prev.find(\n (existing) =>\n existing.region === injury.region &&\n now - existing.timestamp < recentHitTime &&\n existing.type === InjuryType.BRUISE &&\n injury.type === InjuryType.BRUISE,\n );\n\n if (recentHit) {\n const newHitCount = recentHit.hitCount + 1;\n const escalatedSeverity = Math.min(1.0, recentHit.severity + 0.15);\n\n return prev.map((existing) =>\n existing.id === recentHit.id\n ? {\n ...existing,\n hitCount: newHitCount,\n severity: escalatedSeverity,\n timestamp: now, // Update timestamp for progressive tracking\n }\n : existing,\n );\n }\n\n return [...prev, injury];\n };\n\n if (targetPlayerIndex === 0) {\n setPlayer1Injuries(updateInjuries);\n } else if (targetPlayerIndex === 1) {\n setPlayer2Injuries(updateInjuries);\n }\n },\n [],\n );\n\n const {\n handleAttack,\n handleDefend,\n handleStanceSwitch,\n handleStanceSideSwitch,\n handleAIAttack,\n handleAIDefend,\n handleAITechnique,\n moveAIPlayer,\n } = useCombatActions({\n validPlayers,\n playerPositions: [playerPositions[0], playerPositions[1]],\n combatState,\n combatActions,\n combatSystem,\n onPlayerUpdate,\n onPlayerPositionUpdate: handlePlayerPositionUpdate,\n onLateralityUpdate: (playerIndex, laterality) => {\n combatActions.setPlayerLateralityIndex(playerIndex as 0 | 1, laterality);\n },\n onInjuryCreated: handleInjuryCreated,\n addCombatMessage,\n addHitEffect,\n arenaBounds,\n combatAudio,\n playerAnimations: {\n player1: player1Animation,\n player2: player2Animation,\n },\n });\n\n useEffect(() => {\n handleAttackRef.current = handleAttack;\n }, [handleAttack]);\n\n const techniqueSelection = useTechniqueSelection({\n player: player1WithLocalStance,\n enabled:\n !isPaused &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart,\n onTechniqueExecute: useCallback(\n (technique: Technique) => {\n feedbackActions.showTechnique(\n technique.name.korean,\n technique.name.english,\n );\n\n const animationName = resolveTechniqueAnimation(technique);\n setPlayer1AttackAnimation(animationName);\n\n setPlayer1TechniqueId(technique.id);\n\n const attackDuration = preparePlayer1AttackTiming(animationName);\n player1Animation.transitionToAttack(attackDuration);\n combatActions.setExecutingTechnique(true);\n\n onPlayerUpdate(0, {\n stamina: Math.max(0, validPlayers[0].stamina - technique.staminaCost),\n ki: Math.max(0, validPlayers[0].ki - technique.kiCost),\n });\n\n handleAttack(technique);\n\n addCombatMessage(\n `${technique.name.korean} 사용!`,\n `Used ${technique.name.english}!`,\n );\n },\n [\n validPlayers,\n onPlayerUpdate,\n feedbackActions,\n handleAttack,\n addCombatMessage,\n player1Animation,\n combatActions,\n preparePlayer1AttackTiming,\n ],\n ),\n });\n\n const cooldownsMap = useMemo(() => {\n const map = new Map<string, number>();\n techniqueSelection.activeCooldowns.forEach((cd) => {\n map.set(cd.techniqueId, cd.remaining);\n });\n return map;\n }, [techniqueSelection.activeCooldowns]);\n\n const [previousStance, setPreviousStance] = useState<number>(0);\n\n const currentPlayerStance = validPlayers[0].currentStance;\n const currentStanceIndex = useMemo(() => {\n return STANCE_INDEX_MAP.get(currentPlayerStance) ?? 0;\n }, [currentPlayerStance]);\n\n const handleStanceChangeWithAnimation = useCallback(\n (newStance: TrigramStance) => {\n const currentStance = validPlayers[0].currentStance;\n\n // Full trigram stance change; laterality-only side switches use handleStanceSideSwitch.\n const success = player1Animation.transitionToStanceChange(\n currentStance,\n newStance,\n );\n\n if (success) {\n const prevStance = STANCE_INDEX_MAP.get(currentStance) ?? 0;\n setPreviousStance(prevStance);\n\n setPlayer1LocalStance(newStance);\n\n handleStanceSwitch(newStance);\n\n playStanceChangeSound();\n }\n },\n [validPlayers, player1Animation, handleStanceSwitch, playStanceChangeSound],\n );\n\n const player1Health = validPlayers[0].health;\n const player2Health = validPlayers[1].health;\n\n const lastPlayer2HealthRef = useRef(player2Health);\n useEffect(() => {\n const currentHealth = player2Health;\n const previousHealth = lastPlayer2HealthRef.current;\n const damageDone = previousHealth - currentHealth;\n\n if (damageDone > 0 && combatState.roundStarted && !combatState.roundEnded) {\n const getDamageType = (): \"critical\" | \"vital\" | \"normal\" => {\n if (damageDone >= 25) return \"critical\";\n if (damageDone >= 20) return \"vital\";\n return \"normal\";\n };\n const damageType = getDamageType();\n\n feedbackActions.addDamageNumber(\n Math.round(damageDone),\n playerPositions[1],\n damageType,\n );\n\n feedbackActions.incrementCombo();\n\n if (damageType === \"critical\") {\n feedbackActions.addActionFeedback(\n \"critical\",\n \"Critical!\",\n \"치명타!\",\n playerPositions[0],\n );\n }\n }\n\n lastPlayer2HealthRef.current = currentHealth;\n }, [\n player2Health,\n validPlayers,\n playerPositions,\n feedbackActions,\n combatState.roundStarted,\n combatState.roundEnded,\n ]);\n\n const lastPlayer1HealthRef = useRef(player1Health);\n useEffect(() => {\n const currentHealth = player1Health;\n const previousHealth = lastPlayer1HealthRef.current;\n const damageDone = previousHealth - currentHealth;\n\n if (damageDone > 0 && combatState.roundStarted && !combatState.roundEnded) {\n const damageType =\n damageDone >= 20 ? (\"critical\" as const) : (\"normal\" as const);\n feedbackActions.addDamageNumber(\n Math.round(damageDone),\n playerPositions[0],\n damageType,\n );\n }\n\n lastPlayer1HealthRef.current = currentHealth;\n }, [\n player1Health,\n validPlayers,\n playerPositions,\n feedbackActions,\n combatState.roundStarted,\n combatState.roundEnded,\n ]);\n\n const handleAttackWithFeedback = useCallback(() => {\n const basicTechnique = techniqueSelection.availableTechniques[0];\n const animationName = basicTechnique\n ? resolveTechniqueAnimation(basicTechnique)\n : \"jab\";\n setPlayer1AttackAnimation(animationName);\n if (basicTechnique?.id) {\n setPlayer1TechniqueId(basicTechnique.id);\n }\n\n const attackDuration = preparePlayer1AttackTiming(animationName);\n const success = player1Animation.transitionToAttack(attackDuration);\n if (success) {\n combatActions.setExecutingTechnique(true);\n } else {\n console.warn(\n \"Attack animation transition failed; executing attack logic directly.\",\n );\n handleAttack();\n }\n }, [\n player1Animation,\n combatActions,\n handleAttack,\n techniqueSelection.availableTechniques,\n preparePlayer1AttackTiming,\n ]);\n\n const handleDefendWithFeedback = useCallback(() => {\n const defenderPos = playerPositions[0];\n const success = player1Animation.transitionTo(AnimationState.DEFEND);\n if (success) {\n handleDefend();\n feedbackActions.addActionFeedback(\n \"blocked\",\n \"Blocked\",\n \"방어!\",\n defenderPos,\n );\n } else {\n console.warn(\n \"Defend animation transition failed; executing defend logic directly.\",\n );\n handleDefend();\n feedbackActions.addActionFeedback(\n \"blocked\",\n \"Blocked\",\n \"방어!\",\n defenderPos,\n );\n }\n }, [handleDefend, playerPositions, feedbackActions, player1Animation]);\n\n /**\n * Helper function to execute fallback recovery animation\n * when a specific recovery type cannot be performed.\n *\n * Determines the appropriate recovery type based on ground state\n * and transitions to that animation.\n *\n * @korean 대체회복실행\n */\n const executeFallbackRecovery = useCallback(() => {\n const groundState = balanceSystem.getGroundState(\n player1Animation.currentState,\n );\n if (groundState) {\n const recoveryType = determineRecoveryType(groundState);\n const animationState = getRecoveryAnimationState(recoveryType);\n player1Animation.transitionTo(animationState as AnimationState);\n }\n }, [balanceSystem, player1Animation]);\n\n const { queuedInputs, showHints } = useKeyboardControls({\n onStanceChange: useCallback(\n (stanceIndex: number) => {\n const stance = TRIGRAM_STANCES_ORDER[stanceIndex];\n if (stance) {\n handleStanceChangeWithAnimation(stance);\n }\n },\n [handleStanceChangeWithAnimation],\n ),\n onAction: useCallback(\n (action: string) => {\n switch (action) {\n case \"attack\":\n techniqueSelection.executeTechnique();\n break;\n case \"block\":\n handleDefendWithFeedback();\n break;\n case \"recovery_quick\": {\n executeFallbackRecovery();\n break;\n }\n case \"recovery_roll\": {\n const player1 = players[0];\n if (balanceSystem.canRecoverWithType(player1, \"roll_recovery\")) {\n const updatedPlayer = balanceSystem.applyRecoveryCost(\n player1,\n \"roll_recovery\",\n );\n onPlayerUpdate(0, { stamina: updatedPlayer.stamina });\n player1Animation.transitionTo(AnimationState.RECOVERY_ROLL);\n } else {\n audio.playSFX(\"menu_error\");\n const player1Pos = playerPositions[0];\n feedbackActions.addActionFeedback(\n \"blocked\",\n \"Not enough stamina!\",\n \"체력 부족!\",\n player1Pos,\n );\n executeFallbackRecovery();\n }\n break;\n }\n case \"recovery_defensive\": {\n player1Animation.transitionTo(AnimationState.RECOVERY_DEFENSIVE);\n break;\n }\n\n case \"footwork_circular_left\":\n case \"footwork_circular_right\":\n case \"footwork_slide_forward\":\n case \"footwork_slide_back\":\n case \"footwork_pivot_left\":\n case \"footwork_pivot_right\":\n case \"footwork_shuffle\":\n player1Animation.transitionTo(action as AnimationState);\n break;\n\n case \"stance_side_switch\":\n player1Animation.transitionTo(AnimationState.STANCE_SIDE_SWITCH);\n handleStanceSideSwitch(PLAYER_ONE_INDEX);\n break;\n\n }\n },\n [\n techniqueSelection,\n handleDefendWithFeedback,\n executeFallbackRecovery,\n balanceSystem,\n player1Animation,\n handleStanceSideSwitch,\n players,\n onPlayerUpdate,\n audio,\n feedbackActions,\n playerPositions,\n ],\n ),\n enabled:\n !isPaused &&\n !showPauseMenu &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart &&\n !combatState.isExecutingTechnique,\n currentStance: currentStanceIndex,\n playSFX: audio.playSFX,\n currentAnimationState: player1Animation.currentState,\n });\n\n const [stanceWheelExpanded, setStanceWheelExpanded] = useState(false);\n const activeMobileKeyRef = useRef<string | null>(null);\n\n /**\n * Mobile touch control handler - Converts VirtualDPad touch inputs to keyboard events\n *\n * Dispatches synthetic KeyboardEvents with proper properties to ensure compatibility\n * with usePlayerMovement hook. The synthetic events include:\n * - key: The character key (w/a/s/d)\n * - code: The physical key code (KeyW/KeyA/KeyS/KeyD)\n * - bubbles: true - Allows event to propagate through DOM\n * - cancelable: true - Allows event to be prevented\n *\n * These properties are essential for the keyboard event listeners in inputSystem.ts\n * to properly recognize and process the movement commands.\n *\n * @param direction - The D-pad direction or null\n * @param eventType - 'start' for press, 'end' for release\n */\n const handleMobileMove = useCallback(\n (direction: Direction | null, eventType: DPadEventType) => {\n const directionMap: Record<Direction, string> = {\n up: \"w\",\n \"up-right\": \"w\", // Diagonal simplified to primary direction\n right: \"d\",\n \"down-right\": \"s\",\n down: \"s\",\n \"down-left\": \"s\",\n left: \"a\",\n \"up-left\": \"w\",\n };\n\n if (eventType === \"start\" && direction) {\n if (\n activeMobileKeyRef.current &&\n activeMobileKeyRef.current !== directionMap[direction]\n ) {\n const prevKey = activeMobileKeyRef.current;\n window.dispatchEvent(\n new KeyboardEvent(\"keyup\", {\n key: prevKey,\n code: `Key${prevKey.toUpperCase()}`,\n bubbles: true,\n cancelable: true,\n }),\n );\n }\n\n const key = directionMap[direction];\n activeMobileKeyRef.current = key;\n window.dispatchEvent(\n new KeyboardEvent(\"keydown\", {\n key,\n code: `Key${key.toUpperCase()}`,\n bubbles: true,\n cancelable: true,\n }),\n );\n } else if (eventType === \"end\") {\n if (activeMobileKeyRef.current) {\n const key = activeMobileKeyRef.current;\n window.dispatchEvent(\n new KeyboardEvent(\"keyup\", {\n key,\n code: `Key${key.toUpperCase()}`,\n bubbles: true,\n cancelable: true,\n }),\n );\n activeMobileKeyRef.current = null;\n }\n }\n },\n [],\n );\n\n const handleMobileAttack = useCallback(() => {\n techniqueSelection.executeTechnique();\n }, [techniqueSelection]);\n\n const handleMobileBlock = useCallback(\n (eventType: ButtonEventType) => {\n if (eventType === \"start\") {\n handleDefendWithFeedback();\n }\n },\n [handleDefendWithFeedback],\n );\n\n const handleMobileStanceChange = useCallback(\n (stanceIndex: number) => {\n const stance = TRIGRAM_STANCES_ORDER[stanceIndex];\n if (stance) {\n handleStanceChangeWithAnimation(stance);\n }\n },\n [handleStanceChangeWithAnimation],\n );\n\n const handleMobileGesture = useCallback(\n (gesture: GestureEvent) => {\n switch (gesture.type) {\n case \"swipe-right\":\n window.dispatchEvent(new KeyboardEvent(\"keydown\", { key: \"d\" }));\n setTimeout(() => {\n window.dispatchEvent(new KeyboardEvent(\"keyup\", { key: \"d\" }));\n }, 100);\n break;\n case \"swipe-left\":\n window.dispatchEvent(new KeyboardEvent(\"keydown\", { key: \"a\" }));\n setTimeout(() => {\n window.dispatchEvent(new KeyboardEvent(\"keyup\", { key: \"a\" }));\n }, 100);\n break;\n case \"swipe-up\":\n techniqueSelection.executeTechnique();\n break;\n case \"swipe-down\":\n techniqueSelection.executeTechnique();\n break;\n case \"two-finger-tap\":\n audio.playSFX(\"menu_select\");\n break;\n }\n },\n [techniqueSelection, audio],\n );\n\n const toggleStanceWheel = useCallback(() => {\n setStanceWheelExpanded((prev) => !prev);\n }, []);\n\n const mobileControlsEnabled =\n isMobile &&\n !isPaused &&\n !showPauseMenu &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart &&\n !combatState.isExecutingTechnique;\n\n\n useEffect(() => {\n if (isPaused) return;\n\n if (timeRemaining <= 0 && !combatState.roundEnded) {\n combatActions.setRoundEnded(true);\n combatActions.setRoundStarted(false);\n combatActions.setRoundDisplayStatus(\"end\");\n\n combatAudio.stopCombatMusic(1000);\n\n const winner = validPlayers[0].health > validPlayers[1].health ? 0 : 1;\n const roundWinner = validPlayers[winner];\n\n updateMatchScore(winner);\n\n addCombatMessage(\"라운드 종료!\", \"Round Over!\");\n\n setTimeout(() => {\n startTransition(roundWinner, internalRound);\n }, 1500);\n }\n }, [\n timeRemaining,\n combatState.roundEnded,\n combatState.roundStarted,\n validPlayers,\n onGameEnd,\n addCombatMessage,\n internalRound,\n isPaused,\n combatActions,\n combatAudio,\n startTransition,\n updateMatchScore,\n ]);\n\n const executeAIActionCallbackRef = useRef<\n | ((\n action: string,\n targetPos?: Position,\n selectedTechnique?: KoreanTechnique,\n targetVitalPoint?: string,\n ) => void)\n | undefined\n >(undefined);\n\n const { updateDifficultyTarget } = useAICombat({\n player: validPlayers[1],\n opponent: validPlayers[0],\n personality: aiPersonality,\n adaptiveDifficulty,\n isPaused,\n roundStarted: combatState.roundStarted,\n roundEnded: combatState.roundEnded,\n arenaBounds,\n onExecuteAction: (action, targetPos, selectedTechnique, targetVitalPoint) =>\n executeAIActionCallbackRef.current?.(\n action,\n targetPos,\n selectedTechnique,\n targetVitalPoint,\n ),\n onStanceChange: handleAIStanceChange,\n onLateralityChange: () => handleStanceSideSwitch(1), // AI player (index 1)\n playerLaterality: combatState.playerLaterality[1], // AI's own laterality\n opponentLaterality: combatState.playerLaterality[0], // Opponent (human) laterality\n });\n\n const currentDifficultyTier = useMemo(\n () => adaptiveDifficulty.getDifficultyTier(),\n [adaptiveDifficulty],\n );\n\n useEffect(() => {\n if (!combatState.roundEnded || internalRound < 1) {\n return;\n }\n\n const roundsCompleted = internalRound;\n if (roundsCompleted % 2 === 0) {\n const player1 = validPlayersRef.current[0];\n\n adaptiveDifficulty.updateSkillMetrics({\n hitsLanded: player1.hitsLanded ?? 0,\n totalAttacks: (player1.hitsLanded ?? 0) + (player1.misses ?? 0),\n combosExecuted: 0, // TODO (Phase 2): Track combo count in PlayerState\n perfectBlockCount: 0, // TODO (Phase 2): Track perfect blocks in PlayerState\n avgReactionTimeMs: 600, // TODO (Phase 2): Track player reaction time\n vitalPointsHit: 0, // TODO (Phase 2): Track vital point hits\n effectiveStanceChanges: 0, // TODO (Phase 2): Track stance changes\n damageDealt: player1.totalDamageDealt ?? 0,\n damageTaken: player1.totalDamageReceived ?? 0,\n });\n\n const newParams = adaptiveDifficulty.getDifficultyParameters();\n updateDifficultyTarget(newParams);\n\n if (import.meta.env.DEV) {\n const tier = adaptiveDifficulty.getDifficultyTier();\n console.log(\n `[DEV] Difficulty adjusted after round ${roundsCompleted}, new tier: ${tier}`,\n );\n }\n }\n }, [\n combatState.roundEnded,\n internalRound,\n adaptiveDifficulty,\n updateDifficultyTarget,\n ]);\n\n const executeAIActionCallback = useCallback(\n (\n action: string,\n targetPos?: Position,\n selectedTechnique?: KoreanTechnique,\n targetVitalPoint?: string,\n ) => {\n const aiStance = validPlayers[1]?.currentStance ?? TrigramStance.GEON;\n const aiFallbackTechnique = TRIGRAM_TECHNIQUES[aiStance]?.[0];\n const aiFallbackAnim = aiFallbackTechnique\n ? resolveTechniqueAnimation(aiFallbackTechnique)\n : \"jab\";\n switch (action) {\n case \"attack\":\n if (selectedTechnique) {\n const p2AttackAnimName = resolveTechniqueAnimation(selectedTechnique);\n setPlayer2AttackAnimation(p2AttackAnimName);\n\n if (selectedTechnique.id) {\n setPlayer2TechniqueId(selectedTechnique.id);\n }\n const p2AttackAnim = getAnimation(p2AttackAnimName);\n const p2AttackDur = p2AttackAnim?.duration ?? 0.55;\n setPlayer2AttackDuration(p2AttackDur);\n player2Animation.transitionToAttack(p2AttackDur);\n } else {\n setPlayer2AttackAnimation(aiFallbackAnim);\n if (aiFallbackTechnique?.id) {\n setPlayer2TechniqueId(aiFallbackTechnique.id);\n }\n const p2FallbackAnim = getAnimation(aiFallbackAnim);\n const p2FallbackDur = p2FallbackAnim?.duration ?? 0.55;\n setPlayer2AttackDuration(p2FallbackDur);\n player2Animation.transitionToAttack(p2FallbackDur);\n }\n handleAIAttack(selectedTechnique, targetVitalPoint);\n break;\n case \"defend\":\n player2Animation.transitionTo(AnimationState.DEFEND);\n handleAIDefend();\n break;\n case \"technique\":\n case \"combo\":\n if (selectedTechnique) {\n const p2TechAnimName = resolveTechniqueAnimation(selectedTechnique);\n setPlayer2AttackAnimation(p2TechAnimName);\n\n if (selectedTechnique.id) {\n setPlayer2TechniqueId(selectedTechnique.id);\n }\n const p2TechAnim = getAnimation(p2TechAnimName);\n const p2TechDur = p2TechAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2TechDur);\n player2Animation.transitionToAttack(p2TechDur);\n } else {\n setPlayer2AttackAnimation(aiFallbackAnim);\n if (aiFallbackTechnique?.id) {\n setPlayer2TechniqueId(aiFallbackTechnique.id);\n }\n const p2FallbackAnim = getAnimation(aiFallbackAnim);\n const p2FallbackDur = p2FallbackAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2FallbackDur);\n player2Animation.transitionToAttack(p2FallbackDur);\n }\n handleAITechnique(selectedTechnique, targetVitalPoint);\n break;\n case \"approach\":\n case \"retreat\":\n case \"circle\":\n if (targetPos) {\n moveAIPlayer(targetPos);\n }\n break;\n case \"feint\":\n {\n const playerPos = validPlayers[0].position;\n const feintOffsetMeters = 0.5;\n const feintPos = {\n x: playerPos.x + (Math.random() - 0.5) * feintOffsetMeters,\n y: playerPos.y + (Math.random() - 0.5) * feintOffsetMeters,\n };\n moveAIPlayer(feintPos);\n addCombatMessage(\"AI 페인트\", \"AI Feint\");\n\n setTimeout(() => {\n if (\n !combatState.roundEnded &&\n combatState.roundStarted &&\n validPlayers.length >= 2\n ) {\n const currentPlayerPos = validPlayers[0].position;\n const currentAiPos = validPlayers[1].position;\n const dx = currentAiPos.x - currentPlayerPos.x;\n const dy = currentAiPos.y - currentPlayerPos.y;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n const retreatDistanceMeters = 0.8;\n const halfWidth = arenaBounds.worldWidthMeters / 2;\n const halfDepth = arenaBounds.worldDepthMeters / 2;\n const retreatPos = {\n x: Math.max(\n -halfWidth + 0.5, // 0.5m from edge\n Math.min(\n halfWidth - 0.5,\n currentPlayerPos.x + (dx / dist) * retreatDistanceMeters,\n ),\n ),\n y: Math.max(\n -halfDepth + 0.5, // 0.5m from edge\n Math.min(\n halfDepth - 0.5,\n currentPlayerPos.y + (dy / dist) * retreatDistanceMeters,\n ),\n ),\n };\n moveAIPlayer(retreatPos);\n }\n }, 200);\n }\n break;\n case \"counter\":\n if (selectedTechnique) {\n const p2CounterAnimName = resolveTechniqueAnimation(selectedTechnique);\n setPlayer2AttackAnimation(p2CounterAnimName);\n\n if (selectedTechnique.id) {\n setPlayer2TechniqueId(selectedTechnique.id);\n }\n const p2CounterAnim = getAnimation(p2CounterAnimName);\n const p2CounterDur = p2CounterAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2CounterDur);\n player2Animation.transitionToAttack(p2CounterDur);\n } else {\n setPlayer2AttackAnimation(aiFallbackAnim);\n if (aiFallbackTechnique?.id) {\n setPlayer2TechniqueId(aiFallbackTechnique.id);\n }\n const p2FallbackAnim = getAnimation(aiFallbackAnim);\n const p2FallbackDur = p2FallbackAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2FallbackDur);\n player2Animation.transitionToAttack(p2FallbackDur);\n }\n handleAIAttack(selectedTechnique, targetVitalPoint);\n addCombatMessage(\"AI 반격!\", \"AI Counter!\");\n break;\n }\n },\n [\n handleAIAttack,\n handleAIDefend,\n handleAITechnique,\n moveAIPlayer,\n addCombatMessage,\n validPlayers,\n arenaBounds,\n combatState.roundEnded,\n combatState.roundStarted,\n player2Animation,\n ],\n );\n\n useEffect(() => {\n executeAIActionCallbackRef.current = executeAIActionCallback;\n }, [executeAIActionCallback]);\n\n useEffect(() => {\n if (combatState.roundEnded && validPlayers.length === 2) {\n const player = validPlayers[0];\n const totalAttacks = (player.hitsLanded ?? 0) + (player.hitsTaken ?? 0);\n\n if (totalAttacks === 0) return;\n\n adaptiveDifficulty.updateSkillMetrics({\n hitsLanded: player.hitsLanded ?? 0,\n totalAttacks,\n combosExecuted: player.comboCount ?? 0,\n perfectBlockCount: 0,\n avgReactionTimeMs: 500,\n vitalPointsHit: player.vitalPointHits ?? 0,\n effectiveStanceChanges: 0,\n damageDealt: player.totalDamageDealt ?? 0,\n damageTaken: player.totalDamageReceived ?? 0,\n });\n }\n }, [combatState.roundEnded, adaptiveDifficulty, validPlayers]);\n\n const checkGameEnd = useCallback(() => {\n if (combatState.roundEnded) return;\n\n const p1Defeated = validPlayers[0].health <= 0;\n const p2Defeated = validPlayers[1].health <= 0;\n\n if (p1Defeated || p2Defeated) {\n combatActions.setRoundEnded(true);\n combatActions.setRoundStarted(false);\n combatActions.setRoundDisplayStatus(\"ko\");\n const winner = p1Defeated ? 1 : 0;\n const roundWinner = validPlayers[winner];\n\n updateMatchScore(winner);\n\n addCombatMessage(\n p1Defeated ? \"플레이어 1 패배\" : \"플레이어 1 승리!\",\n p1Defeated ? \"Player 1 Defeated\" : \"Player 1 Victory!\",\n );\n\n setTimeout(() => {\n startTransition(roundWinner, internalRound);\n }, 1500);\n }\n }, [\n validPlayers,\n addCombatMessage,\n combatState.roundEnded,\n combatActions,\n internalRound,\n startTransition,\n updateMatchScore,\n ]);\n\n useEffect(() => {\n checkGameEnd();\n }, [player1Health, player2Health, checkGameEnd]);\n\n useEffect(() => {\n const handleCombatInput = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n if (showPauseMenu) {\n handleResume();\n } else {\n handlePause();\n }\n return;\n }\n\n if (isPaused || showPauseMenu) {\n return;\n }\n\n if (!matchCountdownComplete || showRoundStart) {\n return;\n }\n\n if (\n !combatState.roundStarted ||\n combatState.roundEnded ||\n combatState.isExecutingTechnique\n ) {\n return;\n }\n\n const key = event.key.toLowerCase();\n\n if (key >= \"1\" && key <= \"8\") {\n const stanceIndex = parseInt(key) - 1;\n const stances: TrigramStance[] = [\n TrigramStance.GEON,\n TrigramStance.TAE,\n TrigramStance.LI,\n TrigramStance.JIN,\n TrigramStance.SON,\n TrigramStance.GAM,\n TrigramStance.GAN,\n TrigramStance.GON,\n ];\n handleStanceSwitch(stances[stanceIndex]);\n event.preventDefault();\n }\n\n if (key === \" \") {\n handleAttackWithFeedback();\n event.preventDefault();\n }\n\n if (event.key === \"Shift\") {\n handleDefendWithFeedback();\n event.preventDefault();\n }\n\n if (event.key === \"f\" || event.key === \"F\") {\n handleStanceSideSwitch(0); // Human player\n event.preventDefault();\n }\n };\n\n window.addEventListener(\"keydown\", handleCombatInput);\n return () => window.removeEventListener(\"keydown\", handleCombatInput);\n }, [\n combatState.roundStarted,\n combatState.roundEnded,\n combatState.isExecutingTechnique,\n matchCountdownComplete,\n showRoundStart,\n isPaused,\n showPauseMenu,\n handleStanceSwitch,\n handleStanceSideSwitch,\n handleAttackWithFeedback,\n handleDefendWithFeedback,\n handlePause,\n handleResume,\n ]);\n\n const player1MovementState = useMemo(() => {\n if (!validPlayers[0]?.bodyPartHealth) {\n return {\n statusText: { korean: \"정상\", english: \"Normal\" },\n isLimping: false,\n isSevereLimp: false,\n };\n }\n\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0,\n validPlayers[0].bodyPartHealth,\n validPlayers[0].currentStance ?? TrigramStance.GEON,\n validPlayers[0].pain ?? 0,\n );\n\n return {\n statusText: result.statusText,\n isLimping: result.isLimping,\n isSevereLimp: result.isSevereLimp,\n speedMultiplier: result.speedMultiplier,\n };\n }, [validPlayers]);\n\n const player2MovementState = useMemo(() => {\n if (!validPlayers[1]?.bodyPartHealth) {\n return {\n statusText: { korean: \"정상\", english: \"Normal\" },\n isLimping: false,\n isSevereLimp: false,\n };\n }\n\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0,\n validPlayers[1].bodyPartHealth,\n validPlayers[1].currentStance ?? TrigramStance.GEON,\n validPlayers[1].pain ?? 0,\n );\n\n return {\n statusText: result.statusText,\n isLimping: result.isLimping,\n isSevereLimp: result.isSevereLimp,\n speedMultiplier: result.speedMultiplier,\n };\n }, [validPlayers]);\n\n return (\n <div\n style={{\n width: `${width}px`,\n height: `${height}px`,\n position: \"relative\",\n backgroundColor: toHexColor(KOREAN_COLORS.UI_BACKGROUND_DARK),\n overflow: \"hidden\", // Prevent content from extending beyond container\n }}\n data-testid=\"combat-screen\"\n >\n {/* Three.js Canvas for 3D rendering */}\n <Canvas\n style={{ width: `${width}px`, height: `${height}px` }}\n camera={{\n position: cameraConfig.position,\n fov: cameraConfig.fov,\n near: cameraConfig.near,\n far: cameraConfig.far,\n }}\n gl={{\n antialias: renderConfig.antialias,\n alpha: false,\n powerPreference: \"high-performance\",\n failIfMajorPerformanceCaveat: false,\n }}\n dpr={renderConfig.dpr}\n shadows={false} // Temporarily disable shadows\n onCreated={({ gl }) => {\n gl.setClearColor(theme.colors.UI_BACKGROUND_DARK, 1);\n }}\n >\n {/* Lighting - CombatArena3D provides ambient, we add directional for shadows */}\n <ambientLight intensity={0.6} />\n <directionalLight position={[10, 10, 5]} intensity={1.2} />\n\n {/* Adaptive Quality Wrapper monitors FPS and adjusts quality */}\n <AdaptiveQualityWrapper\n enabled={shouldEnableAdaptiveQuality}\n isMobile={isMobile}\n >\n {/* Performance overlay (dev mode) - controlled by showPerformanceOverlay prop */}\n {showPerformanceOverlay && !isMobile && !showPerformanceMonitor && (\n <PerformanceOverlay3D />\n )}\n\n {/* Combat Arena 3D Environment - uses physics-based world dimensions */}\n <CombatArena3D\n lighting=\"cyberpunk\"\n scale={arenaBounds.scale}\n worldWidthMeters={arenaBounds.worldWidthMeters}\n worldDepthMeters={arenaBounds.worldDepthMeters}\n />\n\n {/* Animation updater - updates both player animations at 60fps */}\n <AnimationUpdater\n player1Animation={player1Animation}\n player2Animation={player2Animation}\n />\n\n {/* Acceleration updater - tracks player 1 movement time and updates speed */}\n <AccelerationUpdater\n isMoving={player1IsMoving}\n velocity={player1Velocity}\n movementTimeRef={player1MovementTimeRef}\n lastDirectionRef={player1LastDirectionRef}\n onSpeedUpdate={setPlayer1AccelerationBasedSpeed}\n walkSpeed={player1WalkRunSpeeds.walkSpeed}\n runSpeed={player1WalkRunSpeeds.runSpeed}\n />\n\n {/* Player 1 (Human) */}\n <Player3DWithTransitions\n {...convertPlayerStateToProps(\n validPlayers[0],\n player1PositionWithAttackMovement,\n player1Rotation,\n {\n isMobile,\n facing: \"right\",\n enableFacialExpressions: true,\n enableEyeTracking: true,\n opponentPosition: player2PositionWithAttackMovement,\n },\n )}\n currentAnimation={animationStateToPlayerAnimation(\n player1Animation.currentState,\n )}\n attackAnimation={player1AttackAnimation}\n laterality={combatState.playerLaterality[0]}\n enableTransitionEffects={!isMobile}\n enableStanceSymbol={!isMobile}\n enableStanceAudio={true}\n />\n\n {/* Player 2 (AI) */}\n <Player3DWithTransitions\n {...convertPlayerStateToProps(\n validPlayers[1],\n player2PositionWithAttackMovement,\n player2Rotation,\n {\n isMobile,\n facing: \"right\",\n enableFacialExpressions: true,\n enableEyeTracking: true,\n opponentPosition: player1PositionWithAttackMovement,\n },\n )}\n currentAnimation={animationStateToPlayerAnimation(\n player2Animation.currentState,\n )}\n attackAnimation={player2AttackAnimation}\n laterality={combatState.playerLaterality[1]}\n enableTransitionEffects={!isMobile}\n enableStanceSymbol={!isMobile}\n enableStanceAudio={true}\n />\n\n {/* Movement Status Indicators - Korean/English Bilingual */}\n {/* Player 1 Movement Status */}\n {(player1MovementState.isLimping ||\n player1MovementState.isSevereLimp) && (\n <Html\n position={[\n player1Position3D[0],\n player1Position3D[1] + 2.5,\n player1Position3D[2],\n ]}\n center\n data-testid=\"player1-movement-status\"\n >\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: player1MovementState.isSevereLimp\n ? toHexColor(KOREAN_COLORS.TEXT_ERROR)\n : toHexColor(KOREAN_COLORS.ACCENT_GOLD),\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n textShadow: \"0 0 4px rgba(0,0,0,0.8)\",\n background: \"rgba(0, 0, 0, 0.6)\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n whiteSpace: \"nowrap\",\n }}\n >\n {player1MovementState.statusText.korean} |{\" \"}\n {player1MovementState.statusText.english}\n </div>\n </Html>\n )}\n\n {/* Player 2 Movement Status */}\n {(player2MovementState.isLimping ||\n player2MovementState.isSevereLimp) && (\n <Html\n position={[\n player2Position3D[0],\n player2Position3D[1] + 2.5,\n player2Position3D[2],\n ]}\n center\n data-testid=\"player2-movement-status\"\n >\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: player2MovementState.isSevereLimp\n ? toHexColor(KOREAN_COLORS.TEXT_ERROR)\n : toHexColor(KOREAN_COLORS.ACCENT_GOLD),\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n textShadow: \"0 0 4px rgba(0,0,0,0.8)\",\n background: \"rgba(0, 0, 0, 0.6)\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n whiteSpace: \"nowrap\",\n }}\n >\n {player2MovementState.statusText.korean} |{\" \"}\n {player2MovementState.statusText.english}\n </div>\n </Html>\n )}\n\n {/* Trauma Overlays - Injury Visualization (외상 오버레이 - 부상 시각화) */}\n {/* Player 1 Injuries */}\n <TraumaOverlay3D\n playerId=\"player\"\n health={validPlayers[0].health}\n injuries={player1Injuries}\n characterPosition={player1Position3D}\n isMobile={isMobile}\n showFractures={true}\n />\n\n {/* Player 2 Injuries */}\n <TraumaOverlay3D\n playerId=\"enemy\"\n health={validPlayers[1].health}\n injuries={player2Injuries}\n characterPosition={player2Position3D}\n isMobile={isMobile}\n showFractures={true}\n />\n\n {/* Hit Effects */}\n <HitEffects3D\n effects={combatState.hitEffects}\n onEffectComplete={handleEffectComplete}\n arenaBounds={arenaBounds}\n />\n\n {/* Combat Particle Effects - Blood viscosity, organ damage, audio (전투 입자 효과) */}\n <CombatParticleEffects3D\n hitEffects={combatState.hitEffects}\n enabled={true}\n isMobile={isMobile}\n />\n\n {/* Vital Point Overlay - Show on both players when V is pressed */}\n {overlayVisible && (\n <>\n {/* Player 1 Vital Points */}\n <VitalPointMarkers3D\n position={player1Position3D}\n visible={overlayVisible}\n severityFilter={severityFilters}\n regionFilter={regionFilter}\n searchQuery={searchQuery}\n showLabels={showLabels}\n scale={scale}\n animated={animated}\n onPointClick={() => {\n }}\n />\n\n {/* Player 2 Vital Points */}\n <VitalPointMarkers3D\n position={player2Position3D}\n visible={overlayVisible}\n severityFilter={severityFilters}\n regionFilter={regionFilter}\n searchQuery={searchQuery}\n showLabels={showLabels}\n scale={scale}\n animated={animated}\n onPointClick={() => {\n }}\n />\n\n {/* Vital Point Overlay Controls - only visible when overlay is active */}\n <VitalPointOverlayControlsHtml\n screenPosition={{\n top: `${layoutConstants.hudHeight + layoutConstants.padding}px`,\n left: `${layoutConstants.padding}px`,\n }}\n visible={overlayVisible}\n onVisibleChange={setOverlayVisible}\n severityFilters={severityFilters}\n onSeverityFiltersChange={setSeverityFilters}\n regionFilter={regionFilter}\n onRegionFilterChange={setRegionFilter}\n searchQuery={searchQuery}\n onSearchQueryChange={setSearchQuery}\n showLabels={showLabels}\n onShowLabelsChange={setShowLabels}\n animated={animated}\n onAnimatedChange={setAnimated}\n scale={scale}\n onScaleChange={setScale}\n isMobile={isMobile}\n />\n </>\n )}\n\n {/* Action Feedback - Damage Numbers */}\n <DamageNumbers\n damages={feedbackState.damageNumbers}\n isMobile={isMobile}\n arenaBounds={arenaBounds}\n />\n\n {/* Action Feedback - Action Indicators */}\n <ActionFeedback\n feedbacks={feedbackState.actionFeedbacks}\n isMobile={isMobile}\n arenaBounds={arenaBounds}\n />\n\n {/* Combo Counter */}\n <ComboCounter combo={feedbackState.comboCount} isMobile={isMobile} />\n\n {/* Technique Name Display */}\n {feedbackState.currentTechnique && (\n <TechniqueName\n korean={feedbackState.currentTechnique.korean}\n english={feedbackState.currentTechnique.english}\n isMobile={isMobile}\n onComplete={() => feedbackActions.hideTechnique()}\n />\n )}\n\n {/* Performance Overlay (Development Only) - Toggle with P key */}\n {import.meta.env.DEV && showPerformanceMonitor && (\n <PerformanceOverlay3D visible={true} />\n )}\n\n {/* Visual Feedback Components for Keyboard Controls */}\n <StanceChangeIndicator\n currentStance={currentStanceIndex}\n previousStance={previousStance}\n isMobile={isMobile}\n />\n\n <KeyboardHints\n visible={showHints}\n currentStance={currentStanceIndex}\n isMobile={isMobile}\n />\n\n <InputBufferDisplay queuedInputs={queuedInputs} isMobile={isMobile} />\n\n {/* 3D Balance Indicators - Positioned below top HUD, to the right of side HUDs */}\n {/* Player 1 Balance Indicator - Upper left area, below top HUD */}\n {validPlayers[0] && (\n <BalanceIndicatorOverlayHtml\n player={validPlayers[0] as BalancePlayerState}\n currentTime={currentTime}\n position={[\n -2.5, // Left side of arena (to the right of left HUD in 3D space)\n 2.5, // Upper area (below top HUD)\n -1.0, // Slightly forward toward camera\n ]}\n isMobile={isMobile}\n />\n )}\n\n {/* Player 2 Balance Indicator - Upper right area, below top HUD */}\n {validPlayers[1] && (\n <BalanceIndicatorOverlayHtml\n player={validPlayers[1] as BalancePlayerState}\n currentTime={currentTime}\n position={[\n 2.5, // Right side of arena (to the left of right HUD in 3D space)\n 2.5, // Upper area (below top HUD)\n -1.0, // Slightly forward toward camera\n ]}\n isMobile={isMobile}\n />\n )}\n\n {/* Mobile Touch Controls moved outside Canvas - using MobileControlsOverlay for reliable touch events */}\n\n {/* Performance Monitoring - FPS display (dev mode, toggle with P key) */}\n {process.env.NODE_ENV === \"development\" && showPerformanceMonitor && (\n <FPSMonitor\n enabled={true}\n warningThreshold={50}\n criticalThreshold={30}\n />\n )}\n </AdaptiveQualityWrapper>\n\n {/* Post-processing Effects - desktop high tier only for Android WebGL stability */}\n {renderConfig.postProcessing && (\n <EffectComposer multisampling={4}>\n <Bloom\n luminanceThreshold={0.9}\n luminanceSmoothing={0.9}\n mipmapBlur\n intensity={0.8}\n radius={0.4}\n />\n <Noise opacity={0.03} />\n <Vignette eskil={false} offset={0.1} darkness={0.3} />\n </EffectComposer>\n )}\n </Canvas>\n\n {/* Html UI Overlays (positioned absolutely over Canvas) */}\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n pointerEvents: \"none\",\n zIndex: Z_INDEX.HUD,\n overflow: \"clip\",\n }}\n >\n {/* Top HUD - Round info, timer, return to menu */}\n <CombatTopHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n currentRound={internalRound}\n totalRounds={3}\n timerState={timerState}\n showTimer={\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart\n }\n onReturnToMenu={onReturnToMenu}\n isPaused={isPaused || showPauseMenu}\n />\n\n {/* Left HUD - Player 1 stats.\n On mobile, side HUDs occlude the 3D arena in both portrait and\n landscape; collapse them away so the arena stays fully visible.\n Player status remains available via CombatPortraitStatusStrip and\n bottom combat controls. */}\n {!isMobile && (\n <CombatLeftHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n player={validPlayers[0]}\n laterality={combatState.playerLaterality[0]}\n isInGuard={player1Animation.isInStanceGuard()}\n speedModifiers={player1SpeedModifiers}\n />\n )}\n\n {/* Right HUD - Player 2/AI stats with difficulty indicator */}\n {!isMobile && (\n <CombatRightHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n player={validPlayers[1]}\n laterality={combatState.playerLaterality[1]}\n speedModifiers={player2SpeedModifiers}\n difficultyTier={currentDifficultyTier}\n />\n )}\n\n {/* Portrait-mobile HP/stamina strip. Replaces the hidden side HUDs\n so both players can still see their health at a glance without\n re-introducing arena occlusion. */}\n {isMobile && isPortrait && (\n <CombatPortraitStatusStrip\n width={width}\n height={height}\n player1={validPlayers[0]}\n player2={validPlayers[1]}\n positionScale={positionScale}\n topOffset={layoutConstants.hudHeight}\n />\n )}\n\n {/* Bottom HUD - Technique bar, volume, messages */}\n <CombatBottomHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n visible={\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart\n }\n techniques={techniqueSelection.availableTechniques}\n player={validPlayers[0]}\n selectedIndex={techniqueSelection.selectedIndex}\n cooldowns={cooldownsMap}\n onTechniqueSelect={techniqueSelection.selectTechnique}\n combatMessages={combatState.combatMessages}\n />\n\n {/* Player State Visual Indicators */}\n {/* Player 1 State Overlay - includes consciousness blur, pain vignette, etc.\n In portrait mobile the arena is already rendered in a compressed 3:4\n aspect ratio, so halve the fullscreen vignette/blur/flash intensity\n to avoid further obscuring the scene. */}\n <PlayerStateOverlayHtml\n pain={validPlayers[0].pain}\n balanceState={getBalanceState(validPlayers[0].balance)}\n position=\"left\"\n consciousness={validPlayers[0].consciousness}\n bloodLoss={0} // FIXME: bloodLoss property not yet added to PlayerState interface - overlay will not display until implemented\n stamina={validPlayers[0].stamina}\n isMobile={isMobile}\n intensityScale={isMobile && isPortrait ? 0.5 : 1}\n />\n\n {/* Note: Player 2 (AI) does not get fullscreen state overlays like consciousness blur */}\n {/* as those effects would incorrectly affect the player's view */}\n\n {/* Breathing Disruption Indicators */}\n {/* Player 1 Breathing Indicator - positioned near left HUD */}\n <div\n style={{\n position: \"absolute\",\n left: isMobile ? \"10px\" : \"20px\",\n top: isMobile ? \"120px\" : \"160px\",\n zIndex: Z_INDEX.HUD + 1,\n pointerEvents: \"none\",\n }}\n data-testid=\"player1-breathing-indicator-container\"\n >\n <BreathingIndicator player={validPlayers[0]} isMobile={isMobile} />\n </div>\n\n {/* Player 2 Breathing Indicator - positioned near right HUD */}\n <div\n style={{\n position: \"absolute\",\n right: isMobile ? \"10px\" : \"20px\",\n top: isMobile ? \"120px\" : \"160px\",\n zIndex: Z_INDEX.HUD + 1,\n pointerEvents: \"none\",\n }}\n data-testid=\"player2-breathing-indicator-container\"\n >\n <BreathingIndicator player={validPlayers[1]} isMobile={isMobile} />\n </div>\n\n {/* Pause Menu Overlay */}\n {(isPaused || showPauseMenu) && (\n <PauseMenu\n onResume={handleResume}\n onRestart={handleRestart}\n onReturnToMenu={onReturnToMenu}\n isMobile={isMobile}\n />\n )}\n </div>\n\n {/* Round Announcement Overlay */}\n {showAnnouncement && roundWinner && (\n <RoundAnnouncement\n roundNumber={transitionRoundNumber}\n roundWinner={roundWinner}\n currentScore={matchScore}\n roundStats={{\n damageDealt: roundWinner.totalDamageDealt ?? 0,\n hitsLanded: roundWinner.hitsLanded ?? 0,\n vitalPointsHit: roundWinner.vitalPointHits ?? 0,\n accuracy: calculateAccuracy(roundWinner),\n }}\n onCountdownComplete={() => {\n if (matchScore.player1 >= 2 || matchScore.player2 >= 2) {\n const winner = matchScore.player1 >= 2 ? 0 : 1;\n onGameEnd(winner);\n } else {\n skipCountdown();\n }\n }}\n onSkip={() => {\n if (matchScore.player1 >= 2 || matchScore.player2 >= 2) {\n const winner = matchScore.player1 >= 2 ? 0 : 1;\n onGameEnd(winner);\n } else {\n skipCountdown();\n }\n }}\n isMobile={isMobile}\n totalRounds={3}\n />\n )}\n\n {/* Match Start Countdown Overlay - only shows once at match start */}\n {showMatchCountdown && !hasShownMatchCountdown && (\n <MatchCountdown\n onComplete={() => {\n setHasShownMatchCountdown(true);\n setShowMatchCountdown(false);\n setMatchCountdownComplete(true);\n startRound();\n }}\n isMobile={isMobile}\n showSkip={false}\n />\n )}\n\n {/* Round Start Announcement for subsequent rounds */}\n {/* Note: showRoundStart is only set to true after round 1 ends, so no need for internalRound > 1 check */}\n {showRoundStart && (\n <RoundStartAnnouncement\n roundNumber={internalRound}\n duration={2}\n onComplete={() => {\n if (import.meta.env.DEV) {\n console.log(\n \"[DEV] Round start announcement complete for round\",\n internalRound,\n );\n }\n setShowRoundStart(false);\n startRound();\n }}\n isMobile={isMobile}\n />\n )}\n\n {/* Round Display Status - Brief status messages */}\n {contentReady && combatState.roundDisplayStatus && (\n <RoundDisplayStatus\n status={combatState.roundDisplayStatus}\n isMobile={isMobile}\n />\n )}\n\n {/* Mobile Controls - Pure DOM, rendered OUTSIDE Canvas for reliable touch events */}\n {/* Uses pure DOM handlers instead of drei's Html which can block touch events on mobile */}\n {isMobile && (\n <>\n <MobileControlsOverlay\n onMove={handleMobileMove}\n onAttack={handleMobileAttack}\n onBlock={handleMobileBlock}\n bottom={getMobileControlsBottom(height)}\n viewportWidth={width}\n viewportHeight={height}\n />\n\n <StanceWheelPure\n currentStance={currentStanceIndex}\n onStanceChange={handleMobileStanceChange}\n expanded={stanceWheelExpanded}\n onToggle={toggleStanceWheel}\n disabled={!mobileControlsEnabled}\n opacity={0.8}\n />\n\n <GestureRecognizerPure\n onGesture={handleMobileGesture}\n enabled={mobileControlsEnabled}\n showFeedback={true}\n minSwipeDistance={50}\n />\n </>\n )}\n </div>\n );\n};\n\nexport default CombatScreen3D;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CombatScreen3D.js","names":[],"sources":["../../../../src/components/screens/combat/CombatScreen3D.tsx"],"sourcesContent":["/**\n * CombatScreen3D - Three.js-based combat screen (Black Trigram 흑괘)\n *\n * Maintains all existing combat logic and state management\n * Uses Html overlays for UI and 3D meshes for game objects\n */\n\nimport { Canvas } from \"@react-three/fiber\";\nimport { Html } from \"@react-three/drei\";\nimport {\n Bloom,\n EffectComposer,\n Noise,\n Vignette,\n} from \"@react-three/postprocessing\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useAudio } from \"../../../audio/AudioProvider\";\nimport { useActionFeedback } from \"../../../hooks/useActionFeedback\";\nimport { useCombatTimer } from \"../../../hooks/useCombatTimer\";\nimport { useKeyboardControls } from \"../../../hooks/useKeyboardControls\";\nimport { usePlayerAnimation } from \"../../../hooks/usePlayerAnimation\";\nimport { useRoundTransition } from \"../../../hooks/useRoundTransition\";\nimport { useTechniqueSelection } from \"../../../hooks/useTechniqueSelection\";\nimport { useWebGLContextLossHandler } from \"../../../hooks/useWebGLContextLossHandler\";\nimport { useCombatAttackMovement } from \"./hooks/useCombatAttackMovement\";\nimport { HitEffect, PlayerState } from \"../../../systems\";\nimport { CombatSystem } from \"../../../systems/CombatSystem\";\nimport {\n AdaptiveDifficulty,\n getPersonalityByArchetype,\n} from \"../../../systems/ai\";\nimport {\n AnimationEvents,\n AnimationState,\n AnimationType,\n determineRecoveryType,\n getAnimation,\n getAnimationDurationOrFallback,\n getRecoveryAnimationState,\n resolveTechniqueAnimation,\n TARGET_ANIMATION_FPS,\n} from \"../../../systems/animation\";\nimport { BalanceSystem } from \"../../../systems/combat/BalanceSystem\";\nimport type { BalancePlayerState } from \"../../../systems/combat/BalanceSystem\";\nimport { HitEffectType } from \"../../../systems/effects\";\nimport { injuryMovementModifier } from \"../../../systems/movement/InjuryMovementModifier\";\nimport { TRIGRAM_STANCES_ORDER } from \"../../../systems/trigram/types\";\nimport { TRIGRAM_TECHNIQUES } from \"../../../systems/trigram/techniques\";\nimport type { KoreanTechnique } from \"../../../systems/vitalpoint/types\";\nimport {\n CombatState,\n GameMode,\n PlayerArchetype,\n Position,\n TrigramStance,\n} from \"../../../types\";\nimport { Injury, InjuryType } from \"../../../types/injury\";\nimport { Z_INDEX } from \"../../../types/LayoutTypes\";\nimport {\n COMBAT_TOP_HUD_HEIGHT_PERCENT,\n getMobileControlsBottom,\n} from \"../../../types/constants/layout\";\nimport {\n FONT_FAMILY,\n getPerformanceSettings,\n KOREAN_COLORS,\n ROUND_ANNOUNCEMENT_TIMINGS,\n} from \"@/types/constants\";\nimport { getAnimationTypeForTechnique } from \"../../../data/techniqueMappings\";\nimport { toHexColor } from \"../../../utils/colorHelpers\";\nimport { usePlayerMovement } from \"../../../utils/inputSystem\";\nimport { PerformanceOverlay3D } from \"../../../utils/performance\";\nimport { getHUDHeight } from \"../../../utils/responsiveLayout\";\nimport { getHUDPositionScale } from \"../../../utils/responsiveLayoutHelpers\";\nimport { createPlayerFromArchetype } from \"../../../utils/playerUtils\";\nimport { createCameraConfig } from \"../../../utils/sharedPhysicsConfig\";\nimport { useAdaptiveQuality } from \"../../shared/three/optimization\";\nimport { useKoreanTheme } from \"../../shared/base/useKoreanTheme\";\nimport {\n ActionFeedback,\n TechniqueName,\n} from \"../../shared/three/effects/ActionFeedback\";\nimport { DamageNumbers } from \"../../shared/three/effects/DamageNumbers\";\nimport HitEffects3D from \"../../shared/three/effects/HitEffects3D\";\nimport { VitalPointMarkers3D } from \"../../shared/three/effects/VitalPointMarkers3D\";\nimport { StanceChangeIndicator } from \"../../shared/three/indicators/StanceChangeIndicator\";\nimport { CombatArena3D } from \"../../shared/three/scene/CombatArena3D\";\nimport { BreathingIndicator } from \"../../shared/three/ui/BreathingIndicator\";\nimport { ComboCounter } from \"../../shared/three/ui/ComboCounter\";\nimport { VitalPointOverlayControlsHtml } from \"../../shared/three/ui/VitalPointOverlayControlsHtml\";\nimport { KeyboardHints } from \"./components/controls/KeyboardHints\";\nimport { MatchCountdown } from \"./components/feedback/MatchCountdown\";\nimport { RoundAnnouncement } from \"./components/feedback/RoundAnnouncementOverlayHtml\";\nimport { RoundDisplayStatus } from \"./components/feedback/RoundDisplayStatus\";\nimport { RoundStartAnnouncement } from \"./components/feedback/RoundStartAnnouncementOverlayHtml\";\nimport { InputBufferDisplay } from \"./components/indicators/InputBufferDisplay\";\nimport { GestureEvent } from \"../../../hooks/useTouchControls\";\nimport {\n MovementType,\n SpeedModifierSystem,\n} from \"../../../systems/physics/SpeedModifierSystem\";\nimport { Technique } from \"../../../types\";\nimport {\n animationStateToPlayerAnimation,\n convertPlayerStateToProps,\n getBalanceState,\n} from \"../../../utils/player3DHelpers\";\nimport {\n GestureRecognizerPure,\n MobileControlsOverlay,\n StanceWheelPure,\n} from \"../../shared/mobile\";\nimport { ButtonEventType } from \"../../shared/mobile/ActionButtons\";\nimport { Direction, DPadEventType } from \"../../shared/mobile/VirtualDPad\";\nimport { Player3DWithTransitions } from \"../../shared/three/models/Player3DWithTransitions\";\nimport { PauseMenu } from \"./components/controls/PauseMenu\";\nimport { TraumaOverlay3D } from \"./components/effects/TraumaOverlay3D\";\nimport { CombatParticleEffects3D } from \"./components/effects/CombatParticleEffects3D\";\nimport {\n CombatBottomHUD,\n CombatLeftHUD,\n CombatPortraitStatusStrip,\n CombatRightHUD,\n CombatTopHUD,\n} from \"./components/hud\";\nimport { FPSMonitor } from \"./components/hud/FPSMonitor\";\nimport { PlayerStateOverlayHtml } from \"./components/hud/PlayerStateOverlayHtml\";\nimport { BalanceIndicatorOverlayHtml } from \"../../ui/combat/BalanceIndicatorOverlayHtml\";\nimport {\n ANNOUNCEMENT_FADE_OUT_DELAY,\n calculateAccuracy,\n STANCE_INDEX_MAP,\n} from \"./helpers\";\nimport { AnimationUpdater } from \"./helpers/AnimationUpdater\";\nimport { AccelerationUpdater } from \"../../../systems/movement/helpers/AccelerationUpdater\";\nimport { isRunningSpeed } from \"../../../systems/movement/helpers/accelerationUtils\";\nimport { useAICombat } from \"./hooks/useAICombat\";\nimport { useCombatActions } from \"./hooks/useCombatActions\";\nimport { useCombatAudio } from \"./hooks/useCombatAudio\";\nimport { useCombatLayout } from \"./hooks/useCombatLayout\";\nimport { useCombatState } from \"./hooks/useCombatState\";\n\nconst PLAYER_ONE_INDEX = 0;\n\n/**\n * Props for the CombatScreen3D component.\n * Provides all state and callbacks required for the 3D combat screen.\n */\nexport interface CombatScreen3DProps {\n /**\n * Array of player states (expects exactly 2 players).\n * Each PlayerState contains all combat and status information for a player.\n */\n readonly players: readonly PlayerState[];\n /**\n * Callback to update a player's state by index.\n * @param playerIndex - Index of the player to update (0 or 1).\n * @param updates - Partial PlayerState with updated fields.\n */\n readonly onPlayerUpdate: (\n playerIndex: number,\n updates: Partial<PlayerState>,\n ) => void;\n /**\n * Current round number (1-based).\n */\n readonly currentRound: number;\n /**\n * Remaining time in seconds for the current round.\n */\n readonly timeRemaining: number;\n /**\n * Whether combat is currently paused.\n */\n readonly isPaused: boolean;\n /**\n * Callback when the user exits to the menu.\n */\n readonly onReturnToMenu: () => void;\n /**\n * Callback when the match ends, with the winner's index (0 or 1).\n * @param winner - Index of the winning player.\n */\n readonly onGameEnd: (winner: number) => void;\n /**\n * Optional game mode (affects rules/behavior).\n */\n readonly gameMode?: GameMode;\n /**\n * Canvas width in pixels. Defaults to 1200.\n */\n readonly width?: number;\n /**\n * Canvas height in pixels. Defaults to 800.\n */\n readonly height?: number;\n /**\n * Enable adaptive quality adjustment (default: true on mobile)\n */\n readonly enableAdaptiveQuality?: boolean;\n /**\n * Show performance overlay in dev mode (default: import.meta.env.DEV)\n */\n readonly showPerformanceOverlay?: boolean;\n}\n\n/**\n * CombatScreen3D Component\n * Three.js-based combat screen with 3D characters and effects\n */\n\n/**\n * AdaptiveQualityWrapper - Internal component to use adaptive quality hook\n * Must be inside Canvas to use useFrame from @react-three/fiber\n *\n * Hoisted outside CombatScreen3D to avoid \"Cannot create components during render\"\n * warnings from react-hooks/component-creation. Keeps the component type stable\n * across renders of the parent.\n */\nconst AdaptiveQualityWrapper: React.FC<{\n readonly enabled: boolean;\n readonly isMobile: boolean;\n readonly children: React.ReactNode;\n}> = ({ enabled, isMobile, children }) => {\n useAdaptiveQuality(enabled, isMobile, (newQuality) => {\n if (import.meta.env.DEV) {\n console.log(`[CombatScreen3D] Quality adjusted to: ${newQuality}`);\n }\n });\n\n return <>{children}</>;\n};\n\nexport const CombatScreen3D: React.FC<CombatScreen3DProps> = ({\n players,\n onPlayerUpdate,\n currentRound,\n timeRemaining,\n isPaused,\n onReturnToMenu,\n onGameEnd,\n width = 1200,\n height = 800,\n enableAdaptiveQuality,\n showPerformanceOverlay = import.meta.env.DEV,\n}) => {\n const [contentReady, setContentReady] = useState(false);\n\n const contextLossCountRef = useRef(0);\n\n useWebGLContextLossHandler({\n onContextLost: () => {\n console.warn(\"⚠️ WebGL context lost in CombatScreen\");\n contextLossCountRef.current += 1;\n setContentReady(false);\n },\n onContextRestored: () => {\n setTimeout(() => setContentReady(true), 100);\n },\n autoRestore: true,\n });\n\n useEffect(() => {\n const timer = setTimeout(() => setContentReady(true), 50);\n return () => clearTimeout(timer);\n }, []);\n\n const audio = useAudio();\n\n useEffect(() => {\n if (import.meta.env.DEV) {\n performance.mark(\"combat-3d-render-start\");\n return () => {\n performance.mark(\"combat-3d-render-end\");\n performance.measure(\n \"combat-3d-render\",\n \"combat-3d-render-start\",\n \"combat-3d-render-end\",\n );\n };\n }\n }, []);\n\n const { arenaBounds, isMobile, isPortrait, screenSize, layoutConstants } =\n useCombatLayout(width, height);\n\n const theme = useKoreanTheme({\n variant: \"primary\",\n size: \"md\",\n isMobile,\n });\n\n const positionScale = useMemo(\n () => getHUDPositionScale(screenSize, isMobile),\n [screenSize, isMobile],\n );\n\n const combatTopHudHeight = useMemo(\n () => getHUDHeight(height, COMBAT_TOP_HUD_HEIGHT_PERCENT) * positionScale,\n [height, positionScale],\n );\n\n const cameraConfig = useMemo(() => {\n const base = createCameraConfig(isMobile);\n if (!isPortrait) return base;\n return {\n ...base,\n fov: Math.min(80, base.fov + 15),\n position: [base.position[0], base.position[1], base.position[2] + 4] as [\n number,\n number,\n number,\n ],\n };\n }, [isMobile, isPortrait]);\n\n const renderConfig = useMemo(() => {\n const performanceSettings = getPerformanceSettings(width, isMobile);\n\n return {\n shadowMapSize: performanceSettings.shadowMapSize,\n dpr: performanceSettings.dpr,\n antialias: performanceSettings.antialias,\n maxParticles: performanceSettings.maxParticles,\n postProcessing: performanceSettings.postProcessing,\n };\n }, [isMobile, width]);\n\n const shouldEnableAdaptiveQuality = enableAdaptiveQuality ?? isMobile;\n\n const { state: combatState, actions: combatActions } = useCombatState();\n\n\n const [overlayVisible, setOverlayVisible] = useState(false);\n const [severityFilters, setSeverityFilters] = useState<\n import(\"../../../types/common\").VitalPointSeverity[]\n >([]);\n const [regionFilter, setRegionFilter] =\n useState<\n import(\"../../shared/three/ui/VitalPointOverlayControlsHtml\").BodyRegionFilter\n >(\"all\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [showLabels, setShowLabels] = useState(true);\n const [animated, setAnimated] = useState(true);\n const [scale, setScale] = useState(1.2); // Larger scale for better visibility in combat\n const [showPerformanceMonitor, setShowPerformanceMonitor] = useState(false);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"v\" || e.key === \"V\") {\n setOverlayVisible((prev) => !prev);\n audio.playSFX(\"menu_select\");\n }\n if (e.key === \"F9\" && import.meta.env.DEV) {\n e.preventDefault();\n setShowPerformanceMonitor((prev) => !prev);\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [audio]);\n\n const { state: feedbackState, actions: feedbackActions } = useActionFeedback({\n damageNumberDuration: 1500,\n actionFeedbackDuration: 1200,\n techniqueDuration: 2000,\n comboResetTime: 2000,\n });\n\n const combatAudio = useCombatAudio();\n const { playStanceChangeSound } = combatAudio;\n\n const [matchScore, setMatchScore] = useState({ player1: 0, player2: 0 });\n const matchScoreRef = useRef(matchScore);\n\n const updateMatchScore = useCallback((winner: 0 | 1) => {\n const newScore = {\n player1:\n winner === 0\n ? matchScoreRef.current.player1 + 1\n : matchScoreRef.current.player1,\n player2:\n winner === 1\n ? matchScoreRef.current.player2 + 1\n : matchScoreRef.current.player2,\n };\n matchScoreRef.current = newScore;\n setTimeout(() => setMatchScore(newScore), 0);\n }, []);\n\n const [internalRound, setInternalRound] = useState(currentRound);\n\n const [currentTime, setCurrentTime] = useState(() => Date.now());\n\n const [hasShownMatchCountdown, setHasShownMatchCountdown] = useState(true); // Already shown (skipped)\n const [showMatchCountdown, setShowMatchCountdown] = useState(false); // Don't show\n const [showRoundStart, setShowRoundStart] = useState(false);\n const [matchCountdownComplete, setMatchCountdownComplete] = useState(true); // Already complete (skipped)\n\n const [player1Position, setPlayer1Position] = useState<Position>({\n x: arenaBounds.worldWidthMeters * -0.1, // 10% left of center (~0.8m for 8m arena)\n y: 0, // Centered\n });\n\n const [showPauseMenu, setShowPauseMenu] = useState(false);\n\n const handlePause = useCallback(() => {\n setShowPauseMenu(true);\n audio.playSFX(\"menu_select\");\n }, [audio]);\n\n const handleResume = useCallback(() => {\n setShowPauseMenu(false);\n audio.playSFX(\"menu_select\");\n }, [audio]);\n\n const handleRestart = useCallback(() => {\n\n setInternalRound(1);\n setMatchScore({ player1: 0, player2: 0 });\n matchScoreRef.current = { player1: 0, player2: 0 };\n\n combatActions.setRoundEnded(false);\n combatActions.setRoundStarted(false);\n combatActions.setRoundDisplayStatus(null);\n\n onPlayerUpdate(0, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n onPlayerUpdate(1, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n\n setPlayer1Position({\n x: arenaBounds.worldWidthMeters * -0.1, // 10% left of center in meters\n y: 0, // Centered\n });\n onPlayerUpdate(1, {\n position: {\n x: arenaBounds.worldWidthMeters * 0.1, // 10% right of center in meters\n y: 0, // Centered\n },\n });\n\n setShowPauseMenu(false);\n setShowRoundStart(true);\n\n audio.playSFX(\"menu_select\");\n }, [audio, combatActions, onPlayerUpdate, arenaBounds, setPlayer1Position]);\n\n const handleRoundTransitionComplete = useCallback(() => {\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Round transition complete, checking match status\");\n }\n const currentScore = matchScoreRef.current;\n if (currentScore.player1 >= 2 || currentScore.player2 >= 2) {\n const matchWinner = currentScore.player1 >= 2 ? 0 : 1;\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Match over, winner:\", matchWinner);\n }\n onGameEnd(matchWinner);\n return; // Don't start next round\n }\n\n combatActions.resetRoundState();\n\n setInternalRound((prev) => {\n const nextRound = prev + 1;\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Incrementing round from\", prev, \"to\", nextRound);\n }\n setTimeout(() => {\n if (import.meta.env.DEV) {\n console.log(\n \"[DEV] Showing round start announcement for round\",\n nextRound,\n );\n }\n setShowRoundStart(true);\n }, ANNOUNCEMENT_FADE_OUT_DELAY);\n return nextRound;\n });\n\n onPlayerUpdate(0, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n onPlayerUpdate(1, {\n health: 100,\n stamina: 100,\n ki: 100,\n consciousness: 100,\n pain: 0,\n balance: 100,\n combatState: CombatState.IDLE,\n isStunned: false,\n isBlocking: false,\n });\n\n setPlayer1Position({\n x: arenaBounds.worldWidthMeters * -0.1, // 10% left of center in meters\n y: 0, // Centered\n });\n onPlayerUpdate(1, {\n position: {\n x: arenaBounds.worldWidthMeters * 0.1, // 10% right of center in meters\n y: 0, // Centered\n },\n });\n }, [\n combatActions,\n onGameEnd,\n onPlayerUpdate,\n arenaBounds,\n setPlayer1Position,\n ]);\n\n const {\n showAnnouncement,\n roundWinner,\n currentRoundNumber: transitionRoundNumber,\n skipCountdown,\n startTransition,\n } = useRoundTransition(\n {\n announcementDuration: ROUND_ANNOUNCEMENT_TIMINGS.ANNOUNCEMENT_DURATION,\n countdownDuration: ROUND_ANNOUNCEMENT_TIMINGS.COUNTDOWN_DURATION,\n transitionDuration: ROUND_ANNOUNCEMENT_TIMINGS.TRANSITION_DURATION,\n },\n handleRoundTransitionComplete,\n );\n\n const player2Position = useMemo<Position>(() => {\n if (players.length >= 2 && players[1].position) {\n return players[1].position;\n }\n return {\n x: arenaBounds.worldWidthMeters * 0.1, // 10% right of center (~0.8m for 8m arena)\n y: 0, // Centered\n };\n }, [players, arenaBounds]);\n\n const playerPositions = useMemo<Position[]>(() => {\n return [player1Position, player2Position];\n }, [player1Position, player2Position]);\n\n const player1Position3D: [number, number, number] = useMemo(() => {\n return [playerPositions[0].x, 0, playerPositions[0].y];\n }, [playerPositions]);\n\n const player2Position3D: [number, number, number] = useMemo(() => {\n return [playerPositions[1].x, 0, playerPositions[1].y];\n }, [playerPositions]);\n\n\n const player2Rotation = useMemo(() => {\n const dx = player1Position3D[0] - player2Position3D[0];\n const dz = player1Position3D[2] - player2Position3D[2];\n return Math.atan2(dx, dz);\n }, [player1Position3D, player2Position3D]);\n\n const combatSystem = useMemo(() => new CombatSystem(), []);\n\n const balanceSystem = useMemo(() => new BalanceSystem(), []);\n\n const speedModifierSystem = useMemo(() => new SpeedModifierSystem(), []);\n\n const [player1SpeedModifiers, setPlayer1SpeedModifiers] = useState({\n finalSpeed: 6.0, // BASE_WALK_SPEED (6.0 m/s)\n baseSpeed: 6.0,\n finalAcceleration: 12.0, // BASE_ACCELERATION (12.0 m/s²)\n });\n const [player2SpeedModifiers, setPlayer2SpeedModifiers] = useState({\n finalSpeed: 6.0, // BASE_WALK_SPEED (6.0 m/s)\n baseSpeed: 6.0,\n finalAcceleration: 12.0, // BASE_ACCELERATION (12.0 m/s²)\n });\n\n const [player1WalkRunSpeeds, setPlayer1WalkRunSpeeds] = useState({\n walkSpeed: 6.0,\n runSpeed: 10.0,\n });\n\n useEffect(() => {\n const updateSpeedModifiers = () => {\n if (players.length >= 2) {\n const player1WalkModifiers =\n speedModifierSystem.calculateSpeedModifiers(\n players[0],\n MovementType.WALKING,\n false, // isCrouching\n );\n const player1RunModifiers = speedModifierSystem.calculateSpeedModifiers(\n players[0],\n MovementType.RUNNING,\n false, // isCrouching\n );\n\n setPlayer1SpeedModifiers({\n finalSpeed: player1WalkModifiers.finalSpeed,\n baseSpeed: player1WalkModifiers.baseSpeed,\n finalAcceleration: player1WalkModifiers.finalAcceleration,\n });\n\n setPlayer1WalkRunSpeeds({\n walkSpeed: player1WalkModifiers.finalSpeed,\n runSpeed: player1RunModifiers.finalSpeed,\n });\n\n const player2Modifiers = speedModifierSystem.calculateSpeedModifiers(\n players[1],\n MovementType.WALKING,\n false,\n );\n setPlayer2SpeedModifiers({\n finalSpeed: player2Modifiers.finalSpeed,\n baseSpeed: player2Modifiers.baseSpeed,\n finalAcceleration: player2Modifiers.finalAcceleration,\n });\n }\n };\n\n updateSpeedModifiers();\n\n const intervalId = setInterval(updateSpeedModifiers, 200);\n\n return () => clearInterval(intervalId);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [players]); // speedModifierSystem is memoized and never changes\n\n useEffect(() => {\n const updateTime = () => {\n setCurrentTime(Date.now());\n };\n\n const intervalId = setInterval(updateTime, 200);\n\n return () => clearInterval(intervalId);\n }, []);\n\n const calculateLegInjuryFactor = useCallback(\n (player: PlayerState): number => {\n if (!player.bodyPartHealth) return 0;\n\n const leftLeg = player.bodyPartHealth.legLeft ?? player.maxHealth;\n const rightLeg = player.bodyPartHealth.legRight ?? player.maxHealth;\n const maxHealth = player.maxHealth;\n\n const averageLegHealth = (leftLeg + rightLeg) / (2 * maxHealth);\n return Math.max(0, Math.min(1, 1.0 - averageLegHealth)); // 0 = healthy, 1 = critical\n },\n [],\n );\n\n const player1 = players.length > 0 ? players[0] : undefined;\n const player1Data = useMemo(() => {\n const p1 = player1 ?? createPlayerFromArchetype(PlayerArchetype.MUSA, 0);\n return {\n currentStance: p1.currentStance,\n legInjuryFactor: calculateLegInjuryFactor(p1),\n };\n }, [player1, calculateLegInjuryFactor]);\n\n const [player1AttackAnimation, setPlayer1AttackAnimation] = useState<\n string | undefined\n >(undefined);\n const [player2AttackAnimation, setPlayer2AttackAnimation] = useState<\n string | undefined\n >(undefined);\n\n const [player1TechniqueId, setPlayer1TechniqueId] = useState<\n string | undefined\n >(undefined);\n const [player2TechniqueId, setPlayer2TechniqueId] = useState<\n string | undefined\n >(undefined);\n\n const [player1Injuries, setPlayer1Injuries] = useState<readonly Injury[]>([]);\n const [player2Injuries, setPlayer2Injuries] = useState<readonly Injury[]>([]);\n\n useEffect(() => {\n return () => {\n setPlayer1Injuries([]);\n setPlayer2Injuries([]);\n };\n }, []);\n\n useEffect(() => {\n if (players.length >= 2) {\n const player1 = players[0];\n const player2 = players[1];\n\n if (\n player1?.health === player1?.maxHealth &&\n player2?.health === player2?.maxHealth\n ) {\n setPlayer1Injuries([]);\n setPlayer2Injuries([]);\n }\n }\n }, [players]);\n\n const handlePlayer1PositionChange = useCallback(\n (newPosition: Position) => {\n setPlayer1Position(newPosition);\n onPlayerUpdate(0, { position: newPosition });\n },\n [onPlayerUpdate],\n );\n\n const movementBounds = useMemo(\n () => ({\n worldWidthMeters: arenaBounds.worldWidthMeters,\n worldDepthMeters: arenaBounds.worldDepthMeters,\n }),\n [arenaBounds.worldWidthMeters, arenaBounds.worldDepthMeters],\n );\n\n\n const player1MovementTimeRef = useRef(0);\n const player1LastDirectionRef = useRef<{ x: number; y: number }>({\n x: 0,\n y: 0,\n });\n\n const [player1AccelerationBasedSpeed, setPlayer1AccelerationBasedSpeed] =\n useState(player1WalkRunSpeeds.walkSpeed);\n\n const player1IsRunning = isRunningSpeed(\n player1AccelerationBasedSpeed,\n player1WalkRunSpeeds.runSpeed,\n );\n\n const { isMoving: player1IsMoving, velocity: player1Velocity } =\n usePlayerMovement({\n enabled:\n !isPaused &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart,\n bounds: movementBounds, // Use memoized bounds object\n onPositionChange: handlePlayer1PositionChange, // Use memoized callback\n initialPositionMeters: player1Position,\n currentStance: player1Data.currentStance,\n legInjuryFactor: player1Data.legInjuryFactor,\n isRunning: player1IsRunning, // Use computed acceleration-based running state\n useTacticalSteps: false,\n maxSpeedOverride: player1AccelerationBasedSpeed,\n accelerationOverride: player1SpeedModifiers.finalAcceleration,\n });\n\n const player1Rotation = useMemo(() => {\n if (\n player1IsMoving &&\n player1Velocity &&\n (player1Velocity.x !== 0 || player1Velocity.y !== 0)\n ) {\n const movementRotation = Math.atan2(player1Velocity.x, player1Velocity.y);\n return movementRotation;\n } else {\n const dx = player2Position3D[0] - player1Position3D[0];\n const dz = player2Position3D[2] - player1Position3D[2];\n const targetRotation = Math.atan2(dx, dz);\n return targetRotation;\n }\n }, [player1IsMoving, player1Velocity, player1Position3D, player2Position3D]);\n\n const handleAttackRef = useRef<(() => void) | null>(null);\n\n const player1AnimationRef = useRef<ReturnType<\n typeof usePlayerAnimation\n > | null>(null);\n\n const validPlayersRefForAnimation = useRef<[PlayerState, PlayerState] | null>(\n null,\n );\n\n const player1HitTriggerFrameRef = useRef<number>(6);\n const player1AttackHitFiredRef = useRef<boolean>(false);\n\n const [player1AttackDuration, setPlayer1AttackDuration] =\n useState<number>(0.55);\n const [player2AttackDuration, setPlayer2AttackDuration] =\n useState<number>(0.55);\n\n const clearPlayer1AttackAnimation = useRef<() => void>(() => {\n setPlayer1AttackAnimation(undefined);\n setPlayer1TechniqueId(undefined);\n });\n const clearPlayer2AttackAnimation = useRef<() => void>(() => {\n setPlayer2AttackAnimation(undefined);\n setPlayer2TechniqueId(undefined);\n });\n\n const preparePlayer1AttackTiming = useCallback((animationName: string) => {\n const attackDuration = getAnimationDurationOrFallback(animationName);\n const attackFrames = Math.max(\n 1,\n Math.round(attackDuration * TARGET_ANIMATION_FPS),\n );\n player1HitTriggerFrameRef.current = Math.round(attackFrames * 0.4);\n player1AttackHitFiredRef.current = false;\n setPlayer1AttackDuration(attackDuration);\n return attackDuration;\n }, []);\n\n const player1AnimationEvents = useMemo<AnimationEvents>(\n () => ({\n onFrame: (frame, state) => {\n if (\n state === AnimationState.ATTACK &&\n frame >= player1HitTriggerFrameRef.current &&\n !player1AttackHitFiredRef.current\n ) {\n player1AttackHitFiredRef.current = true;\n handleAttackRef.current?.();\n }\n },\n onAnimationComplete: (state) => {\n if (\n state === AnimationState.ATTACK ||\n state === AnimationState.DEFEND\n ) {\n combatActions.setExecutingTechnique(false);\n if (state === AnimationState.ATTACK) {\n clearPlayer1AttackAnimation.current();\n }\n } else if (state === AnimationState.STANCE_CHANGE) {\n audio.playSFX(\"menu_select\");\n const players = validPlayersRefForAnimation.current;\n const currentStance = players?.[0]?.currentStance;\n if (currentStance && player1AnimationRef.current) {\n player1AnimationRef.current.transitionToStanceGuard(currentStance);\n }\n }\n },\n }),\n [combatActions, audio],\n );\n\n const player1Animation = usePlayerAnimation({\n events: player1AnimationEvents,\n });\n\n useEffect(() => {\n player1AnimationRef.current = player1Animation;\n }, [player1Animation]);\n\n const player2Animation = usePlayerAnimation({\n events: {\n onFrame: (frame, state) => {\n if (state === AnimationState.ATTACK && frame === 6) { /* attack frame hook */ }\n },\n onAnimationComplete: (state) => {\n if (state === AnimationState.ATTACK) {\n clearPlayer2AttackAnimation.current();\n }\n },\n },\n });\n\n const prevPlayer1IsMovingRef = useRef<boolean>(player1IsMoving);\n const prevPlayer1IsRunningRef = useRef<boolean>(player1IsRunning);\n useEffect(() => {\n const movementChanged = prevPlayer1IsMovingRef.current !== player1IsMoving;\n const runningChanged = prevPlayer1IsRunningRef.current !== player1IsRunning;\n\n if (movementChanged || runningChanged) {\n if (player1IsMoving) {\n const targetState = player1IsRunning\n ? AnimationState.RUN\n : AnimationState.WALK;\n if (player1Animation.currentState !== targetState) {\n player1Animation.transitionTo(targetState);\n }\n } else if (\n player1Animation.currentState === AnimationState.WALK ||\n player1Animation.currentState === AnimationState.RUN\n ) {\n player1Animation.transitionToStanceGuard(player1Data.currentStance);\n }\n prevPlayer1IsMovingRef.current = player1IsMoving;\n prevPlayer1IsRunningRef.current = player1IsRunning;\n }\n }, [\n player1IsMoving,\n player1IsRunning,\n player1Animation,\n player1Data.currentStance,\n ]);\n\n const MOVEMENT_DETECTION_THRESHOLD = 0.5;\n\n const player2Stance = useMemo(() => {\n return players[1]?.currentStance ?? TrigramStance.GEON;\n }, [players]);\n\n const prevPlayer2PositionRef = useRef(player2Position);\n useEffect(() => {\n const currentPos = playerPositions[1];\n const prevPos = prevPlayer2PositionRef.current;\n\n const isMoving =\n Math.abs(currentPos.x - prevPos.x) > MOVEMENT_DETECTION_THRESHOLD ||\n Math.abs(currentPos.y - prevPos.y) > MOVEMENT_DETECTION_THRESHOLD;\n\n if (isMoving) {\n if (\n player2Animation.currentState !== AnimationState.WALK &&\n player2Animation.currentState !== AnimationState.ATTACK\n ) {\n player2Animation.transitionTo(AnimationState.WALK);\n }\n } else {\n if (player2Animation.currentState === AnimationState.WALK) {\n player2Animation.transitionToStanceGuard(player2Stance);\n }\n }\n\n prevPlayer2PositionRef.current = currentPos;\n }, [playerPositions, player2Animation, player2Stance]);\n\n const validPlayers = useMemo((): [PlayerState, PlayerState] => {\n if (players.length === 0) {\n const player1 = createPlayerFromArchetype(PlayerArchetype.MUSA, 0);\n const player2 = createPlayerFromArchetype(PlayerArchetype.AMSALJA, 1);\n\n return [\n { ...player1, position: playerPositions[0] },\n { ...player2, position: playerPositions[1] },\n ];\n }\n\n const player1 = players[0];\n const player2 =\n players[1] ?? createPlayerFromArchetype(PlayerArchetype.AMSALJA, 1);\n\n return [\n { ...player1, position: playerPositions[0] },\n { ...player2, position: playerPositions[1] },\n ];\n }, [players, playerPositions]);\n\n const validPlayersRef = useRef<[PlayerState, PlayerState]>(validPlayers);\n useEffect(() => {\n validPlayersRef.current = validPlayers;\n validPlayersRefForAnimation.current = validPlayers;\n }, [validPlayers]);\n\n const getTechniqueAnimationType = useCallback(\n (techniqueId: string | undefined): AnimationType | undefined => {\n if (!techniqueId) return undefined;\n\n return getAnimationTypeForTechnique(techniqueId);\n },\n [],\n );\n\n const {\n player1Position: player1PositionWithAttackMovement,\n player2Position: player2PositionWithAttackMovement,\n } = useCombatAttackMovement({\n player1Attacking: player1Animation.currentState === AnimationState.ATTACK,\n player1AnimationType: getTechniqueAnimationType(player1TechniqueId),\n player1Stance: player1Data.currentStance,\n player1BasePosition: player1Position3D,\n player1AnimationDuration: player1AttackDuration,\n player2Attacking: player2Animation.currentState === AnimationState.ATTACK,\n player2AnimationType: getTechniqueAnimationType(player2TechniqueId),\n player2Stance: validPlayers[1].currentStance,\n player2BasePosition: player2Position3D,\n player2AnimationDuration: player2AttackDuration,\n });\n\n const [player1LocalStance, setPlayer1LocalStance] = useState<TrigramStance>(\n validPlayers[0].currentStance,\n );\n\n useEffect(() => {\n setPlayer1LocalStance(validPlayers[0].currentStance);\n }, [validPlayers]);\n\n const player1WithLocalStance = useMemo(\n (): PlayerState => ({\n ...validPlayers[0],\n currentStance: player1LocalStance,\n }),\n [validPlayers, player1LocalStance],\n );\n\n const startTransitionRef = useRef(startTransition);\n const internalRoundRef = useRef(internalRound);\n useEffect(() => {\n startTransitionRef.current = startTransition;\n internalRoundRef.current = internalRound;\n }, [startTransition, internalRound]);\n\n const addCombatMessage = useCallback(\n (korean: string, english: string) => {\n const message = `${korean} | ${english}`;\n combatActions.addCombatMessage(message);\n },\n [combatActions],\n );\n\n const handleTimeUp = useCallback(() => {\n if (!combatState.roundEnded) {\n combatActions.setRoundEnded(true);\n addCombatMessage(\"시간 종료!\", \"Time's Up!\");\n\n const currentPlayers = validPlayersRef.current;\n const player1Health = currentPlayers[0].health;\n const player2Health = currentPlayers[1].health;\n\n if (player1Health > player2Health) {\n updateMatchScore(0);\n startTransitionRef.current(currentPlayers[0], internalRoundRef.current); // Player 1 wins round\n } else if (player2Health > player1Health) {\n updateMatchScore(1);\n startTransitionRef.current(currentPlayers[1], internalRoundRef.current); // Player 2 wins round\n } else {\n startTransitionRef.current(null, internalRoundRef.current);\n }\n }\n }, [\n combatState.roundEnded,\n combatActions,\n addCombatMessage,\n updateMatchScore,\n ]);\n\n const handleTimeUpRef = useRef(handleTimeUp);\n useEffect(() => {\n handleTimeUpRef.current = handleTimeUp;\n }, [handleTimeUp]);\n\n const timerResetKey = `round-${internalRound}`;\n\n const timerState = useCombatTimer({\n initialTime: Math.max(0, timeRemaining),\n isPaused:\n isPaused ||\n !combatState.roundStarted ||\n combatState.roundEnded ||\n !matchCountdownComplete ||\n showRoundStart,\n onTimeUp: useCallback(() => handleTimeUpRef.current(), []),\n warningThreshold: 10,\n urgentThreshold: 5,\n resetKey: timerResetKey,\n });\n\n const startRound = useCallback(() => {\n if (import.meta.env.DEV) {\n console.log(\"[DEV] Starting round, setting roundStarted=true\");\n }\n combatActions.setRoundStarted(true);\n combatActions.setRoundEnded(false); // Ensure roundEnded is false\n addCombatMessage(\"라운드 시작!\", \"Round Start!\");\n\n const player = validPlayers[0];\n if (player?.archetype) {\n const playerArchetype = player.archetype.toLowerCase();\n combatAudio.playArchetypeMusic(playerArchetype, 2000);\n } else {\n combatAudio.playCombatMusic(2000);\n }\n }, [combatActions, addCombatMessage, validPlayers, combatAudio]);\n\n const hasAutoStartedRef = useRef(false);\n\n useEffect(() => {\n if (matchCountdownComplete && !hasAutoStartedRef.current) {\n hasAutoStartedRef.current = true;\n combatActions.setRoundStarted(true);\n addCombatMessage(\"라운드 시작!\", \"Round Start!\");\n\n const player = validPlayers[0];\n if (player?.archetype) {\n const playerArchetype = player.archetype.toLowerCase();\n combatAudio.playArchetypeMusic(playerArchetype, 2000);\n } else {\n combatAudio.playCombatMusic(2000);\n }\n }\n }, [\n matchCountdownComplete,\n combatActions,\n addCombatMessage,\n validPlayers,\n combatAudio,\n ]);\n\n const adaptiveDifficulty = useMemo(() => new AdaptiveDifficulty(), []);\n\n useEffect(() => {\n try {\n const savedMetrics = localStorage.getItem(\"ai_difficulty_metrics\");\n if (savedMetrics) {\n adaptiveDifficulty.importMetrics(savedMetrics);\n }\n } catch (err) {\n console.warn(\"Failed to load AI difficulty metrics:\", err);\n }\n\n return () => {\n try {\n const metrics = adaptiveDifficulty.exportMetrics();\n localStorage.setItem(\"ai_difficulty_metrics\", metrics);\n } catch (err) {\n console.warn(\"Failed to save AI difficulty metrics:\", err);\n }\n };\n }, [adaptiveDifficulty]);\n\n const aiPersonality = useMemo(\n () => getPersonalityByArchetype(validPlayers[1].archetype),\n [validPlayers],\n );\n\n const handleAIStanceChange = useCallback(\n (stance: TrigramStance) => {\n const currentStance = validPlayers[1].currentStance;\n\n player2Animation.transitionToStanceChange(currentStance, stance);\n\n onPlayerUpdate(1, { currentStance: stance });\n addCombatMessage(\n `AI 자세 변경: ${stance}`,\n `AI Stance Change: ${stance}`,\n );\n },\n [validPlayers, player2Animation, onPlayerUpdate, addCombatMessage],\n );\n\n const handleEffectComplete = useCallback(\n (effectId: string) => {\n combatActions.removeHitEffect(effectId);\n },\n [combatActions],\n );\n\n const createHitEffect = useCallback(\n (\n id: string,\n type: HitEffectType,\n position: Position,\n intensity: number,\n ): HitEffect => ({\n id,\n type,\n attackerId: \"player1\",\n defenderId: \"player2\",\n timestamp: Date.now(),\n duration: 1000,\n position,\n intensity,\n startTime: Date.now(),\n }),\n [],\n );\n\n const addHitEffect = useCallback(\n (type: HitEffectType, position: Position, intensity: number = 1) => {\n const effect = createHitEffect(\n `effect_${Date.now()}`,\n type,\n position,\n intensity,\n );\n combatActions.addHitEffect(effect);\n },\n [createHitEffect, combatActions],\n );\n\n const handlePlayerPositionUpdate = useCallback(\n (playerIndex: number, position: Position) => {\n if (playerIndex === 0) {\n setPlayer1Position(position);\n onPlayerUpdate(0, { position });\n } else if (playerIndex === 1) {\n onPlayerUpdate(1, { position });\n }\n },\n [onPlayerUpdate, setPlayer1Position],\n );\n\n const handleInjuryCreated = useCallback(\n (injury: Injury, targetPlayerIndex: number) => {\n const updateInjuries = (prev: readonly Injury[]): readonly Injury[] => {\n const recentHitTime = 5000; // 5 seconds\n const now = Date.now();\n\n const recentHit = prev.find(\n (existing) =>\n existing.region === injury.region &&\n now - existing.timestamp < recentHitTime &&\n existing.type === InjuryType.BRUISE &&\n injury.type === InjuryType.BRUISE,\n );\n\n if (recentHit) {\n const newHitCount = recentHit.hitCount + 1;\n const escalatedSeverity = Math.min(1.0, recentHit.severity + 0.15);\n\n return prev.map((existing) =>\n existing.id === recentHit.id\n ? {\n ...existing,\n hitCount: newHitCount,\n severity: escalatedSeverity,\n timestamp: now, // Update timestamp for progressive tracking\n }\n : existing,\n );\n }\n\n return [...prev, injury];\n };\n\n if (targetPlayerIndex === 0) {\n setPlayer1Injuries(updateInjuries);\n } else if (targetPlayerIndex === 1) {\n setPlayer2Injuries(updateInjuries);\n }\n },\n [],\n );\n\n const {\n handleAttack,\n handleDefend,\n handleStanceSwitch,\n handleStanceSideSwitch,\n handleAIAttack,\n handleAIDefend,\n handleAITechnique,\n moveAIPlayer,\n } = useCombatActions({\n validPlayers,\n playerPositions: [playerPositions[0], playerPositions[1]],\n combatState,\n combatActions,\n combatSystem,\n onPlayerUpdate,\n onPlayerPositionUpdate: handlePlayerPositionUpdate,\n onLateralityUpdate: (playerIndex, laterality) => {\n combatActions.setPlayerLateralityIndex(playerIndex as 0 | 1, laterality);\n },\n onInjuryCreated: handleInjuryCreated,\n addCombatMessage,\n addHitEffect,\n arenaBounds,\n combatAudio,\n playerAnimations: {\n player1: player1Animation,\n player2: player2Animation,\n },\n });\n\n useEffect(() => {\n handleAttackRef.current = handleAttack;\n }, [handleAttack]);\n\n const techniqueSelection = useTechniqueSelection({\n player: player1WithLocalStance,\n enabled:\n !isPaused &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart,\n onTechniqueExecute: useCallback(\n (technique: Technique) => {\n feedbackActions.showTechnique(\n technique.name.korean,\n technique.name.english,\n );\n\n const animationName = resolveTechniqueAnimation(technique);\n setPlayer1AttackAnimation(animationName);\n\n setPlayer1TechniqueId(technique.id);\n\n const attackDuration = preparePlayer1AttackTiming(animationName);\n player1Animation.transitionToAttack(attackDuration);\n combatActions.setExecutingTechnique(true);\n\n onPlayerUpdate(0, {\n stamina: Math.max(0, validPlayers[0].stamina - technique.staminaCost),\n ki: Math.max(0, validPlayers[0].ki - technique.kiCost),\n });\n\n handleAttack(technique);\n\n addCombatMessage(\n `${technique.name.korean} 사용!`,\n `Used ${technique.name.english}!`,\n );\n },\n [\n validPlayers,\n onPlayerUpdate,\n feedbackActions,\n handleAttack,\n addCombatMessage,\n player1Animation,\n combatActions,\n preparePlayer1AttackTiming,\n ],\n ),\n });\n\n const cooldownsMap = useMemo(() => {\n const map = new Map<string, number>();\n techniqueSelection.activeCooldowns.forEach((cd) => {\n map.set(cd.techniqueId, cd.remaining);\n });\n return map;\n }, [techniqueSelection.activeCooldowns]);\n\n const [previousStance, setPreviousStance] = useState<number>(0);\n\n const currentPlayerStance = validPlayers[0].currentStance;\n const currentStanceIndex = useMemo(() => {\n return STANCE_INDEX_MAP.get(currentPlayerStance) ?? 0;\n }, [currentPlayerStance]);\n\n const handleStanceChangeWithAnimation = useCallback(\n (newStance: TrigramStance) => {\n const currentStance = validPlayers[0].currentStance;\n\n // Full trigram stance change; laterality-only side switches use handleStanceSideSwitch.\n const success = player1Animation.transitionToStanceChange(\n currentStance,\n newStance,\n );\n\n if (success) {\n const prevStance = STANCE_INDEX_MAP.get(currentStance) ?? 0;\n setPreviousStance(prevStance);\n\n setPlayer1LocalStance(newStance);\n\n handleStanceSwitch(newStance);\n\n playStanceChangeSound();\n }\n },\n [validPlayers, player1Animation, handleStanceSwitch, playStanceChangeSound],\n );\n\n const player1Health = validPlayers[0].health;\n const player2Health = validPlayers[1].health;\n\n const lastPlayer2HealthRef = useRef(player2Health);\n useEffect(() => {\n const currentHealth = player2Health;\n const previousHealth = lastPlayer2HealthRef.current;\n const damageDone = previousHealth - currentHealth;\n\n if (damageDone > 0 && combatState.roundStarted && !combatState.roundEnded) {\n const getDamageType = (): \"critical\" | \"vital\" | \"normal\" => {\n if (damageDone >= 25) return \"critical\";\n if (damageDone >= 20) return \"vital\";\n return \"normal\";\n };\n const damageType = getDamageType();\n\n feedbackActions.addDamageNumber(\n Math.round(damageDone),\n playerPositions[1],\n damageType,\n );\n\n feedbackActions.incrementCombo();\n\n if (damageType === \"critical\") {\n feedbackActions.addActionFeedback(\n \"critical\",\n \"Critical!\",\n \"치명타!\",\n playerPositions[0],\n );\n }\n }\n\n lastPlayer2HealthRef.current = currentHealth;\n }, [\n player2Health,\n validPlayers,\n playerPositions,\n feedbackActions,\n combatState.roundStarted,\n combatState.roundEnded,\n ]);\n\n const lastPlayer1HealthRef = useRef(player1Health);\n useEffect(() => {\n const currentHealth = player1Health;\n const previousHealth = lastPlayer1HealthRef.current;\n const damageDone = previousHealth - currentHealth;\n\n if (damageDone > 0 && combatState.roundStarted && !combatState.roundEnded) {\n const damageType =\n damageDone >= 20 ? (\"critical\" as const) : (\"normal\" as const);\n feedbackActions.addDamageNumber(\n Math.round(damageDone),\n playerPositions[0],\n damageType,\n );\n }\n\n lastPlayer1HealthRef.current = currentHealth;\n }, [\n player1Health,\n validPlayers,\n playerPositions,\n feedbackActions,\n combatState.roundStarted,\n combatState.roundEnded,\n ]);\n\n const handleAttackWithFeedback = useCallback(() => {\n const basicTechnique = techniqueSelection.availableTechniques[0];\n const animationName = basicTechnique\n ? resolveTechniqueAnimation(basicTechnique)\n : \"jab\";\n setPlayer1AttackAnimation(animationName);\n if (basicTechnique?.id) {\n setPlayer1TechniqueId(basicTechnique.id);\n }\n\n const attackDuration = preparePlayer1AttackTiming(animationName);\n const success = player1Animation.transitionToAttack(attackDuration);\n if (success) {\n combatActions.setExecutingTechnique(true);\n } else {\n console.warn(\n \"Attack animation transition failed; executing attack logic directly.\",\n );\n handleAttack();\n }\n }, [\n player1Animation,\n combatActions,\n handleAttack,\n techniqueSelection.availableTechniques,\n preparePlayer1AttackTiming,\n ]);\n\n const handleDefendWithFeedback = useCallback(() => {\n const defenderPos = playerPositions[0];\n const success = player1Animation.transitionTo(AnimationState.DEFEND);\n if (success) {\n handleDefend();\n feedbackActions.addActionFeedback(\n \"blocked\",\n \"Blocked\",\n \"방어!\",\n defenderPos,\n );\n } else {\n console.warn(\n \"Defend animation transition failed; executing defend logic directly.\",\n );\n handleDefend();\n feedbackActions.addActionFeedback(\n \"blocked\",\n \"Blocked\",\n \"방어!\",\n defenderPos,\n );\n }\n }, [handleDefend, playerPositions, feedbackActions, player1Animation]);\n\n /**\n * Helper function to execute fallback recovery animation\n * when a specific recovery type cannot be performed.\n *\n * Determines the appropriate recovery type based on ground state\n * and transitions to that animation.\n *\n * @korean 대체회복실행\n */\n const executeFallbackRecovery = useCallback(() => {\n const groundState = balanceSystem.getGroundState(\n player1Animation.currentState,\n );\n if (groundState) {\n const recoveryType = determineRecoveryType(groundState);\n const animationState = getRecoveryAnimationState(recoveryType);\n player1Animation.transitionTo(animationState as AnimationState);\n }\n }, [balanceSystem, player1Animation]);\n\n const { queuedInputs, showHints } = useKeyboardControls({\n onStanceChange: useCallback(\n (stanceIndex: number) => {\n const stance = TRIGRAM_STANCES_ORDER[stanceIndex];\n if (stance) {\n handleStanceChangeWithAnimation(stance);\n }\n },\n [handleStanceChangeWithAnimation],\n ),\n onAction: useCallback(\n (action: string) => {\n switch (action) {\n case \"attack\":\n techniqueSelection.executeTechnique();\n break;\n case \"block\":\n handleDefendWithFeedback();\n break;\n case \"recovery_quick\": {\n executeFallbackRecovery();\n break;\n }\n case \"recovery_roll\": {\n const player1 = players[0];\n if (balanceSystem.canRecoverWithType(player1, \"roll_recovery\")) {\n const updatedPlayer = balanceSystem.applyRecoveryCost(\n player1,\n \"roll_recovery\",\n );\n onPlayerUpdate(0, { stamina: updatedPlayer.stamina });\n player1Animation.transitionTo(AnimationState.RECOVERY_ROLL);\n } else {\n audio.playSFX(\"menu_error\");\n const player1Pos = playerPositions[0];\n feedbackActions.addActionFeedback(\n \"blocked\",\n \"Not enough stamina!\",\n \"체력 부족!\",\n player1Pos,\n );\n executeFallbackRecovery();\n }\n break;\n }\n case \"recovery_defensive\": {\n player1Animation.transitionTo(AnimationState.RECOVERY_DEFENSIVE);\n break;\n }\n\n case \"footwork_circular_left\":\n case \"footwork_circular_right\":\n case \"footwork_slide_forward\":\n case \"footwork_slide_back\":\n case \"footwork_pivot_left\":\n case \"footwork_pivot_right\":\n case \"footwork_shuffle\":\n player1Animation.transitionTo(action as AnimationState);\n break;\n\n case \"stance_side_switch\":\n player1Animation.transitionTo(AnimationState.STANCE_SIDE_SWITCH);\n handleStanceSideSwitch(PLAYER_ONE_INDEX);\n break;\n\n }\n },\n [\n techniqueSelection,\n handleDefendWithFeedback,\n executeFallbackRecovery,\n balanceSystem,\n player1Animation,\n handleStanceSideSwitch,\n players,\n onPlayerUpdate,\n audio,\n feedbackActions,\n playerPositions,\n ],\n ),\n enabled:\n !isPaused &&\n !showPauseMenu &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart &&\n !combatState.isExecutingTechnique,\n currentStance: currentStanceIndex,\n playSFX: audio.playSFX,\n currentAnimationState: player1Animation.currentState,\n });\n\n const [stanceWheelExpanded, setStanceWheelExpanded] = useState(false);\n const activeMobileKeyRef = useRef<string | null>(null);\n\n /**\n * Mobile touch control handler - Converts VirtualDPad touch inputs to keyboard events\n *\n * Dispatches synthetic KeyboardEvents with proper properties to ensure compatibility\n * with usePlayerMovement hook. The synthetic events include:\n * - key: The character key (w/a/s/d)\n * - code: The physical key code (KeyW/KeyA/KeyS/KeyD)\n * - bubbles: true - Allows event to propagate through DOM\n * - cancelable: true - Allows event to be prevented\n *\n * These properties are essential for the keyboard event listeners in inputSystem.ts\n * to properly recognize and process the movement commands.\n *\n * @param direction - The D-pad direction or null\n * @param eventType - 'start' for press, 'end' for release\n */\n const handleMobileMove = useCallback(\n (direction: Direction | null, eventType: DPadEventType) => {\n const directionMap: Record<Direction, string> = {\n up: \"w\",\n \"up-right\": \"w\", // Diagonal simplified to primary direction\n right: \"d\",\n \"down-right\": \"s\",\n down: \"s\",\n \"down-left\": \"s\",\n left: \"a\",\n \"up-left\": \"w\",\n };\n\n if (eventType === \"start\" && direction) {\n if (\n activeMobileKeyRef.current &&\n activeMobileKeyRef.current !== directionMap[direction]\n ) {\n const prevKey = activeMobileKeyRef.current;\n window.dispatchEvent(\n new KeyboardEvent(\"keyup\", {\n key: prevKey,\n code: `Key${prevKey.toUpperCase()}`,\n bubbles: true,\n cancelable: true,\n }),\n );\n }\n\n const key = directionMap[direction];\n activeMobileKeyRef.current = key;\n window.dispatchEvent(\n new KeyboardEvent(\"keydown\", {\n key,\n code: `Key${key.toUpperCase()}`,\n bubbles: true,\n cancelable: true,\n }),\n );\n } else if (eventType === \"end\") {\n if (activeMobileKeyRef.current) {\n const key = activeMobileKeyRef.current;\n window.dispatchEvent(\n new KeyboardEvent(\"keyup\", {\n key,\n code: `Key${key.toUpperCase()}`,\n bubbles: true,\n cancelable: true,\n }),\n );\n activeMobileKeyRef.current = null;\n }\n }\n },\n [],\n );\n\n const handleMobileAttack = useCallback(() => {\n techniqueSelection.executeTechnique();\n }, [techniqueSelection]);\n\n const handleMobileBlock = useCallback(\n (eventType: ButtonEventType) => {\n if (eventType === \"start\") {\n handleDefendWithFeedback();\n }\n },\n [handleDefendWithFeedback],\n );\n\n const handleMobileStanceChange = useCallback(\n (stanceIndex: number) => {\n const stance = TRIGRAM_STANCES_ORDER[stanceIndex];\n if (stance) {\n handleStanceChangeWithAnimation(stance);\n }\n },\n [handleStanceChangeWithAnimation],\n );\n\n const handleMobileGesture = useCallback(\n (gesture: GestureEvent) => {\n switch (gesture.type) {\n case \"swipe-right\":\n window.dispatchEvent(new KeyboardEvent(\"keydown\", { key: \"d\" }));\n setTimeout(() => {\n window.dispatchEvent(new KeyboardEvent(\"keyup\", { key: \"d\" }));\n }, 100);\n break;\n case \"swipe-left\":\n window.dispatchEvent(new KeyboardEvent(\"keydown\", { key: \"a\" }));\n setTimeout(() => {\n window.dispatchEvent(new KeyboardEvent(\"keyup\", { key: \"a\" }));\n }, 100);\n break;\n case \"swipe-up\":\n techniqueSelection.executeTechnique();\n break;\n case \"swipe-down\":\n techniqueSelection.executeTechnique();\n break;\n case \"two-finger-tap\":\n audio.playSFX(\"menu_select\");\n break;\n }\n },\n [techniqueSelection, audio],\n );\n\n const toggleStanceWheel = useCallback(() => {\n setStanceWheelExpanded((prev) => !prev);\n }, []);\n\n const mobileControlsEnabled =\n isMobile &&\n !isPaused &&\n !showPauseMenu &&\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart &&\n !combatState.isExecutingTechnique;\n\n\n useEffect(() => {\n if (isPaused) return;\n\n if (timeRemaining <= 0 && !combatState.roundEnded) {\n combatActions.setRoundEnded(true);\n combatActions.setRoundStarted(false);\n combatActions.setRoundDisplayStatus(\"end\");\n\n combatAudio.stopCombatMusic(1000);\n\n const winner = validPlayers[0].health > validPlayers[1].health ? 0 : 1;\n const roundWinner = validPlayers[winner];\n\n updateMatchScore(winner);\n\n addCombatMessage(\"라운드 종료!\", \"Round Over!\");\n\n setTimeout(() => {\n startTransition(roundWinner, internalRound);\n }, 1500);\n }\n }, [\n timeRemaining,\n combatState.roundEnded,\n combatState.roundStarted,\n validPlayers,\n onGameEnd,\n addCombatMessage,\n internalRound,\n isPaused,\n combatActions,\n combatAudio,\n startTransition,\n updateMatchScore,\n ]);\n\n const executeAIActionCallbackRef = useRef<\n | ((\n action: string,\n targetPos?: Position,\n selectedTechnique?: KoreanTechnique,\n targetVitalPoint?: string,\n ) => void)\n | undefined\n >(undefined);\n\n const { updateDifficultyTarget } = useAICombat({\n player: validPlayers[1],\n opponent: validPlayers[0],\n personality: aiPersonality,\n adaptiveDifficulty,\n isPaused,\n roundStarted: combatState.roundStarted,\n roundEnded: combatState.roundEnded,\n arenaBounds,\n onExecuteAction: (action, targetPos, selectedTechnique, targetVitalPoint) =>\n executeAIActionCallbackRef.current?.(\n action,\n targetPos,\n selectedTechnique,\n targetVitalPoint,\n ),\n onStanceChange: handleAIStanceChange,\n onLateralityChange: () => handleStanceSideSwitch(1), // AI player (index 1)\n playerLaterality: combatState.playerLaterality[1], // AI's own laterality\n opponentLaterality: combatState.playerLaterality[0], // Opponent (human) laterality\n });\n\n const currentDifficultyTier = useMemo(\n () => adaptiveDifficulty.getDifficultyTier(),\n [adaptiveDifficulty],\n );\n\n useEffect(() => {\n if (!combatState.roundEnded || internalRound < 1) {\n return;\n }\n\n const roundsCompleted = internalRound;\n if (roundsCompleted % 2 === 0) {\n const player1 = validPlayersRef.current[0];\n\n adaptiveDifficulty.updateSkillMetrics({\n hitsLanded: player1.hitsLanded ?? 0,\n totalAttacks: (player1.hitsLanded ?? 0) + (player1.misses ?? 0),\n combosExecuted: 0, // TODO (Phase 2): Track combo count in PlayerState\n perfectBlockCount: 0, // TODO (Phase 2): Track perfect blocks in PlayerState\n avgReactionTimeMs: 600, // TODO (Phase 2): Track player reaction time\n vitalPointsHit: 0, // TODO (Phase 2): Track vital point hits\n effectiveStanceChanges: 0, // TODO (Phase 2): Track stance changes\n damageDealt: player1.totalDamageDealt ?? 0,\n damageTaken: player1.totalDamageReceived ?? 0,\n });\n\n const newParams = adaptiveDifficulty.getDifficultyParameters();\n updateDifficultyTarget(newParams);\n\n if (import.meta.env.DEV) {\n const tier = adaptiveDifficulty.getDifficultyTier();\n console.log(\n `[DEV] Difficulty adjusted after round ${roundsCompleted}, new tier: ${tier}`,\n );\n }\n }\n }, [\n combatState.roundEnded,\n internalRound,\n adaptiveDifficulty,\n updateDifficultyTarget,\n ]);\n\n const executeAIActionCallback = useCallback(\n (\n action: string,\n targetPos?: Position,\n selectedTechnique?: KoreanTechnique,\n targetVitalPoint?: string,\n ) => {\n const aiStance = validPlayers[1]?.currentStance ?? TrigramStance.GEON;\n const aiFallbackTechnique = TRIGRAM_TECHNIQUES[aiStance]?.[0];\n const aiFallbackAnim = aiFallbackTechnique\n ? resolveTechniqueAnimation(aiFallbackTechnique)\n : \"jab\";\n switch (action) {\n case \"attack\":\n if (selectedTechnique) {\n const p2AttackAnimName = resolveTechniqueAnimation(selectedTechnique);\n setPlayer2AttackAnimation(p2AttackAnimName);\n\n if (selectedTechnique.id) {\n setPlayer2TechniqueId(selectedTechnique.id);\n }\n const p2AttackAnim = getAnimation(p2AttackAnimName);\n const p2AttackDur = p2AttackAnim?.duration ?? 0.55;\n setPlayer2AttackDuration(p2AttackDur);\n player2Animation.transitionToAttack(p2AttackDur);\n } else {\n setPlayer2AttackAnimation(aiFallbackAnim);\n if (aiFallbackTechnique?.id) {\n setPlayer2TechniqueId(aiFallbackTechnique.id);\n }\n const p2FallbackAnim = getAnimation(aiFallbackAnim);\n const p2FallbackDur = p2FallbackAnim?.duration ?? 0.55;\n setPlayer2AttackDuration(p2FallbackDur);\n player2Animation.transitionToAttack(p2FallbackDur);\n }\n handleAIAttack(selectedTechnique, targetVitalPoint);\n break;\n case \"defend\":\n player2Animation.transitionTo(AnimationState.DEFEND);\n handleAIDefend();\n break;\n case \"technique\":\n case \"combo\":\n if (selectedTechnique) {\n const p2TechAnimName = resolveTechniqueAnimation(selectedTechnique);\n setPlayer2AttackAnimation(p2TechAnimName);\n\n if (selectedTechnique.id) {\n setPlayer2TechniqueId(selectedTechnique.id);\n }\n const p2TechAnim = getAnimation(p2TechAnimName);\n const p2TechDur = p2TechAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2TechDur);\n player2Animation.transitionToAttack(p2TechDur);\n } else {\n setPlayer2AttackAnimation(aiFallbackAnim);\n if (aiFallbackTechnique?.id) {\n setPlayer2TechniqueId(aiFallbackTechnique.id);\n }\n const p2FallbackAnim = getAnimation(aiFallbackAnim);\n const p2FallbackDur = p2FallbackAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2FallbackDur);\n player2Animation.transitionToAttack(p2FallbackDur);\n }\n handleAITechnique(selectedTechnique, targetVitalPoint);\n break;\n case \"approach\":\n case \"retreat\":\n case \"circle\":\n if (targetPos) {\n moveAIPlayer(targetPos);\n }\n break;\n case \"feint\":\n {\n const playerPos = validPlayers[0].position;\n const feintOffsetMeters = 0.5;\n const feintPos = {\n x: playerPos.x + (Math.random() - 0.5) * feintOffsetMeters,\n y: playerPos.y + (Math.random() - 0.5) * feintOffsetMeters,\n };\n moveAIPlayer(feintPos);\n addCombatMessage(\"AI 페인트\", \"AI Feint\");\n\n setTimeout(() => {\n if (\n !combatState.roundEnded &&\n combatState.roundStarted &&\n validPlayers.length >= 2\n ) {\n const currentPlayerPos = validPlayers[0].position;\n const currentAiPos = validPlayers[1].position;\n const dx = currentAiPos.x - currentPlayerPos.x;\n const dy = currentAiPos.y - currentPlayerPos.y;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n const retreatDistanceMeters = 0.8;\n const halfWidth = arenaBounds.worldWidthMeters / 2;\n const halfDepth = arenaBounds.worldDepthMeters / 2;\n const retreatPos = {\n x: Math.max(\n -halfWidth + 0.5, // 0.5m from edge\n Math.min(\n halfWidth - 0.5,\n currentPlayerPos.x + (dx / dist) * retreatDistanceMeters,\n ),\n ),\n y: Math.max(\n -halfDepth + 0.5, // 0.5m from edge\n Math.min(\n halfDepth - 0.5,\n currentPlayerPos.y + (dy / dist) * retreatDistanceMeters,\n ),\n ),\n };\n moveAIPlayer(retreatPos);\n }\n }, 200);\n }\n break;\n case \"counter\":\n if (selectedTechnique) {\n const p2CounterAnimName = resolveTechniqueAnimation(selectedTechnique);\n setPlayer2AttackAnimation(p2CounterAnimName);\n\n if (selectedTechnique.id) {\n setPlayer2TechniqueId(selectedTechnique.id);\n }\n const p2CounterAnim = getAnimation(p2CounterAnimName);\n const p2CounterDur = p2CounterAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2CounterDur);\n player2Animation.transitionToAttack(p2CounterDur);\n } else {\n setPlayer2AttackAnimation(aiFallbackAnim);\n if (aiFallbackTechnique?.id) {\n setPlayer2TechniqueId(aiFallbackTechnique.id);\n }\n const p2FallbackAnim = getAnimation(aiFallbackAnim);\n const p2FallbackDur = p2FallbackAnim?.duration ?? 0.6;\n setPlayer2AttackDuration(p2FallbackDur);\n player2Animation.transitionToAttack(p2FallbackDur);\n }\n handleAIAttack(selectedTechnique, targetVitalPoint);\n addCombatMessage(\"AI 반격!\", \"AI Counter!\");\n break;\n }\n },\n [\n handleAIAttack,\n handleAIDefend,\n handleAITechnique,\n moveAIPlayer,\n addCombatMessage,\n validPlayers,\n arenaBounds,\n combatState.roundEnded,\n combatState.roundStarted,\n player2Animation,\n ],\n );\n\n useEffect(() => {\n executeAIActionCallbackRef.current = executeAIActionCallback;\n }, [executeAIActionCallback]);\n\n useEffect(() => {\n if (combatState.roundEnded && validPlayers.length === 2) {\n const player = validPlayers[0];\n const totalAttacks = (player.hitsLanded ?? 0) + (player.hitsTaken ?? 0);\n\n if (totalAttacks === 0) return;\n\n adaptiveDifficulty.updateSkillMetrics({\n hitsLanded: player.hitsLanded ?? 0,\n totalAttacks,\n combosExecuted: player.comboCount ?? 0,\n perfectBlockCount: 0,\n avgReactionTimeMs: 500,\n vitalPointsHit: player.vitalPointHits ?? 0,\n effectiveStanceChanges: 0,\n damageDealt: player.totalDamageDealt ?? 0,\n damageTaken: player.totalDamageReceived ?? 0,\n });\n }\n }, [combatState.roundEnded, adaptiveDifficulty, validPlayers]);\n\n const checkGameEnd = useCallback(() => {\n if (combatState.roundEnded) return;\n\n const p1Defeated = validPlayers[0].health <= 0;\n const p2Defeated = validPlayers[1].health <= 0;\n\n if (p1Defeated || p2Defeated) {\n combatActions.setRoundEnded(true);\n combatActions.setRoundStarted(false);\n combatActions.setRoundDisplayStatus(\"ko\");\n const winner = p1Defeated ? 1 : 0;\n const roundWinner = validPlayers[winner];\n\n updateMatchScore(winner);\n\n addCombatMessage(\n p1Defeated ? \"플레이어 1 패배\" : \"플레이어 1 승리!\",\n p1Defeated ? \"Player 1 Defeated\" : \"Player 1 Victory!\",\n );\n\n setTimeout(() => {\n startTransition(roundWinner, internalRound);\n }, 1500);\n }\n }, [\n validPlayers,\n addCombatMessage,\n combatState.roundEnded,\n combatActions,\n internalRound,\n startTransition,\n updateMatchScore,\n ]);\n\n useEffect(() => {\n checkGameEnd();\n }, [player1Health, player2Health, checkGameEnd]);\n\n useEffect(() => {\n const handleCombatInput = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n if (showPauseMenu) {\n handleResume();\n } else {\n handlePause();\n }\n return;\n }\n\n if (isPaused || showPauseMenu) {\n return;\n }\n\n if (!matchCountdownComplete || showRoundStart) {\n return;\n }\n\n if (\n !combatState.roundStarted ||\n combatState.roundEnded ||\n combatState.isExecutingTechnique\n ) {\n return;\n }\n\n const key = event.key.toLowerCase();\n\n if (key >= \"1\" && key <= \"8\") {\n const stanceIndex = parseInt(key) - 1;\n const stances: TrigramStance[] = [\n TrigramStance.GEON,\n TrigramStance.TAE,\n TrigramStance.LI,\n TrigramStance.JIN,\n TrigramStance.SON,\n TrigramStance.GAM,\n TrigramStance.GAN,\n TrigramStance.GON,\n ];\n handleStanceSwitch(stances[stanceIndex]);\n event.preventDefault();\n }\n\n if (key === \" \") {\n handleAttackWithFeedback();\n event.preventDefault();\n }\n\n if (event.key === \"Shift\") {\n handleDefendWithFeedback();\n event.preventDefault();\n }\n\n if (event.key === \"f\" || event.key === \"F\") {\n handleStanceSideSwitch(0); // Human player\n event.preventDefault();\n }\n };\n\n window.addEventListener(\"keydown\", handleCombatInput);\n return () => window.removeEventListener(\"keydown\", handleCombatInput);\n }, [\n combatState.roundStarted,\n combatState.roundEnded,\n combatState.isExecutingTechnique,\n matchCountdownComplete,\n showRoundStart,\n isPaused,\n showPauseMenu,\n handleStanceSwitch,\n handleStanceSideSwitch,\n handleAttackWithFeedback,\n handleDefendWithFeedback,\n handlePause,\n handleResume,\n ]);\n\n const player1MovementState = useMemo(() => {\n if (!validPlayers[0]?.bodyPartHealth) {\n return {\n statusText: { korean: \"정상\", english: \"Normal\" },\n isLimping: false,\n isSevereLimp: false,\n };\n }\n\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0,\n validPlayers[0].bodyPartHealth,\n validPlayers[0].currentStance ?? TrigramStance.GEON,\n validPlayers[0].pain ?? 0,\n );\n\n return {\n statusText: result.statusText,\n isLimping: result.isLimping,\n isSevereLimp: result.isSevereLimp,\n speedMultiplier: result.speedMultiplier,\n };\n }, [validPlayers]);\n\n const player2MovementState = useMemo(() => {\n if (!validPlayers[1]?.bodyPartHealth) {\n return {\n statusText: { korean: \"정상\", english: \"Normal\" },\n isLimping: false,\n isSevereLimp: false,\n };\n }\n\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0,\n validPlayers[1].bodyPartHealth,\n validPlayers[1].currentStance ?? TrigramStance.GEON,\n validPlayers[1].pain ?? 0,\n );\n\n return {\n statusText: result.statusText,\n isLimping: result.isLimping,\n isSevereLimp: result.isSevereLimp,\n speedMultiplier: result.speedMultiplier,\n };\n }, [validPlayers]);\n\n return (\n <div\n style={{\n width: `${width}px`,\n height: `${height}px`,\n position: \"relative\",\n backgroundColor: toHexColor(KOREAN_COLORS.UI_BACKGROUND_DARK),\n overflow: \"hidden\", // Prevent content from extending beyond container\n }}\n data-testid=\"combat-screen\"\n >\n {/* Three.js Canvas for 3D rendering */}\n <Canvas\n style={{ width: `${width}px`, height: `${height}px` }}\n camera={{\n position: cameraConfig.position,\n fov: cameraConfig.fov,\n near: cameraConfig.near,\n far: cameraConfig.far,\n }}\n gl={{\n antialias: renderConfig.antialias,\n alpha: false,\n powerPreference: \"high-performance\",\n failIfMajorPerformanceCaveat: false,\n }}\n dpr={renderConfig.dpr}\n shadows={false} // Temporarily disable shadows\n onCreated={({ gl }) => {\n gl.setClearColor(theme.colors.UI_BACKGROUND_DARK, 1);\n }}\n >\n {/* Lighting - CombatArena3D provides ambient, we add directional for shadows */}\n <ambientLight intensity={0.6} />\n <directionalLight position={[10, 10, 5]} intensity={1.2} />\n\n {/* Adaptive Quality Wrapper monitors FPS and adjusts quality */}\n <AdaptiveQualityWrapper\n enabled={shouldEnableAdaptiveQuality}\n isMobile={isMobile}\n >\n {/* Performance overlay (dev mode) - controlled by showPerformanceOverlay prop */}\n {showPerformanceOverlay && !isMobile && !showPerformanceMonitor && (\n <PerformanceOverlay3D />\n )}\n\n {/* Combat Arena 3D Environment - uses physics-based world dimensions */}\n <CombatArena3D\n lighting=\"cyberpunk\"\n scale={arenaBounds.scale}\n worldWidthMeters={arenaBounds.worldWidthMeters}\n worldDepthMeters={arenaBounds.worldDepthMeters}\n />\n\n {/* Animation updater - updates both player animations at 60fps */}\n <AnimationUpdater\n player1Animation={player1Animation}\n player2Animation={player2Animation}\n />\n\n {/* Acceleration updater - tracks player 1 movement time and updates speed */}\n <AccelerationUpdater\n isMoving={player1IsMoving}\n velocity={player1Velocity}\n movementTimeRef={player1MovementTimeRef}\n lastDirectionRef={player1LastDirectionRef}\n onSpeedUpdate={setPlayer1AccelerationBasedSpeed}\n walkSpeed={player1WalkRunSpeeds.walkSpeed}\n runSpeed={player1WalkRunSpeeds.runSpeed}\n />\n\n {/* Player 1 (Human) */}\n <Player3DWithTransitions\n {...convertPlayerStateToProps(\n validPlayers[0],\n player1PositionWithAttackMovement,\n player1Rotation,\n {\n isMobile,\n facing: \"right\",\n enableFacialExpressions: true,\n enableEyeTracking: true,\n opponentPosition: player2PositionWithAttackMovement,\n },\n )}\n currentAnimation={animationStateToPlayerAnimation(\n player1Animation.currentState,\n )}\n attackAnimation={player1AttackAnimation}\n laterality={combatState.playerLaterality[0]}\n enableTransitionEffects={!isMobile}\n enableStanceSymbol={!isMobile}\n enableStanceAudio={true}\n />\n\n {/* Player 2 (AI) */}\n <Player3DWithTransitions\n {...convertPlayerStateToProps(\n validPlayers[1],\n player2PositionWithAttackMovement,\n player2Rotation,\n {\n isMobile,\n facing: \"right\",\n enableFacialExpressions: true,\n enableEyeTracking: true,\n opponentPosition: player1PositionWithAttackMovement,\n },\n )}\n currentAnimation={animationStateToPlayerAnimation(\n player2Animation.currentState,\n )}\n attackAnimation={player2AttackAnimation}\n laterality={combatState.playerLaterality[1]}\n enableTransitionEffects={!isMobile}\n enableStanceSymbol={!isMobile}\n enableStanceAudio={true}\n />\n\n {/* Movement Status Indicators - Korean/English Bilingual */}\n {/* Player 1 Movement Status */}\n {(player1MovementState.isLimping ||\n player1MovementState.isSevereLimp) && (\n <Html\n position={[\n player1Position3D[0],\n player1Position3D[1] + 2.5,\n player1Position3D[2],\n ]}\n center\n data-testid=\"player1-movement-status\"\n >\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: player1MovementState.isSevereLimp\n ? toHexColor(KOREAN_COLORS.TEXT_ERROR)\n : toHexColor(KOREAN_COLORS.ACCENT_GOLD),\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n textShadow: \"0 0 4px rgba(0,0,0,0.8)\",\n background: \"rgba(0, 0, 0, 0.6)\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n whiteSpace: \"nowrap\",\n }}\n >\n {player1MovementState.statusText.korean} |{\" \"}\n {player1MovementState.statusText.english}\n </div>\n </Html>\n )}\n\n {/* Player 2 Movement Status */}\n {(player2MovementState.isLimping ||\n player2MovementState.isSevereLimp) && (\n <Html\n position={[\n player2Position3D[0],\n player2Position3D[1] + 2.5,\n player2Position3D[2],\n ]}\n center\n data-testid=\"player2-movement-status\"\n >\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: player2MovementState.isSevereLimp\n ? toHexColor(KOREAN_COLORS.TEXT_ERROR)\n : toHexColor(KOREAN_COLORS.ACCENT_GOLD),\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n textShadow: \"0 0 4px rgba(0,0,0,0.8)\",\n background: \"rgba(0, 0, 0, 0.6)\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n whiteSpace: \"nowrap\",\n }}\n >\n {player2MovementState.statusText.korean} |{\" \"}\n {player2MovementState.statusText.english}\n </div>\n </Html>\n )}\n\n {/* Trauma Overlays - Injury Visualization (외상 오버레이 - 부상 시각화) */}\n {/* Player 1 Injuries */}\n <TraumaOverlay3D\n playerId=\"player\"\n health={validPlayers[0].health}\n injuries={player1Injuries}\n characterPosition={player1Position3D}\n isMobile={isMobile}\n showFractures={true}\n />\n\n {/* Player 2 Injuries */}\n <TraumaOverlay3D\n playerId=\"enemy\"\n health={validPlayers[1].health}\n injuries={player2Injuries}\n characterPosition={player2Position3D}\n isMobile={isMobile}\n showFractures={true}\n />\n\n {/* Hit Effects */}\n <HitEffects3D\n effects={combatState.hitEffects}\n onEffectComplete={handleEffectComplete}\n arenaBounds={arenaBounds}\n />\n\n {/* Combat Particle Effects - Blood viscosity, organ damage, audio (전투 입자 효과) */}\n <CombatParticleEffects3D\n hitEffects={combatState.hitEffects}\n enabled={true}\n isMobile={isMobile}\n />\n\n {/* Vital Point Overlay - Show on both players when V is pressed */}\n {overlayVisible && (\n <>\n {/* Player 1 Vital Points */}\n <VitalPointMarkers3D\n position={player1Position3D}\n visible={overlayVisible}\n severityFilter={severityFilters}\n regionFilter={regionFilter}\n searchQuery={searchQuery}\n showLabels={showLabels}\n scale={scale}\n animated={animated}\n onPointClick={() => {\n }}\n />\n\n {/* Player 2 Vital Points */}\n <VitalPointMarkers3D\n position={player2Position3D}\n visible={overlayVisible}\n severityFilter={severityFilters}\n regionFilter={regionFilter}\n searchQuery={searchQuery}\n showLabels={showLabels}\n scale={scale}\n animated={animated}\n onPointClick={() => {\n }}\n />\n\n {/* Vital Point Overlay Controls - only visible when overlay is active */}\n <VitalPointOverlayControlsHtml\n screenPosition={{\n top: `${combatTopHudHeight + layoutConstants.padding}px`,\n left: `${layoutConstants.padding}px`,\n }}\n visible={overlayVisible}\n onVisibleChange={setOverlayVisible}\n severityFilters={severityFilters}\n onSeverityFiltersChange={setSeverityFilters}\n regionFilter={regionFilter}\n onRegionFilterChange={setRegionFilter}\n searchQuery={searchQuery}\n onSearchQueryChange={setSearchQuery}\n showLabels={showLabels}\n onShowLabelsChange={setShowLabels}\n animated={animated}\n onAnimatedChange={setAnimated}\n scale={scale}\n onScaleChange={setScale}\n isMobile={isMobile}\n />\n </>\n )}\n\n {/* Action Feedback - Damage Numbers */}\n <DamageNumbers\n damages={feedbackState.damageNumbers}\n isMobile={isMobile}\n arenaBounds={arenaBounds}\n />\n\n {/* Action Feedback - Action Indicators */}\n <ActionFeedback\n feedbacks={feedbackState.actionFeedbacks}\n isMobile={isMobile}\n arenaBounds={arenaBounds}\n />\n\n {/* Combo Counter */}\n <ComboCounter combo={feedbackState.comboCount} isMobile={isMobile} />\n\n {/* Technique Name Display */}\n {feedbackState.currentTechnique && (\n <TechniqueName\n korean={feedbackState.currentTechnique.korean}\n english={feedbackState.currentTechnique.english}\n isMobile={isMobile}\n onComplete={() => feedbackActions.hideTechnique()}\n />\n )}\n\n {/* Performance Overlay (Development Only) - Toggle with P key */}\n {import.meta.env.DEV && showPerformanceMonitor && (\n <PerformanceOverlay3D visible={true} />\n )}\n\n {/* Visual Feedback Components for Keyboard Controls */}\n <StanceChangeIndicator\n currentStance={currentStanceIndex}\n previousStance={previousStance}\n isMobile={isMobile}\n />\n\n <KeyboardHints\n visible={showHints}\n currentStance={currentStanceIndex}\n isMobile={isMobile}\n />\n\n <InputBufferDisplay queuedInputs={queuedInputs} isMobile={isMobile} />\n\n {/* 3D Balance Indicators - Positioned below top HUD, to the right of side HUDs */}\n {/* Player 1 Balance Indicator - Upper left area, below top HUD */}\n {validPlayers[0] && (\n <BalanceIndicatorOverlayHtml\n player={validPlayers[0] as BalancePlayerState}\n currentTime={currentTime}\n position={[\n -2.5, // Left side of arena (to the right of left HUD in 3D space)\n 2.5, // Upper area (below top HUD)\n -1.0, // Slightly forward toward camera\n ]}\n isMobile={isMobile}\n />\n )}\n\n {/* Player 2 Balance Indicator - Upper right area, below top HUD */}\n {validPlayers[1] && (\n <BalanceIndicatorOverlayHtml\n player={validPlayers[1] as BalancePlayerState}\n currentTime={currentTime}\n position={[\n 2.5, // Right side of arena (to the left of right HUD in 3D space)\n 2.5, // Upper area (below top HUD)\n -1.0, // Slightly forward toward camera\n ]}\n isMobile={isMobile}\n />\n )}\n\n {/* Mobile Touch Controls moved outside Canvas - using MobileControlsOverlay for reliable touch events */}\n\n {/* Performance Monitoring - FPS display (dev mode, toggle with P key) */}\n {process.env.NODE_ENV === \"development\" && showPerformanceMonitor && (\n <FPSMonitor\n enabled={true}\n warningThreshold={50}\n criticalThreshold={30}\n />\n )}\n </AdaptiveQualityWrapper>\n\n {/* Post-processing Effects - desktop high tier only for Android WebGL stability */}\n {renderConfig.postProcessing && (\n <EffectComposer multisampling={4}>\n <Bloom\n luminanceThreshold={0.9}\n luminanceSmoothing={0.9}\n mipmapBlur\n intensity={0.8}\n radius={0.4}\n />\n <Noise opacity={0.03} />\n <Vignette eskil={false} offset={0.1} darkness={0.3} />\n </EffectComposer>\n )}\n </Canvas>\n\n {/* Html UI Overlays (positioned absolutely over Canvas) */}\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n pointerEvents: \"none\",\n zIndex: Z_INDEX.HUD,\n overflow: \"clip\",\n }}\n >\n {/* Top HUD - Round info, timer, return to menu */}\n <CombatTopHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n currentRound={internalRound}\n totalRounds={3}\n timerState={timerState}\n showTimer={\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart\n }\n onReturnToMenu={onReturnToMenu}\n isPaused={isPaused || showPauseMenu}\n />\n\n {/* Left HUD - Player 1 stats.\n On mobile, side HUDs occlude the 3D arena in both portrait and\n landscape; collapse them away so the arena stays fully visible.\n Player status remains available via CombatPortraitStatusStrip and\n bottom combat controls. */}\n {!isMobile && (\n <CombatLeftHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n player={validPlayers[0]}\n laterality={combatState.playerLaterality[0]}\n isInGuard={player1Animation.isInStanceGuard()}\n speedModifiers={player1SpeedModifiers}\n />\n )}\n\n {/* Right HUD - Player 2/AI stats with difficulty indicator */}\n {!isMobile && (\n <CombatRightHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n player={validPlayers[1]}\n laterality={combatState.playerLaterality[1]}\n speedModifiers={player2SpeedModifiers}\n difficultyTier={currentDifficultyTier}\n />\n )}\n\n {/* Portrait-mobile HP/stamina strip. Replaces the hidden side HUDs\n so both players can still see their health at a glance without\n re-introducing arena occlusion. */}\n {isMobile && isPortrait && (\n <CombatPortraitStatusStrip\n width={width}\n height={height}\n player1={validPlayers[0]}\n player2={validPlayers[1]}\n positionScale={positionScale}\n topOffset={combatTopHudHeight}\n />\n )}\n\n {/* Bottom HUD - Technique bar, volume, messages */}\n <CombatBottomHUD\n width={width}\n height={height}\n isMobile={isMobile}\n positionScale={positionScale}\n visible={\n combatState.roundStarted &&\n !combatState.roundEnded &&\n matchCountdownComplete &&\n !showRoundStart\n }\n techniques={techniqueSelection.availableTechniques}\n player={validPlayers[0]}\n selectedIndex={techniqueSelection.selectedIndex}\n cooldowns={cooldownsMap}\n onTechniqueSelect={techniqueSelection.selectTechnique}\n combatMessages={combatState.combatMessages}\n />\n\n {/* Player State Visual Indicators */}\n {/* Player 1 State Overlay - includes consciousness blur, pain vignette, etc.\n In portrait mobile the arena is already rendered in a compressed 3:4\n aspect ratio, so halve the fullscreen vignette/blur/flash intensity\n to avoid further obscuring the scene. */}\n <PlayerStateOverlayHtml\n pain={validPlayers[0].pain}\n balanceState={getBalanceState(validPlayers[0].balance)}\n position=\"left\"\n consciousness={validPlayers[0].consciousness}\n bloodLoss={0} // FIXME: bloodLoss property not yet added to PlayerState interface - overlay will not display until implemented\n stamina={validPlayers[0].stamina}\n isMobile={isMobile}\n intensityScale={isMobile && isPortrait ? 0.5 : 1}\n />\n\n {/* Note: Player 2 (AI) does not get fullscreen state overlays like consciousness blur */}\n {/* as those effects would incorrectly affect the player's view */}\n\n {/* Breathing Disruption Indicators */}\n {/* Player 1 Breathing Indicator - positioned near left HUD */}\n <div\n style={{\n position: \"absolute\",\n left: isMobile ? \"10px\" : \"20px\",\n top: isMobile ? \"120px\" : \"160px\",\n zIndex: Z_INDEX.HUD + 1,\n pointerEvents: \"none\",\n }}\n data-testid=\"player1-breathing-indicator-container\"\n >\n <BreathingIndicator player={validPlayers[0]} isMobile={isMobile} />\n </div>\n\n {/* Player 2 Breathing Indicator - positioned near right HUD */}\n <div\n style={{\n position: \"absolute\",\n right: isMobile ? \"10px\" : \"20px\",\n top: isMobile ? \"120px\" : \"160px\",\n zIndex: Z_INDEX.HUD + 1,\n pointerEvents: \"none\",\n }}\n data-testid=\"player2-breathing-indicator-container\"\n >\n <BreathingIndicator player={validPlayers[1]} isMobile={isMobile} />\n </div>\n\n {/* Pause Menu Overlay */}\n {(isPaused || showPauseMenu) && (\n <PauseMenu\n onResume={handleResume}\n onRestart={handleRestart}\n onReturnToMenu={onReturnToMenu}\n isMobile={isMobile}\n />\n )}\n </div>\n\n {/* Round Announcement Overlay */}\n {showAnnouncement && roundWinner && (\n <RoundAnnouncement\n roundNumber={transitionRoundNumber}\n roundWinner={roundWinner}\n currentScore={matchScore}\n roundStats={{\n damageDealt: roundWinner.totalDamageDealt ?? 0,\n hitsLanded: roundWinner.hitsLanded ?? 0,\n vitalPointsHit: roundWinner.vitalPointHits ?? 0,\n accuracy: calculateAccuracy(roundWinner),\n }}\n onCountdownComplete={() => {\n if (matchScore.player1 >= 2 || matchScore.player2 >= 2) {\n const winner = matchScore.player1 >= 2 ? 0 : 1;\n onGameEnd(winner);\n } else {\n skipCountdown();\n }\n }}\n onSkip={() => {\n if (matchScore.player1 >= 2 || matchScore.player2 >= 2) {\n const winner = matchScore.player1 >= 2 ? 0 : 1;\n onGameEnd(winner);\n } else {\n skipCountdown();\n }\n }}\n isMobile={isMobile}\n totalRounds={3}\n />\n )}\n\n {/* Match Start Countdown Overlay - only shows once at match start */}\n {showMatchCountdown && !hasShownMatchCountdown && (\n <MatchCountdown\n onComplete={() => {\n setHasShownMatchCountdown(true);\n setShowMatchCountdown(false);\n setMatchCountdownComplete(true);\n startRound();\n }}\n isMobile={isMobile}\n showSkip={false}\n />\n )}\n\n {/* Round Start Announcement for subsequent rounds */}\n {/* Note: showRoundStart is only set to true after round 1 ends, so no need for internalRound > 1 check */}\n {showRoundStart && (\n <RoundStartAnnouncement\n roundNumber={internalRound}\n duration={2}\n onComplete={() => {\n if (import.meta.env.DEV) {\n console.log(\n \"[DEV] Round start announcement complete for round\",\n internalRound,\n );\n }\n setShowRoundStart(false);\n startRound();\n }}\n isMobile={isMobile}\n />\n )}\n\n {/* Round Display Status - Brief status messages */}\n {contentReady && combatState.roundDisplayStatus && (\n <RoundDisplayStatus\n status={combatState.roundDisplayStatus}\n isMobile={isMobile}\n />\n )}\n\n {/* Mobile Controls - Pure DOM, rendered OUTSIDE Canvas for reliable touch events */}\n {/* Uses pure DOM handlers instead of drei's Html which can block touch events on mobile */}\n {isMobile && (\n <>\n <MobileControlsOverlay\n onMove={handleMobileMove}\n onAttack={handleMobileAttack}\n onBlock={handleMobileBlock}\n bottom={getMobileControlsBottom(height)}\n viewportWidth={width}\n viewportHeight={height}\n />\n\n <StanceWheelPure\n currentStance={currentStanceIndex}\n onStanceChange={handleMobileStanceChange}\n expanded={stanceWheelExpanded}\n onToggle={toggleStanceWheel}\n disabled={!mobileControlsEnabled}\n opacity={0.8}\n />\n\n <GestureRecognizerPure\n onGesture={handleMobileGesture}\n enabled={mobileControlsEnabled}\n showFeedback={true}\n minSwipeDistance={50}\n />\n </>\n )}\n </div>\n );\n};\n\nexport default CombatScreen3D;\n"],"mappings":"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"}
|