blacktrigram 0.7.47 → 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.
Files changed (471) hide show
  1. package/lib/App2.js.map +1 -1
  2. package/lib/audio/AudioAssetLoader.js.map +1 -1
  3. package/lib/audio/AudioAssetRegistry.js.map +1 -1
  4. package/lib/audio/AudioCache.js.map +1 -1
  5. package/lib/audio/AudioManager.js.map +1 -1
  6. package/lib/audio/AudioMonitor.js.map +1 -1
  7. package/lib/audio/AudioPool.js.map +1 -1
  8. package/lib/audio/AudioProvider.js.map +1 -1
  9. package/lib/audio/AudioUtils.js.map +1 -1
  10. package/lib/audio/BoneImpactAudioMap.js.map +1 -1
  11. package/lib/audio/VariantSelector.js.map +1 -1
  12. package/lib/audio/types.js.map +1 -1
  13. package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
  14. package/lib/components/screens/combat/CombatScreen3D.js +29 -25
  15. package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
  16. package/lib/components/screens/combat/components/controls/CombatButtons.js.map +1 -1
  17. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
  18. package/lib/components/screens/combat/components/controls/ControlsGuide.js.map +1 -1
  19. package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
  20. package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
  21. package/lib/components/screens/combat/components/controls/PauseMenuButton.js.map +1 -1
  22. package/lib/components/screens/combat/components/controls/QuickSettings.js.map +1 -1
  23. package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
  24. package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
  25. package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
  26. package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
  27. package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
  28. package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
  29. package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
  30. package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
  31. package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
  32. package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
  33. package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
  34. package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
  35. package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js.map +1 -1
  36. package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
  37. package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
  38. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js +2 -2
  39. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
  40. package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
  41. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js +1 -1
  42. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
  43. package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
  44. package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
  45. package/lib/components/screens/combat/components/hud/CombatTopHUD.js +2 -1
  46. package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
  47. package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
  48. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  49. package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
  50. package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
  51. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  52. package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
  53. package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
  54. package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
  55. package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
  56. package/lib/components/screens/combat/helpers/AnimationUpdater.js +4 -2
  57. package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
  58. package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
  59. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  60. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  61. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  62. package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
  63. package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
  64. package/lib/components/screens/combat/hooks/useCombatLayout.js +11 -5
  65. package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
  66. package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
  67. package/lib/components/screens/controls/ControlsScreen3D.js +1 -1
  68. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  69. package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
  70. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  71. package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
  72. package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
  73. package/lib/components/screens/controls/components/Key3D.js.map +1 -1
  74. package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
  75. package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
  76. package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
  77. package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
  78. package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
  79. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  80. package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
  81. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  82. package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
  83. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  84. package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
  85. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  86. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  87. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  88. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  89. package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
  90. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  91. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  92. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  93. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  94. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  95. package/lib/components/screens/philosophy/PhilosophyScreen3D.js +1 -1
  96. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  97. package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
  98. package/lib/components/screens/training/TrainingScreen3D.js +3 -11
  99. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  100. package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
  101. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  102. package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
  103. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  104. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  105. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  106. package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
  107. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  108. package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
  109. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  110. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  111. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  112. package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
  113. package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
  114. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js +2 -2
  115. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
  116. package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
  117. package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
  118. package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
  119. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  120. package/lib/components/screens/training/hooks/useTrainingActions.d.ts +1 -0
  121. package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
  122. package/lib/components/screens/training/hooks/useTrainingActions.js +6 -4
  123. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  124. package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
  125. package/lib/components/screens/training/hooks/useTrainingLayout.js +11 -5
  126. package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
  127. package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
  128. package/lib/components/shared/base/BaseButton.js.map +1 -1
  129. package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
  130. package/lib/components/shared/base/BasePanel.js.map +1 -1
  131. package/lib/components/shared/base/BaseText.js.map +1 -1
  132. package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
  133. package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
  134. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  135. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  136. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  137. package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
  138. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  139. package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
  140. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  141. package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
  142. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  143. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  144. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  145. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  146. package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
  147. package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
  148. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  149. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  150. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  151. package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
  152. package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
  153. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  154. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  155. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  156. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  157. package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
  158. package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
  159. package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
  160. package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
  161. package/lib/components/shared/three/models/SkeletalPlayer3D.js +7 -5
  162. package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
  163. package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
  164. package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
  165. package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
  166. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  167. package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
  168. package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
  169. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  170. package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
  171. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  172. package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
  173. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  174. package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
  175. package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
  176. package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
  177. package/lib/components/shared/three/ui/MenuList.js.map +1 -1
  178. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  179. package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
  180. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  181. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  182. package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
  183. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  184. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  185. package/lib/components/shared/ui/BackButton.js.map +1 -1
  186. package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
  187. package/lib/components/shared/ui/CombatTimer.js.map +1 -1
  188. package/lib/components/shared/ui/ErrorModal.js.map +1 -1
  189. package/lib/components/shared/ui/LoadingState.js.map +1 -1
  190. package/lib/components/shared/ui/SplashScreen.js +2 -2
  191. package/lib/components/shared/ui/SplashScreen.js.map +1 -1
  192. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  193. package/lib/components/shared/ui/VolumeControl.js.map +1 -1
  194. package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
  195. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  196. package/lib/constants/bodyDimensions.js.map +1 -1
  197. package/lib/constants/bodyRenderingConstants.js.map +1 -1
  198. package/lib/data/archetypeClothing.js.map +1 -1
  199. package/lib/data/archetypePhysicalAttributes.js.map +1 -1
  200. package/lib/data/techniqueMappings.js.map +1 -1
  201. package/lib/data/techniques.js.map +1 -1
  202. package/lib/hooks/useActionFeedback.js.map +1 -1
  203. package/lib/hooks/useBalanceAnimations.js.map +1 -1
  204. package/lib/hooks/useCombatTimer.js.map +1 -1
  205. package/lib/hooks/useDebounce.js.map +1 -1
  206. package/lib/hooks/useHUDLayout.d.ts.map +1 -1
  207. package/lib/hooks/useHUDLayout.js +3 -2
  208. package/lib/hooks/useHUDLayout.js.map +1 -1
  209. package/lib/hooks/useHandPoseTransitions.js.map +1 -1
  210. package/lib/hooks/useKeyboardControls.js.map +1 -1
  211. package/lib/hooks/useMatchCountdown.js.map +1 -1
  212. package/lib/hooks/useMuscleActivation.js.map +1 -1
  213. package/lib/hooks/usePauseMenu.js.map +1 -1
  214. package/lib/hooks/usePlayerAnimation.js.map +1 -1
  215. package/lib/hooks/useResponsiveLayout.js.map +1 -1
  216. package/lib/hooks/useRoundTransition.js.map +1 -1
  217. package/lib/hooks/useSkeletalAnimation.d.ts.map +1 -1
  218. package/lib/hooks/useSkeletalAnimation.js +1 -1
  219. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  220. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  221. package/lib/hooks/useThrottle.js.map +1 -1
  222. package/lib/hooks/useTouchControls.js.map +1 -1
  223. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  224. package/lib/hooks/useWindowSize.js.map +1 -1
  225. package/lib/systems/CombatSystem.js.map +1 -1
  226. package/lib/systems/EffectCalculator.js.map +1 -1
  227. package/lib/systems/LayoutSystem.js.map +1 -1
  228. package/lib/systems/PlayerEffectManager.js.map +1 -1
  229. package/lib/systems/ResponsiveScaling.js.map +1 -1
  230. package/lib/systems/TrigramSystem.js.map +1 -1
  231. package/lib/systems/VitalPointSystem.js.map +1 -1
  232. package/lib/systems/ai/AIPersonality.js.map +1 -1
  233. package/lib/systems/ai/AdaptiveDifficulty.js +16 -16
  234. package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
  235. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  236. package/lib/systems/ai/ComboSystem.js.map +1 -1
  237. package/lib/systems/ai/DecisionTree.js.map +1 -1
  238. package/lib/systems/ai/TrainingAI.js.map +1 -1
  239. package/lib/systems/ai/types.js.map +1 -1
  240. package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
  241. package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
  242. package/lib/systems/animation/builders/HandPoses.js.map +1 -1
  243. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  244. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  245. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts +6 -0
  246. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts.map +1 -1
  247. package/lib/systems/animation/builders/KickPhaseApplicator.js +16 -9
  248. package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
  249. package/lib/systems/animation/builders/KoreanGuardPositions.d.ts +4 -4
  250. package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
  251. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts +1 -1
  252. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts.map +1 -1
  253. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js +5 -5
  254. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  255. package/lib/systems/animation/builders/MartialArtsConstants.d.ts +112 -71
  256. package/lib/systems/animation/builders/MartialArtsConstants.d.ts.map +1 -1
  257. package/lib/systems/animation/builders/MartialArtsConstants.js +113 -72
  258. package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
  259. package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
  260. package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
  261. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  262. package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
  263. package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
  264. package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
  265. package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
  266. package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
  267. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  268. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
  269. package/lib/systems/animation/catalogs/EnhancedAttackAnimations.js.map +1 -1
  270. package/lib/systems/animation/catalogs/EnhancedElbowKneeAnimations.js.map +1 -1
  271. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  272. package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
  273. package/lib/systems/animation/catalogs/GamStanceAnimations.js +21 -0
  274. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -0
  275. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js +34 -2
  276. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
  277. package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
  278. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
  279. package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
  280. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts +9 -0
  281. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts.map +1 -1
  282. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +288 -0
  283. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -0
  284. package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
  285. package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
  286. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
  287. package/lib/systems/animation/catalogs/KickAnimations.d.ts +2 -2
  288. package/lib/systems/animation/catalogs/KickAnimations.js +2 -2
  289. package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
  290. package/lib/systems/animation/catalogs/LiStanceAnimations.js +14 -1
  291. package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
  292. package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
  293. package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
  294. package/lib/systems/animation/catalogs/PunchAnimations.d.ts +1 -1
  295. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  296. package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
  297. package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
  298. package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
  299. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
  300. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
  301. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  302. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  303. package/lib/systems/animation/catalogs/StanceGuardPoses.d.ts +6 -6
  304. package/lib/systems/animation/catalogs/StanceGuardPoses.js +36 -36
  305. package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
  306. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  307. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  308. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  309. package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
  310. package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
  311. package/lib/systems/animation/constants/AnatomicalLimits.js.map +1 -1
  312. package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
  313. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  314. package/lib/systems/animation/core/AnimationPriority.js +15 -15
  315. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  316. package/lib/systems/animation/core/AnimationRegistry.d.ts +30 -0
  317. package/lib/systems/animation/core/AnimationRegistry.d.ts.map +1 -1
  318. package/lib/systems/animation/core/AnimationRegistry.js +74 -12
  319. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  320. package/lib/systems/animation/core/AnimationStateMachine.js +16 -16
  321. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  322. package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
  323. package/lib/systems/animation/core/AnimationTransitions.js +34 -0
  324. package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
  325. package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
  326. package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
  327. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  328. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  329. package/lib/systems/animation/core/index.d.ts +1 -1
  330. package/lib/systems/animation/core/index.d.ts.map +1 -1
  331. package/lib/systems/animation/core/types.d.ts +24 -0
  332. package/lib/systems/animation/core/types.d.ts.map +1 -1
  333. package/lib/systems/animation/core/types.js +27 -11
  334. package/lib/systems/animation/core/types.js.map +1 -1
  335. package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
  336. package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
  337. package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
  338. package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
  339. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  340. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  341. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  342. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  343. package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
  344. package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
  345. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  346. package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
  347. package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
  348. package/lib/systems/bodypart/types.js.map +1 -1
  349. package/lib/systems/breathing/BreathingDisruptionSystem.js +19 -19
  350. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  351. package/lib/systems/breathing/feedback.js.map +1 -1
  352. package/lib/systems/breathing/integration.js.map +1 -1
  353. package/lib/systems/combat/BalanceSystem.js +19 -19
  354. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  355. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  356. package/lib/systems/combat/CombatStateSystem.js +17 -17
  357. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  358. package/lib/systems/combat/ConsciousnessSystem.js +24 -24
  359. package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
  360. package/lib/systems/combat/FallIntegration.js.map +1 -1
  361. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  362. package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
  363. package/lib/systems/combat/PainResponseSystem.js +21 -21
  364. package/lib/systems/combat/PainResponseSystem.js.map +1 -1
  365. package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
  366. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  367. package/lib/systems/combat/typeGuards.js.map +1 -1
  368. package/lib/systems/effects.js.map +1 -1
  369. package/lib/systems/game.js.map +1 -1
  370. package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
  371. package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
  372. package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
  373. package/lib/systems/movement/integration.js.map +1 -1
  374. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  375. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  376. package/lib/systems/physics/CoordinateMapper.js.map +1 -1
  377. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  378. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  379. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  380. package/lib/systems/physics/SpeedModifierSystem.js +6 -6
  381. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  382. package/lib/systems/trigram/KoreanCulture.js.map +1 -1
  383. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  384. package/lib/systems/trigram/StanceManager.js.map +1 -1
  385. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  386. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  387. package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
  388. package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
  389. package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
  390. package/lib/systems/trigram/techniques/GeonTechniques.js.map +1 -1
  391. package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
  392. package/lib/systems/trigram/techniques/JinTechniques.js.map +1 -1
  393. package/lib/systems/trigram/techniques/LiTechniques.js.map +1 -1
  394. package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
  395. package/lib/systems/trigram/techniques/TaeTechniques.js.map +1 -1
  396. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  397. package/lib/systems/trigram/techniques/index.js.map +1 -1
  398. package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
  399. package/lib/systems/trigram/types.js.map +1 -1
  400. package/lib/systems/types.js.map +1 -1
  401. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  402. package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
  403. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  404. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  405. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  406. package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
  407. package/lib/types/AccessibilityTypes.js.map +1 -1
  408. package/lib/types/LayoutTypes.js.map +1 -1
  409. package/lib/types/PhysicsTypes.js.map +1 -1
  410. package/lib/types/common.js.map +1 -1
  411. package/lib/types/constants/animations.js.map +1 -1
  412. package/lib/types/constants/colors.js.map +1 -1
  413. package/lib/types/constants/designSystem.js.map +1 -1
  414. package/lib/types/constants/index.js.map +1 -1
  415. package/lib/types/constants/layout.d.ts +21 -0
  416. package/lib/types/constants/layout.d.ts.map +1 -1
  417. package/lib/types/constants/layout.js +22 -1
  418. package/lib/types/constants/layout.js.map +1 -1
  419. package/lib/types/constants/performance.js.map +1 -1
  420. package/lib/types/constants/typography.js.map +1 -1
  421. package/lib/types/constants/ui.js.map +1 -1
  422. package/lib/types/facial.js +19 -19
  423. package/lib/types/facial.js.map +1 -1
  424. package/lib/types/hand-animation.js.map +1 -1
  425. package/lib/types/injury.js.map +1 -1
  426. package/lib/types/muscle.js.map +1 -1
  427. package/lib/types/physics.js.map +1 -1
  428. package/lib/types/physicsConstants.js.map +1 -1
  429. package/lib/types/player-visual.d.ts +1 -1
  430. package/lib/types/player-visual.d.ts.map +1 -1
  431. package/lib/types/skeletal.js.map +1 -1
  432. package/lib/types/techniqueId.js.map +1 -1
  433. package/lib/utils/accessibility.js.map +1 -1
  434. package/lib/utils/arenaWorldDimensions.js.map +1 -1
  435. package/lib/utils/assetConfig.js.map +1 -1
  436. package/lib/utils/characterScaling.js.map +1 -1
  437. package/lib/utils/colorHelpers.js.map +1 -1
  438. package/lib/utils/colorUtils.js.map +1 -1
  439. package/lib/utils/combatReadiness.js.map +1 -1
  440. package/lib/utils/controlMapping.js.map +1 -1
  441. package/lib/utils/deviceDetection.js +6 -7
  442. package/lib/utils/deviceDetection.js.map +1 -1
  443. package/lib/utils/effectUtils.js.map +1 -1
  444. package/lib/utils/fabricTextures.js.map +1 -1
  445. package/lib/utils/hapticFeedback.js.map +1 -1
  446. package/lib/utils/haptics.js.map +1 -1
  447. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  448. package/lib/utils/inputSystem.js.map +1 -1
  449. package/lib/utils/koreanThemeHelpers.js.map +1 -1
  450. package/lib/utils/math.js.map +1 -1
  451. package/lib/utils/mobileLayoutHelpers.js.map +1 -1
  452. package/lib/utils/mobileUIUtils.js.map +1 -1
  453. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  454. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  455. package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
  456. package/lib/utils/performanceOptimization.js.map +1 -1
  457. package/lib/utils/player3DHelpers.js.map +1 -1
  458. package/lib/utils/playerUtils.js.map +1 -1
  459. package/lib/utils/responsiveLayout.js.map +1 -1
  460. package/lib/utils/responsiveLayoutHelpers.d.ts +7 -0
  461. package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
  462. package/lib/utils/responsiveLayoutHelpers.js +16 -2
  463. package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
  464. package/lib/utils/responsiveOrientationConstants.js.map +1 -1
  465. package/lib/utils/safeAreaUtils.js.map +1 -1
  466. package/lib/utils/sharedPhysicsConfig.js.map +1 -1
  467. package/lib/utils/skeletonScaling.js.map +1 -1
  468. package/lib/utils/stanceHelpers.js.map +1 -1
  469. package/lib/utils/threeObjectPool.js.map +1 -1
  470. package/lib/utils/visualEffects.js.map +1 -1
  471. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"MovementPhysics.js","names":[],"sources":["../../../src/systems/physics/MovementPhysics.ts"],"sourcesContent":["/**\n * Physics-based movement system for realistic combat movement.\n *\n * **Korean**: 이동 물리 시스템 (Movement Physics System)\n *\n * This module implements realistic physics-based player movement with proper\n * acceleration/deceleration, foot-wide step precision, and stance-based speed\n * modifiers for authentic Korean martial arts combat feel.\n *\n * ## Features\n *\n * - **Realistic Acceleration**: 0 to 2m/s in 0.5 seconds (4.0 m/s²)\n * - **Realistic Deceleration**: 2m/s to 0 in 0.3 seconds (6.67 m/s²)\n * - **Foot-wide Steps**: Discrete 30cm movement increments for tactical positioning\n * - **Stance Modifiers**: 8 trigram stances with different speed characteristics\n * - **Injury Integration**: Movement speed reduced by leg damage (10-50%)\n *\n * @module systems/physics/MovementPhysics\n * @category Physics System\n * @korean 이동물리\n */\n\nimport { TrigramStance } from \"@/types/common\";\nimport { BASE_MOVEMENT_ACCELERATION } from \"@/types/physicsConstants\";\nimport type { MovementArenaBounds } from \"@/types/PhysicsTypes\";\nimport * as THREE from \"three\";\n\n/**\n * Movement input from keyboard/gamepad controls.\n *\n * **Korean**: 이동 입력 (Movement Input)\n *\n * @category Physics System\n * @korean 이동입력\n */\nexport interface MovementInput {\n /** Forward/backward input (-1 to 1, where 1 is forward) */\n readonly forward: number;\n /** Lateral left/right input (-1 to 1, where 1 is right) */\n readonly lateral: number;\n /** Whether sprint/run key is held */\n readonly isRunning: boolean;\n /** Whether any movement input is active */\n readonly isMoving: boolean;\n /** Whether to use tactical step mode (30cm grid) */\n readonly useTacticalSteps: boolean;\n}\n\n/**\n * Complete movement state for physics calculations.\n *\n * **Korean**: 이동 상태 (Movement State)\n *\n * Contains position, velocity, and current movement parameters.\n * All vectors are mutable for performance (updated in-place during physics loop).\n *\n * @category Physics System\n * @korean 이동상태\n */\nexport interface MovementState {\n /**\n * Current position in 3D space (meters).\n *\n * NOTE: This is a readonly reference to a mutable THREE.Vector3.\n * The physics engine intentionally mutates the vector in-place\n * (e.g. via position.add(...)) for performance. The readonly\n * modifier prevents reassignment of the Vector3 instance, not\n * mutation of its components.\n */\n readonly position: THREE.Vector3;\n /**\n * Current velocity vector (m/s).\n *\n * NOTE: This is a readonly reference to a mutable THREE.Vector3.\n * The physics engine updates this vector in-place each frame.\n * Callers must not reassign the velocity reference, but may pass\n * it to APIs that read or modify its components.\n */\n readonly velocity: THREE.Vector3;\n /** Current acceleration magnitude (m/s²) */\n acceleration: number;\n /** Maximum speed for current state (m/s) */\n maxSpeed: number;\n /** Current Eight Trigram stance */\n readonly currentStance: TrigramStance;\n /** Leg injury percentage (0-1, where 1 is fully injured) */\n legInjuryFactor: number;\n}\n\n/**\n * Stance-based speed modifiers for Eight Trigram system.\n *\n * **Korean**: 팔괘 속도 배수 (Eight Trigram Speed Multipliers)\n *\n * Each trigram stance has unique movement characteristics based on\n * traditional Korean martial arts philosophy:\n *\n * - ☰ 건 (Geon/Heaven): 100% - Balanced, standard speed\n * - ☱ 태 (Tae/Lake): 110% - Fluid movement, flowing techniques\n * - ☲ 리 (Li/Fire): 120% - Aggressive, fast attacks\n * - ☳ 진 (Jin/Thunder): 115% - Explosive power\n * - ☴ 손 (Son/Wind): 125% - Continuous motion, fastest stance\n * - ☵ 감 (Gam/Water): 105% - Adaptive, slightly faster than neutral\n * - ☶ 간 (Gan/Mountain): 80% - Solid defense, slower movement\n * - ☷ 곤 (Gon/Earth): 85% - Grounded, stable but slower\n *\n * @korean 자세속도배수\n */\nexport const STANCE_SPEED_MODIFIERS: Record<TrigramStance, number> = {\n [TrigramStance.GEON]: 1.0, // Heaven: balanced\n [TrigramStance.TAE]: 1.1, // Lake: fluid\n [TrigramStance.LI]: 1.2, // Fire: aggressive\n [TrigramStance.JIN]: 1.15, // Thunder: explosive\n [TrigramStance.SON]: 1.25, // Wind: fastest\n [TrigramStance.GAM]: 1.05, // Water: adaptive\n [TrigramStance.GAN]: 0.8, // Mountain: defensive\n [TrigramStance.GON]: 0.85, // Earth: grounded\n};\n\n/**\n * Physics-based movement engine for combat.\n *\n * **Korean**: 이동 물리 엔진 (Movement Physics Engine)\n *\n * Implements realistic acceleration, deceleration, and stance-based movement\n * for authentic Korean martial arts combat. Supports both continuous movement\n * and tactical foot-wide steps for precise positioning.\n *\n * @example\n * ```typescript\n * const physics = new MovementPhysics();\n *\n * const state: MovementState = {\n * position: new THREE.Vector3(0, 0, 0),\n * velocity: new THREE.Vector3(0, 0, 0),\n * acceleration: 0,\n * maxSpeed: 2.0,\n * currentStance: TrigramStance.GEON,\n * legInjuryFactor: 0,\n * };\n *\n * const input: MovementInput = {\n * forward: 1.0,\n * lateral: 0,\n * isRunning: false,\n * isMoving: true,\n * useTacticalSteps: false,\n * };\n *\n * // In game loop at 60fps\n * physics.updateMovement(state, input, deltaTime);\n * ```\n *\n * @category Physics System\n * @korean 이동물리엔진\n */\nexport class MovementPhysics {\n /**\n * Base acceleration rate (m/s²)\n * Achieves 0 to 6m/s in 0.2 seconds (instant-response combat movement)\n * Increased from 12.0 to 30.0 for arcade-style responsiveness\n *\n * Imported from physicsConstants.ts to maintain consistency across systems.\n *\n * **Korean**: 기본 가속도 (Base Acceleration)\n */\n private readonly BASE_ACCELERATION = BASE_MOVEMENT_ACCELERATION;\n\n /**\n * Base deceleration rate (m/s²)\n * Achieves 6m/s to 0 in 0.3 seconds (responsive combat stopping)\n *\n * **Korean**: 기본 감속도 (Base Deceleration)\n */\n private readonly BASE_DECELERATION = 20.0;\n\n /**\n * Foot-wide step size (meters)\n * Standard Korean martial arts step is approximately 30cm\n *\n * **Korean**: 보법 거리 (Step Distance)\n */\n private readonly STEP_SIZE = 0.3;\n\n /**\n * Base walking speed (m/s)\n * Optimized for responsive combat movement - crosses 14m arena in ~2.3s\n *\n * **Korean**: 기본 걷기 속도 (Base Walking Speed)\n */\n private readonly BASE_WALK_SPEED = 6.0;\n\n /**\n * Base running speed (m/s)\n * Sprint speed for rapid repositioning - crosses 14m arena in ~1.4s\n *\n * **Korean**: 기본 달리기 속도 (Base Running Speed)\n */\n private readonly BASE_RUN_SPEED = 10.0;\n\n /**\n * Reference arena size for speed calibration (meters).\n * All speeds are calibrated for a 10m arena.\n *\n * **Korean**: 기준 경기장 크기 (Reference Arena Size)\n */\n private readonly REFERENCE_ARENA_SIZE = 10.0;\n\n /**\n * Current arena width in meters for arena-aware speed scaling.\n *\n * **Korean**: 현재 경기장 너비 (Current Arena Width)\n */\n private _arenaWidthMeters: number = 10.0;\n\n // LATERAL_SPEED removed - now using state.maxSpeed for all directions\n // This ensures speed override applies to lateral movement too\n\n /**\n * Override for max speed from external speed modifier systems.\n *\n * **Korean**: 최대속도 재정의 (Max Speed Override)\n */\n private _overrideMaxSpeed: number | null = null;\n\n /**\n * Override for acceleration from external speed modifier systems.\n *\n * **Korean**: 가속도 재정의 (Acceleration Override)\n */\n private _overrideAcceleration: number | null = null;\n\n /**\n * Cached arena speed scale to avoid repeated calculations.\n *\n * **Korean**: 캐시된 경기장 속도 배수 (Cached Arena Speed Scale)\n */\n private _cachedArenaSpeedScale: number = 1.0;\n\n // Temporary vectors to avoid allocations in update loop\n private readonly tempTargetVelocity = new THREE.Vector3();\n private readonly tempMovement = new THREE.Vector3();\n private readonly tempDirection = new THREE.Vector3();\n private readonly tempTargetDirection = new THREE.Vector3();\n\n /**\n * Create a new MovementPhysics instance.\n *\n * **Korean**: 이동 물리 생성 (Create Movement Physics)\n *\n * @param arenaWidthMeters - Width of the arena in meters (default: 10m, min: 1m)\n * @throws {Error} If arenaWidthMeters is not a positive number\n *\n * @example\n * ```typescript\n * // Default 10m arena (1.0x speed scale)\n * const physics = new MovementPhysics();\n *\n * // Small 6m arena (0.7x speed scale)\n * const smallPhysics = new MovementPhysics(6.0);\n *\n * // Large 14m arena (1.3x speed scale)\n * const largePhysics = new MovementPhysics(14.0);\n * ```\n *\n */\n constructor(arenaWidthMeters: number = 10.0) {\n if (arenaWidthMeters <= 0 || !Number.isFinite(arenaWidthMeters)) {\n throw new Error(\n `Arena width must be a positive finite number, got: ${arenaWidthMeters}`,\n );\n }\n this._arenaWidthMeters = arenaWidthMeters;\n this._cachedArenaSpeedScale = this.calculateArenaSpeedScale();\n }\n\n /**\n * Calculate arena-aware speed scaling factor.\n *\n * **Korean**: 경기장 크기 기반 속도 배수 (Arena-Based Speed Multiplier)\n *\n * Scales movement speed proportionally to arena size to maintain consistent\n * gameplay feel across different screen resolutions. Smaller arenas get\n * slightly slower speeds, larger arenas get slightly faster speeds.\n *\n * Formula: scaleFactor = arenaWidth / referenceArenaSize\n * Clamped to [0.7, 1.3] range for balanced gameplay\n *\n * Examples:\n * - 6m arena: 0.7x speed (70% of base)\n * - 10m arena: 1.0x speed (baseline)\n * - 14m arena: 1.3x speed (130% of base)\n *\n * @returns Speed multiplier (0.7 to 1.3)\n *\n * @korean 경기장속도배수\n */\n private calculateArenaSpeedScale(): number {\n const rawScale = this._arenaWidthMeters / this.REFERENCE_ARENA_SIZE;\n // Clamp to reasonable range to maintain gameplay balance\n return Math.max(0.7, Math.min(1.3, rawScale));\n }\n\n /**\n * Update player movement based on input and physics.\n *\n * **Korean**: 이동 업데이트 (Update Movement)\n *\n * Called every frame (60fps) to update player position based on\n * current velocity, acceleration, and input. Applies stance modifiers\n * and injury penalties automatically.\n *\n * @param state - Current movement state (modified in-place)\n * @param input - Current movement input from controls\n * @param deltaTime - Time since last update (seconds)\n * @param bounds - Optional arena bounds for clamping position (meters)\n *\n * @korean 이동업데이트\n */\n public updateMovement(\n state: MovementState,\n input: MovementInput,\n deltaTime: number,\n bounds?: MovementArenaBounds,\n ): void {\n // Use cached arena-aware speed scaling\n const arenaSpeedScale = this._cachedArenaSpeedScale;\n\n // Calculate stance speed modifier\n const stanceModifier = this.getStanceSpeedModifier(state.currentStance);\n\n // Calculate injury penalty (0-50% speed reduction)\n const injuryPenalty = 1.0 - state.legInjuryFactor * 0.5;\n\n // Calculate base target speed (walking or running)\n const baseSpeed = input.isRunning\n ? this.BASE_RUN_SPEED\n : this.BASE_WALK_SPEED;\n\n // Apply all modifiers including arena scaling to get final max speed (or use override)\n state.maxSpeed =\n this._overrideMaxSpeed ??\n baseSpeed * arenaSpeedScale * stanceModifier * injuryPenalty;\n\n // Use override acceleration if set, otherwise use base\n const currentAcceleration =\n this._overrideAcceleration ?? this.BASE_ACCELERATION;\n\n // Calculate target velocity based on input direction\n // forward > 0 = moving in positive Z direction (toward bottom of screen)\n // forward < 0 = moving in negative Z direction (toward top of screen)\n // ✅ REMOVED backward multiplier: All directions use full speed for responsive gameplay\n // The backward penalty should be applied contextually by the combat system\n // based on player facing direction vs movement direction\n // ✅ FIX: Both lateral and forward now use state.maxSpeed (which includes all modifiers)\n // This ensures consistent speed in all movement directions and includes arena scaling\n this.tempTargetVelocity.set(\n input.lateral * state.maxSpeed,\n 0,\n input.forward * state.maxSpeed,\n );\n\n // Apply acceleration or deceleration\n if (input.isMoving) {\n // Accelerate toward target velocity with realistic direction changes\n const currentSpeed = state.velocity.length();\n const targetSpeed = this.tempTargetVelocity.length();\n\n if (currentSpeed < targetSpeed) {\n // Check if direction change is needed\n if (currentSpeed > 0.001 && targetSpeed > 0.001) {\n // Current movement direction\n this.tempDirection.copy(state.velocity).normalize();\n // Desired movement direction (reuse temp vector to avoid allocation)\n this.tempTargetDirection.copy(this.tempTargetVelocity).normalize();\n const directionDot = this.tempDirection.dot(this.tempTargetDirection);\n\n if (directionDot < 0) {\n // Moving in opposite direction: decelerate first before reversing\n const velocityDelta = this.BASE_DECELERATION * deltaTime;\n const newSpeed = Math.max(currentSpeed - velocityDelta, 0);\n\n if (newSpeed > 0.001) {\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n } else {\n // Fully stopped; can now start accelerating in new direction\n state.velocity.set(0, 0, 0);\n }\n state.acceleration = -this.BASE_DECELERATION;\n } else if (directionDot < 0.7) {\n // Perpendicular direction change (e.g., forward to strafe): moderate deceleration\n const blendedAccel = currentAcceleration * 0.6; // Reduced acceleration for sharp turns\n const velocityDelta = blendedAccel * deltaTime;\n const newSpeed = Math.min(\n currentSpeed + velocityDelta,\n targetSpeed,\n );\n this.tempDirection.copy(this.tempTargetVelocity).normalize();\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n state.acceleration = blendedAccel;\n } else {\n // Same or similar direction: full acceleration\n this.tempDirection.copy(this.tempTargetVelocity).normalize();\n const velocityDelta = currentAcceleration * deltaTime;\n const newSpeed = Math.min(\n currentSpeed + velocityDelta,\n targetSpeed,\n );\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n state.acceleration = currentAcceleration;\n }\n } else {\n // Very low speed: safe to accelerate directly toward target\n this.tempDirection.copy(this.tempTargetVelocity).normalize();\n const velocityDelta = currentAcceleration * deltaTime;\n const newSpeed = Math.min(currentSpeed + velocityDelta, targetSpeed);\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n state.acceleration = currentAcceleration;\n }\n } else {\n // Already at or above target speed: snap to target velocity\n state.velocity.copy(this.tempTargetVelocity);\n state.acceleration = 0;\n }\n } else {\n // Decelerate to stop\n const currentSpeed = state.velocity.length();\n if (currentSpeed > 0.01) {\n this.tempDirection.copy(state.velocity).normalize();\n const velocityDelta = this.BASE_DECELERATION * deltaTime;\n const newSpeed = Math.max(currentSpeed - velocityDelta, 0);\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n } else {\n state.velocity.set(0, 0, 0);\n }\n state.acceleration = -this.BASE_DECELERATION;\n }\n\n // Calculate movement delta for this frame\n this.tempMovement.copy(state.velocity).multiplyScalar(deltaTime);\n\n // Apply tactical step quantization if enabled\n if (input.useTacticalSteps) {\n // Quantize to 30cm grid steps\n this.tempMovement.x =\n Math.round(this.tempMovement.x / this.STEP_SIZE) * this.STEP_SIZE;\n this.tempMovement.z =\n Math.round(this.tempMovement.z / this.STEP_SIZE) * this.STEP_SIZE;\n }\n\n // Update position\n state.position.add(this.tempMovement);\n\n // Apply arena bounds clamping if bounds provided\n if (bounds) {\n // Check if position exceeded boundaries\n const exceededMinX = state.position.x < bounds.minX;\n const exceededMaxX = state.position.x > bounds.maxX;\n const exceededMinZ = state.position.z < bounds.minZ;\n const exceededMaxZ = state.position.z > bounds.maxZ;\n\n // Clamp position to arena boundaries\n state.position.x = Math.max(bounds.minX, Math.min(bounds.maxX, state.position.x));\n state.position.z = Math.max(bounds.minZ, Math.min(bounds.maxZ, state.position.z));\n\n // Zero velocity component if exceeded boundary (smooth stopping)\n if (exceededMinX || exceededMaxX) {\n state.velocity.x = 0;\n }\n if (exceededMinZ || exceededMaxZ) {\n state.velocity.z = 0;\n }\n }\n }\n\n /**\n * Get speed modifier for a specific trigram stance.\n *\n * **Korean**: 자세 속도 배수 가져오기 (Get Stance Speed Modifier)\n *\n * @param stance - Eight Trigram stance\n * @returns Speed multiplier (0.8 to 1.25)\n *\n * @korean 자세속도배수\n */\n public getStanceSpeedModifier(stance: TrigramStance): number {\n return STANCE_SPEED_MODIFIERS[stance];\n }\n\n /**\n * Calculate movement penalty from leg injury.\n *\n * **Korean**: 부상 이동 페널티 (Injury Movement Penalty)\n *\n * Leg damage reduces movement speed by 10-50% based on injury severity.\n *\n * @param legHealthPercentage - Remaining leg health (0-1)\n * @returns Injury factor (0 = no injury, 1 = maximum injury)\n *\n * @korean 부상페널티\n */\n public calculateInjuryPenalty(legHealthPercentage: number): number {\n // Injury penalty scales from 0% (healthy) to 50% (critical)\n // Clamp between 0 and 1\n const healthFactor = Math.max(0, Math.min(1, legHealthPercentage));\n return 1.0 - healthFactor;\n }\n\n /**\n * Get maximum speed for current state configuration.\n *\n * **Korean**: 최대 속도 계산 (Calculate Maximum Speed)\n *\n * @param isRunning - Whether running (vs walking)\n * @param stance - Current trigram stance\n * @param legInjuryFactor - Leg injury severity (0-1)\n * @returns Maximum speed in m/s (includes arena scaling)\n *\n * @korean 최대속도\n */\n public getMaxSpeed(\n isRunning: boolean,\n stance: TrigramStance,\n legInjuryFactor: number,\n ): number {\n const arenaSpeedScale = this._cachedArenaSpeedScale;\n const baseSpeed = isRunning ? this.BASE_RUN_SPEED : this.BASE_WALK_SPEED;\n const stanceModifier = this.getStanceSpeedModifier(stance);\n const injuryPenalty = 1.0 - legInjuryFactor * 0.5;\n return baseSpeed * arenaSpeedScale * stanceModifier * injuryPenalty;\n }\n\n /**\n * Calculate time required to reach target speed from current velocity.\n *\n * **Korean**: 가속 시간 (Acceleration Time)\n *\n * @param currentSpeed - Current speed magnitude (m/s)\n * @param targetSpeed - Desired speed magnitude (m/s)\n * @returns Time in seconds to reach target speed\n *\n * @korean 가속시간\n */\n public getAccelerationTime(\n currentSpeed: number,\n targetSpeed: number,\n ): number {\n const speedDiff = Math.abs(targetSpeed - currentSpeed);\n return speedDiff / this.BASE_ACCELERATION;\n }\n\n /**\n * Calculate stopping distance from current velocity.\n *\n * **Korean**: 제동 거리 (Braking Distance)\n *\n * @param currentSpeed - Current speed magnitude (m/s)\n * @returns Distance in meters required to stop\n *\n * @korean 제동거리\n */\n public getStoppingDistance(currentSpeed: number): number {\n // Using kinematic equation: d = v² / (2a)\n return (currentSpeed * currentSpeed) / (2 * this.BASE_DECELERATION);\n }\n\n /**\n * Get tactical step size.\n *\n * **Korean**: 보법 거리 (Step Distance)\n *\n * @returns Step size in meters (0.3m = 30cm)\n *\n * @korean 보법거리\n */\n public getStepSize(): number {\n return this.STEP_SIZE;\n }\n\n /**\n * Override maximum speed for external speed modifier systems.\n *\n * **Korean**: 최대 속도 설정 (Set Maximum Speed)\n *\n * Allows external systems (like SpeedModifierSystem) to override\n * the calculated maximum speed. This is applied in the next\n * updateMovement call.\n *\n * @param speed - Maximum speed in m/s\n *\n */\n public setMaxSpeed(speed: number): void {\n this._overrideMaxSpeed = speed;\n }\n\n /**\n * Override acceleration for external speed modifier systems.\n *\n * **Korean**: 가속도 설정 (Set Acceleration)\n *\n * Allows external systems (like SpeedModifierSystem) to override\n * the base acceleration rate. This is applied in the next\n * updateMovement call.\n *\n * @param acceleration - Acceleration in m/s²\n *\n */\n public setAcceleration(acceleration: number): void {\n this._overrideAcceleration = acceleration;\n }\n\n /**\n * Clear speed and acceleration overrides.\n *\n * **Korean**: 속도 재정의 해제 (Clear Speed Overrides)\n *\n * Resets movement to use default calculations without external\n * override values.\n *\n */\n public clearOverrides(): void {\n this._overrideMaxSpeed = null;\n this._overrideAcceleration = null;\n }\n\n /**\n * Set arena width for arena-aware speed scaling.\n *\n * **Korean**: 경기장 너비 설정 (Set Arena Width)\n *\n * Updates the arena width used for speed scaling calculations.\n * Call this when the arena size changes (e.g., screen resize).\n * Recalculates and caches the arena speed scale.\n *\n * @param widthMeters - Arena width in meters (must be positive)\n * @throws {Error} If widthMeters is not a positive number\n *\n */\n public setArenaWidth(widthMeters: number): void {\n if (widthMeters <= 0 || !Number.isFinite(widthMeters)) {\n throw new Error(\n `Arena width must be a positive finite number, got: ${widthMeters}`,\n );\n }\n this._arenaWidthMeters = widthMeters;\n this._cachedArenaSpeedScale = this.calculateArenaSpeedScale();\n }\n\n /**\n * Get current arena width.\n *\n * **Korean**: 경기장 너비 가져오기 (Get Arena Width)\n *\n * @returns Arena width in meters\n *\n */\n public getArenaWidth(): number {\n return this._arenaWidthMeters;\n }\n\n /**\n * Get current arena speed scale factor.\n *\n * **Korean**: 경기장 속도 배수 가져오기 (Get Arena Speed Scale)\n *\n * Returns the cached arena speed scale value.\n *\n * @returns Arena-based speed multiplier (0.7 to 1.3)\n *\n */\n public getArenaSpeedScale(): number {\n return this._cachedArenaSpeedScale;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MovementPhysics.js","names":[],"sources":["../../../src/systems/physics/MovementPhysics.ts"],"sourcesContent":["/**\n * Physics-based movement system for realistic combat movement.\n *\n * **Korean**: 이동 물리 시스템 (Movement Physics System)\n *\n * This module implements realistic physics-based player movement with proper\n * acceleration/deceleration, foot-wide step precision, and stance-based speed\n * modifiers for authentic Korean martial arts combat feel.\n *\n * ## Features\n *\n * - **Realistic Acceleration**: 0 to 2m/s in 0.5 seconds (4.0 m/s²)\n * - **Realistic Deceleration**: 2m/s to 0 in 0.3 seconds (6.67 m/s²)\n * - **Foot-wide Steps**: Discrete 30cm movement increments for tactical positioning\n * - **Stance Modifiers**: 8 trigram stances with different speed characteristics\n * - **Injury Integration**: Movement speed reduced by leg damage (10-50%)\n *\n * @module systems/physics/MovementPhysics\n * @category Physics System\n * @korean 이동물리\n */\n\nimport { TrigramStance } from \"@/types/common\";\nimport { BASE_MOVEMENT_ACCELERATION } from \"@/types/physicsConstants\";\nimport type { MovementArenaBounds } from \"@/types/PhysicsTypes\";\nimport * as THREE from \"three\";\n\n/**\n * Movement input from keyboard/gamepad controls.\n *\n * **Korean**: 이동 입력 (Movement Input)\n *\n * @category Physics System\n * @korean 이동입력\n */\nexport interface MovementInput {\n /** Forward/backward input (-1 to 1, where 1 is forward) */\n readonly forward: number;\n /** Lateral left/right input (-1 to 1, where 1 is right) */\n readonly lateral: number;\n /** Whether sprint/run key is held */\n readonly isRunning: boolean;\n /** Whether any movement input is active */\n readonly isMoving: boolean;\n /** Whether to use tactical step mode (30cm grid) */\n readonly useTacticalSteps: boolean;\n}\n\n/**\n * Complete movement state for physics calculations.\n *\n * **Korean**: 이동 상태 (Movement State)\n *\n * Contains position, velocity, and current movement parameters.\n * All vectors are mutable for performance (updated in-place during physics loop).\n *\n * @category Physics System\n * @korean 이동상태\n */\nexport interface MovementState {\n /**\n * Current position in 3D space (meters).\n *\n * NOTE: This is a readonly reference to a mutable THREE.Vector3.\n * The physics engine intentionally mutates the vector in-place\n * (e.g. via position.add(...)) for performance. The readonly\n * modifier prevents reassignment of the Vector3 instance, not\n * mutation of its components.\n */\n readonly position: THREE.Vector3;\n /**\n * Current velocity vector (m/s).\n *\n * NOTE: This is a readonly reference to a mutable THREE.Vector3.\n * The physics engine updates this vector in-place each frame.\n * Callers must not reassign the velocity reference, but may pass\n * it to APIs that read or modify its components.\n */\n readonly velocity: THREE.Vector3;\n /** Current acceleration magnitude (m/s²) */\n acceleration: number;\n /** Maximum speed for current state (m/s) */\n maxSpeed: number;\n /** Current Eight Trigram stance */\n readonly currentStance: TrigramStance;\n /** Leg injury percentage (0-1, where 1 is fully injured) */\n legInjuryFactor: number;\n}\n\n/**\n * Stance-based speed modifiers for Eight Trigram system.\n *\n * **Korean**: 팔괘 속도 배수 (Eight Trigram Speed Multipliers)\n *\n * Each trigram stance has unique movement characteristics based on\n * traditional Korean martial arts philosophy:\n *\n * - ☰ 건 (Geon/Heaven): 100% - Balanced, standard speed\n * - ☱ 태 (Tae/Lake): 110% - Fluid movement, flowing techniques\n * - ☲ 리 (Li/Fire): 120% - Aggressive, fast attacks\n * - ☳ 진 (Jin/Thunder): 115% - Explosive power\n * - ☴ 손 (Son/Wind): 125% - Continuous motion, fastest stance\n * - ☵ 감 (Gam/Water): 105% - Adaptive, slightly faster than neutral\n * - ☶ 간 (Gan/Mountain): 80% - Solid defense, slower movement\n * - ☷ 곤 (Gon/Earth): 85% - Grounded, stable but slower\n *\n * @korean 자세속도배수\n */\nexport const STANCE_SPEED_MODIFIERS: Record<TrigramStance, number> = {\n [TrigramStance.GEON]: 1.0, // Heaven: balanced\n [TrigramStance.TAE]: 1.1, // Lake: fluid\n [TrigramStance.LI]: 1.2, // Fire: aggressive\n [TrigramStance.JIN]: 1.15, // Thunder: explosive\n [TrigramStance.SON]: 1.25, // Wind: fastest\n [TrigramStance.GAM]: 1.05, // Water: adaptive\n [TrigramStance.GAN]: 0.8, // Mountain: defensive\n [TrigramStance.GON]: 0.85, // Earth: grounded\n};\n\n/**\n * Physics-based movement engine for combat.\n *\n * **Korean**: 이동 물리 엔진 (Movement Physics Engine)\n *\n * Implements realistic acceleration, deceleration, and stance-based movement\n * for authentic Korean martial arts combat. Supports both continuous movement\n * and tactical foot-wide steps for precise positioning.\n *\n * @example\n * ```typescript\n * const physics = new MovementPhysics();\n *\n * const state: MovementState = {\n * position: new THREE.Vector3(0, 0, 0),\n * velocity: new THREE.Vector3(0, 0, 0),\n * acceleration: 0,\n * maxSpeed: 2.0,\n * currentStance: TrigramStance.GEON,\n * legInjuryFactor: 0,\n * };\n *\n * const input: MovementInput = {\n * forward: 1.0,\n * lateral: 0,\n * isRunning: false,\n * isMoving: true,\n * useTacticalSteps: false,\n * };\n *\n * // In game loop at 60fps\n * physics.updateMovement(state, input, deltaTime);\n * ```\n *\n * @category Physics System\n * @korean 이동물리엔진\n */\nexport class MovementPhysics {\n /**\n * Base acceleration rate (m/s²)\n * Achieves 0 to 6m/s in 0.2 seconds (instant-response combat movement)\n * Increased from 12.0 to 30.0 for arcade-style responsiveness\n *\n * Imported from physicsConstants.ts to maintain consistency across systems.\n *\n * **Korean**: 기본 가속도 (Base Acceleration)\n */\n private readonly BASE_ACCELERATION = BASE_MOVEMENT_ACCELERATION;\n\n /**\n * Base deceleration rate (m/s²)\n * Achieves 6m/s to 0 in 0.3 seconds (responsive combat stopping)\n *\n * **Korean**: 기본 감속도 (Base Deceleration)\n */\n private readonly BASE_DECELERATION = 20.0;\n\n /**\n * Foot-wide step size (meters)\n * Standard Korean martial arts step is approximately 30cm\n *\n * **Korean**: 보법 거리 (Step Distance)\n */\n private readonly STEP_SIZE = 0.3;\n\n /**\n * Base walking speed (m/s)\n * Optimized for responsive combat movement - crosses 14m arena in ~2.3s\n *\n * **Korean**: 기본 걷기 속도 (Base Walking Speed)\n */\n private readonly BASE_WALK_SPEED = 6.0;\n\n /**\n * Base running speed (m/s)\n * Sprint speed for rapid repositioning - crosses 14m arena in ~1.4s\n *\n * **Korean**: 기본 달리기 속도 (Base Running Speed)\n */\n private readonly BASE_RUN_SPEED = 10.0;\n\n /**\n * Reference arena size for speed calibration (meters).\n * All speeds are calibrated for a 10m arena.\n *\n * **Korean**: 기준 경기장 크기 (Reference Arena Size)\n */\n private readonly REFERENCE_ARENA_SIZE = 10.0;\n\n /**\n * Current arena width in meters for arena-aware speed scaling.\n *\n * **Korean**: 현재 경기장 너비 (Current Arena Width)\n */\n private _arenaWidthMeters: number = 10.0;\n\n // LATERAL_SPEED removed - now using state.maxSpeed for all directions\n // This ensures speed override applies to lateral movement too\n\n /**\n * Override for max speed from external speed modifier systems.\n *\n * **Korean**: 최대속도 재정의 (Max Speed Override)\n */\n private _overrideMaxSpeed: number | null = null;\n\n /**\n * Override for acceleration from external speed modifier systems.\n *\n * **Korean**: 가속도 재정의 (Acceleration Override)\n */\n private _overrideAcceleration: number | null = null;\n\n /**\n * Cached arena speed scale to avoid repeated calculations.\n *\n * **Korean**: 캐시된 경기장 속도 배수 (Cached Arena Speed Scale)\n */\n private _cachedArenaSpeedScale: number = 1.0;\n\n // Temporary vectors to avoid allocations in update loop\n private readonly tempTargetVelocity = new THREE.Vector3();\n private readonly tempMovement = new THREE.Vector3();\n private readonly tempDirection = new THREE.Vector3();\n private readonly tempTargetDirection = new THREE.Vector3();\n\n /**\n * Create a new MovementPhysics instance.\n *\n * **Korean**: 이동 물리 생성 (Create Movement Physics)\n *\n * @param arenaWidthMeters - Width of the arena in meters (default: 10m, min: 1m)\n * @throws {Error} If arenaWidthMeters is not a positive number\n *\n * @example\n * ```typescript\n * // Default 10m arena (1.0x speed scale)\n * const physics = new MovementPhysics();\n *\n * // Small 6m arena (0.7x speed scale)\n * const smallPhysics = new MovementPhysics(6.0);\n *\n * // Large 14m arena (1.3x speed scale)\n * const largePhysics = new MovementPhysics(14.0);\n * ```\n *\n */\n constructor(arenaWidthMeters: number = 10.0) {\n if (arenaWidthMeters <= 0 || !Number.isFinite(arenaWidthMeters)) {\n throw new Error(\n `Arena width must be a positive finite number, got: ${arenaWidthMeters}`,\n );\n }\n this._arenaWidthMeters = arenaWidthMeters;\n this._cachedArenaSpeedScale = this.calculateArenaSpeedScale();\n }\n\n /**\n * Calculate arena-aware speed scaling factor.\n *\n * **Korean**: 경기장 크기 기반 속도 배수 (Arena-Based Speed Multiplier)\n *\n * Scales movement speed proportionally to arena size to maintain consistent\n * gameplay feel across different screen resolutions. Smaller arenas get\n * slightly slower speeds, larger arenas get slightly faster speeds.\n *\n * Formula: scaleFactor = arenaWidth / referenceArenaSize\n * Clamped to [0.7, 1.3] range for balanced gameplay\n *\n * Examples:\n * - 6m arena: 0.7x speed (70% of base)\n * - 10m arena: 1.0x speed (baseline)\n * - 14m arena: 1.3x speed (130% of base)\n *\n * @returns Speed multiplier (0.7 to 1.3)\n *\n * @korean 경기장속도배수\n */\n private calculateArenaSpeedScale(): number {\n const rawScale = this._arenaWidthMeters / this.REFERENCE_ARENA_SIZE;\n // Clamp to reasonable range to maintain gameplay balance\n return Math.max(0.7, Math.min(1.3, rawScale));\n }\n\n /**\n * Update player movement based on input and physics.\n *\n * **Korean**: 이동 업데이트 (Update Movement)\n *\n * Called every frame (60fps) to update player position based on\n * current velocity, acceleration, and input. Applies stance modifiers\n * and injury penalties automatically.\n *\n * @param state - Current movement state (modified in-place)\n * @param input - Current movement input from controls\n * @param deltaTime - Time since last update (seconds)\n * @param bounds - Optional arena bounds for clamping position (meters)\n *\n * @korean 이동업데이트\n */\n public updateMovement(\n state: MovementState,\n input: MovementInput,\n deltaTime: number,\n bounds?: MovementArenaBounds,\n ): void {\n // Use cached arena-aware speed scaling\n const arenaSpeedScale = this._cachedArenaSpeedScale;\n\n // Calculate stance speed modifier\n const stanceModifier = this.getStanceSpeedModifier(state.currentStance);\n\n // Calculate injury penalty (0-50% speed reduction)\n const injuryPenalty = 1.0 - state.legInjuryFactor * 0.5;\n\n // Calculate base target speed (walking or running)\n const baseSpeed = input.isRunning\n ? this.BASE_RUN_SPEED\n : this.BASE_WALK_SPEED;\n\n // Apply all modifiers including arena scaling to get final max speed (or use override)\n state.maxSpeed =\n this._overrideMaxSpeed ??\n baseSpeed * arenaSpeedScale * stanceModifier * injuryPenalty;\n\n // Use override acceleration if set, otherwise use base\n const currentAcceleration =\n this._overrideAcceleration ?? this.BASE_ACCELERATION;\n\n // Calculate target velocity based on input direction\n // forward > 0 = moving in positive Z direction (toward bottom of screen)\n // forward < 0 = moving in negative Z direction (toward top of screen)\n // ✅ REMOVED backward multiplier: All directions use full speed for responsive gameplay\n // The backward penalty should be applied contextually by the combat system\n // based on player facing direction vs movement direction\n // ✅ FIX: Both lateral and forward now use state.maxSpeed (which includes all modifiers)\n // This ensures consistent speed in all movement directions and includes arena scaling\n this.tempTargetVelocity.set(\n input.lateral * state.maxSpeed,\n 0,\n input.forward * state.maxSpeed,\n );\n\n // Apply acceleration or deceleration\n if (input.isMoving) {\n // Accelerate toward target velocity with realistic direction changes\n const currentSpeed = state.velocity.length();\n const targetSpeed = this.tempTargetVelocity.length();\n\n if (currentSpeed < targetSpeed) {\n // Check if direction change is needed\n if (currentSpeed > 0.001 && targetSpeed > 0.001) {\n // Current movement direction\n this.tempDirection.copy(state.velocity).normalize();\n // Desired movement direction (reuse temp vector to avoid allocation)\n this.tempTargetDirection.copy(this.tempTargetVelocity).normalize();\n const directionDot = this.tempDirection.dot(this.tempTargetDirection);\n\n if (directionDot < 0) {\n // Moving in opposite direction: decelerate first before reversing\n const velocityDelta = this.BASE_DECELERATION * deltaTime;\n const newSpeed = Math.max(currentSpeed - velocityDelta, 0);\n\n if (newSpeed > 0.001) {\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n } else {\n // Fully stopped; can now start accelerating in new direction\n state.velocity.set(0, 0, 0);\n }\n state.acceleration = -this.BASE_DECELERATION;\n } else if (directionDot < 0.7) {\n // Perpendicular direction change (e.g., forward to strafe): moderate deceleration\n const blendedAccel = currentAcceleration * 0.6; // Reduced acceleration for sharp turns\n const velocityDelta = blendedAccel * deltaTime;\n const newSpeed = Math.min(\n currentSpeed + velocityDelta,\n targetSpeed,\n );\n this.tempDirection.copy(this.tempTargetVelocity).normalize();\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n state.acceleration = blendedAccel;\n } else {\n // Same or similar direction: full acceleration\n this.tempDirection.copy(this.tempTargetVelocity).normalize();\n const velocityDelta = currentAcceleration * deltaTime;\n const newSpeed = Math.min(\n currentSpeed + velocityDelta,\n targetSpeed,\n );\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n state.acceleration = currentAcceleration;\n }\n } else {\n // Very low speed: safe to accelerate directly toward target\n this.tempDirection.copy(this.tempTargetVelocity).normalize();\n const velocityDelta = currentAcceleration * deltaTime;\n const newSpeed = Math.min(currentSpeed + velocityDelta, targetSpeed);\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n state.acceleration = currentAcceleration;\n }\n } else {\n // Already at or above target speed: snap to target velocity\n state.velocity.copy(this.tempTargetVelocity);\n state.acceleration = 0;\n }\n } else {\n // Decelerate to stop\n const currentSpeed = state.velocity.length();\n if (currentSpeed > 0.01) {\n this.tempDirection.copy(state.velocity).normalize();\n const velocityDelta = this.BASE_DECELERATION * deltaTime;\n const newSpeed = Math.max(currentSpeed - velocityDelta, 0);\n state.velocity.copy(this.tempDirection.multiplyScalar(newSpeed));\n } else {\n state.velocity.set(0, 0, 0);\n }\n state.acceleration = -this.BASE_DECELERATION;\n }\n\n // Calculate movement delta for this frame\n this.tempMovement.copy(state.velocity).multiplyScalar(deltaTime);\n\n // Apply tactical step quantization if enabled\n if (input.useTacticalSteps) {\n // Quantize to 30cm grid steps\n this.tempMovement.x =\n Math.round(this.tempMovement.x / this.STEP_SIZE) * this.STEP_SIZE;\n this.tempMovement.z =\n Math.round(this.tempMovement.z / this.STEP_SIZE) * this.STEP_SIZE;\n }\n\n // Update position\n state.position.add(this.tempMovement);\n\n // Apply arena bounds clamping if bounds provided\n if (bounds) {\n // Check if position exceeded boundaries\n const exceededMinX = state.position.x < bounds.minX;\n const exceededMaxX = state.position.x > bounds.maxX;\n const exceededMinZ = state.position.z < bounds.minZ;\n const exceededMaxZ = state.position.z > bounds.maxZ;\n\n // Clamp position to arena boundaries\n state.position.x = Math.max(bounds.minX, Math.min(bounds.maxX, state.position.x));\n state.position.z = Math.max(bounds.minZ, Math.min(bounds.maxZ, state.position.z));\n\n // Zero velocity component if exceeded boundary (smooth stopping)\n if (exceededMinX || exceededMaxX) {\n state.velocity.x = 0;\n }\n if (exceededMinZ || exceededMaxZ) {\n state.velocity.z = 0;\n }\n }\n }\n\n /**\n * Get speed modifier for a specific trigram stance.\n *\n * **Korean**: 자세 속도 배수 가져오기 (Get Stance Speed Modifier)\n *\n * @param stance - Eight Trigram stance\n * @returns Speed multiplier (0.8 to 1.25)\n *\n * @korean 자세속도배수\n */\n public getStanceSpeedModifier(stance: TrigramStance): number {\n return STANCE_SPEED_MODIFIERS[stance];\n }\n\n /**\n * Calculate movement penalty from leg injury.\n *\n * **Korean**: 부상 이동 페널티 (Injury Movement Penalty)\n *\n * Leg damage reduces movement speed by 10-50% based on injury severity.\n *\n * @param legHealthPercentage - Remaining leg health (0-1)\n * @returns Injury factor (0 = no injury, 1 = maximum injury)\n *\n * @korean 부상페널티\n */\n public calculateInjuryPenalty(legHealthPercentage: number): number {\n // Injury penalty scales from 0% (healthy) to 50% (critical)\n // Clamp between 0 and 1\n const healthFactor = Math.max(0, Math.min(1, legHealthPercentage));\n return 1.0 - healthFactor;\n }\n\n /**\n * Get maximum speed for current state configuration.\n *\n * **Korean**: 최대 속도 계산 (Calculate Maximum Speed)\n *\n * @param isRunning - Whether running (vs walking)\n * @param stance - Current trigram stance\n * @param legInjuryFactor - Leg injury severity (0-1)\n * @returns Maximum speed in m/s (includes arena scaling)\n *\n * @korean 최대속도\n */\n public getMaxSpeed(\n isRunning: boolean,\n stance: TrigramStance,\n legInjuryFactor: number,\n ): number {\n const arenaSpeedScale = this._cachedArenaSpeedScale;\n const baseSpeed = isRunning ? this.BASE_RUN_SPEED : this.BASE_WALK_SPEED;\n const stanceModifier = this.getStanceSpeedModifier(stance);\n const injuryPenalty = 1.0 - legInjuryFactor * 0.5;\n return baseSpeed * arenaSpeedScale * stanceModifier * injuryPenalty;\n }\n\n /**\n * Calculate time required to reach target speed from current velocity.\n *\n * **Korean**: 가속 시간 (Acceleration Time)\n *\n * @param currentSpeed - Current speed magnitude (m/s)\n * @param targetSpeed - Desired speed magnitude (m/s)\n * @returns Time in seconds to reach target speed\n *\n * @korean 가속시간\n */\n public getAccelerationTime(\n currentSpeed: number,\n targetSpeed: number,\n ): number {\n const speedDiff = Math.abs(targetSpeed - currentSpeed);\n return speedDiff / this.BASE_ACCELERATION;\n }\n\n /**\n * Calculate stopping distance from current velocity.\n *\n * **Korean**: 제동 거리 (Braking Distance)\n *\n * @param currentSpeed - Current speed magnitude (m/s)\n * @returns Distance in meters required to stop\n *\n * @korean 제동거리\n */\n public getStoppingDistance(currentSpeed: number): number {\n // Using kinematic equation: d = v² / (2a)\n return (currentSpeed * currentSpeed) / (2 * this.BASE_DECELERATION);\n }\n\n /**\n * Get tactical step size.\n *\n * **Korean**: 보법 거리 (Step Distance)\n *\n * @returns Step size in meters (0.3m = 30cm)\n *\n * @korean 보법거리\n */\n public getStepSize(): number {\n return this.STEP_SIZE;\n }\n\n /**\n * Override maximum speed for external speed modifier systems.\n *\n * **Korean**: 최대 속도 설정 (Set Maximum Speed)\n *\n * Allows external systems (like SpeedModifierSystem) to override\n * the calculated maximum speed. This is applied in the next\n * updateMovement call.\n *\n * @param speed - Maximum speed in m/s\n *\n */\n public setMaxSpeed(speed: number): void {\n this._overrideMaxSpeed = speed;\n }\n\n /**\n * Override acceleration for external speed modifier systems.\n *\n * **Korean**: 가속도 설정 (Set Acceleration)\n *\n * Allows external systems (like SpeedModifierSystem) to override\n * the base acceleration rate. This is applied in the next\n * updateMovement call.\n *\n * @param acceleration - Acceleration in m/s²\n *\n */\n public setAcceleration(acceleration: number): void {\n this._overrideAcceleration = acceleration;\n }\n\n /**\n * Clear speed and acceleration overrides.\n *\n * **Korean**: 속도 재정의 해제 (Clear Speed Overrides)\n *\n * Resets movement to use default calculations without external\n * override values.\n *\n */\n public clearOverrides(): void {\n this._overrideMaxSpeed = null;\n this._overrideAcceleration = null;\n }\n\n /**\n * Set arena width for arena-aware speed scaling.\n *\n * **Korean**: 경기장 너비 설정 (Set Arena Width)\n *\n * Updates the arena width used for speed scaling calculations.\n * Call this when the arena size changes (e.g., screen resize).\n * Recalculates and caches the arena speed scale.\n *\n * @param widthMeters - Arena width in meters (must be positive)\n * @throws {Error} If widthMeters is not a positive number\n *\n */\n public setArenaWidth(widthMeters: number): void {\n if (widthMeters <= 0 || !Number.isFinite(widthMeters)) {\n throw new Error(\n `Arena width must be a positive finite number, got: ${widthMeters}`,\n );\n }\n this._arenaWidthMeters = widthMeters;\n this._cachedArenaSpeedScale = this.calculateArenaSpeedScale();\n }\n\n /**\n * Get current arena width.\n *\n * **Korean**: 경기장 너비 가져오기 (Get Arena Width)\n *\n * @returns Arena width in meters\n *\n */\n public getArenaWidth(): number {\n return this._arenaWidthMeters;\n }\n\n /**\n * Get current arena speed scale factor.\n *\n * **Korean**: 경기장 속도 배수 가져오기 (Get Arena Speed Scale)\n *\n * Returns the cached arena speed scale value.\n *\n * @returns Arena-based speed multiplier (0.7 to 1.3)\n *\n */\n public getArenaSpeedScale(): number {\n return this._cachedArenaSpeedScale;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PhysicalReachCalculator.js","names":[],"sources":["../../../src/systems/physics/PhysicalReachCalculator.ts"],"sourcesContent":["/**\n * Physical Reach Calculator\n *\n * **Korean**: 물리적 도달 거리 계산기\n *\n * Calculates actual combat reach based on physical attributes and animation timing.\n * Integrates archetype-specific limb lengths with animation hit windows for\n * reality-based hit detection.\n *\n * ## Philosophy\n *\n * Black Trigram emphasizes realistic combat. Hit detection must account for:\n * - Physical differences between archetypes (arm/leg length)\n * - Animation phase (chamber vs extension vs retraction)\n * - Technique type (punch vs kick vs elbow)\n * - Stance modifiers from Eight Trigrams\n *\n * A small Hacker (73cm arms) cannot reach as far as a large Jojik (84cm arms),\n * and this difference must be reflected in combat.\n *\n * @module systems/physics/PhysicalReachCalculator\n * @category Combat Physics\n * @korean 물리적도달계산기\n */\n\nimport { PhysicalAttributes } from \"@/types\";\nimport { TrigramStance } from \"../../types/common\";\nimport { \n STANCE_REACH_MODIFIERS, \n TechniqueType,\n PhysicalReachConfig,\n} from \"../../types/physics\";\nimport {\n AnimationType,\n getAnimationHitTiming,\n getCurrentReachMultiplier,\n isWithinHitWindow,\n} from \"../animation\";\n\n/**\n * Physical reach calculation result.\n *\n * **Korean**: 물리적 도달 계산 결과\n *\n * @korean 물리적도달결과\n */\nexport interface PhysicalReachResult {\n /**\n * Base limb length in meters.\n * Archetype-specific arm or leg length from physical attributes.\n * @korean 기본팔다리길이\n */\n readonly baseLimbLength: number;\n\n /**\n * Body pivot contribution in meters (kicks only).\n * Accounts for hip rotation and torso lean during kicks (~0.25m).\n * @korean 몸통회전기여도\n */\n readonly bodyPivotContribution: number;\n\n /**\n * Technique type used.\n * @korean 기술유형\n */\n readonly techniqueType: TechniqueType;\n\n /**\n * Current animation time in seconds.\n * @korean 현재애니메이션시간\n */\n readonly animationTime: number;\n\n /**\n * Animation reach multiplier at current time (0.0 - 1.5).\n * @korean 애니메이션도달배수\n */\n readonly animationReachMultiplier: number;\n\n /**\n * Base extension from technique reachConfig (0.0 - 1.5).\n * Designer-specified reach multiplier from technique definition.\n * @korean 기본확장배수\n */\n readonly baseExtension?: number;\n\n /**\n * Final extension multiplier used in reach calculation.\n * When reachConfig is provided, applies curve factor to hybrid peak:\n * `(animationReachMultiplier / peakMultiplier) * max(baseExtension, peakMultiplier)`\n * Otherwise uses time-varying animationReachMultiplier directly.\n * @korean 최종확장배수\n */\n readonly finalExtensionMultiplier: number;\n\n /**\n * Stance reach modifier (0.9 - 1.2).\n * @korean 자세도달수정자\n */\n readonly stanceModifier: number;\n\n /**\n * Final effective reach in meters.\n * (baseLimbLength + bodyPivotContribution) × finalExtensionMultiplier × stanceModifier\n * @korean 최종유효도달\n */\n readonly effectiveReach: number;\n\n /**\n * Whether currently within hit window.\n * @korean 타격창내여부\n */\n readonly canHit: boolean;\n}\n\n/**\n * Physical Reach Calculator.\n *\n * **Korean**: 물리적 도달 계산기\n *\n * Calculates reality-based reach using archetype physical attributes\n * and animation timing.\n *\n * @korean 물리적도달계산기\n */\nexport class PhysicalReachCalculator {\n /**\n * Calculate effective reach for a technique at a specific animation time.\n *\n * **Korean**: 특정 애니메이션 시간의 유효 도달 거리 계산\n *\n * This is the core method that integrates:\n * 1. Physical attributes (archetype-specific limb length)\n * 2. Animation timing (hit window and extension phase)\n * 3. Technique baseExtension (designer-specified reach)\n * 4. Stance modifiers (Eight Trigrams reach bonuses)\n * 5. Body pivot contribution (hip rotation and torso lean for kicks)\n *\n * **Hybrid Reach System**: Uses the maximum of:\n * - `reachConfig.baseExtension` (designer-specified reach)\n * - `maxReachMultiplier` (animation-driven reach)\n *\n * This ensures techniques get at least their designed reach while allowing\n * animations to extend beyond the base if needed.\n *\n * **Body Pivot Mechanics for Kicks**:\n * Kicks benefit from whole-body rotation that punches don't utilize:\n * - Hip rotation adds ~0.15m (pelvis width + pivot)\n * - Torso lean adds ~0.1m (forward lean during kick)\n * - Total body pivot: ~0.25m additional reach\n *\n * This accounts for the biomechanics of kicks where the fighter rotates\n * their entire body to extend reach, unlike punches which rely primarily\n * on arm extension.\n *\n * @param physicalAttributes - Fighter's physical attributes\n * @param animationType - Animation being executed\n * @param animationTime - Current time in animation (seconds)\n * @param stance - Current trigram stance\n * @param reachConfig - Optional technique reach configuration with baseExtension\n * @returns Physical reach calculation result\n *\n * @example\n * ```typescript\n * const calculator = new PhysicalReachCalculator();\n *\n * // With reachConfig (uses max of baseExtension and animation multiplier)\n * const frontKick = calculator.calculateReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * 0.27, // Peak time\n * TrigramStance.GEON,\n * { bodyPart: \"leg\", techniqueType: \"kick\", baseExtension: 1.05 }\n * );\n * // Uses max(1.05, 1.0) = 1.05 for proper designed reach\n *\n * // Without reachConfig (uses only animation multiplier - backward compatible)\n * const legacyKick = calculator.calculateReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * 0.27,\n * TrigramStance.GEON\n * );\n * // Uses animation multiplier (1.0) only\n * ```\n *\n * @korean 도달계산\n */\n calculateReach(\n physicalAttributes: PhysicalAttributes,\n animationType: AnimationType,\n animationTime: number,\n stance: TrigramStance,\n reachConfig?: PhysicalReachConfig,\n ): PhysicalReachResult {\n // Determine technique type from animation\n const techniqueType = this.getTechniqueTypeFromAnimation(animationType);\n\n // Get base limb length for technique type\n const baseLimbLength = this.getLimbLength(\n physicalAttributes,\n techniqueType,\n );\n\n // Get animation hit timing\n const canHit = isWithinHitWindow(animationType, animationTime);\n const animationReachMultiplier = getCurrentReachMultiplier(\n animationType,\n animationTime,\n );\n\n // **Hybrid Reach System with Curve Factor**:\n // Apply baseExtension at the peak reach level, then scale by the time-varying\n // curve factor so reach still ramps up and down with the animation.\n // This prevents phantom hits at the start/end of the hit window.\n const baseExtension = reachConfig?.baseExtension;\n\n // Retrieve peak (max) reach multiplier for this animation's hit window\n const hitTiming = getAnimationHitTiming(animationType);\n const rawPeakMultiplier = hitTiming?.hitWindow.maxReachMultiplier;\n\n // Determine whether we have valid timing data. When timing is missing or\n // the configured peak multiplier is non-positive, fall back to a neutral\n // curve so reach/damage checks remain possible for those techniques.\n const hasValidTiming =\n rawPeakMultiplier !== undefined && rawPeakMultiplier > 0;\n\n const fallbackBase = baseExtension ?? 1;\n\n const peakMultiplier = hasValidTiming ? rawPeakMultiplier : fallbackBase;\n\n const effectiveAnimationReachMultiplier = hasValidTiming\n ? animationReachMultiplier\n : fallbackBase;\n\n // Normalized curve factor in [0, 1] that represents where we are on\n // the reach curve. When peakMultiplier is 0, we treat reach as 0.\n const curveFactor =\n peakMultiplier > 0 ? effectiveAnimationReachMultiplier / peakMultiplier : 0;\n\n // Apply the hybrid \"max\" at the peak level, then reapply the curve\n const peakExtension =\n baseExtension !== undefined\n ? Math.max(baseExtension, peakMultiplier)\n : peakMultiplier;\n\n const finalExtensionMultiplier = curveFactor * peakExtension;\n\n // Get stance modifier\n const stanceModifier = STANCE_REACH_MODIFIERS[stance];\n\n // Calculate final effective reach\n // Convert cm to meters for consistency with physics system\n const baseLimbLengthMeters = baseLimbLength / 100;\n\n // Add body pivot/offset contribution based on technique type\n // This accounts for the fact that limbs extend from the body surface,\n // not the body center, plus rotational contributions\n let bodyPivotContribution: number;\n\n if (techniqueType === \"kick\" || techniqueType === \"knee\") {\n // Kicks benefit from hip rotation and torso lean which add 0.25m\n // This accounts for:\n // - Hip width/rotation (0.15m)\n // - Torso lean during kick (0.1m)\n // Total body pivot contribution: 0.25m for kicks\n bodyPivotContribution = 0.25;\n } else if (\n techniqueType === \"punch\" ||\n techniqueType === \"pressure_point\"\n ) {\n // Punches extend from the shoulder, which is offset from body center\n // Shoulder offset = shoulderWidth / 2 (converted to meters)\n // Plus torso rotation contribution for cross/hooks (~0.1m)\n // Average shoulder width ~45cm → offset ~0.225m, plus rotation ~0.1m\n // Total: ~0.30m for arm techniques\n const shoulderOffset = physicalAttributes.shoulderWidth / 2 / 100; // Convert cm to m\n const torsoRotation = 0.1; // 10cm from torso rotation during punches\n bodyPivotContribution = shoulderOffset + torsoRotation;\n } else if (techniqueType === \"elbow\") {\n // Elbows are close range but still extend from shoulder\n // Less torso rotation contribution\n const shoulderOffset = physicalAttributes.shoulderWidth / 2 / 100;\n bodyPivotContribution = shoulderOffset;\n } else {\n bodyPivotContribution = 0;\n }\n\n const effectiveReach =\n (baseLimbLengthMeters + bodyPivotContribution) *\n finalExtensionMultiplier *\n stanceModifier;\n\n return {\n baseLimbLength: baseLimbLengthMeters,\n bodyPivotContribution,\n techniqueType,\n animationTime,\n animationReachMultiplier,\n baseExtension,\n finalExtensionMultiplier,\n stanceModifier,\n effectiveReach,\n canHit,\n };\n }\n\n /**\n * Calculate maximum possible reach for a technique.\n *\n * **Korean**: 기술의 최대 가능 도달 거리\n *\n * Calculates reach at peak animation time (maximum extension).\n * Uses hybrid reach system with reachConfig if provided.\n *\n * @param physicalAttributes - Fighter's physical attributes\n * @param animationType - Animation type\n * @param stance - Current trigram stance\n * @param reachConfig - Optional technique reach configuration with baseExtension\n * @returns Maximum effective reach in meters\n *\n * @example\n * ```typescript\n * const calculator = new PhysicalReachCalculator();\n *\n * // With reachConfig for accurate designed reach\n * const maxReachWithConfig = calculator.calculateMaxReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * TrigramStance.GEON,\n * { bodyPart: \"leg\", techniqueType: \"kick\", baseExtension: 1.05 }\n * );\n * // Uses max(1.05, 1.0) = 1.05\n *\n * // Without reachConfig (backward compatible)\n * const maxReachLegacy = calculator.calculateMaxReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * TrigramStance.GEON\n * );\n * // Uses animation multiplier only (1.0)\n * ```\n *\n * @korean 최대도달계산\n */\n calculateMaxReach(\n physicalAttributes: PhysicalAttributes,\n animationType: AnimationType,\n stance: TrigramStance,\n reachConfig?: PhysicalReachConfig,\n ): number {\n const hitTiming = getAnimationHitTiming(animationType);\n \n // Handle missing AnimationHitTiming entries\n // When timing data is unavailable, use baseExtension if provided,\n // otherwise use a neutral 1.0 multiplier to keep reach calculations functional.\n // This ensures techniques like GEON_ROUNDHOUSE, WATER_COUNTER, IRON_BLOCK\n // (which have technique definitions but missing animation timing entries)\n // can still perform reach/damage checks.\n if (!hitTiming) {\n // Use fallback approach: calculate reach with neutral timing\n const fallbackTime = 0.5; // Midpoint of typical animation\n const result = this.calculateReach(\n physicalAttributes,\n animationType,\n fallbackTime,\n stance,\n reachConfig,\n );\n return result.effectiveReach;\n }\n \n const peakTime = hitTiming.hitWindow.peakTime;\n\n const result = this.calculateReach(\n physicalAttributes,\n animationType,\n peakTime,\n stance,\n reachConfig,\n );\n\n return result.effectiveReach;\n }\n\n /**\n * Get limb length for a technique type.\n *\n * **Korean**: 기술 유형에 대한 팔다리 길이 가져오기\n *\n * @param physicalAttributes - Fighter's physical attributes\n * @param techniqueType - Type of technique\n * @returns Limb length in centimeters\n *\n * @private\n * @korean 팔다리길이가져오기\n */\n private getLimbLength(\n physicalAttributes: PhysicalAttributes,\n techniqueType: TechniqueType,\n ): number {\n switch (techniqueType) {\n case \"punch\":\n case \"elbow\":\n case \"pressure_point\":\n // Use arm length for hand-based techniques\n return physicalAttributes.armLength;\n\n case \"kick\":\n case \"knee\":\n // Use leg length for leg-based techniques\n return physicalAttributes.legLength;\n\n default:\n // Fallback to arm length\n return physicalAttributes.armLength;\n }\n }\n\n /**\n * Determine technique type from animation type.\n *\n * Public method exposed to avoid duplication across codebase.\n *\n * **Korean**: 애니메이션 타입에서 기술 유형 결정\n *\n * @param animationType - Animation type\n * @returns Technique type\n *\n * @korean 기술유형결정\n */\n public getTechniqueTypeFromAnimation(\n animationType: AnimationType,\n ): TechniqueType {\n // Punch techniques\n if (\n animationType === AnimationType.JAB ||\n animationType === AnimationType.CROSS ||\n animationType === AnimationType.HOOK ||\n animationType === AnimationType.UPPERCUT ||\n animationType === AnimationType.OVERHAND ||\n animationType === AnimationType.BACKFIST ||\n animationType === AnimationType.HAMMER_FIST ||\n animationType === AnimationType.PALM_STRIKE ||\n animationType === AnimationType.SPEAR_HAND_STRIKE ||\n animationType === AnimationType.HEAVEN_STRIKE ||\n animationType === AnimationType.FLOWING_CROSS ||\n animationType === AnimationType.SOLAR_PLEXUS_STRIKE ||\n animationType === AnimationType.FLOWING_PUSH ||\n animationType === AnimationType.LIVER_DISRUPTION ||\n animationType === AnimationType.EAR_STRIKE\n ) {\n return \"punch\";\n }\n\n // Kick techniques\n if (\n animationType === AnimationType.FRONT_KICK ||\n animationType === AnimationType.ROUNDHOUSE_KICK ||\n animationType === AnimationType.SIDE_KICK ||\n animationType === AnimationType.BACK_KICK ||\n animationType === AnimationType.AXE_KICK ||\n animationType === AnimationType.CRESCENT_KICK ||\n animationType === AnimationType.LOW_KICK ||\n animationType === AnimationType.PUSH_KICK ||\n animationType === AnimationType.JUMPING_KICK ||\n animationType === AnimationType.SPINNING_HEEL_KICK ||\n animationType === AnimationType.TORNADO_KICK\n ) {\n return \"kick\";\n }\n\n // Elbow techniques\n if (\n animationType === AnimationType.ELBOW_STRIKE ||\n animationType === AnimationType.ELBOW_UPPERCUT ||\n animationType === AnimationType.SPINNING_ELBOW ||\n animationType === AnimationType.TEMPLE_ELBOW ||\n animationType === AnimationType.SPINNING_BACK_ELBOW ||\n animationType === AnimationType.SPINAL_ELBOW ||\n animationType === AnimationType.BRACHIAL_ELBOW\n ) {\n return \"elbow\";\n }\n\n // Knee techniques\n if (\n animationType === AnimationType.KNEE_STRIKE ||\n animationType === AnimationType.FLYING_KNEE ||\n animationType === AnimationType.KIDNEY_KNEE ||\n animationType === AnimationType.FEMORAL_KNEE\n ) {\n return \"knee\";\n }\n\n // Pressure point techniques\n if (\n animationType === AnimationType.NERVE_STRIKE ||\n animationType === AnimationType.PRESSURE_POINT_STRIKE ||\n animationType === AnimationType.NERVE_PARALYSIS ||\n animationType === AnimationType.THROAT_STRIKE ||\n animationType === AnimationType.EYE_GOUGE\n ) {\n return \"pressure_point\";\n }\n\n // Default to \"punch\" for any techniques not explicitly mapped above, including\n // complex grappling or hybrid animations. For *reach calculation* purposes we\n // approximate these using primary arm/forearm extension, since initial contact\n // is typically established with the upper limbs before the torso closes distance.\n // If a dedicated grappling TechniqueType and reach model are introduced later,\n // update this fallback to return that specific type instead of \"punch\".\n return \"punch\";\n }\n}\n\n/**\n * Singleton instance for convenient access.\n *\n * **Korean**: 싱글톤 인스턴스\n *\n * @example\n * ```typescript\n * import { physicalReachCalculator } from '@/systems/physics/PhysicalReachCalculator';\n *\n * const reach = physicalReachCalculator.calculateReach(\n * playerPhysical,\n * AnimationType.ROUNDHOUSE_KICK,\n * 0.32, // Peak time\n * TrigramStance.GEON\n * );\n * ```\n *\n * @korean 싱글톤인스턴스\n */\nexport const physicalReachCalculator = new PhysicalReachCalculator();\n"],"mappings":"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"}
1
+ {"version":3,"file":"PhysicalReachCalculator.js","names":[],"sources":["../../../src/systems/physics/PhysicalReachCalculator.ts"],"sourcesContent":["/**\n * Physical Reach Calculator\n *\n * **Korean**: 물리적 도달 거리 계산기\n *\n * Calculates actual combat reach based on physical attributes and animation timing.\n * Integrates archetype-specific limb lengths with animation hit windows for\n * reality-based hit detection.\n *\n * ## Philosophy\n *\n * Black Trigram emphasizes realistic combat. Hit detection must account for:\n * - Physical differences between archetypes (arm/leg length)\n * - Animation phase (chamber vs extension vs retraction)\n * - Technique type (punch vs kick vs elbow)\n * - Stance modifiers from Eight Trigrams\n *\n * A small Hacker (73cm arms) cannot reach as far as a large Jojik (84cm arms),\n * and this difference must be reflected in combat.\n *\n * @module systems/physics/PhysicalReachCalculator\n * @category Combat Physics\n * @korean 물리적도달계산기\n */\n\nimport { PhysicalAttributes } from \"@/types\";\nimport { TrigramStance } from \"../../types/common\";\nimport { \n STANCE_REACH_MODIFIERS, \n TechniqueType,\n PhysicalReachConfig,\n} from \"../../types/physics\";\nimport {\n AnimationType,\n getAnimationHitTiming,\n getCurrentReachMultiplier,\n isWithinHitWindow,\n} from \"../animation\";\n\n/**\n * Physical reach calculation result.\n *\n * **Korean**: 물리적 도달 계산 결과\n *\n * @korean 물리적도달결과\n */\nexport interface PhysicalReachResult {\n /**\n * Base limb length in meters.\n * Archetype-specific arm or leg length from physical attributes.\n * @korean 기본팔다리길이\n */\n readonly baseLimbLength: number;\n\n /**\n * Body pivot contribution in meters (kicks only).\n * Accounts for hip rotation and torso lean during kicks (~0.25m).\n * @korean 몸통회전기여도\n */\n readonly bodyPivotContribution: number;\n\n /**\n * Technique type used.\n * @korean 기술유형\n */\n readonly techniqueType: TechniqueType;\n\n /**\n * Current animation time in seconds.\n * @korean 현재애니메이션시간\n */\n readonly animationTime: number;\n\n /**\n * Animation reach multiplier at current time (0.0 - 1.5).\n * @korean 애니메이션도달배수\n */\n readonly animationReachMultiplier: number;\n\n /**\n * Base extension from technique reachConfig (0.0 - 1.5).\n * Designer-specified reach multiplier from technique definition.\n * @korean 기본확장배수\n */\n readonly baseExtension?: number;\n\n /**\n * Final extension multiplier used in reach calculation.\n * When reachConfig is provided, applies curve factor to hybrid peak:\n * `(animationReachMultiplier / peakMultiplier) * max(baseExtension, peakMultiplier)`\n * Otherwise uses time-varying animationReachMultiplier directly.\n * @korean 최종확장배수\n */\n readonly finalExtensionMultiplier: number;\n\n /**\n * Stance reach modifier (0.9 - 1.2).\n * @korean 자세도달수정자\n */\n readonly stanceModifier: number;\n\n /**\n * Final effective reach in meters.\n * (baseLimbLength + bodyPivotContribution) × finalExtensionMultiplier × stanceModifier\n * @korean 최종유효도달\n */\n readonly effectiveReach: number;\n\n /**\n * Whether currently within hit window.\n * @korean 타격창내여부\n */\n readonly canHit: boolean;\n}\n\n/**\n * Physical Reach Calculator.\n *\n * **Korean**: 물리적 도달 계산기\n *\n * Calculates reality-based reach using archetype physical attributes\n * and animation timing.\n *\n * @korean 물리적도달계산기\n */\nexport class PhysicalReachCalculator {\n /**\n * Calculate effective reach for a technique at a specific animation time.\n *\n * **Korean**: 특정 애니메이션 시간의 유효 도달 거리 계산\n *\n * This is the core method that integrates:\n * 1. Physical attributes (archetype-specific limb length)\n * 2. Animation timing (hit window and extension phase)\n * 3. Technique baseExtension (designer-specified reach)\n * 4. Stance modifiers (Eight Trigrams reach bonuses)\n * 5. Body pivot contribution (hip rotation and torso lean for kicks)\n *\n * **Hybrid Reach System**: Uses the maximum of:\n * - `reachConfig.baseExtension` (designer-specified reach)\n * - `maxReachMultiplier` (animation-driven reach)\n *\n * This ensures techniques get at least their designed reach while allowing\n * animations to extend beyond the base if needed.\n *\n * **Body Pivot Mechanics for Kicks**:\n * Kicks benefit from whole-body rotation that punches don't utilize:\n * - Hip rotation adds ~0.15m (pelvis width + pivot)\n * - Torso lean adds ~0.1m (forward lean during kick)\n * - Total body pivot: ~0.25m additional reach\n *\n * This accounts for the biomechanics of kicks where the fighter rotates\n * their entire body to extend reach, unlike punches which rely primarily\n * on arm extension.\n *\n * @param physicalAttributes - Fighter's physical attributes\n * @param animationType - Animation being executed\n * @param animationTime - Current time in animation (seconds)\n * @param stance - Current trigram stance\n * @param reachConfig - Optional technique reach configuration with baseExtension\n * @returns Physical reach calculation result\n *\n * @example\n * ```typescript\n * const calculator = new PhysicalReachCalculator();\n *\n * // With reachConfig (uses max of baseExtension and animation multiplier)\n * const frontKick = calculator.calculateReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * 0.27, // Peak time\n * TrigramStance.GEON,\n * { bodyPart: \"leg\", techniqueType: \"kick\", baseExtension: 1.05 }\n * );\n * // Uses max(1.05, 1.0) = 1.05 for proper designed reach\n *\n * // Without reachConfig (uses only animation multiplier - backward compatible)\n * const legacyKick = calculator.calculateReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * 0.27,\n * TrigramStance.GEON\n * );\n * // Uses animation multiplier (1.0) only\n * ```\n *\n * @korean 도달계산\n */\n calculateReach(\n physicalAttributes: PhysicalAttributes,\n animationType: AnimationType,\n animationTime: number,\n stance: TrigramStance,\n reachConfig?: PhysicalReachConfig,\n ): PhysicalReachResult {\n // Determine technique type from animation\n const techniqueType = this.getTechniqueTypeFromAnimation(animationType);\n\n // Get base limb length for technique type\n const baseLimbLength = this.getLimbLength(\n physicalAttributes,\n techniqueType,\n );\n\n // Get animation hit timing\n const canHit = isWithinHitWindow(animationType, animationTime);\n const animationReachMultiplier = getCurrentReachMultiplier(\n animationType,\n animationTime,\n );\n\n // **Hybrid Reach System with Curve Factor**:\n // Apply baseExtension at the peak reach level, then scale by the time-varying\n // curve factor so reach still ramps up and down with the animation.\n // This prevents phantom hits at the start/end of the hit window.\n const baseExtension = reachConfig?.baseExtension;\n\n // Retrieve peak (max) reach multiplier for this animation's hit window\n const hitTiming = getAnimationHitTiming(animationType);\n const rawPeakMultiplier = hitTiming?.hitWindow.maxReachMultiplier;\n\n // Determine whether we have valid timing data. When timing is missing or\n // the configured peak multiplier is non-positive, fall back to a neutral\n // curve so reach/damage checks remain possible for those techniques.\n const hasValidTiming =\n rawPeakMultiplier !== undefined && rawPeakMultiplier > 0;\n\n const fallbackBase = baseExtension ?? 1;\n\n const peakMultiplier = hasValidTiming ? rawPeakMultiplier : fallbackBase;\n\n const effectiveAnimationReachMultiplier = hasValidTiming\n ? animationReachMultiplier\n : fallbackBase;\n\n // Normalized curve factor in [0, 1] that represents where we are on\n // the reach curve. When peakMultiplier is 0, we treat reach as 0.\n const curveFactor =\n peakMultiplier > 0 ? effectiveAnimationReachMultiplier / peakMultiplier : 0;\n\n // Apply the hybrid \"max\" at the peak level, then reapply the curve\n const peakExtension =\n baseExtension !== undefined\n ? Math.max(baseExtension, peakMultiplier)\n : peakMultiplier;\n\n const finalExtensionMultiplier = curveFactor * peakExtension;\n\n // Get stance modifier\n const stanceModifier = STANCE_REACH_MODIFIERS[stance];\n\n // Calculate final effective reach\n // Convert cm to meters for consistency with physics system\n const baseLimbLengthMeters = baseLimbLength / 100;\n\n // Add body pivot/offset contribution based on technique type\n // This accounts for the fact that limbs extend from the body surface,\n // not the body center, plus rotational contributions\n let bodyPivotContribution: number;\n\n if (techniqueType === \"kick\" || techniqueType === \"knee\") {\n // Kicks benefit from hip rotation and torso lean which add 0.25m\n // This accounts for:\n // - Hip width/rotation (0.15m)\n // - Torso lean during kick (0.1m)\n // Total body pivot contribution: 0.25m for kicks\n bodyPivotContribution = 0.25;\n } else if (\n techniqueType === \"punch\" ||\n techniqueType === \"pressure_point\"\n ) {\n // Punches extend from the shoulder, which is offset from body center\n // Shoulder offset = shoulderWidth / 2 (converted to meters)\n // Plus torso rotation contribution for cross/hooks (~0.1m)\n // Average shoulder width ~45cm → offset ~0.225m, plus rotation ~0.1m\n // Total: ~0.30m for arm techniques\n const shoulderOffset = physicalAttributes.shoulderWidth / 2 / 100; // Convert cm to m\n const torsoRotation = 0.1; // 10cm from torso rotation during punches\n bodyPivotContribution = shoulderOffset + torsoRotation;\n } else if (techniqueType === \"elbow\") {\n // Elbows are close range but still extend from shoulder\n // Less torso rotation contribution\n const shoulderOffset = physicalAttributes.shoulderWidth / 2 / 100;\n bodyPivotContribution = shoulderOffset;\n } else {\n bodyPivotContribution = 0;\n }\n\n const effectiveReach =\n (baseLimbLengthMeters + bodyPivotContribution) *\n finalExtensionMultiplier *\n stanceModifier;\n\n return {\n baseLimbLength: baseLimbLengthMeters,\n bodyPivotContribution,\n techniqueType,\n animationTime,\n animationReachMultiplier,\n baseExtension,\n finalExtensionMultiplier,\n stanceModifier,\n effectiveReach,\n canHit,\n };\n }\n\n /**\n * Calculate maximum possible reach for a technique.\n *\n * **Korean**: 기술의 최대 가능 도달 거리\n *\n * Calculates reach at peak animation time (maximum extension).\n * Uses hybrid reach system with reachConfig if provided.\n *\n * @param physicalAttributes - Fighter's physical attributes\n * @param animationType - Animation type\n * @param stance - Current trigram stance\n * @param reachConfig - Optional technique reach configuration with baseExtension\n * @returns Maximum effective reach in meters\n *\n * @example\n * ```typescript\n * const calculator = new PhysicalReachCalculator();\n *\n * // With reachConfig for accurate designed reach\n * const maxReachWithConfig = calculator.calculateMaxReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * TrigramStance.GEON,\n * { bodyPart: \"leg\", techniqueType: \"kick\", baseExtension: 1.05 }\n * );\n * // Uses max(1.05, 1.0) = 1.05\n *\n * // Without reachConfig (backward compatible)\n * const maxReachLegacy = calculator.calculateMaxReach(\n * MUSA_PHYSICAL,\n * AnimationType.FRONT_KICK,\n * TrigramStance.GEON\n * );\n * // Uses animation multiplier only (1.0)\n * ```\n *\n * @korean 최대도달계산\n */\n calculateMaxReach(\n physicalAttributes: PhysicalAttributes,\n animationType: AnimationType,\n stance: TrigramStance,\n reachConfig?: PhysicalReachConfig,\n ): number {\n const hitTiming = getAnimationHitTiming(animationType);\n \n // Handle missing AnimationHitTiming entries\n // When timing data is unavailable, use baseExtension if provided,\n // otherwise use a neutral 1.0 multiplier to keep reach calculations functional.\n // This ensures techniques like GEON_ROUNDHOUSE, WATER_COUNTER, IRON_BLOCK\n // (which have technique definitions but missing animation timing entries)\n // can still perform reach/damage checks.\n if (!hitTiming) {\n // Use fallback approach: calculate reach with neutral timing\n const fallbackTime = 0.5; // Midpoint of typical animation\n const result = this.calculateReach(\n physicalAttributes,\n animationType,\n fallbackTime,\n stance,\n reachConfig,\n );\n return result.effectiveReach;\n }\n \n const peakTime = hitTiming.hitWindow.peakTime;\n\n const result = this.calculateReach(\n physicalAttributes,\n animationType,\n peakTime,\n stance,\n reachConfig,\n );\n\n return result.effectiveReach;\n }\n\n /**\n * Get limb length for a technique type.\n *\n * **Korean**: 기술 유형에 대한 팔다리 길이 가져오기\n *\n * @param physicalAttributes - Fighter's physical attributes\n * @param techniqueType - Type of technique\n * @returns Limb length in centimeters\n *\n * @private\n * @korean 팔다리길이가져오기\n */\n private getLimbLength(\n physicalAttributes: PhysicalAttributes,\n techniqueType: TechniqueType,\n ): number {\n switch (techniqueType) {\n case \"punch\":\n case \"elbow\":\n case \"pressure_point\":\n // Use arm length for hand-based techniques\n return physicalAttributes.armLength;\n\n case \"kick\":\n case \"knee\":\n // Use leg length for leg-based techniques\n return physicalAttributes.legLength;\n\n default:\n // Fallback to arm length\n return physicalAttributes.armLength;\n }\n }\n\n /**\n * Determine technique type from animation type.\n *\n * Public method exposed to avoid duplication across codebase.\n *\n * **Korean**: 애니메이션 타입에서 기술 유형 결정\n *\n * @param animationType - Animation type\n * @returns Technique type\n *\n * @korean 기술유형결정\n */\n public getTechniqueTypeFromAnimation(\n animationType: AnimationType,\n ): TechniqueType {\n // Punch techniques\n if (\n animationType === AnimationType.JAB ||\n animationType === AnimationType.CROSS ||\n animationType === AnimationType.HOOK ||\n animationType === AnimationType.UPPERCUT ||\n animationType === AnimationType.OVERHAND ||\n animationType === AnimationType.BACKFIST ||\n animationType === AnimationType.HAMMER_FIST ||\n animationType === AnimationType.PALM_STRIKE ||\n animationType === AnimationType.SPEAR_HAND_STRIKE ||\n animationType === AnimationType.HEAVEN_STRIKE ||\n animationType === AnimationType.FLOWING_CROSS ||\n animationType === AnimationType.SOLAR_PLEXUS_STRIKE ||\n animationType === AnimationType.FLOWING_PUSH ||\n animationType === AnimationType.LIVER_DISRUPTION ||\n animationType === AnimationType.EAR_STRIKE\n ) {\n return \"punch\";\n }\n\n // Kick techniques\n if (\n animationType === AnimationType.FRONT_KICK ||\n animationType === AnimationType.ROUNDHOUSE_KICK ||\n animationType === AnimationType.SIDE_KICK ||\n animationType === AnimationType.BACK_KICK ||\n animationType === AnimationType.AXE_KICK ||\n animationType === AnimationType.CRESCENT_KICK ||\n animationType === AnimationType.LOW_KICK ||\n animationType === AnimationType.PUSH_KICK ||\n animationType === AnimationType.JUMPING_KICK ||\n animationType === AnimationType.SPINNING_HEEL_KICK ||\n animationType === AnimationType.TORNADO_KICK\n ) {\n return \"kick\";\n }\n\n // Elbow techniques\n if (\n animationType === AnimationType.ELBOW_STRIKE ||\n animationType === AnimationType.ELBOW_UPPERCUT ||\n animationType === AnimationType.SPINNING_ELBOW ||\n animationType === AnimationType.TEMPLE_ELBOW ||\n animationType === AnimationType.SPINNING_BACK_ELBOW ||\n animationType === AnimationType.SPINAL_ELBOW ||\n animationType === AnimationType.BRACHIAL_ELBOW\n ) {\n return \"elbow\";\n }\n\n // Knee techniques\n if (\n animationType === AnimationType.KNEE_STRIKE ||\n animationType === AnimationType.FLYING_KNEE ||\n animationType === AnimationType.KIDNEY_KNEE ||\n animationType === AnimationType.FEMORAL_KNEE\n ) {\n return \"knee\";\n }\n\n // Pressure point techniques\n if (\n animationType === AnimationType.NERVE_STRIKE ||\n animationType === AnimationType.PRESSURE_POINT_STRIKE ||\n animationType === AnimationType.NERVE_PARALYSIS ||\n animationType === AnimationType.THROAT_STRIKE ||\n animationType === AnimationType.EYE_GOUGE\n ) {\n return \"pressure_point\";\n }\n\n // Default to \"punch\" for any techniques not explicitly mapped above, including\n // complex grappling or hybrid animations. For *reach calculation* purposes we\n // approximate these using primary arm/forearm extension, since initial contact\n // is typically established with the upper limbs before the torso closes distance.\n // If a dedicated grappling TechniqueType and reach model are introduced later,\n // update this fallback to return that specific type instead of \"punch\".\n return \"punch\";\n }\n}\n\n/**\n * Singleton instance for convenient access.\n *\n * **Korean**: 싱글톤 인스턴스\n *\n * @example\n * ```typescript\n * import { physicalReachCalculator } from '@/systems/physics/PhysicalReachCalculator';\n *\n * const reach = physicalReachCalculator.calculateReach(\n * playerPhysical,\n * AnimationType.ROUNDHOUSE_KICK,\n * 0.32, // Peak time\n * TrigramStance.GEON\n * );\n * ```\n *\n * @korean 싱글톤인스턴스\n */\nexport const physicalReachCalculator = new PhysicalReachCalculator();\n"],"mappings":"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"}
@@ -125,7 +125,7 @@ var SpeedModifierSystem = class {
125
125
  * @returns Complete speed modifier state with all factors
126
126
  *
127
127
  */
128
- calculateSpeedModifiers(playerState, movementType = MovementType.WALKING, isCrouching = false) {
128
+ calculateSpeedModifiers(playerState, movementType = "walking", isCrouching = false) {
129
129
  const baseSpeed = this.getBaseSpeed(movementType, isCrouching, playerState.physicalAttributes);
130
130
  const injuryPenalty = this.calculateInjuryPenalty(playerState.bodyPartHealth, playerState.bodyPartMaxHealth, playerState.pain);
131
131
  const stanceModifier = this.getStanceSpeedModifier(playerState.currentStance);
@@ -163,11 +163,11 @@ var SpeedModifierSystem = class {
163
163
  const archetypeWalkSpeed = physicalAttributes?.walkSpeed ?? this.BASE_WALKING_SPEED;
164
164
  const archetypeRunSpeed = physicalAttributes?.runSpeed ?? this.BASE_RUNNING_SPEED;
165
165
  switch (movementType) {
166
- case MovementType.WALKING: return archetypeWalkSpeed;
167
- case MovementType.RUNNING: return archetypeRunSpeed;
168
- case MovementType.BACKWARD: return archetypeWalkSpeed * this.BACKWARD_SPEED_MULTIPLIER;
169
- case MovementType.LATERAL: return archetypeWalkSpeed * (this.LATERAL_SPEED / this.BASE_WALKING_SPEED);
170
- case MovementType.CROUCHING: return this.CROUCHING_SPEED;
166
+ case "walking": return archetypeWalkSpeed;
167
+ case "running": return archetypeRunSpeed;
168
+ case "backward": return archetypeWalkSpeed * this.BACKWARD_SPEED_MULTIPLIER;
169
+ case "lateral": return archetypeWalkSpeed * (this.LATERAL_SPEED / this.BASE_WALKING_SPEED);
170
+ case "crouching": return this.CROUCHING_SPEED;
171
171
  default: return archetypeWalkSpeed;
172
172
  }
173
173
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SpeedModifierSystem.js","names":[],"sources":["../../../src/systems/physics/SpeedModifierSystem.ts"],"sourcesContent":["/**\n * Speed Modifier System\n *\n * **Korean**: 속도 변경 시스템 (Speed Modifier System)\n *\n * Implements comprehensive movement speed modifier system that dynamically adjusts\n * player movement speed based on multiple factors: combat stance, leg injuries,\n * stamina depletion, and combat state. Integrates with physics-based movement\n * system for authentic Korean martial arts combat feel.\n *\n * ## System Features\n *\n * - Base movement speeds for walking, running, backward, lateral, and crouching\n * - Eight Trigram stance-based speed modifiers (80% to 125%)\n * - Injury-based speed reduction from leg damage (0% to 100% penalty)\n * - Stamina-based acceleration penalty (0% to 75% penalty)\n * - Combat state speed adjustments (0% to 100% penalty)\n * - Multiplicative and additive modifier stacking\n *\n * ## Speed Calculation Formula\n *\n * ```\n * Final Speed = Base Speed\n * × Stance Modifier\n * × (1 - Injury Penalty from Legs, Torso & Pain)\n * × (1 - Combat State Penalty)\n *\n * Final Acceleration = Base Acceleration\n * × (1 - Stamina Penalty)\n * ```\n *\n * @module systems/physics/SpeedModifierSystem\n * @category Physics System\n * @korean 속도변경시스템\n */\n\nimport type {\n BodyPartHealth,\n BodyPartMaxHealth,\n} from \"@/systems/bodypart/types\";\nimport type { PlayerState } from \"@/systems/player\";\nimport { CombatState, TrigramStance } from \"@/types/common\";\nimport { BASE_MOVEMENT_ACCELERATION } from \"@/types/physicsConstants\";\nimport { STANCE_SPEED_MODIFIERS } from \"./MovementPhysics\";\nimport { injuryMovementModifier } from \"@/systems/movement/InjuryMovementModifier\";\n\n/**\n * Complete speed modifier state for physics calculations.\n *\n * **Korean**: 속도 변경 상태 (Speed Modifier State)\n *\n * Contains all calculated speed modifiers and final values for application\n * to the physics-based movement system.\n *\n * @category Physics System\n * @korean 속도변경상태\n */\nexport interface SpeedModifierState {\n /** Base movement speed before modifiers (m/s) */\n readonly baseSpeed: number;\n /** Stance-based speed multiplier (0.80 to 1.25) */\n readonly stanceModifier: number;\n /** Injury-based speed reduction (0.0 to 0.75, percentage reduction) - Korean: 부상감소 */\n readonly injuryPenalty: number;\n /** Combat state speed reduction (0.0 to 1.0, percentage reduction) */\n readonly combatStatePenalty: number;\n /** Stamina-based acceleration reduction (0.0 to 0.75, percentage reduction) - Korean: 스태미나효과 */\n readonly staminaPenalty: number;\n /** Final calculated movement speed (m/s) */\n readonly finalSpeed: number;\n /** Final calculated acceleration (m/s²) */\n readonly finalAcceleration: number;\n /** Whether running is allowed (false when stamina < 10%) */\n readonly canRun: boolean;\n}\n\n/**\n * Movement type enumeration.\n *\n * **Korean**: 이동 유형 (Movement Type)\n *\n * @category Physics System\n */\nexport enum MovementType {\n /** Walking forward - Korean: 걷기 */\n WALKING = \"walking\",\n /** Running/sprinting forward - Korean: 달리기 */\n RUNNING = \"running\",\n /** Moving backward - Korean: 후퇴 */\n BACKWARD = \"backward\",\n /** Side-stepping left/right - Korean: 측면이동 */\n LATERAL = \"lateral\",\n /** Crouching movement - Korean: 웅크리기 */\n CROUCHING = \"crouching\",\n}\n\n/**\n * Speed Modifier System class.\n *\n * **Korean**: 속도 변경 시스템 클래스\n *\n * Calculates comprehensive speed modifiers from multiple factors including\n * stance, injuries, stamina, and combat state. Integrates with existing\n * body part and movement systems.\n *\n * @example\n * ```typescript\n * const system = new SpeedModifierSystem();\n *\n * const modifiers = system.calculateSpeedModifiers(\n * playerState,\n * MovementType.RUNNING,\n * true // isCrouching\n * );\n *\n * // Apply to movement physics\n * movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n * movementPhysics.setAcceleration(modifiers.finalAcceleration);\n * ```\n *\n * @category Physics System\n */\nexport class SpeedModifierSystem {\n /**\n * Base walking speed (m/s)\n * Standard walking pace for combat movement - crosses 14m arena in ~2.3s\n *\n * **Korean**: 기본 걷기 속도 (Base Walking Speed)\n */\n private readonly BASE_WALKING_SPEED = 6.0;\n\n /**\n * Base running speed (m/s)\n * Sprint speed for rapid repositioning - crosses 14m arena in ~1.4s\n *\n * **Korean**: 기본 달리기 속도 (Base Running Speed)\n */\n private readonly BASE_RUNNING_SPEED = 10.0;\n\n /**\n * Lateral movement speed (m/s)\n * Fast side-stepping for combat positioning\n *\n * **Korean**: 측면 이동 속도 (Lateral Movement Speed)\n */\n private readonly LATERAL_SPEED = 5.0;\n\n /**\n * Crouching movement speed (m/s)\n * Defensive low movement for cautious approach\n *\n * **Korean**: 웅크림 이동 속도 (Crouching Movement Speed)\n */\n private readonly CROUCHING_SPEED = 3.0;\n\n /**\n * Backward speed multiplier (75% of forward speed)\n *\n * **Korean**: 후퇴 속도 배수 (Backward Speed Multiplier)\n */\n private readonly BACKWARD_SPEED_MULTIPLIER = 0.75;\n\n /**\n * Base acceleration rate (m/s²)\n * Instant-response acceleration for combat movement\n * (e.g., reaches 6 m/s walking speed in 0.2s; 10 m/s sprint speed in 0.33s)\n * Increased from 12.0 to 30.0 for responsive, arcade-style combat feel\n *\n * Imported from physicsConstants.ts to maintain consistency across systems.\n *\n * **Korean**: 기본 가속도 (Base Acceleration)\n */\n private readonly BASE_ACCELERATION = BASE_MOVEMENT_ACCELERATION;\n\n /**\n * Combat state speed penalty multipliers\n *\n * **Korean**: 전투 상태 속도 패널티 (Combat State Speed Penalties)\n */\n private readonly COMBAT_STATE_PENALTIES: Record<CombatState, number> = {\n [CombatState.IDLE]: 0.0, // No penalty when idle\n [CombatState.ATTACKING]: 0.3, // -30% during attack commitment\n [CombatState.DEFENDING]: 0.2, // -20% while guarding\n [CombatState.STUNNED]: 1.0, // Cannot move when stunned\n [CombatState.RECOVERING]: 0.4, // -40% during recovery frames\n [CombatState.COUNTERING]: 0.25, // -25% during counter execution\n [CombatState.TRANSITIONING]: 0.15, // -15% during stance transitions\n [CombatState.GRAPPLING]: 0.8, // -80% while controlling opponent\n [CombatState.GRAPPLED]: 1.0, // Cannot move while being controlled\n };\n\n // Constructor removed - no longer need MovementPenaltySystem instance\n // Using injuryMovementModifier singleton instead\n\n /**\n * Calculate comprehensive speed modifiers for player movement.\n *\n * **Korean**: 속도 변경 계산 (Calculate Speed Modifiers)\n *\n * Analyzes player state and returns complete speed modifier information\n * including all individual factors and final calculated values.\n *\n * @param playerState - Current player state with stance, health, stamina\n * @param movementType - Type of movement being performed\n * @param isCrouching - Whether player is in crouching stance\n * @returns Complete speed modifier state with all factors\n *\n */\n public calculateSpeedModifiers(\n playerState: PlayerState,\n movementType: MovementType = MovementType.WALKING,\n isCrouching: boolean = false,\n ): SpeedModifierState {\n // Get base speed based on movement type and archetype-specific speeds\n const baseSpeed = this.getBaseSpeed(\n movementType,\n isCrouching,\n playerState.physicalAttributes,\n );\n\n // Calculate injury penalty from leg damage using NEW InjuryMovementModifier system\n // This replaces the old MovementPenaltySystem with comprehensive injury calculations\n const injuryPenalty = this.calculateInjuryPenalty(\n playerState.bodyPartHealth,\n playerState.bodyPartMaxHealth,\n playerState.pain,\n );\n\n // Calculate stance modifier separately.\n // NOTE: InjuryMovementModifier is called with neutral GEON stance inside\n // calculateInjuryPenalty() so that injury effects are isolated from stance.\n // The actual current stance effect must be applied here via stanceModifier.\n const stanceModifier = this.getStanceSpeedModifier(\n playerState.currentStance,\n );\n\n // Calculate combat state penalty\n const combatStatePenalty = this.getCombatStatePenalty(\n playerState.combatState,\n );\n\n // Calculate stamina penalty (affects acceleration only)\n const staminaPenalty = this.calculateStaminaPenalty(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Check if running is allowed\n const canRun = this.canPlayerRun(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Calculate final speed with all modifiers applied multiplicatively\n // Formula: Base × Stance × (1 - Injury) × (1 - CombatState)\n // Note: Injury penalty now excludes stance (calculated with GEON), so we apply stance here\n const finalSpeed =\n baseSpeed *\n stanceModifier *\n (1.0 - injuryPenalty) *\n (1.0 - combatStatePenalty);\n\n // Calculate final acceleration using archetype-specific base and stamina penalty\n // Formula: ArchetypeAcceleration × (1 - StaminaPenalty)\n const archetypeAcceleration =\n playerState.physicalAttributes?.acceleration ?? this.BASE_ACCELERATION;\n const finalAcceleration = archetypeAcceleration * (1.0 - staminaPenalty);\n\n return {\n baseSpeed,\n stanceModifier,\n injuryPenalty,\n combatStatePenalty,\n staminaPenalty,\n finalSpeed,\n finalAcceleration,\n canRun,\n };\n }\n\n /**\n * Get base speed for movement type.\n *\n * **Korean**: 기본 속도 계산 (Get Base Speed)\n *\n * Uses archetype-specific walk/run speeds when available,\n * falls back to default values for backwards compatibility.\n *\n * @param movementType - Type of movement\n * @param isCrouching - Whether player is crouching\n * @param physicalAttributes - Player's physical attributes (optional)\n * @returns Base speed in m/s\n *\n * @private\n */\n private getBaseSpeed(\n movementType: MovementType,\n isCrouching: boolean,\n physicalAttributes?: import(\"@/types\").PhysicalAttributes,\n ): number {\n if (isCrouching) {\n return this.CROUCHING_SPEED;\n }\n\n // Use archetype-specific speeds if available\n const archetypeWalkSpeed =\n physicalAttributes?.walkSpeed ?? this.BASE_WALKING_SPEED;\n const archetypeRunSpeed =\n physicalAttributes?.runSpeed ?? this.BASE_RUNNING_SPEED;\n\n switch (movementType) {\n case MovementType.WALKING:\n return archetypeWalkSpeed;\n case MovementType.RUNNING:\n return archetypeRunSpeed;\n case MovementType.BACKWARD:\n return archetypeWalkSpeed * this.BACKWARD_SPEED_MULTIPLIER;\n case MovementType.LATERAL:\n // Lateral speed scales proportionally to archetype walk speed\n return (\n archetypeWalkSpeed * (this.LATERAL_SPEED / this.BASE_WALKING_SPEED)\n );\n case MovementType.CROUCHING:\n return this.CROUCHING_SPEED;\n default:\n return archetypeWalkSpeed;\n }\n }\n\n /**\n * Get stance-based speed modifier.\n *\n * **Korean**: 자세 속도 배수 계산 (Get Stance Speed Modifier)\n *\n * @param stance - Current Eight Trigram stance\n * @returns Speed multiplier (0.80 to 1.25)\n *\n * @private\n */\n private getStanceSpeedModifier(stance: TrigramStance): number {\n return STANCE_SPEED_MODIFIERS[stance] ?? 1.0;\n }\n\n /**\n * Calculate injury-based speed penalty from leg damage.\n *\n * **Korean**: 부상 속도 패널티 계산 (Calculate Injury Penalty)\n *\n * Uses NEW InjuryMovementModifier to determine speed reduction based on\n * leg damage severity, torso damage, and pain levels.\n * NOTE: Stance modifier is calculated separately to maintain compatibility\n * with existing SpeedModifierState interface.\n * \n * Penalties are progressive and realistic:\n * - Leg injuries: 0-100% penalty based on health\n * - Torso injuries: 0-30% minor penalty\n * - Both legs injured: Additional 20% cumulative penalty\n * - Pain overload: -15% when pain ≥ 80\n *\n * @param bodyPartHealth - Current body part health\n * @param bodyPartMaxHealth - Maximum body part health\n * @param painLevel - Current pain level (0-100)\n * @returns Speed penalty as percentage (0.0 to 0.9 max)\n *\n * @private\n */\n private calculateInjuryPenalty(\n bodyPartHealth: BodyPartHealth | undefined,\n bodyPartMaxHealth: BodyPartMaxHealth | undefined,\n painLevel: number,\n ): number {\n if (!bodyPartHealth || !bodyPartMaxHealth) {\n return 0.0; // No penalty if body part health not tracked\n }\n\n // Use NEW InjuryMovementModifier system for comprehensive injury calculation\n // Use NEUTRAL stance (GEON = 1.0x) to get pure injury penalty without stance influence\n // Stance is applied separately in calculateSpeedModifiers for compatibility\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0, // Base speed of 1.0 to get pure multiplier\n bodyPartHealth,\n TrigramStance.GEON, // Neutral stance to isolate injury penalty\n painLevel,\n );\n\n // Convert speedMultiplier to penalty percentage\n // speedMultiplier of 1.0 = no penalty (0.0)\n // speedMultiplier of 0.5 = 50% penalty (0.5)\n // speedMultiplier of 0.1 = 90% penalty (0.9)\n const penalty = 1.0 - result.speedMultiplier;\n\n // Return penalty (already clamped by InjuryMovementModifier to min 0.1 speed)\n return Math.min(penalty, 0.9);\n }\n\n /**\n * Calculate combat state speed penalty.\n *\n * **Korean**: 전투 상태 속도 패널티 계산 (Get Combat State Penalty)\n *\n * Different combat states restrict movement:\n * - IDLE: 0% penalty (full movement)\n * - ATTACKING: -30% penalty (committed to technique)\n * - DEFENDING: -20% penalty (guard up, limited mobility)\n * - STUNNED: -100% penalty (cannot move)\n * - RECOVERING: -40% penalty (vulnerable, slow movement)\n * - COUNTERING: -25% penalty (counter execution)\n * - TRANSITIONING: -15% penalty (stance change)\n *\n * @param combatState - Current combat state\n * @returns Speed penalty as percentage (0.0 to 1.0)\n *\n * @private\n */\n private getCombatStatePenalty(combatState: CombatState): number {\n return this.COMBAT_STATE_PENALTIES[combatState] ?? 0.0;\n }\n\n /**\n * Calculate stamina-based acceleration penalty.\n *\n * **Korean**: 스태미나 가속 패널티 계산 (Calculate Stamina Penalty)\n *\n * Stamina affects acceleration rate, making it harder to change direction\n * or speed up when fatigued:\n * - High stamina (70-100%): 0% penalty (normal acceleration)\n * - Medium stamina (40-70%): -20% penalty\n * - Low stamina (10-40%): -50% penalty\n * - Depleted stamina (<10%): -75% penalty, cannot run\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns Acceleration penalty as percentage (0.0 to 0.75)\n *\n * @private\n */\n private calculateStaminaPenalty(\n currentStamina: number,\n maxStamina: number,\n ): number {\n if (maxStamina <= 0) {\n return 0.0; // No penalty if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n\n if (staminaPercent >= 70) {\n return 0.0; // High stamina: no penalty\n } else if (staminaPercent >= 40) {\n return 0.2; // Medium stamina: -20% acceleration\n } else if (staminaPercent >= 10) {\n return 0.5; // Low stamina: -50% acceleration\n } else {\n return 0.75; // Depleted stamina: -75% acceleration\n }\n }\n\n /**\n * Check if player can run based on stamina level.\n *\n * **Korean**: 달리기 가능 확인 (Can Player Run)\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns True if player has enough stamina to run\n *\n * @private\n */\n private canPlayerRun(currentStamina: number, maxStamina: number): boolean {\n if (maxStamina <= 0) {\n return true; // Allow running if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n return staminaPercent >= 10; // Cannot run when stamina < 10%\n }\n\n /**\n * Apply speed modifiers to movement physics system.\n *\n * **Korean**: 속도 변경 적용 (Apply Speed Modifiers)\n *\n * Convenience method to directly apply calculated modifiers to a\n * movement physics instance.\n *\n * @param movementPhysics - Movement physics system to update\n * @param modifiers - Calculated speed modifier state\n *\n */\n public applySpeedModifiers(\n movementPhysics: {\n setMaxSpeed: (speed: number) => void;\n setAcceleration: (accel: number) => void;\n },\n modifiers: SpeedModifierState,\n ): void {\n movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n movementPhysics.setAcceleration(modifiers.finalAcceleration);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAmFA,IAAY,eAAL,yBAAA,cAAA;;CAEL,aAAA,aAAU;;CAEV,aAAA,aAAU;;CAEV,aAAA,cAAW;;CAEX,aAAA,aAAU;;CAEV,aAAA,eAAY;;KACb;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BD,IAAa,sBAAb,MAAiC;;;;;;;CAO/B,qBAAsC;;;;;;;CAQtC,qBAAsC;;;;;;;CAQtC,gBAAiC;;;;;;;CAQjC,kBAAmC;;;;;;CAOnC,4BAA6C;;;;;;;;;;;CAY7C,oBAAA;;;;;;CAOA,yBAAuE;GACpE,YAAY,OAAO;GACnB,YAAY,YAAY;GACxB,YAAY,YAAY;GACxB,YAAY,UAAU;GACtB,YAAY,aAAa;GACzB,YAAY,aAAa;GACzB,YAAY,gBAAgB;GAC5B,YAAY,YAAY;GACxB,YAAY,WAAW;EACzB;;;;;;;;;;;;;;;CAmBD,wBACE,aACA,eAA6B,aAAa,SAC1C,cAAuB,OACH;EAEpB,MAAM,YAAY,KAAK,aACrB,cACA,aACA,YAAY,mBACb;EAID,MAAM,gBAAgB,KAAK,uBACzB,YAAY,gBACZ,YAAY,mBACZ,YAAY,KACb;EAMD,MAAM,iBAAiB,KAAK,uBAC1B,YAAY,cACb;EAGD,MAAM,qBAAqB,KAAK,sBAC9B,YAAY,YACb;EAGD,MAAM,iBAAiB,KAAK,wBAC1B,YAAY,SACZ,YAAY,WACb;EAGD,MAAM,SAAS,KAAK,aAClB,YAAY,SACZ,YAAY,WACb;EAiBD,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,YAjBA,YACA,kBACC,IAAM,kBACN,IAAM;GAeP,oBAVA,YAAY,oBAAoB,gBAAgB,KAAK,sBACJ,IAAM;GAUvD;GACD;;;;;;;;;;;;;;;;;CAkBH,aACE,cACA,aACA,oBACQ;EACR,IAAI,aACF,OAAO,KAAK;EAId,MAAM,qBACJ,oBAAoB,aAAa,KAAK;EACxC,MAAM,oBACJ,oBAAoB,YAAY,KAAK;EAEvC,QAAQ,cAAR;GACE,KAAK,aAAa,SAChB,OAAO;GACT,KAAK,aAAa,SAChB,OAAO;GACT,KAAK,aAAa,UAChB,OAAO,qBAAqB,KAAK;GACnC,KAAK,aAAa,SAEhB,OACE,sBAAsB,KAAK,gBAAgB,KAAK;GAEpD,KAAK,aAAa,WAChB,OAAO,KAAK;GACd,SACE,OAAO;;;;;;;;;;;;;CAcb,uBAA+B,QAA+B;EAC5D,OAAO,uBAAuB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3C,uBACE,gBACA,mBACA,WACQ;EACR,IAAI,CAAC,kBAAkB,CAAC,mBACtB,OAAO;EAiBT,MAAM,UAAU,IAXD,uBAAuB,uBACpC,GACA,gBACA,cAAc,MACd,UAOoB,CAAO;EAG7B,OAAO,KAAK,IAAI,SAAS,GAAI;;;;;;;;;;;;;;;;;;;;;CAsB/B,sBAA8B,aAAkC;EAC9D,OAAO,KAAK,uBAAuB,gBAAgB;;;;;;;;;;;;;;;;;;;;CAqBrD,wBACE,gBACA,YACQ;EACR,IAAI,cAAc,GAChB,OAAO;EAGT,MAAM,iBAAkB,iBAAiB,aAAc;EAEvD,IAAI,kBAAkB,IACpB,OAAO;OACF,IAAI,kBAAkB,IAC3B,OAAO;OACF,IAAI,kBAAkB,IAC3B,OAAO;OAEP,OAAO;;;;;;;;;;;;;CAeX,aAAqB,gBAAwB,YAA6B;EACxE,IAAI,cAAc,GAChB,OAAO;EAIT,OADwB,iBAAiB,aAAc,OAC9B;;;;;;;;;;;;;;CAe3B,oBACE,iBAIA,WACM;EACN,gBAAgB,YAAY,UAAU,WAAW;EACjD,gBAAgB,gBAAgB,UAAU,kBAAkB"}
1
+ {"version":3,"file":"SpeedModifierSystem.js","names":[],"sources":["../../../src/systems/physics/SpeedModifierSystem.ts"],"sourcesContent":["/**\n * Speed Modifier System\n *\n * **Korean**: 속도 변경 시스템 (Speed Modifier System)\n *\n * Implements comprehensive movement speed modifier system that dynamically adjusts\n * player movement speed based on multiple factors: combat stance, leg injuries,\n * stamina depletion, and combat state. Integrates with physics-based movement\n * system for authentic Korean martial arts combat feel.\n *\n * ## System Features\n *\n * - Base movement speeds for walking, running, backward, lateral, and crouching\n * - Eight Trigram stance-based speed modifiers (80% to 125%)\n * - Injury-based speed reduction from leg damage (0% to 100% penalty)\n * - Stamina-based acceleration penalty (0% to 75% penalty)\n * - Combat state speed adjustments (0% to 100% penalty)\n * - Multiplicative and additive modifier stacking\n *\n * ## Speed Calculation Formula\n *\n * ```\n * Final Speed = Base Speed\n * × Stance Modifier\n * × (1 - Injury Penalty from Legs, Torso & Pain)\n * × (1 - Combat State Penalty)\n *\n * Final Acceleration = Base Acceleration\n * × (1 - Stamina Penalty)\n * ```\n *\n * @module systems/physics/SpeedModifierSystem\n * @category Physics System\n * @korean 속도변경시스템\n */\n\nimport type {\n BodyPartHealth,\n BodyPartMaxHealth,\n} from \"@/systems/bodypart/types\";\nimport type { PlayerState } from \"@/systems/player\";\nimport { CombatState, TrigramStance } from \"@/types/common\";\nimport { BASE_MOVEMENT_ACCELERATION } from \"@/types/physicsConstants\";\nimport { STANCE_SPEED_MODIFIERS } from \"./MovementPhysics\";\nimport { injuryMovementModifier } from \"@/systems/movement/InjuryMovementModifier\";\n\n/**\n * Complete speed modifier state for physics calculations.\n *\n * **Korean**: 속도 변경 상태 (Speed Modifier State)\n *\n * Contains all calculated speed modifiers and final values for application\n * to the physics-based movement system.\n *\n * @category Physics System\n * @korean 속도변경상태\n */\nexport interface SpeedModifierState {\n /** Base movement speed before modifiers (m/s) */\n readonly baseSpeed: number;\n /** Stance-based speed multiplier (0.80 to 1.25) */\n readonly stanceModifier: number;\n /** Injury-based speed reduction (0.0 to 0.75, percentage reduction) - Korean: 부상감소 */\n readonly injuryPenalty: number;\n /** Combat state speed reduction (0.0 to 1.0, percentage reduction) */\n readonly combatStatePenalty: number;\n /** Stamina-based acceleration reduction (0.0 to 0.75, percentage reduction) - Korean: 스태미나효과 */\n readonly staminaPenalty: number;\n /** Final calculated movement speed (m/s) */\n readonly finalSpeed: number;\n /** Final calculated acceleration (m/s²) */\n readonly finalAcceleration: number;\n /** Whether running is allowed (false when stamina < 10%) */\n readonly canRun: boolean;\n}\n\n/**\n * Movement type enumeration.\n *\n * **Korean**: 이동 유형 (Movement Type)\n *\n * @category Physics System\n */\nexport enum MovementType {\n /** Walking forward - Korean: 걷기 */\n WALKING = \"walking\",\n /** Running/sprinting forward - Korean: 달리기 */\n RUNNING = \"running\",\n /** Moving backward - Korean: 후퇴 */\n BACKWARD = \"backward\",\n /** Side-stepping left/right - Korean: 측면이동 */\n LATERAL = \"lateral\",\n /** Crouching movement - Korean: 웅크리기 */\n CROUCHING = \"crouching\",\n}\n\n/**\n * Speed Modifier System class.\n *\n * **Korean**: 속도 변경 시스템 클래스\n *\n * Calculates comprehensive speed modifiers from multiple factors including\n * stance, injuries, stamina, and combat state. Integrates with existing\n * body part and movement systems.\n *\n * @example\n * ```typescript\n * const system = new SpeedModifierSystem();\n *\n * const modifiers = system.calculateSpeedModifiers(\n * playerState,\n * MovementType.RUNNING,\n * true // isCrouching\n * );\n *\n * // Apply to movement physics\n * movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n * movementPhysics.setAcceleration(modifiers.finalAcceleration);\n * ```\n *\n * @category Physics System\n */\nexport class SpeedModifierSystem {\n /**\n * Base walking speed (m/s)\n * Standard walking pace for combat movement - crosses 14m arena in ~2.3s\n *\n * **Korean**: 기본 걷기 속도 (Base Walking Speed)\n */\n private readonly BASE_WALKING_SPEED = 6.0;\n\n /**\n * Base running speed (m/s)\n * Sprint speed for rapid repositioning - crosses 14m arena in ~1.4s\n *\n * **Korean**: 기본 달리기 속도 (Base Running Speed)\n */\n private readonly BASE_RUNNING_SPEED = 10.0;\n\n /**\n * Lateral movement speed (m/s)\n * Fast side-stepping for combat positioning\n *\n * **Korean**: 측면 이동 속도 (Lateral Movement Speed)\n */\n private readonly LATERAL_SPEED = 5.0;\n\n /**\n * Crouching movement speed (m/s)\n * Defensive low movement for cautious approach\n *\n * **Korean**: 웅크림 이동 속도 (Crouching Movement Speed)\n */\n private readonly CROUCHING_SPEED = 3.0;\n\n /**\n * Backward speed multiplier (75% of forward speed)\n *\n * **Korean**: 후퇴 속도 배수 (Backward Speed Multiplier)\n */\n private readonly BACKWARD_SPEED_MULTIPLIER = 0.75;\n\n /**\n * Base acceleration rate (m/s²)\n * Instant-response acceleration for combat movement\n * (e.g., reaches 6 m/s walking speed in 0.2s; 10 m/s sprint speed in 0.33s)\n * Increased from 12.0 to 30.0 for responsive, arcade-style combat feel\n *\n * Imported from physicsConstants.ts to maintain consistency across systems.\n *\n * **Korean**: 기본 가속도 (Base Acceleration)\n */\n private readonly BASE_ACCELERATION = BASE_MOVEMENT_ACCELERATION;\n\n /**\n * Combat state speed penalty multipliers\n *\n * **Korean**: 전투 상태 속도 패널티 (Combat State Speed Penalties)\n */\n private readonly COMBAT_STATE_PENALTIES: Record<CombatState, number> = {\n [CombatState.IDLE]: 0.0, // No penalty when idle\n [CombatState.ATTACKING]: 0.3, // -30% during attack commitment\n [CombatState.DEFENDING]: 0.2, // -20% while guarding\n [CombatState.STUNNED]: 1.0, // Cannot move when stunned\n [CombatState.RECOVERING]: 0.4, // -40% during recovery frames\n [CombatState.COUNTERING]: 0.25, // -25% during counter execution\n [CombatState.TRANSITIONING]: 0.15, // -15% during stance transitions\n [CombatState.GRAPPLING]: 0.8, // -80% while controlling opponent\n [CombatState.GRAPPLED]: 1.0, // Cannot move while being controlled\n };\n\n // Constructor removed - no longer need MovementPenaltySystem instance\n // Using injuryMovementModifier singleton instead\n\n /**\n * Calculate comprehensive speed modifiers for player movement.\n *\n * **Korean**: 속도 변경 계산 (Calculate Speed Modifiers)\n *\n * Analyzes player state and returns complete speed modifier information\n * including all individual factors and final calculated values.\n *\n * @param playerState - Current player state with stance, health, stamina\n * @param movementType - Type of movement being performed\n * @param isCrouching - Whether player is in crouching stance\n * @returns Complete speed modifier state with all factors\n *\n */\n public calculateSpeedModifiers(\n playerState: PlayerState,\n movementType: MovementType = MovementType.WALKING,\n isCrouching: boolean = false,\n ): SpeedModifierState {\n // Get base speed based on movement type and archetype-specific speeds\n const baseSpeed = this.getBaseSpeed(\n movementType,\n isCrouching,\n playerState.physicalAttributes,\n );\n\n // Calculate injury penalty from leg damage using NEW InjuryMovementModifier system\n // This replaces the old MovementPenaltySystem with comprehensive injury calculations\n const injuryPenalty = this.calculateInjuryPenalty(\n playerState.bodyPartHealth,\n playerState.bodyPartMaxHealth,\n playerState.pain,\n );\n\n // Calculate stance modifier separately.\n // NOTE: InjuryMovementModifier is called with neutral GEON stance inside\n // calculateInjuryPenalty() so that injury effects are isolated from stance.\n // The actual current stance effect must be applied here via stanceModifier.\n const stanceModifier = this.getStanceSpeedModifier(\n playerState.currentStance,\n );\n\n // Calculate combat state penalty\n const combatStatePenalty = this.getCombatStatePenalty(\n playerState.combatState,\n );\n\n // Calculate stamina penalty (affects acceleration only)\n const staminaPenalty = this.calculateStaminaPenalty(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Check if running is allowed\n const canRun = this.canPlayerRun(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Calculate final speed with all modifiers applied multiplicatively\n // Formula: Base × Stance × (1 - Injury) × (1 - CombatState)\n // Note: Injury penalty now excludes stance (calculated with GEON), so we apply stance here\n const finalSpeed =\n baseSpeed *\n stanceModifier *\n (1.0 - injuryPenalty) *\n (1.0 - combatStatePenalty);\n\n // Calculate final acceleration using archetype-specific base and stamina penalty\n // Formula: ArchetypeAcceleration × (1 - StaminaPenalty)\n const archetypeAcceleration =\n playerState.physicalAttributes?.acceleration ?? this.BASE_ACCELERATION;\n const finalAcceleration = archetypeAcceleration * (1.0 - staminaPenalty);\n\n return {\n baseSpeed,\n stanceModifier,\n injuryPenalty,\n combatStatePenalty,\n staminaPenalty,\n finalSpeed,\n finalAcceleration,\n canRun,\n };\n }\n\n /**\n * Get base speed for movement type.\n *\n * **Korean**: 기본 속도 계산 (Get Base Speed)\n *\n * Uses archetype-specific walk/run speeds when available,\n * falls back to default values for backwards compatibility.\n *\n * @param movementType - Type of movement\n * @param isCrouching - Whether player is crouching\n * @param physicalAttributes - Player's physical attributes (optional)\n * @returns Base speed in m/s\n *\n * @private\n */\n private getBaseSpeed(\n movementType: MovementType,\n isCrouching: boolean,\n physicalAttributes?: import(\"@/types\").PhysicalAttributes,\n ): number {\n if (isCrouching) {\n return this.CROUCHING_SPEED;\n }\n\n // Use archetype-specific speeds if available\n const archetypeWalkSpeed =\n physicalAttributes?.walkSpeed ?? this.BASE_WALKING_SPEED;\n const archetypeRunSpeed =\n physicalAttributes?.runSpeed ?? this.BASE_RUNNING_SPEED;\n\n switch (movementType) {\n case MovementType.WALKING:\n return archetypeWalkSpeed;\n case MovementType.RUNNING:\n return archetypeRunSpeed;\n case MovementType.BACKWARD:\n return archetypeWalkSpeed * this.BACKWARD_SPEED_MULTIPLIER;\n case MovementType.LATERAL:\n // Lateral speed scales proportionally to archetype walk speed\n return (\n archetypeWalkSpeed * (this.LATERAL_SPEED / this.BASE_WALKING_SPEED)\n );\n case MovementType.CROUCHING:\n return this.CROUCHING_SPEED;\n default:\n return archetypeWalkSpeed;\n }\n }\n\n /**\n * Get stance-based speed modifier.\n *\n * **Korean**: 자세 속도 배수 계산 (Get Stance Speed Modifier)\n *\n * @param stance - Current Eight Trigram stance\n * @returns Speed multiplier (0.80 to 1.25)\n *\n * @private\n */\n private getStanceSpeedModifier(stance: TrigramStance): number {\n return STANCE_SPEED_MODIFIERS[stance] ?? 1.0;\n }\n\n /**\n * Calculate injury-based speed penalty from leg damage.\n *\n * **Korean**: 부상 속도 패널티 계산 (Calculate Injury Penalty)\n *\n * Uses NEW InjuryMovementModifier to determine speed reduction based on\n * leg damage severity, torso damage, and pain levels.\n * NOTE: Stance modifier is calculated separately to maintain compatibility\n * with existing SpeedModifierState interface.\n * \n * Penalties are progressive and realistic:\n * - Leg injuries: 0-100% penalty based on health\n * - Torso injuries: 0-30% minor penalty\n * - Both legs injured: Additional 20% cumulative penalty\n * - Pain overload: -15% when pain ≥ 80\n *\n * @param bodyPartHealth - Current body part health\n * @param bodyPartMaxHealth - Maximum body part health\n * @param painLevel - Current pain level (0-100)\n * @returns Speed penalty as percentage (0.0 to 0.9 max)\n *\n * @private\n */\n private calculateInjuryPenalty(\n bodyPartHealth: BodyPartHealth | undefined,\n bodyPartMaxHealth: BodyPartMaxHealth | undefined,\n painLevel: number,\n ): number {\n if (!bodyPartHealth || !bodyPartMaxHealth) {\n return 0.0; // No penalty if body part health not tracked\n }\n\n // Use NEW InjuryMovementModifier system for comprehensive injury calculation\n // Use NEUTRAL stance (GEON = 1.0x) to get pure injury penalty without stance influence\n // Stance is applied separately in calculateSpeedModifiers for compatibility\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0, // Base speed of 1.0 to get pure multiplier\n bodyPartHealth,\n TrigramStance.GEON, // Neutral stance to isolate injury penalty\n painLevel,\n );\n\n // Convert speedMultiplier to penalty percentage\n // speedMultiplier of 1.0 = no penalty (0.0)\n // speedMultiplier of 0.5 = 50% penalty (0.5)\n // speedMultiplier of 0.1 = 90% penalty (0.9)\n const penalty = 1.0 - result.speedMultiplier;\n\n // Return penalty (already clamped by InjuryMovementModifier to min 0.1 speed)\n return Math.min(penalty, 0.9);\n }\n\n /**\n * Calculate combat state speed penalty.\n *\n * **Korean**: 전투 상태 속도 패널티 계산 (Get Combat State Penalty)\n *\n * Different combat states restrict movement:\n * - IDLE: 0% penalty (full movement)\n * - ATTACKING: -30% penalty (committed to technique)\n * - DEFENDING: -20% penalty (guard up, limited mobility)\n * - STUNNED: -100% penalty (cannot move)\n * - RECOVERING: -40% penalty (vulnerable, slow movement)\n * - COUNTERING: -25% penalty (counter execution)\n * - TRANSITIONING: -15% penalty (stance change)\n *\n * @param combatState - Current combat state\n * @returns Speed penalty as percentage (0.0 to 1.0)\n *\n * @private\n */\n private getCombatStatePenalty(combatState: CombatState): number {\n return this.COMBAT_STATE_PENALTIES[combatState] ?? 0.0;\n }\n\n /**\n * Calculate stamina-based acceleration penalty.\n *\n * **Korean**: 스태미나 가속 패널티 계산 (Calculate Stamina Penalty)\n *\n * Stamina affects acceleration rate, making it harder to change direction\n * or speed up when fatigued:\n * - High stamina (70-100%): 0% penalty (normal acceleration)\n * - Medium stamina (40-70%): -20% penalty\n * - Low stamina (10-40%): -50% penalty\n * - Depleted stamina (<10%): -75% penalty, cannot run\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns Acceleration penalty as percentage (0.0 to 0.75)\n *\n * @private\n */\n private calculateStaminaPenalty(\n currentStamina: number,\n maxStamina: number,\n ): number {\n if (maxStamina <= 0) {\n return 0.0; // No penalty if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n\n if (staminaPercent >= 70) {\n return 0.0; // High stamina: no penalty\n } else if (staminaPercent >= 40) {\n return 0.2; // Medium stamina: -20% acceleration\n } else if (staminaPercent >= 10) {\n return 0.5; // Low stamina: -50% acceleration\n } else {\n return 0.75; // Depleted stamina: -75% acceleration\n }\n }\n\n /**\n * Check if player can run based on stamina level.\n *\n * **Korean**: 달리기 가능 확인 (Can Player Run)\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns True if player has enough stamina to run\n *\n * @private\n */\n private canPlayerRun(currentStamina: number, maxStamina: number): boolean {\n if (maxStamina <= 0) {\n return true; // Allow running if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n return staminaPercent >= 10; // Cannot run when stamina < 10%\n }\n\n /**\n * Apply speed modifiers to movement physics system.\n *\n * **Korean**: 속도 변경 적용 (Apply Speed Modifiers)\n *\n * Convenience method to directly apply calculated modifiers to a\n * movement physics instance.\n *\n * @param movementPhysics - Movement physics system to update\n * @param modifiers - Calculated speed modifier state\n *\n */\n public applySpeedModifiers(\n movementPhysics: {\n setMaxSpeed: (speed: number) => void;\n setAcceleration: (accel: number) => void;\n },\n modifiers: SpeedModifierState,\n ): void {\n movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n movementPhysics.setAcceleration(modifiers.finalAcceleration);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAmFA,IAAY,eAAL,yBAAA,cAAA;;CAEL,aAAA,aAAA;;CAEA,aAAA,aAAA;;CAEA,aAAA,cAAA;;CAEA,aAAA,aAAA;;CAEA,aAAA,eAAA;;AACF,EAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,IAAa,sBAAb,MAAiC;;;;;;;CAO/B,qBAAsC;;;;;;;CAQtC,qBAAsC;;;;;;;CAQtC,gBAAiC;;;;;;;CAQjC,kBAAmC;;;;;;CAOnC,4BAA6C;;;;;;;;;;;CAY7C,oBAAA;;;;;;CAOA,yBAAuE;GACpE,YAAY,OAAO;GACnB,YAAY,YAAY;GACxB,YAAY,YAAY;GACxB,YAAY,UAAU;GACtB,YAAY,aAAa;GACzB,YAAY,aAAa;GACzB,YAAY,gBAAgB;GAC5B,YAAY,YAAY;GACxB,YAAY,WAAW;CAC1B;;;;;;;;;;;;;;;CAmBA,wBACE,aACA,eAAA,WACA,cAAuB,OACH;EAEpB,MAAM,YAAY,KAAK,aACrB,cACA,aACA,YAAY,kBACd;EAIA,MAAM,gBAAgB,KAAK,uBACzB,YAAY,gBACZ,YAAY,mBACZ,YAAY,IACd;EAMA,MAAM,iBAAiB,KAAK,uBAC1B,YAAY,aACd;EAGA,MAAM,qBAAqB,KAAK,sBAC9B,YAAY,WACd;EAGA,MAAM,iBAAiB,KAAK,wBAC1B,YAAY,SACZ,YAAY,UACd;EAGA,MAAM,SAAS,KAAK,aAClB,YAAY,SACZ,YAAY,UACd;EAiBA,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,YAjBA,YACA,kBACC,IAAM,kBACN,IAAM;GAeP,oBAVA,YAAY,oBAAoB,gBAAgB,KAAK,sBACJ,IAAM;GAUvD;EACF;CACF;;;;;;;;;;;;;;;;CAiBA,aACE,cACA,aACA,oBACQ;EACR,IAAI,aACF,OAAO,KAAK;EAId,MAAM,qBACJ,oBAAoB,aAAa,KAAK;EACxC,MAAM,oBACJ,oBAAoB,YAAY,KAAK;EAEvC,QAAQ,cAAR;GACE,KAAA,WACE,OAAO;GACT,KAAA,WACE,OAAO;GACT,KAAA,YACE,OAAO,qBAAqB,KAAK;GACnC,KAAA,WAEE,OACE,sBAAsB,KAAK,gBAAgB,KAAK;GAEpD,KAAA,aACE,OAAO,KAAK;GACd,SACE,OAAO;EACX;CACF;;;;;;;;;;;CAYA,uBAA+B,QAA+B;EAC5D,OAAO,uBAAuB,WAAW;CAC3C;;;;;;;;;;;;;;;;;;;;;;;;CAyBA,uBACE,gBACA,mBACA,WACQ;EACR,IAAI,CAAC,kBAAkB,CAAC,mBACtB,OAAO;EAiBT,MAAM,UAAU,IAXD,uBAAuB,uBACpC,GACA,gBACA,cAAc,MACd,SAOoB,EAAO;EAG7B,OAAO,KAAK,IAAI,SAAS,EAAG;CAC9B;;;;;;;;;;;;;;;;;;;;CAqBA,sBAA8B,aAAkC;EAC9D,OAAO,KAAK,uBAAuB,gBAAgB;CACrD;;;;;;;;;;;;;;;;;;;CAoBA,wBACE,gBACA,YACQ;EACR,IAAI,cAAc,GAChB,OAAO;EAGT,MAAM,iBAAkB,iBAAiB,aAAc;EAEvD,IAAI,kBAAkB,IACpB,OAAO;OACF,IAAI,kBAAkB,IAC3B,OAAO;OACF,IAAI,kBAAkB,IAC3B,OAAO;OAEP,OAAO;CAEX;;;;;;;;;;;;CAaA,aAAqB,gBAAwB,YAA6B;EACxE,IAAI,cAAc,GAChB,OAAO;EAIT,OADwB,iBAAiB,aAAc,OAC9B;CAC3B;;;;;;;;;;;;;CAcA,oBACE,iBAIA,WACM;EACN,gBAAgB,YAAY,UAAU,UAAU;EAChD,gBAAgB,gBAAgB,UAAU,iBAAiB;CAC7D;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"KoreanCulture.js","names":[],"sources":["../../../src/systems/trigram/KoreanCulture.ts"],"sourcesContent":["import type { KoreanText, TrigramStance } from \"../../types\";\n\n/**\n * Korean cultural elements and philosophy for martial arts\n */\nexport class KoreanCulture {\n /**\n * Traditional Korean martial arts values\n */\n static readonly MARTIAL_VALUES = {\n honor: { korean: \"명예\", english: \"Honor\" },\n respect: { korean: \"존경\", english: \"Respect\" },\n discipline: { korean: \"절제\", english: \"Discipline\" },\n perseverance: { korean: \"인내\", english: \"Perseverance\" },\n loyalty: { korean: \"충성\", english: \"Loyalty\" },\n righteousness: { korean: \"의\", english: \"Righteousness\" },\n } as const;\n\n /**\n * Trigram philosophical meanings\n */\n static readonly TRIGRAM_PHILOSOPHY: Record<TrigramStance, KoreanText> = {\n geon: {\n korean: \"하늘의 창조력과 무한한 가능성\",\n english: \"Heaven's creative force and infinite possibilities\",\n },\n tae: {\n korean: \"호수의 평온함과 유연한 적응\",\n english: \"Lake's tranquility and flexible adaptation\",\n },\n li: {\n korean: \"불의 밝음과 정확한 판단\",\n english: \"Fire's brightness and precise judgment\",\n },\n jin: {\n korean: \"천둥의 역동성과 순간적 행동\",\n english: \"Thunder's dynamism and instantaneous action\",\n },\n son: {\n korean: \"바람의 지속성과 점진적 변화\",\n english: \"Wind's persistence and gradual change\",\n },\n gam: {\n korean: \"물의 깊이와 흐르는 지혜\",\n english: \"Water's depth and flowing wisdom\",\n },\n gan: {\n korean: \"산의 견고함과 정적인 힘\",\n english: \"Mountain's solidity and static strength\",\n },\n gon: {\n korean: \"땅의 포용과 양육하는 힘\",\n english: \"Earth's embrace and nurturing power\",\n },\n };\n\n /**\n * Korean martial arts terminology\n */\n static readonly MARTIAL_TERMS = {\n techniques: {\n strike: { korean: \"타격\", english: \"Strike\" },\n block: { korean: \"막기\", english: \"Block\" },\n throw: { korean: \"던지기\", english: \"Throw\" },\n lock: { korean: \"꺾기\", english: \"Lock\" },\n pressure: { korean: \"압박\", english: \"Pressure\" },\n },\n body_parts: {\n head: { korean: \"머리\", english: \"Head\" },\n neck: { korean: \"목\", english: \"Neck\" },\n torso: { korean: \"몸통\", english: \"Torso\" },\n arm: { korean: \"팔\", english: \"Arm\" },\n leg: { korean: \"다리\", english: \"Leg\" },\n },\n concepts: {\n ki: { korean: \"기\", english: \"Ki/Energy\" },\n balance: { korean: \"균형\", english: \"Balance\" },\n harmony: { korean: \"조화\", english: \"Harmony\" },\n flow: { korean: \"흐름\", english: \"Flow\" },\n center: { korean: \"중심\", english: \"Center\" },\n },\n } as const;\n\n /**\n * Get cultural wisdom for a stance\n */\n static getStanceWisdom(stance: TrigramStance): KoreanText {\n return this.TRIGRAM_PHILOSOPHY[stance];\n }\n\n /**\n * Get martial arts greeting\n */\n static getMartialGreeting(): KoreanText {\n return {\n korean: \"태권도!\",\n english: \"Taekwondo!\",\n };\n }\n\n /**\n * Get respect bow phrase\n */\n static getRespectPhrase(): KoreanText {\n return {\n korean: \"경례!\",\n english: \"Bow with respect!\",\n };\n }\n\n /**\n * Get training motivation phrases\n */\n static getMotivationPhrases(): readonly KoreanText[] {\n return [\n {\n korean: \"마음을 비우고 수련하라\",\n english: \"Empty your mind and train\",\n },\n { korean: \"강한 의지로 극복하라\", english: \"Overcome with strong will\" },\n {\n korean: \"겸손함이 진정한 힘이다\",\n english: \"Humility is true strength\",\n },\n {\n korean: \"끊임없는 노력이 완성을 만든다\",\n english: \"Continuous effort creates perfection\",\n },\n ];\n }\n}\n"],"mappings":";;;;AAKA,IAAa,gBAAb,MAA2B;;;;CAIzB,OAAgB,iBAAiB;EAC/B,OAAO;GAAE,QAAQ;GAAM,SAAS;GAAS;EACzC,SAAS;GAAE,QAAQ;GAAM,SAAS;GAAW;EAC7C,YAAY;GAAE,QAAQ;GAAM,SAAS;GAAc;EACnD,cAAc;GAAE,QAAQ;GAAM,SAAS;GAAgB;EACvD,SAAS;GAAE,QAAQ;GAAM,SAAS;GAAW;EAC7C,eAAe;GAAE,QAAQ;GAAK,SAAS;GAAiB;EACzD;;;;CAKD,OAAgB,qBAAwD;EACtE,MAAM;GACJ,QAAQ;GACR,SAAS;GACV;EACD,KAAK;GACH,QAAQ;GACR,SAAS;GACV;EACD,IAAI;GACF,QAAQ;GACR,SAAS;GACV;EACD,KAAK;GACH,QAAQ;GACR,SAAS;GACV;EACD,KAAK;GACH,QAAQ;GACR,SAAS;GACV;EACD,KAAK;GACH,QAAQ;GACR,SAAS;GACV;EACD,KAAK;GACH,QAAQ;GACR,SAAS;GACV;EACD,KAAK;GACH,QAAQ;GACR,SAAS;GACV;EACF;;;;CAKD,OAAgB,gBAAgB;EAC9B,YAAY;GACV,QAAQ;IAAE,QAAQ;IAAM,SAAS;IAAU;GAC3C,OAAO;IAAE,QAAQ;IAAM,SAAS;IAAS;GACzC,OAAO;IAAE,QAAQ;IAAO,SAAS;IAAS;GAC1C,MAAM;IAAE,QAAQ;IAAM,SAAS;IAAQ;GACvC,UAAU;IAAE,QAAQ;IAAM,SAAS;IAAY;GAChD;EACD,YAAY;GACV,MAAM;IAAE,QAAQ;IAAM,SAAS;IAAQ;GACvC,MAAM;IAAE,QAAQ;IAAK,SAAS;IAAQ;GACtC,OAAO;IAAE,QAAQ;IAAM,SAAS;IAAS;GACzC,KAAK;IAAE,QAAQ;IAAK,SAAS;IAAO;GACpC,KAAK;IAAE,QAAQ;IAAM,SAAS;IAAO;GACtC;EACD,UAAU;GACR,IAAI;IAAE,QAAQ;IAAK,SAAS;IAAa;GACzC,SAAS;IAAE,QAAQ;IAAM,SAAS;IAAW;GAC7C,SAAS;IAAE,QAAQ;IAAM,SAAS;IAAW;GAC7C,MAAM;IAAE,QAAQ;IAAM,SAAS;IAAQ;GACvC,QAAQ;IAAE,QAAQ;IAAM,SAAS;IAAU;GAC5C;EACF;;;;CAKD,OAAO,gBAAgB,QAAmC;EACxD,OAAO,KAAK,mBAAmB;;;;;CAMjC,OAAO,qBAAiC;EACtC,OAAO;GACL,QAAQ;GACR,SAAS;GACV;;;;;CAMH,OAAO,mBAA+B;EACpC,OAAO;GACL,QAAQ;GACR,SAAS;GACV;;;;;CAMH,OAAO,uBAA8C;EACnD,OAAO;GACL;IACE,QAAQ;IACR,SAAS;IACV;GACD;IAAE,QAAQ;IAAe,SAAS;IAA6B;GAC/D;IACE,QAAQ;IACR,SAAS;IACV;GACD;IACE,QAAQ;IACR,SAAS;IACV;GACF"}
1
+ {"version":3,"file":"KoreanCulture.js","names":[],"sources":["../../../src/systems/trigram/KoreanCulture.ts"],"sourcesContent":["import type { KoreanText, TrigramStance } from \"../../types\";\n\n/**\n * Korean cultural elements and philosophy for martial arts\n */\nexport class KoreanCulture {\n /**\n * Traditional Korean martial arts values\n */\n static readonly MARTIAL_VALUES = {\n honor: { korean: \"명예\", english: \"Honor\" },\n respect: { korean: \"존경\", english: \"Respect\" },\n discipline: { korean: \"절제\", english: \"Discipline\" },\n perseverance: { korean: \"인내\", english: \"Perseverance\" },\n loyalty: { korean: \"충성\", english: \"Loyalty\" },\n righteousness: { korean: \"의\", english: \"Righteousness\" },\n } as const;\n\n /**\n * Trigram philosophical meanings\n */\n static readonly TRIGRAM_PHILOSOPHY: Record<TrigramStance, KoreanText> = {\n geon: {\n korean: \"하늘의 창조력과 무한한 가능성\",\n english: \"Heaven's creative force and infinite possibilities\",\n },\n tae: {\n korean: \"호수의 평온함과 유연한 적응\",\n english: \"Lake's tranquility and flexible adaptation\",\n },\n li: {\n korean: \"불의 밝음과 정확한 판단\",\n english: \"Fire's brightness and precise judgment\",\n },\n jin: {\n korean: \"천둥의 역동성과 순간적 행동\",\n english: \"Thunder's dynamism and instantaneous action\",\n },\n son: {\n korean: \"바람의 지속성과 점진적 변화\",\n english: \"Wind's persistence and gradual change\",\n },\n gam: {\n korean: \"물의 깊이와 흐르는 지혜\",\n english: \"Water's depth and flowing wisdom\",\n },\n gan: {\n korean: \"산의 견고함과 정적인 힘\",\n english: \"Mountain's solidity and static strength\",\n },\n gon: {\n korean: \"땅의 포용과 양육하는 힘\",\n english: \"Earth's embrace and nurturing power\",\n },\n };\n\n /**\n * Korean martial arts terminology\n */\n static readonly MARTIAL_TERMS = {\n techniques: {\n strike: { korean: \"타격\", english: \"Strike\" },\n block: { korean: \"막기\", english: \"Block\" },\n throw: { korean: \"던지기\", english: \"Throw\" },\n lock: { korean: \"꺾기\", english: \"Lock\" },\n pressure: { korean: \"압박\", english: \"Pressure\" },\n },\n body_parts: {\n head: { korean: \"머리\", english: \"Head\" },\n neck: { korean: \"목\", english: \"Neck\" },\n torso: { korean: \"몸통\", english: \"Torso\" },\n arm: { korean: \"팔\", english: \"Arm\" },\n leg: { korean: \"다리\", english: \"Leg\" },\n },\n concepts: {\n ki: { korean: \"기\", english: \"Ki/Energy\" },\n balance: { korean: \"균형\", english: \"Balance\" },\n harmony: { korean: \"조화\", english: \"Harmony\" },\n flow: { korean: \"흐름\", english: \"Flow\" },\n center: { korean: \"중심\", english: \"Center\" },\n },\n } as const;\n\n /**\n * Get cultural wisdom for a stance\n */\n static getStanceWisdom(stance: TrigramStance): KoreanText {\n return this.TRIGRAM_PHILOSOPHY[stance];\n }\n\n /**\n * Get martial arts greeting\n */\n static getMartialGreeting(): KoreanText {\n return {\n korean: \"태권도!\",\n english: \"Taekwondo!\",\n };\n }\n\n /**\n * Get respect bow phrase\n */\n static getRespectPhrase(): KoreanText {\n return {\n korean: \"경례!\",\n english: \"Bow with respect!\",\n };\n }\n\n /**\n * Get training motivation phrases\n */\n static getMotivationPhrases(): readonly KoreanText[] {\n return [\n {\n korean: \"마음을 비우고 수련하라\",\n english: \"Empty your mind and train\",\n },\n { korean: \"강한 의지로 극복하라\", english: \"Overcome with strong will\" },\n {\n korean: \"겸손함이 진정한 힘이다\",\n english: \"Humility is true strength\",\n },\n {\n korean: \"끊임없는 노력이 완성을 만든다\",\n english: \"Continuous effort creates perfection\",\n },\n ];\n }\n}\n"],"mappings":";;;;AAKA,IAAa,gBAAb,MAA2B;;;;CAIzB,OAAgB,iBAAiB;EAC/B,OAAO;GAAE,QAAQ;GAAM,SAAS;EAAQ;EACxC,SAAS;GAAE,QAAQ;GAAM,SAAS;EAAU;EAC5C,YAAY;GAAE,QAAQ;GAAM,SAAS;EAAa;EAClD,cAAc;GAAE,QAAQ;GAAM,SAAS;EAAe;EACtD,SAAS;GAAE,QAAQ;GAAM,SAAS;EAAU;EAC5C,eAAe;GAAE,QAAQ;GAAK,SAAS;EAAgB;CACzD;;;;CAKA,OAAgB,qBAAwD;EACtE,MAAM;GACJ,QAAQ;GACR,SAAS;EACX;EACA,KAAK;GACH,QAAQ;GACR,SAAS;EACX;EACA,IAAI;GACF,QAAQ;GACR,SAAS;EACX;EACA,KAAK;GACH,QAAQ;GACR,SAAS;EACX;EACA,KAAK;GACH,QAAQ;GACR,SAAS;EACX;EACA,KAAK;GACH,QAAQ;GACR,SAAS;EACX;EACA,KAAK;GACH,QAAQ;GACR,SAAS;EACX;EACA,KAAK;GACH,QAAQ;GACR,SAAS;EACX;CACF;;;;CAKA,OAAgB,gBAAgB;EAC9B,YAAY;GACV,QAAQ;IAAE,QAAQ;IAAM,SAAS;GAAS;GAC1C,OAAO;IAAE,QAAQ;IAAM,SAAS;GAAQ;GACxC,OAAO;IAAE,QAAQ;IAAO,SAAS;GAAQ;GACzC,MAAM;IAAE,QAAQ;IAAM,SAAS;GAAO;GACtC,UAAU;IAAE,QAAQ;IAAM,SAAS;GAAW;EAChD;EACA,YAAY;GACV,MAAM;IAAE,QAAQ;IAAM,SAAS;GAAO;GACtC,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAO;GACrC,OAAO;IAAE,QAAQ;IAAM,SAAS;GAAQ;GACxC,KAAK;IAAE,QAAQ;IAAK,SAAS;GAAM;GACnC,KAAK;IAAE,QAAQ;IAAM,SAAS;GAAM;EACtC;EACA,UAAU;GACR,IAAI;IAAE,QAAQ;IAAK,SAAS;GAAY;GACxC,SAAS;IAAE,QAAQ;IAAM,SAAS;GAAU;GAC5C,SAAS;IAAE,QAAQ;IAAM,SAAS;GAAU;GAC5C,MAAM;IAAE,QAAQ;IAAM,SAAS;GAAO;GACtC,QAAQ;IAAE,QAAQ;IAAM,SAAS;GAAS;EAC5C;CACF;;;;CAKA,OAAO,gBAAgB,QAAmC;EACxD,OAAO,KAAK,mBAAmB;CACjC;;;;CAKA,OAAO,qBAAiC;EACtC,OAAO;GACL,QAAQ;GACR,SAAS;EACX;CACF;;;;CAKA,OAAO,mBAA+B;EACpC,OAAO;GACL,QAAQ;GACR,SAAS;EACX;CACF;;;;CAKA,OAAO,uBAA8C;EACnD,OAAO;GACL;IACE,QAAQ;IACR,SAAS;GACX;GACA;IAAE,QAAQ;IAAe,SAAS;GAA4B;GAC9D;IACE,QAAQ;IACR,SAAS;GACX;GACA;IACE,QAAQ;IACR,SAAS;GACX;EACF;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"KoreanTechniques.js","names":[],"sources":["../../../src/systems/trigram/KoreanTechniques.ts"],"sourcesContent":["import { PlayerArchetype } from \"../../types\";\nimport { TrigramStance } from \"../../types/common\";\nimport { PlayerState } from \"../player\";\nimport { PLAYER_ARCHETYPES_DATA } from \"../types\";\nimport { KoreanTechnique } from \"../vitalpoint\";\nimport {\n DARK_OPS_ARCHETYPE_BONUSES,\n DARK_OPS_TECHNIQUES,\n TRIGRAM_TECHNIQUES,\n} from \"./techniques/index\";\n\n/**\n * Korean martial arts techniques system\n */\nexport class KoreanTechniquesSystem {\n /**\n * Get available techniques for a trigram stance\n */\n static getAvailableTechniques(\n stance: TrigramStance\n ): readonly KoreanTechnique[] {\n return (TRIGRAM_TECHNIQUES[stance] as readonly KoreanTechnique[]) || [];\n }\n\n /**\n * Get Dark Ops techniques (암흑작전부대 기술)\n * Specialized techniques for 암살자 (Amsalja) archetype\n */\n static getDarkOpsTechniques(): readonly KoreanTechnique[] {\n return DARK_OPS_TECHNIQUES;\n }\n\n /**\n * Get all available techniques including Dark Ops\n */\n static getAllAvailableTechniques(\n stance: TrigramStance,\n archetype?: PlayerArchetype\n ): readonly KoreanTechnique[] {\n const stanceTechniques = this.getAvailableTechniques(stance);\n\n // Add Dark Ops techniques for 암살자 (Amsalja) archetype\n if (archetype === PlayerArchetype.AMSALJA) {\n const darkOpsTechniques = DARK_OPS_TECHNIQUES.filter(\n (tech) => tech.stance === stance\n );\n return [...stanceTechniques, ...darkOpsTechniques];\n }\n\n return stanceTechniques;\n }\n\n /**\n * Get primary technique for stance\n */\n static getPrimaryTechnique(stance: TrigramStance): KoreanTechnique | null {\n const techniques = this.getAvailableTechniques(stance);\n return techniques[0] ?? null;\n }\n\n /**\n * Check if player can execute technique\n */\n static canExecuteTechnique(\n player: PlayerState,\n technique: KoreanTechnique\n ): boolean {\n return (\n player.ki >= technique.kiCost &&\n player.stamina >= technique.staminaCost &&\n player.currentStance === technique.stance\n );\n }\n\n /**\n * Get technique effectiveness against target stance\n */\n static getTechniqueEffectiveness(\n attackerStance: TrigramStance,\n defenderStance: TrigramStance\n ): number {\n return (\n TECHNIQUE_EFFECTIVENESS_MATRIX[attackerStance]?.[defenderStance] ?? 1.0\n );\n }\n\n /**\n * Get all techniques\n */\n static getAllTechniques(): KoreanTechnique[] {\n // Fix: Convert readonly array to mutable array using spread operator\n const stanceTechniques = Object.values(TRIGRAM_TECHNIQUES).flat();\n const darkOpsTechniques = [...DARK_OPS_TECHNIQUES];\n return [...stanceTechniques, ...darkOpsTechniques] as KoreanTechnique[];\n }\n\n static getTechniquesByArchetype(\n archetype: PlayerArchetype\n ): readonly KoreanTechnique[] {\n const allTechniques = this.getAllTechniques();\n\n // Filter techniques based on archetype preferences\n const archetypeData = PLAYER_ARCHETYPES_DATA[archetype]; // Fix: Now properly imported\n const favoredStances = archetypeData.favoredStances || [];\n\n // Filter by favored stances (excludes Dark Ops techniques initially)\n const filteredTechniques = allTechniques.filter((technique) => {\n // Exclude Dark Ops from initial filtering\n if (technique.id.startsWith(\"darkops_\")) {\n return false;\n }\n return favoredStances.includes(technique.stance);\n });\n\n // Add Dark Ops techniques for 암살자 (Amsalja) only\n if (archetype === PlayerArchetype.AMSALJA) {\n return [...filteredTechniques, ...DARK_OPS_TECHNIQUES];\n }\n\n return filteredTechniques;\n }\n\n static getTechniqueById(id: string): KoreanTechnique | undefined {\n const allTechniques = this.getAllTechniques();\n return allTechniques.find((technique) => technique.id === id);\n }\n\n /**\n * Check if technique is a Dark Ops technique\n */\n static isDarkOpsTechnique(techniqueId: string): boolean {\n return DARK_OPS_TECHNIQUES.some((tech) => tech.id === techniqueId);\n }\n\n /**\n * Get Dark Ops archetype effectiveness multiplier\n * Uses DARK_OPS_ARCHETYPE_BONUSES from techniques.ts\n */\n static getDarkOpsArchetypeBonus(archetype: PlayerArchetype): number {\n return DARK_OPS_ARCHETYPE_BONUSES[archetype] || 1.0;\n }\n\n /**\n * Get night operations bonus (simulated)\n * In a full game, this would use actual game time\n */\n static getNightOperationsBonus(): number {\n // Simulate night time for now (in real game, use game clock)\n // Night: 00:00-06:00, 18:00-23:59 = 1.25x\n // Day: 06:00-18:00 = 1.0x\n const hour = new Date().getHours();\n if (hour >= 0 && hour < 6) return 1.25; // Night\n if (hour >= 18 && hour < 24) return 1.25; // Night\n if (hour >= 5 && hour < 7) return 1.15; // Twilight\n if (hour >= 17 && hour < 19) return 1.15; // Twilight\n return 1.0; // Day\n }\n}\n\n// Export functions for backwards compatibility\nexport function getTechniquesByStance(\n stance: TrigramStance\n): KoreanTechnique[] {\n // Fix: Convert readonly array to mutable array\n return [\n ...((TRIGRAM_TECHNIQUES[stance] as unknown as KoreanTechnique[]) || []),\n ];\n}\n\n// Export TRIGRAM_TECHNIQUES for tests\nexport { DARK_OPS_TECHNIQUES, TRIGRAM_TECHNIQUES } from \"./techniques/index\";\n\n// Export Dark Ops constants\nexport {\n DARK_OPS_ARCHETYPE_BONUSES,\n DARK_OPS_NIGHT_BONUS,\n DARK_OPS_SPECIAL_EFFECTS,\n DARK_OPS_UNITS,\n} from \"./techniques/index\";\n\n// Export technique effectiveness matrix\nexport const TECHNIQUE_EFFECTIVENESS_MATRIX: Record<\n TrigramStance,\n Partial<Record<TrigramStance, number>>\n> = {\n [TrigramStance.GEON]: {\n [TrigramStance.GON]: 1.2,\n [TrigramStance.SON]: 0.8,\n },\n [TrigramStance.TAE]: {\n [TrigramStance.JIN]: 1.2,\n [TrigramStance.GAN]: 0.8,\n },\n [TrigramStance.LI]: {\n [TrigramStance.GAM]: 1.2,\n [TrigramStance.TAE]: 0.8,\n },\n [TrigramStance.JIN]: {\n [TrigramStance.SON]: 1.2,\n [TrigramStance.GEON]: 0.8,\n },\n [TrigramStance.SON]: {\n [TrigramStance.GON]: 1.2,\n [TrigramStance.LI]: 0.8,\n },\n [TrigramStance.GAM]: {\n [TrigramStance.LI]: 1.2,\n [TrigramStance.JIN]: 0.8,\n },\n [TrigramStance.GAN]: {\n [TrigramStance.TAE]: 1.2,\n [TrigramStance.GAM]: 0.8,\n },\n [TrigramStance.GON]: {\n [TrigramStance.GEON]: 1.2,\n [TrigramStance.SON]: 0.8,\n },\n};\n"],"mappings":";;;;;;;;AAcA,IAAa,yBAAb,MAAoC;;;;CAIlC,OAAO,uBACL,QAC4B;EAC5B,OAAQ,mBAAmB,WAA0C,EAAE;;;;;;CAOzE,OAAO,uBAAmD;EACxD,OAAO;;;;;CAMT,OAAO,0BACL,QACA,WAC4B;EAC5B,MAAM,mBAAmB,KAAK,uBAAuB,OAAO;EAG5D,IAAI,cAAc,gBAAgB,SAAS;GACzC,MAAM,oBAAoB,oBAAoB,QAC3C,SAAS,KAAK,WAAW,OAC3B;GACD,OAAO,CAAC,GAAG,kBAAkB,GAAG,kBAAkB;;EAGpD,OAAO;;;;;CAMT,OAAO,oBAAoB,QAA+C;EAExE,OADmB,KAAK,uBAAuB,OACxC,CAAW,MAAM;;;;;CAM1B,OAAO,oBACL,QACA,WACS;EACT,OACE,OAAO,MAAM,UAAU,UACvB,OAAO,WAAW,UAAU,eAC5B,OAAO,kBAAkB,UAAU;;;;;CAOvC,OAAO,0BACL,gBACA,gBACQ;EACR,OACE,+BAA+B,kBAAkB,mBAAmB;;;;;CAOxE,OAAO,mBAAsC;EAE3C,MAAM,mBAAmB,OAAO,OAAO,mBAAmB,CAAC,MAAM;EACjE,MAAM,oBAAoB,CAAC,GAAG,oBAAoB;EAClD,OAAO,CAAC,GAAG,kBAAkB,GAAG,kBAAkB;;CAGpD,OAAO,yBACL,WAC4B;EAC5B,MAAM,gBAAgB,KAAK,kBAAkB;EAI7C,MAAM,iBADgB,uBAAuB,WACR,kBAAkB,EAAE;EAGzD,MAAM,qBAAqB,cAAc,QAAQ,cAAc;GAE7D,IAAI,UAAU,GAAG,WAAW,WAAW,EACrC,OAAO;GAET,OAAO,eAAe,SAAS,UAAU,OAAO;IAChD;EAGF,IAAI,cAAc,gBAAgB,SAChC,OAAO,CAAC,GAAG,oBAAoB,GAAG,oBAAoB;EAGxD,OAAO;;CAGT,OAAO,iBAAiB,IAAyC;EAE/D,OADsB,KAAK,kBACpB,CAAc,MAAM,cAAc,UAAU,OAAO,GAAG;;;;;CAM/D,OAAO,mBAAmB,aAA8B;EACtD,OAAO,oBAAoB,MAAM,SAAS,KAAK,OAAO,YAAY;;;;;;CAOpE,OAAO,yBAAyB,WAAoC;EAClE,OAAO,2BAA2B,cAAc;;;;;;CAOlD,OAAO,0BAAkC;EAIvC,MAAM,wBAAO,IAAI,MAAM,EAAC,UAAU;EAClC,IAAI,QAAQ,KAAK,OAAO,GAAG,OAAO;EAClC,IAAI,QAAQ,MAAM,OAAO,IAAI,OAAO;EACpC,IAAI,QAAQ,KAAK,OAAO,GAAG,OAAO;EAClC,IAAI,QAAQ,MAAM,OAAO,IAAI,OAAO;EACpC,OAAO;;;AAKX,SAAgB,sBACd,QACmB;CAEnB,OAAO,CACL,GAAK,mBAAmB,WAA4C,EAAE,CACvE;;AAeH,IAAa,iCAGT;EACD,cAAc,OAAO;GACnB,cAAc,MAAM;GACpB,cAAc,MAAM;EACtB;EACA,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,MAAM;EACtB;EACA,cAAc,KAAK;GACjB,cAAc,MAAM;GACpB,cAAc,MAAM;EACtB;EACA,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,OAAO;EACvB;EACA,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,KAAK;EACrB;EACA,cAAc,MAAM;GAClB,cAAc,KAAK;GACnB,cAAc,MAAM;EACtB;EACA,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,MAAM;EACtB;EACA,cAAc,MAAM;GAClB,cAAc,OAAO;GACrB,cAAc,MAAM;EACtB;CACF"}
1
+ {"version":3,"file":"KoreanTechniques.js","names":[],"sources":["../../../src/systems/trigram/KoreanTechniques.ts"],"sourcesContent":["import { PlayerArchetype } from \"../../types\";\nimport { TrigramStance } from \"../../types/common\";\nimport { PlayerState } from \"../player\";\nimport { PLAYER_ARCHETYPES_DATA } from \"../types\";\nimport { KoreanTechnique } from \"../vitalpoint\";\nimport {\n DARK_OPS_ARCHETYPE_BONUSES,\n DARK_OPS_TECHNIQUES,\n TRIGRAM_TECHNIQUES,\n} from \"./techniques/index\";\n\n/**\n * Korean martial arts techniques system\n */\nexport class KoreanTechniquesSystem {\n /**\n * Get available techniques for a trigram stance\n */\n static getAvailableTechniques(\n stance: TrigramStance\n ): readonly KoreanTechnique[] {\n return (TRIGRAM_TECHNIQUES[stance] as readonly KoreanTechnique[]) || [];\n }\n\n /**\n * Get Dark Ops techniques (암흑작전부대 기술)\n * Specialized techniques for 암살자 (Amsalja) archetype\n */\n static getDarkOpsTechniques(): readonly KoreanTechnique[] {\n return DARK_OPS_TECHNIQUES;\n }\n\n /**\n * Get all available techniques including Dark Ops\n */\n static getAllAvailableTechniques(\n stance: TrigramStance,\n archetype?: PlayerArchetype\n ): readonly KoreanTechnique[] {\n const stanceTechniques = this.getAvailableTechniques(stance);\n\n // Add Dark Ops techniques for 암살자 (Amsalja) archetype\n if (archetype === PlayerArchetype.AMSALJA) {\n const darkOpsTechniques = DARK_OPS_TECHNIQUES.filter(\n (tech) => tech.stance === stance\n );\n return [...stanceTechniques, ...darkOpsTechniques];\n }\n\n return stanceTechniques;\n }\n\n /**\n * Get primary technique for stance\n */\n static getPrimaryTechnique(stance: TrigramStance): KoreanTechnique | null {\n const techniques = this.getAvailableTechniques(stance);\n return techniques[0] ?? null;\n }\n\n /**\n * Check if player can execute technique\n */\n static canExecuteTechnique(\n player: PlayerState,\n technique: KoreanTechnique\n ): boolean {\n return (\n player.ki >= technique.kiCost &&\n player.stamina >= technique.staminaCost &&\n player.currentStance === technique.stance\n );\n }\n\n /**\n * Get technique effectiveness against target stance\n */\n static getTechniqueEffectiveness(\n attackerStance: TrigramStance,\n defenderStance: TrigramStance\n ): number {\n return (\n TECHNIQUE_EFFECTIVENESS_MATRIX[attackerStance]?.[defenderStance] ?? 1.0\n );\n }\n\n /**\n * Get all techniques\n */\n static getAllTechniques(): KoreanTechnique[] {\n // Fix: Convert readonly array to mutable array using spread operator\n const stanceTechniques = Object.values(TRIGRAM_TECHNIQUES).flat();\n const darkOpsTechniques = [...DARK_OPS_TECHNIQUES];\n return [...stanceTechniques, ...darkOpsTechniques] as KoreanTechnique[];\n }\n\n static getTechniquesByArchetype(\n archetype: PlayerArchetype\n ): readonly KoreanTechnique[] {\n const allTechniques = this.getAllTechniques();\n\n // Filter techniques based on archetype preferences\n const archetypeData = PLAYER_ARCHETYPES_DATA[archetype]; // Fix: Now properly imported\n const favoredStances = archetypeData.favoredStances || [];\n\n // Filter by favored stances (excludes Dark Ops techniques initially)\n const filteredTechniques = allTechniques.filter((technique) => {\n // Exclude Dark Ops from initial filtering\n if (technique.id.startsWith(\"darkops_\")) {\n return false;\n }\n return favoredStances.includes(technique.stance);\n });\n\n // Add Dark Ops techniques for 암살자 (Amsalja) only\n if (archetype === PlayerArchetype.AMSALJA) {\n return [...filteredTechniques, ...DARK_OPS_TECHNIQUES];\n }\n\n return filteredTechniques;\n }\n\n static getTechniqueById(id: string): KoreanTechnique | undefined {\n const allTechniques = this.getAllTechniques();\n return allTechniques.find((technique) => technique.id === id);\n }\n\n /**\n * Check if technique is a Dark Ops technique\n */\n static isDarkOpsTechnique(techniqueId: string): boolean {\n return DARK_OPS_TECHNIQUES.some((tech) => tech.id === techniqueId);\n }\n\n /**\n * Get Dark Ops archetype effectiveness multiplier\n * Uses DARK_OPS_ARCHETYPE_BONUSES from techniques.ts\n */\n static getDarkOpsArchetypeBonus(archetype: PlayerArchetype): number {\n return DARK_OPS_ARCHETYPE_BONUSES[archetype] || 1.0;\n }\n\n /**\n * Get night operations bonus (simulated)\n * In a full game, this would use actual game time\n */\n static getNightOperationsBonus(): number {\n // Simulate night time for now (in real game, use game clock)\n // Night: 00:00-06:00, 18:00-23:59 = 1.25x\n // Day: 06:00-18:00 = 1.0x\n const hour = new Date().getHours();\n if (hour >= 0 && hour < 6) return 1.25; // Night\n if (hour >= 18 && hour < 24) return 1.25; // Night\n if (hour >= 5 && hour < 7) return 1.15; // Twilight\n if (hour >= 17 && hour < 19) return 1.15; // Twilight\n return 1.0; // Day\n }\n}\n\n// Export functions for backwards compatibility\nexport function getTechniquesByStance(\n stance: TrigramStance\n): KoreanTechnique[] {\n // Fix: Convert readonly array to mutable array\n return [\n ...((TRIGRAM_TECHNIQUES[stance] as unknown as KoreanTechnique[]) || []),\n ];\n}\n\n// Export TRIGRAM_TECHNIQUES for tests\nexport { DARK_OPS_TECHNIQUES, TRIGRAM_TECHNIQUES } from \"./techniques/index\";\n\n// Export Dark Ops constants\nexport {\n DARK_OPS_ARCHETYPE_BONUSES,\n DARK_OPS_NIGHT_BONUS,\n DARK_OPS_SPECIAL_EFFECTS,\n DARK_OPS_UNITS,\n} from \"./techniques/index\";\n\n// Export technique effectiveness matrix\nexport const TECHNIQUE_EFFECTIVENESS_MATRIX: Record<\n TrigramStance,\n Partial<Record<TrigramStance, number>>\n> = {\n [TrigramStance.GEON]: {\n [TrigramStance.GON]: 1.2,\n [TrigramStance.SON]: 0.8,\n },\n [TrigramStance.TAE]: {\n [TrigramStance.JIN]: 1.2,\n [TrigramStance.GAN]: 0.8,\n },\n [TrigramStance.LI]: {\n [TrigramStance.GAM]: 1.2,\n [TrigramStance.TAE]: 0.8,\n },\n [TrigramStance.JIN]: {\n [TrigramStance.SON]: 1.2,\n [TrigramStance.GEON]: 0.8,\n },\n [TrigramStance.SON]: {\n [TrigramStance.GON]: 1.2,\n [TrigramStance.LI]: 0.8,\n },\n [TrigramStance.GAM]: {\n [TrigramStance.LI]: 1.2,\n [TrigramStance.JIN]: 0.8,\n },\n [TrigramStance.GAN]: {\n [TrigramStance.TAE]: 1.2,\n [TrigramStance.GAM]: 0.8,\n },\n [TrigramStance.GON]: {\n [TrigramStance.GEON]: 1.2,\n [TrigramStance.SON]: 0.8,\n },\n};\n"],"mappings":";;;;;;;;AAcA,IAAa,yBAAb,MAAoC;;;;CAIlC,OAAO,uBACL,QAC4B;EAC5B,OAAQ,mBAAmB,WAA0C,CAAC;CACxE;;;;;CAMA,OAAO,uBAAmD;EACxD,OAAO;CACT;;;;CAKA,OAAO,0BACL,QACA,WAC4B;EAC5B,MAAM,mBAAmB,KAAK,uBAAuB,MAAM;EAG3D,IAAI,cAAc,gBAAgB,SAAS;GACzC,MAAM,oBAAoB,oBAAoB,QAC3C,SAAS,KAAK,WAAW,MAC5B;GACA,OAAO,CAAC,GAAG,kBAAkB,GAAG,iBAAiB;EACnD;EAEA,OAAO;CACT;;;;CAKA,OAAO,oBAAoB,QAA+C;EAExE,OADmB,KAAK,uBAAuB,MACxC,EAAW,MAAM;CAC1B;;;;CAKA,OAAO,oBACL,QACA,WACS;EACT,OACE,OAAO,MAAM,UAAU,UACvB,OAAO,WAAW,UAAU,eAC5B,OAAO,kBAAkB,UAAU;CAEvC;;;;CAKA,OAAO,0BACL,gBACA,gBACQ;EACR,OACE,+BAA+B,kBAAkB,mBAAmB;CAExE;;;;CAKA,OAAO,mBAAsC;EAE3C,MAAM,mBAAmB,OAAO,OAAO,kBAAkB,EAAE,KAAK;EAChE,MAAM,oBAAoB,CAAC,GAAG,mBAAmB;EACjD,OAAO,CAAC,GAAG,kBAAkB,GAAG,iBAAiB;CACnD;CAEA,OAAO,yBACL,WAC4B;EAC5B,MAAM,gBAAgB,KAAK,iBAAiB;EAI5C,MAAM,iBADgB,uBAAuB,WACR,kBAAkB,CAAC;EAGxD,MAAM,qBAAqB,cAAc,QAAQ,cAAc;GAE7D,IAAI,UAAU,GAAG,WAAW,UAAU,GACpC,OAAO;GAET,OAAO,eAAe,SAAS,UAAU,MAAM;EACjD,CAAC;EAGD,IAAI,cAAc,gBAAgB,SAChC,OAAO,CAAC,GAAG,oBAAoB,GAAG,mBAAmB;EAGvD,OAAO;CACT;CAEA,OAAO,iBAAiB,IAAyC;EAE/D,OADsB,KAAK,iBACpB,EAAc,MAAM,cAAc,UAAU,OAAO,EAAE;CAC9D;;;;CAKA,OAAO,mBAAmB,aAA8B;EACtD,OAAO,oBAAoB,MAAM,SAAS,KAAK,OAAO,WAAW;CACnE;;;;;CAMA,OAAO,yBAAyB,WAAoC;EAClE,OAAO,2BAA2B,cAAc;CAClD;;;;;CAMA,OAAO,0BAAkC;EAIvC,MAAM,wBAAO,IAAI,KAAK,GAAE,SAAS;EACjC,IAAI,QAAQ,KAAK,OAAO,GAAG,OAAO;EAClC,IAAI,QAAQ,MAAM,OAAO,IAAI,OAAO;EACpC,IAAI,QAAQ,KAAK,OAAO,GAAG,OAAO;EAClC,IAAI,QAAQ,MAAM,OAAO,IAAI,OAAO;EACpC,OAAO;CACT;AACF;AAGA,SAAgB,sBACd,QACmB;CAEnB,OAAO,CACL,GAAK,mBAAmB,WAA4C,CAAC,CACvE;AACF;AAcA,IAAa,iCAGT;EACD,cAAc,OAAO;GACnB,cAAc,MAAM;GACpB,cAAc,MAAM;CACvB;EACC,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,MAAM;CACvB;EACC,cAAc,KAAK;GACjB,cAAc,MAAM;GACpB,cAAc,MAAM;CACvB;EACC,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,OAAO;CACxB;EACC,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,KAAK;CACtB;EACC,cAAc,MAAM;GAClB,cAAc,KAAK;GACnB,cAAc,MAAM;CACvB;EACC,cAAc,MAAM;GAClB,cAAc,MAAM;GACpB,cAAc,MAAM;CACvB;EACC,cAAc,MAAM;GAClB,cAAc,OAAO;GACrB,cAAc,MAAM;CACvB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"StanceManager.js","names":[],"sources":["../../../src/systems/trigram/StanceManager.ts"],"sourcesContent":["import { TrigramStance } from \"../../types/common\";\nimport { PlayerState } from \"../player\";\nimport { PLAYER_ARCHETYPES_DATA } from \"../types\";\nimport { TrigramCalculator } from \"./TrigramCalculator\";\nimport { StanceLaterality, TrigramTransitionCost } from \"./types\";\n\nexport interface StanceChangeResult {\n readonly success: boolean;\n readonly updatedPlayer: PlayerState;\n readonly cost: TrigramTransitionCost;\n readonly laterality?: StanceLaterality;\n readonly message?: string;\n}\n\n/**\n * Manager for trigram stance changes and laterality state\n * \n * **Korean**: 자세 관리자\n * \n * Manages both trigram stance selection (8 stances) and laterality (left/right).\n * Supports authentic Korean martial arts stance configurations with:\n * - 8 trigram stances (☰–☷)\n * - 2 laterality options (left/right foot forward)\n * - 16 total stance configurations\n * \n * Laterality transitions take 400ms (24 frames @ 60fps) and cost 2 stamina.\n */\nexport class StanceManager {\n private readonly minTransitionInterval = 500;\n private readonly lateralityTransitionTime = 400; // 400ms for stance side switch\n private currentStance?: TrigramStance;\n private currentLaterality: StanceLaterality = \"right\"; // Default: right foot forward\n\n constructor() {\n // No initialization needed\n }\n\n /**\n * Get the current stance\n * \n * @returns Current trigram stance or undefined if not set\n * @korean 현재자세가져오기\n */\n public getCurrent(): TrigramStance | undefined {\n return this.currentStance;\n }\n\n /**\n * Get the current stance laterality (left or right foot forward)\n * \n * **Korean**: 현재 측면성\n * \n * @returns Current laterality (\"left\" or \"right\")\n * @korean 현재측면성가져오기\n */\n public getCurrentLaterality(): StanceLaterality {\n return this.currentLaterality;\n }\n\n /**\n * Switch stance side (left ↔ right) without changing trigram stance\n * \n * **Korean**: 자세 측면 전환\n * \n * Mirrors the current guard position from left to right or vice versa.\n * Takes 400ms (24 frames @ 60fps) and costs 2 stamina.\n * \n * Korean terminology:\n * - 왼발서기 (Oenbal Seogi): Left foot forward\n * - 오른발서기 (Oreun Bal Seogi): Right foot forward\n * \n * @param player - Current player state\n * @param currentLaterality - Current laterality to toggle from\n * @returns Result with updated laterality\n * @korean 측면전환\n */\n public switchStanceSide(player: PlayerState, currentLaterality: StanceLaterality): StanceChangeResult {\n const lateralityCost: TrigramTransitionCost = {\n ki: 0,\n stamina: 2,\n timeMilliseconds: this.lateralityTransitionTime,\n };\n\n // Check if player has enough stamina\n if (player.stamina < lateralityCost.stamina) {\n return {\n success: false,\n updatedPlayer: player,\n cost: lateralityCost,\n laterality: currentLaterality,\n message: \"Insufficient stamina to switch stance side\",\n };\n }\n\n // Check cooldown\n const timeSinceLastChange = Date.now() - (player.lastStanceChangeTime || 0);\n if (timeSinceLastChange < this.minTransitionInterval) {\n return {\n success: false,\n updatedPlayer: player,\n cost: lateralityCost,\n laterality: currentLaterality,\n message: \"Stance side switch on cooldown\",\n };\n }\n\n // Switch laterality (toggle from current)\n const newLaterality: StanceLaterality = \n currentLaterality === \"left\" ? \"right\" : \"left\";\n this.currentLaterality = newLaterality;\n\n // Apply stamina cost and update timestamp\n const updatedPlayer: PlayerState = {\n ...player,\n stamina: Math.max(0, player.stamina - lateralityCost.stamina),\n lastStanceChangeTime: Date.now(),\n };\n\n return {\n success: true,\n updatedPlayer,\n cost: lateralityCost,\n laterality: newLaterality,\n };\n }\n\n /**\n * Attempt to change stance\n * \n * @param player - Current player state\n * @param newStance - Target trigram stance\n * @returns Result with success status and updated player\n * @korean 자세변경\n */\n changeStance(\n player: PlayerState,\n newStance: TrigramStance\n ): StanceChangeResult {\n const cost = this.getStanceTransitionCost(\n player.currentStance,\n newStance,\n player\n );\n\n // Check if transition is possible\n if (!this.canChangeStance(player, newStance)) {\n return {\n success: false,\n updatedPlayer: player,\n cost,\n laterality: this.currentLaterality,\n message:\n \"Cannot change stance - insufficient resources or cooldown active\",\n };\n }\n\n // Same stance - no cost, but update laterality info\n if (player.currentStance === newStance) {\n this.currentStance = newStance;\n return {\n success: true,\n updatedPlayer: {\n ...player,\n lastStanceChangeTime: Date.now(),\n },\n cost: { ki: 0, stamina: 0, timeMilliseconds: 0 },\n laterality: this.currentLaterality,\n };\n }\n\n // Apply stance change\n const updatedPlayer: PlayerState = {\n ...player,\n currentStance: newStance,\n ki: Math.max(0, player.ki - cost.ki),\n stamina: Math.max(0, player.stamina - cost.stamina),\n lastStanceChangeTime: Date.now(),\n };\n this.currentStance = newStance;\n\n return {\n success: true,\n updatedPlayer,\n cost,\n laterality: this.currentLaterality,\n };\n }\n\n /**\n * Check if player can change to the specified stance\n */\n canChangeStance(player: PlayerState, newStance: TrigramStance): boolean {\n const cost = this.getStanceTransitionCost(\n player.currentStance,\n newStance,\n player\n );\n\n // Check resources\n if (player.ki < cost.ki || player.stamina < cost.stamina) {\n return false;\n }\n\n // Check cooldown\n const timeSinceLastChange = Date.now() - (player.lastStanceChangeTime || 0);\n if (timeSinceLastChange < this.minTransitionInterval) {\n return false;\n }\n\n // Check if player is stunned or incapacitated\n if (player.isStunned || player.consciousness < 50) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Calculate the cost of transitioning between stances\n */\n getStanceTransitionCost(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n player: PlayerState\n ): TrigramTransitionCost {\n if (fromStance === toStance) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 };\n }\n\n const baseCost = { ki: 10, stamina: 15, timeMilliseconds: 500 };\n const difficulty = TrigramCalculator.calculateTransitionDifficulty(\n fromStance,\n toStance\n );\n const difficultyMultiplier = 1 + difficulty;\n\n // Apply archetype modifiers\n const archetypeData = PLAYER_ARCHETYPES_DATA[player.archetype];\n const favoredStances = archetypeData.favoredStances || [];\n const archetypeModifier = favoredStances.includes(toStance) ? 0.8 : 1.0;\n\n return {\n ki: Math.floor(baseCost.ki * difficultyMultiplier * archetypeModifier),\n stamina: Math.floor(\n baseCost.stamina * difficultyMultiplier * archetypeModifier\n ),\n timeMilliseconds: Math.floor(\n baseCost.timeMilliseconds * difficultyMultiplier\n ),\n };\n }\n\n /**\n * Get optimal stance recommendation\n */\n getOptimalStance(player: PlayerState, opponent?: PlayerState): TrigramStance {\n if (opponent) {\n // Get counter stance against opponent\n return TrigramCalculator.getCounterStance(opponent.currentStance);\n }\n\n // Default to archetype preferred stance\n const archetypeData = PLAYER_ARCHETYPES_DATA[player.archetype];\n const favoredStances = archetypeData.favoredStances || [];\n\n return favoredStances.length > 0 ? favoredStances[0] : TrigramStance.GEON; // Fix: Use enum value\n }\n\n /**\n * Get all valid transitions from current stance\n */\n getValidTransitions(player: PlayerState): TrigramStance[] {\n return Object.values(TrigramStance).filter(\n (\n stance // Fix: Use enum values\n ) => this.canChangeStance(player, stance)\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StanceManager.js","names":[],"sources":["../../../src/systems/trigram/StanceManager.ts"],"sourcesContent":["import { TrigramStance } from \"../../types/common\";\nimport { PlayerState } from \"../player\";\nimport { PLAYER_ARCHETYPES_DATA } from \"../types\";\nimport { TrigramCalculator } from \"./TrigramCalculator\";\nimport { StanceLaterality, TrigramTransitionCost } from \"./types\";\n\nexport interface StanceChangeResult {\n readonly success: boolean;\n readonly updatedPlayer: PlayerState;\n readonly cost: TrigramTransitionCost;\n readonly laterality?: StanceLaterality;\n readonly message?: string;\n}\n\n/**\n * Manager for trigram stance changes and laterality state\n * \n * **Korean**: 자세 관리자\n * \n * Manages both trigram stance selection (8 stances) and laterality (left/right).\n * Supports authentic Korean martial arts stance configurations with:\n * - 8 trigram stances (☰–☷)\n * - 2 laterality options (left/right foot forward)\n * - 16 total stance configurations\n * \n * Laterality transitions take 400ms (24 frames @ 60fps) and cost 2 stamina.\n */\nexport class StanceManager {\n private readonly minTransitionInterval = 500;\n private readonly lateralityTransitionTime = 400; // 400ms for stance side switch\n private currentStance?: TrigramStance;\n private currentLaterality: StanceLaterality = \"right\"; // Default: right foot forward\n\n constructor() {\n // No initialization needed\n }\n\n /**\n * Get the current stance\n * \n * @returns Current trigram stance or undefined if not set\n * @korean 현재자세가져오기\n */\n public getCurrent(): TrigramStance | undefined {\n return this.currentStance;\n }\n\n /**\n * Get the current stance laterality (left or right foot forward)\n * \n * **Korean**: 현재 측면성\n * \n * @returns Current laterality (\"left\" or \"right\")\n * @korean 현재측면성가져오기\n */\n public getCurrentLaterality(): StanceLaterality {\n return this.currentLaterality;\n }\n\n /**\n * Switch stance side (left ↔ right) without changing trigram stance\n * \n * **Korean**: 자세 측면 전환\n * \n * Mirrors the current guard position from left to right or vice versa.\n * Takes 400ms (24 frames @ 60fps) and costs 2 stamina.\n * \n * Korean terminology:\n * - 왼발서기 (Oenbal Seogi): Left foot forward\n * - 오른발서기 (Oreun Bal Seogi): Right foot forward\n * \n * @param player - Current player state\n * @param currentLaterality - Current laterality to toggle from\n * @returns Result with updated laterality\n * @korean 측면전환\n */\n public switchStanceSide(player: PlayerState, currentLaterality: StanceLaterality): StanceChangeResult {\n const lateralityCost: TrigramTransitionCost = {\n ki: 0,\n stamina: 2,\n timeMilliseconds: this.lateralityTransitionTime,\n };\n\n // Check if player has enough stamina\n if (player.stamina < lateralityCost.stamina) {\n return {\n success: false,\n updatedPlayer: player,\n cost: lateralityCost,\n laterality: currentLaterality,\n message: \"Insufficient stamina to switch stance side\",\n };\n }\n\n // Check cooldown\n const timeSinceLastChange = Date.now() - (player.lastStanceChangeTime || 0);\n if (timeSinceLastChange < this.minTransitionInterval) {\n return {\n success: false,\n updatedPlayer: player,\n cost: lateralityCost,\n laterality: currentLaterality,\n message: \"Stance side switch on cooldown\",\n };\n }\n\n // Switch laterality (toggle from current)\n const newLaterality: StanceLaterality = \n currentLaterality === \"left\" ? \"right\" : \"left\";\n this.currentLaterality = newLaterality;\n\n // Apply stamina cost and update timestamp\n const updatedPlayer: PlayerState = {\n ...player,\n stamina: Math.max(0, player.stamina - lateralityCost.stamina),\n lastStanceChangeTime: Date.now(),\n };\n\n return {\n success: true,\n updatedPlayer,\n cost: lateralityCost,\n laterality: newLaterality,\n };\n }\n\n /**\n * Attempt to change stance\n * \n * @param player - Current player state\n * @param newStance - Target trigram stance\n * @returns Result with success status and updated player\n * @korean 자세변경\n */\n changeStance(\n player: PlayerState,\n newStance: TrigramStance\n ): StanceChangeResult {\n const cost = this.getStanceTransitionCost(\n player.currentStance,\n newStance,\n player\n );\n\n // Check if transition is possible\n if (!this.canChangeStance(player, newStance)) {\n return {\n success: false,\n updatedPlayer: player,\n cost,\n laterality: this.currentLaterality,\n message:\n \"Cannot change stance - insufficient resources or cooldown active\",\n };\n }\n\n // Same stance - no cost, but update laterality info\n if (player.currentStance === newStance) {\n this.currentStance = newStance;\n return {\n success: true,\n updatedPlayer: {\n ...player,\n lastStanceChangeTime: Date.now(),\n },\n cost: { ki: 0, stamina: 0, timeMilliseconds: 0 },\n laterality: this.currentLaterality,\n };\n }\n\n // Apply stance change\n const updatedPlayer: PlayerState = {\n ...player,\n currentStance: newStance,\n ki: Math.max(0, player.ki - cost.ki),\n stamina: Math.max(0, player.stamina - cost.stamina),\n lastStanceChangeTime: Date.now(),\n };\n this.currentStance = newStance;\n\n return {\n success: true,\n updatedPlayer,\n cost,\n laterality: this.currentLaterality,\n };\n }\n\n /**\n * Check if player can change to the specified stance\n */\n canChangeStance(player: PlayerState, newStance: TrigramStance): boolean {\n const cost = this.getStanceTransitionCost(\n player.currentStance,\n newStance,\n player\n );\n\n // Check resources\n if (player.ki < cost.ki || player.stamina < cost.stamina) {\n return false;\n }\n\n // Check cooldown\n const timeSinceLastChange = Date.now() - (player.lastStanceChangeTime || 0);\n if (timeSinceLastChange < this.minTransitionInterval) {\n return false;\n }\n\n // Check if player is stunned or incapacitated\n if (player.isStunned || player.consciousness < 50) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Calculate the cost of transitioning between stances\n */\n getStanceTransitionCost(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n player: PlayerState\n ): TrigramTransitionCost {\n if (fromStance === toStance) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 };\n }\n\n const baseCost = { ki: 10, stamina: 15, timeMilliseconds: 500 };\n const difficulty = TrigramCalculator.calculateTransitionDifficulty(\n fromStance,\n toStance\n );\n const difficultyMultiplier = 1 + difficulty;\n\n // Apply archetype modifiers\n const archetypeData = PLAYER_ARCHETYPES_DATA[player.archetype];\n const favoredStances = archetypeData.favoredStances || [];\n const archetypeModifier = favoredStances.includes(toStance) ? 0.8 : 1.0;\n\n return {\n ki: Math.floor(baseCost.ki * difficultyMultiplier * archetypeModifier),\n stamina: Math.floor(\n baseCost.stamina * difficultyMultiplier * archetypeModifier\n ),\n timeMilliseconds: Math.floor(\n baseCost.timeMilliseconds * difficultyMultiplier\n ),\n };\n }\n\n /**\n * Get optimal stance recommendation\n */\n getOptimalStance(player: PlayerState, opponent?: PlayerState): TrigramStance {\n if (opponent) {\n // Get counter stance against opponent\n return TrigramCalculator.getCounterStance(opponent.currentStance);\n }\n\n // Default to archetype preferred stance\n const archetypeData = PLAYER_ARCHETYPES_DATA[player.archetype];\n const favoredStances = archetypeData.favoredStances || [];\n\n return favoredStances.length > 0 ? favoredStances[0] : TrigramStance.GEON; // Fix: Use enum value\n }\n\n /**\n * Get all valid transitions from current stance\n */\n getValidTransitions(player: PlayerState): TrigramStance[] {\n return Object.values(TrigramStance).filter(\n (\n stance // Fix: Use enum values\n ) => this.canChangeStance(player, stance)\n );\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TransitionCalculator.js","names":[],"sources":["../../../src/systems/trigram/TransitionCalculator.ts"],"sourcesContent":["import { TrigramStance } from \"../../types\";\nimport { TrigramStance as TrigramStanceEnum } from \"../../types/common\";\nimport {\n calculateStanceDistance,\n determineTransitionType,\n getStanceTransition,\n type StanceTransitionType,\n} from \"../animation/core/AnimationTransitions\";\nimport { PlayerState } from \"../player\";\nimport { TrigramTransitionCost, TrigramTransitionRule } from \"./types\";\n\n/**\n * Calculator for trigram stance transition costs and validation\n *\n * **Korean**: 자세 전환 계산기\n *\n * Calculates costs, paths, and validation for transitions between trigram stances.\n * Integrates with the animation system's stance transition matrix.\n *\n * @category Trigram System\n * @korean 자세전환계산기\n */\nexport class TransitionCalculator {\n private calculateBaseCost(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramTransitionCost {\n if (from === to) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 };\n }\n\n return { ki: 10, stamina: 15, timeMilliseconds: 500 };\n }\n\n generateTransitionRule(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramTransitionRule {\n const cost = this.calculateBaseCost(from, to);\n\n return {\n from,\n to,\n cost,\n effectiveness: 1.0, // Fix: Add missing effectiveness property\n conditions: [],\n description: {\n korean: `${from}에서 ${to}로 전환`,\n english: `Transition from ${from} to ${to}`,\n },\n };\n }\n\n /**\n * Calculate the cost of transitioning between stances\n *\n * **Korean**: 자세 전환 비용 계산\n *\n * Calculates ki, stamina, and time costs based on stance distance.\n * Uses animation system's transition configurations for accurate timing.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition cost breakdown\n *\n * @korean 자세전환비용계산\n */\n static calculateCost(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramTransitionCost {\n if (from === to) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 };\n }\n\n // Get transition from animation system for accurate timing\n const transition = getStanceTransition(from, to);\n const timeMs = transition?.duration ?? 600;\n\n const baseCost = { ki: 15, stamina: 10, timeMilliseconds: timeMs };\n const modifier = this.getAdjacencyModifier(from, to);\n\n return {\n ki: Math.floor(baseCost.ki * modifier),\n stamina: Math.floor(baseCost.stamina * modifier),\n timeMilliseconds: timeMs, // Use actual transition duration\n };\n }\n\n /**\n * Check if a transition is valid for a player\n */\n static canTransition(\n from: TrigramStance,\n to: TrigramStance,\n player: PlayerState\n ): boolean {\n const cost = this.calculateCost(from, to);\n return player.ki >= cost.ki && player.stamina >= cost.stamina;\n }\n\n /**\n * Check if transition is valid based on player state\n */\n static isTransitionValid(\n from: TrigramStance,\n to: TrigramStance,\n player: PlayerState\n ): boolean {\n return this.canTransition(from, to, player);\n }\n\n /**\n * Get Ki cost for transition\n */\n static getKiCost(\n from: TrigramStance,\n to: TrigramStance,\n _player: PlayerState\n ): number {\n return this.calculateCost(from, to).ki;\n }\n\n /**\n * Get Stamina cost for transition\n */\n static getStaminaCost(\n from: TrigramStance,\n to: TrigramStance,\n _player: PlayerState\n ): number {\n return this.calculateCost(from, to).stamina;\n }\n\n /**\n * Get transition time\n */\n static getTransitionTime(\n from: TrigramStance,\n to: TrigramStance,\n _player: PlayerState\n ): number {\n return this.calculateCost(from, to).timeMilliseconds; // Fix property name\n }\n\n /**\n * Get adjacency modifier for stance transitions\n *\n * **Korean**: 인접도 수정자\n *\n * Uses the animation system's distance calculation for consistency.\n * Adjacent stances (distance 1) get 0.7x cost, others get 1.0x cost.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Cost modifier (0.7 for adjacent, 1.0 for distant)\n *\n * @korean 인접도수정자\n */\n private static getAdjacencyModifier(\n from: TrigramStance,\n to: TrigramStance\n ): number {\n const distance = calculateStanceDistance(from, to);\n\n // Adjacent stances (distance 1) have reduced cost\n if (distance === 1) return 0.7;\n\n // Near-adjacent (distance 2) have slightly reduced cost\n if (distance === 2) return 0.85;\n\n // Distant/opposite stances have full cost\n return 1.0;\n }\n\n /**\n * Get the shortest transition path between stances\n *\n * **Korean**: 최단 전환 경로\n *\n * For direct transitions, returns [from, to].\n * For indirect transitions, may include intermediate stances for smoother animation.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Array of stances in transition path\n *\n * @example\n * ```typescript\n * // Adjacent stances - direct path\n * getTransitionPath(TrigramStance.GEON, TrigramStance.TAE);\n * // Returns: [\"geon\", \"tae\"]\n *\n * // Opposite stances - may use intermediate\n * getTransitionPath(TrigramStance.GEON, TrigramStance.GON);\n * // Returns: [\"geon\", \"gon\"] (direct is shortest even though opposite)\n * ```\n *\n * @korean 최단전환경로\n */\n static getTransitionPath(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramStance[] {\n if (from === to) return [from];\n\n // For all transitions, direct path is used\n // The animation system handles the complexity with keyframes\n return [from, to];\n }\n\n /**\n * Get transition type for a stance change\n *\n * **Korean**: 전환 유형 가져오기\n *\n * Determines if transition is direct (adjacent), indirect (opposite), or self.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition type classification\n *\n * @korean 전환유형가져오기\n */\n static getTransitionType(\n from: TrigramStance,\n to: TrigramStance\n ): StanceTransitionType {\n return determineTransitionType(from, to);\n }\n\n /**\n * Calculate stance distance around the wheel\n *\n * **Korean**: 자세 거리 계산\n *\n * Returns the number of steps between stances on the octagonal wheel.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Distance (0-4)\n *\n * @korean 자세거리계산\n */\n static getStanceDistance(from: TrigramStance, to: TrigramStance): number {\n return calculateStanceDistance(from, to);\n }\n\n /**\n * Calculate total cost for a transition path\n */\n static calculatePathCost(path: TrigramStance[]): TrigramTransitionCost {\n if (path.length <= 1) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 }; // Fix: Use timeMilliseconds\n }\n\n const totalCost = { ki: 0, stamina: 0, timeMilliseconds: 0 };\n\n for (let i = 0; i < path.length - 1; i++) {\n const stepCost = this.calculateCost(path[i], path[i + 1]);\n totalCost.ki += stepCost.ki;\n totalCost.stamina += stepCost.stamina;\n totalCost.timeMilliseconds += stepCost.timeMilliseconds;\n }\n\n return totalCost;\n }\n\n /**\n * Get all valid transitions from a stance\n */\n static getValidTransitions(\n from: TrigramStance,\n player: PlayerState\n ): TrigramTransitionRule[] {\n const transitions: TrigramTransitionRule[] = [];\n\n for (const to of Object.values(TrigramStanceEnum)) {\n if (this.isTransitionValid(from, to, player)) {\n const cost = this.calculateCost(from, to);\n\n transitions.push({\n from,\n to,\n cost,\n effectiveness: 1.0, // Add missing property\n conditions: [],\n description: {\n korean: `${from}에서 ${to}로`,\n english: `From ${from} to ${to}`,\n },\n });\n }\n }\n\n return transitions;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransitionCalculator.js","names":[],"sources":["../../../src/systems/trigram/TransitionCalculator.ts"],"sourcesContent":["import { TrigramStance } from \"../../types\";\nimport { TrigramStance as TrigramStanceEnum } from \"../../types/common\";\nimport {\n calculateStanceDistance,\n determineTransitionType,\n getStanceTransition,\n type StanceTransitionType,\n} from \"../animation/core/AnimationTransitions\";\nimport { PlayerState } from \"../player\";\nimport { TrigramTransitionCost, TrigramTransitionRule } from \"./types\";\n\n/**\n * Calculator for trigram stance transition costs and validation\n *\n * **Korean**: 자세 전환 계산기\n *\n * Calculates costs, paths, and validation for transitions between trigram stances.\n * Integrates with the animation system's stance transition matrix.\n *\n * @category Trigram System\n * @korean 자세전환계산기\n */\nexport class TransitionCalculator {\n private calculateBaseCost(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramTransitionCost {\n if (from === to) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 };\n }\n\n return { ki: 10, stamina: 15, timeMilliseconds: 500 };\n }\n\n generateTransitionRule(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramTransitionRule {\n const cost = this.calculateBaseCost(from, to);\n\n return {\n from,\n to,\n cost,\n effectiveness: 1.0, // Fix: Add missing effectiveness property\n conditions: [],\n description: {\n korean: `${from}에서 ${to}로 전환`,\n english: `Transition from ${from} to ${to}`,\n },\n };\n }\n\n /**\n * Calculate the cost of transitioning between stances\n *\n * **Korean**: 자세 전환 비용 계산\n *\n * Calculates ki, stamina, and time costs based on stance distance.\n * Uses animation system's transition configurations for accurate timing.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition cost breakdown\n *\n * @korean 자세전환비용계산\n */\n static calculateCost(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramTransitionCost {\n if (from === to) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 };\n }\n\n // Get transition from animation system for accurate timing\n const transition = getStanceTransition(from, to);\n const timeMs = transition?.duration ?? 600;\n\n const baseCost = { ki: 15, stamina: 10, timeMilliseconds: timeMs };\n const modifier = this.getAdjacencyModifier(from, to);\n\n return {\n ki: Math.floor(baseCost.ki * modifier),\n stamina: Math.floor(baseCost.stamina * modifier),\n timeMilliseconds: timeMs, // Use actual transition duration\n };\n }\n\n /**\n * Check if a transition is valid for a player\n */\n static canTransition(\n from: TrigramStance,\n to: TrigramStance,\n player: PlayerState\n ): boolean {\n const cost = this.calculateCost(from, to);\n return player.ki >= cost.ki && player.stamina >= cost.stamina;\n }\n\n /**\n * Check if transition is valid based on player state\n */\n static isTransitionValid(\n from: TrigramStance,\n to: TrigramStance,\n player: PlayerState\n ): boolean {\n return this.canTransition(from, to, player);\n }\n\n /**\n * Get Ki cost for transition\n */\n static getKiCost(\n from: TrigramStance,\n to: TrigramStance,\n _player: PlayerState\n ): number {\n return this.calculateCost(from, to).ki;\n }\n\n /**\n * Get Stamina cost for transition\n */\n static getStaminaCost(\n from: TrigramStance,\n to: TrigramStance,\n _player: PlayerState\n ): number {\n return this.calculateCost(from, to).stamina;\n }\n\n /**\n * Get transition time\n */\n static getTransitionTime(\n from: TrigramStance,\n to: TrigramStance,\n _player: PlayerState\n ): number {\n return this.calculateCost(from, to).timeMilliseconds; // Fix property name\n }\n\n /**\n * Get adjacency modifier for stance transitions\n *\n * **Korean**: 인접도 수정자\n *\n * Uses the animation system's distance calculation for consistency.\n * Adjacent stances (distance 1) get 0.7x cost, others get 1.0x cost.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Cost modifier (0.7 for adjacent, 1.0 for distant)\n *\n * @korean 인접도수정자\n */\n private static getAdjacencyModifier(\n from: TrigramStance,\n to: TrigramStance\n ): number {\n const distance = calculateStanceDistance(from, to);\n\n // Adjacent stances (distance 1) have reduced cost\n if (distance === 1) return 0.7;\n\n // Near-adjacent (distance 2) have slightly reduced cost\n if (distance === 2) return 0.85;\n\n // Distant/opposite stances have full cost\n return 1.0;\n }\n\n /**\n * Get the shortest transition path between stances\n *\n * **Korean**: 최단 전환 경로\n *\n * For direct transitions, returns [from, to].\n * For indirect transitions, may include intermediate stances for smoother animation.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Array of stances in transition path\n *\n * @example\n * ```typescript\n * // Adjacent stances - direct path\n * getTransitionPath(TrigramStance.GEON, TrigramStance.TAE);\n * // Returns: [\"geon\", \"tae\"]\n *\n * // Opposite stances - may use intermediate\n * getTransitionPath(TrigramStance.GEON, TrigramStance.GON);\n * // Returns: [\"geon\", \"gon\"] (direct is shortest even though opposite)\n * ```\n *\n * @korean 최단전환경로\n */\n static getTransitionPath(\n from: TrigramStance,\n to: TrigramStance\n ): TrigramStance[] {\n if (from === to) return [from];\n\n // For all transitions, direct path is used\n // The animation system handles the complexity with keyframes\n return [from, to];\n }\n\n /**\n * Get transition type for a stance change\n *\n * **Korean**: 전환 유형 가져오기\n *\n * Determines if transition is direct (adjacent), indirect (opposite), or self.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition type classification\n *\n * @korean 전환유형가져오기\n */\n static getTransitionType(\n from: TrigramStance,\n to: TrigramStance\n ): StanceTransitionType {\n return determineTransitionType(from, to);\n }\n\n /**\n * Calculate stance distance around the wheel\n *\n * **Korean**: 자세 거리 계산\n *\n * Returns the number of steps between stances on the octagonal wheel.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Distance (0-4)\n *\n * @korean 자세거리계산\n */\n static getStanceDistance(from: TrigramStance, to: TrigramStance): number {\n return calculateStanceDistance(from, to);\n }\n\n /**\n * Calculate total cost for a transition path\n */\n static calculatePathCost(path: TrigramStance[]): TrigramTransitionCost {\n if (path.length <= 1) {\n return { ki: 0, stamina: 0, timeMilliseconds: 0 }; // Fix: Use timeMilliseconds\n }\n\n const totalCost = { ki: 0, stamina: 0, timeMilliseconds: 0 };\n\n for (let i = 0; i < path.length - 1; i++) {\n const stepCost = this.calculateCost(path[i], path[i + 1]);\n totalCost.ki += stepCost.ki;\n totalCost.stamina += stepCost.stamina;\n totalCost.timeMilliseconds += stepCost.timeMilliseconds;\n }\n\n return totalCost;\n }\n\n /**\n * Get all valid transitions from a stance\n */\n static getValidTransitions(\n from: TrigramStance,\n player: PlayerState\n ): TrigramTransitionRule[] {\n const transitions: TrigramTransitionRule[] = [];\n\n for (const to of Object.values(TrigramStanceEnum)) {\n if (this.isTransitionValid(from, to, player)) {\n const cost = this.calculateCost(from, to);\n\n transitions.push({\n from,\n to,\n cost,\n effectiveness: 1.0, // Add missing property\n conditions: [],\n description: {\n korean: `${from}에서 ${to}로`,\n english: `From ${from} to ${to}`,\n },\n });\n }\n }\n\n return transitions;\n }\n}\n"],"mappings":"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"}