blacktrigram 0.7.45 → 0.7.48

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 (450) 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 +22 -11
  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.js.map +1 -1
  38. package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
  39. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
  40. package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
  41. package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
  42. package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
  43. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  44. package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
  45. package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
  46. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  47. package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
  48. package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
  49. package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
  50. package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
  51. package/lib/components/screens/combat/helpers/AnimationUpdater.js +4 -2
  52. package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
  53. package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
  54. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  55. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  56. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  57. package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
  58. package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
  59. package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
  60. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  61. package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
  62. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  63. package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
  64. package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
  65. package/lib/components/screens/controls/components/Key3D.js.map +1 -1
  66. package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
  67. package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
  68. package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
  69. package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
  70. package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
  71. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  72. package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
  73. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  74. package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
  75. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  76. package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
  77. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  78. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  79. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  80. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  81. package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
  82. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  83. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  84. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  85. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  86. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  87. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  88. package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
  89. package/lib/components/screens/training/TrainingScreen3D.js +1 -0
  90. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  91. package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
  92. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  93. package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
  94. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  95. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  96. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  97. package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
  98. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  99. package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
  100. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  101. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  102. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  103. package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
  104. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
  105. package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
  106. package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
  107. package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
  108. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  109. package/lib/components/screens/training/hooks/useTrainingActions.d.ts +1 -0
  110. package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
  111. package/lib/components/screens/training/hooks/useTrainingActions.js +6 -4
  112. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  113. package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
  114. package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
  115. package/lib/components/shared/base/BaseButton.js.map +1 -1
  116. package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
  117. package/lib/components/shared/base/BasePanel.js.map +1 -1
  118. package/lib/components/shared/base/BaseText.js.map +1 -1
  119. package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
  120. package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
  121. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  122. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  123. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  124. package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
  125. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  126. package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
  127. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  128. package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
  129. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  130. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  131. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  132. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  133. package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
  134. package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
  135. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  136. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  137. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  138. package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
  139. package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
  140. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  141. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  142. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  143. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  144. package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
  145. package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
  146. package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
  147. package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
  148. package/lib/components/shared/three/models/SkeletalPlayer3D.js +7 -5
  149. package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
  150. package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
  151. package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
  152. package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
  153. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  154. package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
  155. package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
  156. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  157. package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
  158. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  159. package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
  160. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  161. package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
  162. package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
  163. package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
  164. package/lib/components/shared/three/ui/MenuList.js.map +1 -1
  165. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  166. package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
  167. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  168. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  169. package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
  170. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  171. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  172. package/lib/components/shared/ui/BackButton.js.map +1 -1
  173. package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
  174. package/lib/components/shared/ui/CombatTimer.js.map +1 -1
  175. package/lib/components/shared/ui/ErrorModal.js.map +1 -1
  176. package/lib/components/shared/ui/LoadingState.js.map +1 -1
  177. package/lib/components/shared/ui/SplashScreen.js +2 -2
  178. package/lib/components/shared/ui/SplashScreen.js.map +1 -1
  179. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  180. package/lib/components/shared/ui/VolumeControl.js.map +1 -1
  181. package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
  182. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  183. package/lib/constants/bodyDimensions.js.map +1 -1
  184. package/lib/constants/bodyRenderingConstants.js.map +1 -1
  185. package/lib/data/archetypeClothing.js.map +1 -1
  186. package/lib/data/archetypePhysicalAttributes.js.map +1 -1
  187. package/lib/data/techniqueMappings.js.map +1 -1
  188. package/lib/data/techniques.js.map +1 -1
  189. package/lib/hooks/useActionFeedback.js.map +1 -1
  190. package/lib/hooks/useBalanceAnimations.js.map +1 -1
  191. package/lib/hooks/useCombatTimer.js.map +1 -1
  192. package/lib/hooks/useDebounce.js.map +1 -1
  193. package/lib/hooks/useHUDLayout.js.map +1 -1
  194. package/lib/hooks/useHandPoseTransitions.js.map +1 -1
  195. package/lib/hooks/useKeyboardControls.js.map +1 -1
  196. package/lib/hooks/useMatchCountdown.js.map +1 -1
  197. package/lib/hooks/useMuscleActivation.js.map +1 -1
  198. package/lib/hooks/usePauseMenu.js.map +1 -1
  199. package/lib/hooks/usePlayerAnimation.js.map +1 -1
  200. package/lib/hooks/useResponsiveLayout.js.map +1 -1
  201. package/lib/hooks/useRoundTransition.js.map +1 -1
  202. package/lib/hooks/useSkeletalAnimation.d.ts.map +1 -1
  203. package/lib/hooks/useSkeletalAnimation.js +1 -1
  204. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  205. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  206. package/lib/hooks/useThrottle.js.map +1 -1
  207. package/lib/hooks/useTouchControls.js.map +1 -1
  208. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  209. package/lib/hooks/useWindowSize.js.map +1 -1
  210. package/lib/systems/CombatSystem.js.map +1 -1
  211. package/lib/systems/EffectCalculator.js.map +1 -1
  212. package/lib/systems/LayoutSystem.js.map +1 -1
  213. package/lib/systems/PlayerEffectManager.js.map +1 -1
  214. package/lib/systems/ResponsiveScaling.js.map +1 -1
  215. package/lib/systems/TrigramSystem.js.map +1 -1
  216. package/lib/systems/VitalPointSystem.js.map +1 -1
  217. package/lib/systems/ai/AIPersonality.js.map +1 -1
  218. package/lib/systems/ai/AdaptiveDifficulty.js +16 -16
  219. package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
  220. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  221. package/lib/systems/ai/ComboSystem.js.map +1 -1
  222. package/lib/systems/ai/DecisionTree.js.map +1 -1
  223. package/lib/systems/ai/TrainingAI.js.map +1 -1
  224. package/lib/systems/ai/types.js.map +1 -1
  225. package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
  226. package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
  227. package/lib/systems/animation/builders/HandPoses.js.map +1 -1
  228. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  229. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  230. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts +6 -0
  231. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts.map +1 -1
  232. package/lib/systems/animation/builders/KickPhaseApplicator.js +16 -9
  233. package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
  234. package/lib/systems/animation/builders/KoreanGuardPositions.d.ts +4 -4
  235. package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
  236. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts +1 -1
  237. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts.map +1 -1
  238. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js +5 -5
  239. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  240. package/lib/systems/animation/builders/MartialArtsConstants.d.ts +112 -71
  241. package/lib/systems/animation/builders/MartialArtsConstants.d.ts.map +1 -1
  242. package/lib/systems/animation/builders/MartialArtsConstants.js +113 -72
  243. package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
  244. package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
  245. package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
  246. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  247. package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
  248. package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
  249. package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
  250. package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
  251. package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
  252. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  253. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
  254. package/lib/systems/animation/catalogs/EnhancedAttackAnimations.js.map +1 -1
  255. package/lib/systems/animation/catalogs/EnhancedElbowKneeAnimations.js.map +1 -1
  256. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  257. package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
  258. package/lib/systems/animation/catalogs/GamStanceAnimations.js +21 -0
  259. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -0
  260. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js +34 -2
  261. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
  262. package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
  263. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
  264. package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
  265. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts +9 -0
  266. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts.map +1 -1
  267. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +288 -0
  268. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -0
  269. package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
  270. package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
  271. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
  272. package/lib/systems/animation/catalogs/KickAnimations.d.ts +2 -2
  273. package/lib/systems/animation/catalogs/KickAnimations.js +2 -2
  274. package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
  275. package/lib/systems/animation/catalogs/LiStanceAnimations.js +14 -1
  276. package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
  277. package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
  278. package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
  279. package/lib/systems/animation/catalogs/PunchAnimations.d.ts +1 -1
  280. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  281. package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
  282. package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
  283. package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
  284. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
  285. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
  286. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  287. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  288. package/lib/systems/animation/catalogs/StanceGuardPoses.d.ts +6 -6
  289. package/lib/systems/animation/catalogs/StanceGuardPoses.js +36 -36
  290. package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
  291. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  292. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  293. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  294. package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
  295. package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
  296. package/lib/systems/animation/constants/AnatomicalLimits.js.map +1 -1
  297. package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
  298. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  299. package/lib/systems/animation/core/AnimationPriority.js +15 -15
  300. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  301. package/lib/systems/animation/core/AnimationRegistry.d.ts +30 -0
  302. package/lib/systems/animation/core/AnimationRegistry.d.ts.map +1 -1
  303. package/lib/systems/animation/core/AnimationRegistry.js +74 -12
  304. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  305. package/lib/systems/animation/core/AnimationStateMachine.js +16 -16
  306. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  307. package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
  308. package/lib/systems/animation/core/AnimationTransitions.js +34 -0
  309. package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
  310. package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
  311. package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
  312. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  313. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  314. package/lib/systems/animation/core/index.d.ts +1 -1
  315. package/lib/systems/animation/core/index.d.ts.map +1 -1
  316. package/lib/systems/animation/core/types.d.ts +24 -0
  317. package/lib/systems/animation/core/types.d.ts.map +1 -1
  318. package/lib/systems/animation/core/types.js +27 -11
  319. package/lib/systems/animation/core/types.js.map +1 -1
  320. package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
  321. package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
  322. package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
  323. package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
  324. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  325. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  326. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  327. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  328. package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
  329. package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
  330. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  331. package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
  332. package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
  333. package/lib/systems/bodypart/types.js.map +1 -1
  334. package/lib/systems/breathing/BreathingDisruptionSystem.js +19 -19
  335. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  336. package/lib/systems/breathing/feedback.js.map +1 -1
  337. package/lib/systems/breathing/integration.js.map +1 -1
  338. package/lib/systems/combat/BalanceSystem.js +19 -19
  339. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  340. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  341. package/lib/systems/combat/CombatStateSystem.js +17 -17
  342. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  343. package/lib/systems/combat/ConsciousnessSystem.js +24 -24
  344. package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
  345. package/lib/systems/combat/FallIntegration.js.map +1 -1
  346. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  347. package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
  348. package/lib/systems/combat/PainResponseSystem.js +21 -21
  349. package/lib/systems/combat/PainResponseSystem.js.map +1 -1
  350. package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
  351. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  352. package/lib/systems/combat/typeGuards.js.map +1 -1
  353. package/lib/systems/effects.js.map +1 -1
  354. package/lib/systems/game.js.map +1 -1
  355. package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
  356. package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
  357. package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
  358. package/lib/systems/movement/integration.js.map +1 -1
  359. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  360. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  361. package/lib/systems/physics/CoordinateMapper.js.map +1 -1
  362. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  363. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  364. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  365. package/lib/systems/physics/SpeedModifierSystem.js +6 -6
  366. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  367. package/lib/systems/trigram/KoreanCulture.js.map +1 -1
  368. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  369. package/lib/systems/trigram/StanceManager.js.map +1 -1
  370. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  371. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  372. package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
  373. package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
  374. package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
  375. package/lib/systems/trigram/techniques/GeonTechniques.js.map +1 -1
  376. package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
  377. package/lib/systems/trigram/techniques/JinTechniques.js.map +1 -1
  378. package/lib/systems/trigram/techniques/LiTechniques.js.map +1 -1
  379. package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
  380. package/lib/systems/trigram/techniques/TaeTechniques.js.map +1 -1
  381. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  382. package/lib/systems/trigram/techniques/index.js.map +1 -1
  383. package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
  384. package/lib/systems/trigram/types.js.map +1 -1
  385. package/lib/systems/types.js.map +1 -1
  386. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  387. package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
  388. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  389. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  390. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  391. package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
  392. package/lib/types/AccessibilityTypes.js.map +1 -1
  393. package/lib/types/LayoutTypes.js.map +1 -1
  394. package/lib/types/PhysicsTypes.js.map +1 -1
  395. package/lib/types/common.js.map +1 -1
  396. package/lib/types/constants/animations.js.map +1 -1
  397. package/lib/types/constants/colors.js.map +1 -1
  398. package/lib/types/constants/designSystem.js.map +1 -1
  399. package/lib/types/constants/index.js.map +1 -1
  400. package/lib/types/constants/layout.js.map +1 -1
  401. package/lib/types/constants/performance.js.map +1 -1
  402. package/lib/types/constants/typography.js.map +1 -1
  403. package/lib/types/constants/ui.js.map +1 -1
  404. package/lib/types/facial.js +19 -19
  405. package/lib/types/facial.js.map +1 -1
  406. package/lib/types/hand-animation.js.map +1 -1
  407. package/lib/types/injury.js.map +1 -1
  408. package/lib/types/muscle.js.map +1 -1
  409. package/lib/types/physics.js.map +1 -1
  410. package/lib/types/physicsConstants.js.map +1 -1
  411. package/lib/types/player-visual.d.ts +1 -1
  412. package/lib/types/player-visual.d.ts.map +1 -1
  413. package/lib/types/skeletal.js.map +1 -1
  414. package/lib/types/techniqueId.js.map +1 -1
  415. package/lib/utils/accessibility.js.map +1 -1
  416. package/lib/utils/arenaWorldDimensions.js.map +1 -1
  417. package/lib/utils/assetConfig.js.map +1 -1
  418. package/lib/utils/characterScaling.js.map +1 -1
  419. package/lib/utils/colorHelpers.js.map +1 -1
  420. package/lib/utils/colorUtils.js.map +1 -1
  421. package/lib/utils/combatReadiness.js.map +1 -1
  422. package/lib/utils/controlMapping.js.map +1 -1
  423. package/lib/utils/deviceDetection.js +6 -7
  424. package/lib/utils/deviceDetection.js.map +1 -1
  425. package/lib/utils/effectUtils.js.map +1 -1
  426. package/lib/utils/fabricTextures.js.map +1 -1
  427. package/lib/utils/hapticFeedback.js.map +1 -1
  428. package/lib/utils/haptics.js.map +1 -1
  429. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  430. package/lib/utils/inputSystem.js.map +1 -1
  431. package/lib/utils/koreanThemeHelpers.js.map +1 -1
  432. package/lib/utils/math.js.map +1 -1
  433. package/lib/utils/mobileLayoutHelpers.js.map +1 -1
  434. package/lib/utils/mobileUIUtils.js.map +1 -1
  435. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  436. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  437. package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
  438. package/lib/utils/performanceOptimization.js.map +1 -1
  439. package/lib/utils/player3DHelpers.js.map +1 -1
  440. package/lib/utils/playerUtils.js.map +1 -1
  441. package/lib/utils/responsiveLayout.js.map +1 -1
  442. package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
  443. package/lib/utils/responsiveOrientationConstants.js.map +1 -1
  444. package/lib/utils/safeAreaUtils.js.map +1 -1
  445. package/lib/utils/sharedPhysicsConfig.js.map +1 -1
  446. package/lib/utils/skeletonScaling.js.map +1 -1
  447. package/lib/utils/stanceHelpers.js.map +1 -1
  448. package/lib/utils/threeObjectPool.js.map +1 -1
  449. package/lib/utils/visualEffects.js.map +1 -1
  450. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"ResponsiveScaling.js","names":[],"sources":["../../src/systems/ResponsiveScaling.ts"],"sourcesContent":["/**\n * Responsive Scaling System for Black Trigram\n * \n * Centralized scaling calculations for responsive layout across all screen sizes.\n * Implements proportional font and spacing scaling with smooth transitions.\n * \n * Features:\n * - Five screen size categories (mobile, tablet, desktop, large, xlarge)\n * - Font scaling: 0.8x (mobile) to 1.4x (4K displays)\n * - Spacing scaling: 0.5x (mobile) to 1.5x (4K displays)\n * - Korean text readability: 14-24px range enforced\n * - Smooth CSS transitions for resize operations\n * - 60fps performance maintained\n * \n * @module systems/ResponsiveScaling\n * @category Responsive Layout\n * @korean 반응형스케일시스템\n */\n\nimport type {\n ScreenSize,\n ResponsiveBreakpoints,\n FontScaleMap,\n SpacingScaleMap,\n ResponsiveScaleConfig,\n ResizeTransitionConfig,\n ResponsiveValues,\n ScreenSizeTestResult,\n} from '../types/ResponsiveTypes';\n\n// Re-export types for convenience\nexport type {\n ScreenSize,\n ResponsiveBreakpoints,\n FontScaleMap,\n SpacingScaleMap,\n ResponsiveScaleConfig,\n ResizeTransitionConfig,\n ResponsiveValues,\n ScreenSizeTestResult,\n};\n\n/**\n * Standard breakpoints for responsive design\n * Maps viewport widths to device categories\n * \n * Note: XLARGE is defined as a reference value (2560px) but xlarge category\n * starts at LARGE (1920px). This allows for consistent scaling across all\n * displays from 1920px upwards, including 2K, 4K, and ultra-wide monitors.\n * \n * @constant\n * @category Responsive Layout\n */\nexport const RESPONSIVE_BREAKPOINTS: ResponsiveBreakpoints = {\n MOBILE: 768, // < 768px: Mobile devices\n TABLET: 1024, // 768-1024px: Tablets\n DESKTOP: 1440, // 1024-1440px: Standard desktop\n LARGE: 1920, // 1440-1920px: HD/2K displays\n XLARGE: 2560, // Reference for 4K displays (xlarge starts at 1920px)\n} as const;\n\n/**\n * Font scaling multipliers by screen size\n * Base size (16px) * scale = final size\n * \n * Results clamped to 14-24px for readability\n * \n * @constant\n * @category Typography\n */\nexport const FONT_SCALE_MAP: FontScaleMap = {\n mobile: 0.8, // 16px * 0.8 = 12.8px → clamped to 14px min\n tablet: 0.9, // 16px * 0.9 = 14.4px\n desktop: 1.0, // 16px * 1.0 = 16px (base)\n large: 1.2, // 16px * 1.2 = 19.2px\n xlarge: 1.4, // 16px * 1.4 = 22.4px → clamped to 24px max\n} as const;\n\n/**\n * Spacing scaling multipliers by screen size\n * Base spacing * scale = final spacing\n * \n * @constant\n * @category Layout\n */\nexport const SPACING_SCALE_MAP: SpacingScaleMap = {\n mobile: 0.5, // Compact spacing for small screens\n tablet: 0.75, // Moderate spacing for tablets\n desktop: 1.0, // Standard reference spacing\n large: 1.25, // Spacious for large displays\n xlarge: 1.5, // Maximum spacing for 4K\n} as const;\n\n/**\n * Default transition configuration for smooth resizing\n * Optimized for 60fps performance\n * \n * @constant\n * @category Animation\n */\nexport const DEFAULT_RESIZE_TRANSITION: ResizeTransitionConfig = {\n duration: '300ms',\n easing: 'ease-in-out',\n properties: ['font-size', 'padding', 'margin', 'width', 'height'] as const,\n enabled: true,\n} as const;\n\n/**\n * Font size constraints for Korean and English text\n * Ensures readability across all screen sizes\n * \n * @constant\n * @category Typography\n */\nexport const FONT_SIZE_CONSTRAINTS = {\n /** Minimum body text size for readability */\n MIN_BODY_SIZE: 14,\n /** Maximum size before text becomes too large */\n MAX_SIZE: 24,\n /** Base reference size (desktop) */\n BASE_SIZE: 16,\n} as const;\n\n/**\n * Determine screen size category from viewport width\n * \n * Categories:\n * - mobile: < 768px (phones)\n * - tablet: 768-1024px (tablets)\n * - desktop: 1024-1440px (standard monitors)\n * - large: 1440-1920px (HD/2K displays)\n * - xlarge: ≥1920px (4K/ultra-wide)\n * \n * @param width - Viewport width in pixels\n * @returns Screen size category\n * \n * @example\n * ```typescript\n * getScreenSize(375); // 'mobile'\n * getScreenSize(768); // 'tablet'\n * getScreenSize(1920); // 'xlarge'\n * ```\n * \n * @korean 화면크기얻기\n */\nexport function getScreenSize(width: number): ScreenSize {\n if (width < RESPONSIVE_BREAKPOINTS.MOBILE) return 'mobile';\n if (width < RESPONSIVE_BREAKPOINTS.TABLET) return 'tablet';\n if (width < RESPONSIVE_BREAKPOINTS.DESKTOP) return 'desktop';\n if (width < RESPONSIVE_BREAKPOINTS.LARGE) return 'large';\n return 'xlarge';\n}\n\n/**\n * Calculate scaled font size with readability constraints\n * \n * Formula: baseSize * scale\n * Clamped: max(minSize, min(maxSize, calculated))\n * \n * Ensures Korean and English text remain readable at all sizes\n * \n * @param baseSize - Base font size in pixels (typically 16px)\n * @param screenSize - Current screen size category\n * @param minSize - Minimum allowed size (default: 14px)\n * @param maxSize - Maximum allowed size (default: 24px)\n * @returns Calculated font size in pixels\n * \n * @example\n * ```typescript\n * calculateFontSize(16, 'mobile'); // 14 (clamped from 12.8)\n * calculateFontSize(16, 'desktop'); // 16\n * calculateFontSize(16, 'xlarge'); // 22.4\n * calculateFontSize(20, 'xlarge', 14, 24); // 24 (clamped from 28)\n * ```\n * \n * @korean 글꼴크기계산\n */\nexport function calculateFontSize(\n baseSize: number,\n screenSize: ScreenSize,\n minSize: number = FONT_SIZE_CONSTRAINTS.MIN_BODY_SIZE,\n maxSize: number = FONT_SIZE_CONSTRAINTS.MAX_SIZE\n): number {\n const scale = FONT_SCALE_MAP[screenSize];\n const scaled = baseSize * scale;\n \n // Clamp to readable range\n return Math.max(minSize, Math.min(maxSize, scaled));\n}\n\n/**\n * Calculate scaled spacing value\n * \n * Formula: baseSpacing * scale\n * Rounded to nearest integer for crisp rendering\n * \n * @param baseSpacing - Base spacing value in pixels\n * @param screenSize - Current screen size category\n * @returns Calculated spacing in pixels (rounded)\n * \n * @example\n * ```typescript\n * calculateSpacing(20, 'mobile'); // 10 (20 * 0.5)\n * calculateSpacing(20, 'desktop'); // 20\n * calculateSpacing(20, 'xlarge'); // 30 (20 * 1.5)\n * ```\n * \n * @korean 간격계산\n */\nexport function calculateSpacing(\n baseSpacing: number,\n screenSize: ScreenSize\n): number {\n const scale = SPACING_SCALE_MAP[screenSize];\n return Math.round(baseSpacing * scale);\n}\n\n/**\n * Get font scale multiplier for screen size\n * \n * @param screenSize - Screen size category\n * @returns Scale multiplier (0.8 - 1.4)\n * \n * @example\n * ```typescript\n * getFontScale('mobile'); // 0.8\n * getFontScale('desktop'); // 1.0\n * getFontScale('xlarge'); // 1.4\n * ```\n * \n * @korean 글꼴스케일얻기\n */\nexport function getFontScale(screenSize: ScreenSize): number {\n return FONT_SCALE_MAP[screenSize];\n}\n\n/**\n * Get spacing scale multiplier for screen size\n * \n * @param screenSize - Screen size category\n * @returns Scale multiplier (0.5 - 1.5)\n * \n * @example\n * ```typescript\n * getSpacingScale('mobile'); // 0.5\n * getSpacingScale('desktop'); // 1.0\n * getSpacingScale('xlarge'); // 1.5\n * ```\n * \n * @korean 간격스케일얻기\n */\nexport function getSpacingScale(screenSize: ScreenSize): number {\n return SPACING_SCALE_MAP[screenSize];\n}\n\n/**\n * Create CSS transition string for smooth resizing\n * \n * @param config - Transition configuration (optional)\n * @returns CSS transition string\n * \n * @example\n * ```typescript\n * createTransitionString();\n * // 'font-size 300ms ease-in-out, padding 300ms ease-in-out, ...'\n * \n * createTransitionString({ duration: '200ms', easing: 'linear' });\n * // 'font-size 200ms linear, padding 200ms linear, ...'\n * ```\n * \n * @korean 전환문자열생성\n */\nexport function createTransitionString(\n config: Partial<ResizeTransitionConfig> = {}\n): string {\n const {\n duration = DEFAULT_RESIZE_TRANSITION.duration,\n easing = DEFAULT_RESIZE_TRANSITION.easing,\n properties = DEFAULT_RESIZE_TRANSITION.properties,\n enabled = DEFAULT_RESIZE_TRANSITION.enabled,\n } = config;\n\n if (!enabled) {\n return 'none';\n }\n\n return properties\n .map((prop) => `${prop} ${duration} ${easing}`)\n .join(', ');\n}\n\n/**\n * Create complete responsive scale configuration\n * \n * @param width - Viewport width\n * @param height - Viewport height\n * @returns Complete responsive configuration\n * \n * @example\n * ```typescript\n * const config = createResponsiveConfig(375, 667);\n * console.log(config.screenSize); // 'mobile'\n * console.log(config.fontScale); // 0.8\n * console.log(config.spacingScale); // 0.5\n * ```\n * \n * @korean 반응형설정생성\n */\nexport function createResponsiveConfig(\n width: number,\n height: number\n): ResponsiveScaleConfig {\n const screenSize = getScreenSize(width);\n const fontScale = getFontScale(screenSize);\n const spacingScale = getSpacingScale(screenSize);\n\n return {\n screenSize,\n fontScale,\n spacingScale,\n viewport: { width, height },\n };\n}\n\n/**\n * Calculate all responsive values for a component\n * \n * Computes font sizes, spacing, and transitions based on screen size\n * Ready-to-use values for component styling\n * \n * @param width - Viewport width\n * @param baseFontSize - Base font size (default: 16px)\n * @param baseSpacing - Base spacing unit (default: 16px)\n * @returns Complete responsive values\n * \n * @example\n * ```typescript\n * const values = calculateResponsiveValues(375);\n * \n * <div style={{\n * fontSize: values.fontSize.body,\n * padding: values.spacing.md,\n * transition: values.transition,\n * }}>\n * Responsive content\n * </div>\n * ```\n * \n * @korean 반응형값계산\n */\nexport function calculateResponsiveValues(\n width: number,\n baseFontSize: number = FONT_SIZE_CONSTRAINTS.BASE_SIZE,\n baseSpacing: number = 16\n): ResponsiveValues {\n const screenSize = getScreenSize(width);\n \n // Calculate font sizes for all text levels\n const fontSize = {\n small: calculateFontSize(baseFontSize * 0.75, screenSize, 12, 18),\n body: calculateFontSize(baseFontSize, screenSize),\n title: calculateFontSize(baseFontSize * 1.5, screenSize, 18, 28),\n hero: calculateFontSize(baseFontSize * 2.25, screenSize, 24, 36),\n hud: calculateFontSize(baseFontSize * 1.25, screenSize, 16, 24),\n };\n\n // Calculate spacing scale\n const spacing = {\n xs: calculateSpacing(baseSpacing * 0.5, screenSize),\n sm: calculateSpacing(baseSpacing * 0.75, screenSize),\n md: calculateSpacing(baseSpacing, screenSize),\n lg: calculateSpacing(baseSpacing * 1.5, screenSize),\n xl: calculateSpacing(baseSpacing * 2, screenSize),\n };\n\n // Create transition string\n const transition = createTransitionString();\n\n return {\n fontSize,\n spacing,\n transition,\n };\n}\n\n/**\n * Test screen size determination for validation\n * \n * Useful for testing and debugging responsive breakpoints.\n * Screen size is determined by width (breakpoints), but height is included\n * in the result for testing portrait/landscape orientations.\n * \n * @param width - Viewport width to test\n * @param height - Viewport height to test\n * @returns Test result with screen size and device type flags\n * \n * @example\n * ```typescript\n * const result = testScreenSize(768, 1024);\n * console.log(result.screenSize); // 'tablet'\n * console.log(result.isTablet); // true\n * console.log(result.isMobile); // false\n * ```\n * \n * @korean 화면크기테스트\n */\nexport function testScreenSize(\n width: number,\n height: number\n): ScreenSizeTestResult {\n const screenSize = getScreenSize(width);\n const isLandscape = width > height;\n \n return {\n width,\n height,\n screenSize,\n isMobile: screenSize === 'mobile',\n isTablet: screenSize === 'tablet',\n isDesktop: screenSize === 'desktop' || screenSize === 'large' || screenSize === 'xlarge',\n // Include landscape in test result for completeness\n isLandscape,\n };\n}\n\n/**\n * Check if screen size is mobile\n * \n * @param width - Viewport width\n * @returns True if mobile screen size\n * \n * @korean 모바일확인\n */\nexport function isMobileSize(width: number): boolean {\n return getScreenSize(width) === 'mobile';\n}\n\n/**\n * Check if screen size is tablet\n * \n * @param width - Viewport width\n * @returns True if tablet screen size\n * \n * @korean 태블릿확인\n */\nexport function isTabletSize(width: number): boolean {\n return getScreenSize(width) === 'tablet';\n}\n\n/**\n * Check if screen size is desktop or larger\n * \n * @param width - Viewport width\n * @returns True if desktop, large, or xlarge screen size\n * \n * @korean 데스크톱확인\n */\nexport function isDesktopSize(width: number): boolean {\n const size = getScreenSize(width);\n return size === 'desktop' || size === 'large' || size === 'xlarge';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ResponsiveScaling.js","names":[],"sources":["../../src/systems/ResponsiveScaling.ts"],"sourcesContent":["/**\n * Responsive Scaling System for Black Trigram\n * \n * Centralized scaling calculations for responsive layout across all screen sizes.\n * Implements proportional font and spacing scaling with smooth transitions.\n * \n * Features:\n * - Five screen size categories (mobile, tablet, desktop, large, xlarge)\n * - Font scaling: 0.8x (mobile) to 1.4x (4K displays)\n * - Spacing scaling: 0.5x (mobile) to 1.5x (4K displays)\n * - Korean text readability: 14-24px range enforced\n * - Smooth CSS transitions for resize operations\n * - 60fps performance maintained\n * \n * @module systems/ResponsiveScaling\n * @category Responsive Layout\n * @korean 반응형스케일시스템\n */\n\nimport type {\n ScreenSize,\n ResponsiveBreakpoints,\n FontScaleMap,\n SpacingScaleMap,\n ResponsiveScaleConfig,\n ResizeTransitionConfig,\n ResponsiveValues,\n ScreenSizeTestResult,\n} from '../types/ResponsiveTypes';\n\n// Re-export types for convenience\nexport type {\n ScreenSize,\n ResponsiveBreakpoints,\n FontScaleMap,\n SpacingScaleMap,\n ResponsiveScaleConfig,\n ResizeTransitionConfig,\n ResponsiveValues,\n ScreenSizeTestResult,\n};\n\n/**\n * Standard breakpoints for responsive design\n * Maps viewport widths to device categories\n * \n * Note: XLARGE is defined as a reference value (2560px) but xlarge category\n * starts at LARGE (1920px). This allows for consistent scaling across all\n * displays from 1920px upwards, including 2K, 4K, and ultra-wide monitors.\n * \n * @constant\n * @category Responsive Layout\n */\nexport const RESPONSIVE_BREAKPOINTS: ResponsiveBreakpoints = {\n MOBILE: 768, // < 768px: Mobile devices\n TABLET: 1024, // 768-1024px: Tablets\n DESKTOP: 1440, // 1024-1440px: Standard desktop\n LARGE: 1920, // 1440-1920px: HD/2K displays\n XLARGE: 2560, // Reference for 4K displays (xlarge starts at 1920px)\n} as const;\n\n/**\n * Font scaling multipliers by screen size\n * Base size (16px) * scale = final size\n * \n * Results clamped to 14-24px for readability\n * \n * @constant\n * @category Typography\n */\nexport const FONT_SCALE_MAP: FontScaleMap = {\n mobile: 0.8, // 16px * 0.8 = 12.8px → clamped to 14px min\n tablet: 0.9, // 16px * 0.9 = 14.4px\n desktop: 1.0, // 16px * 1.0 = 16px (base)\n large: 1.2, // 16px * 1.2 = 19.2px\n xlarge: 1.4, // 16px * 1.4 = 22.4px → clamped to 24px max\n} as const;\n\n/**\n * Spacing scaling multipliers by screen size\n * Base spacing * scale = final spacing\n * \n * @constant\n * @category Layout\n */\nexport const SPACING_SCALE_MAP: SpacingScaleMap = {\n mobile: 0.5, // Compact spacing for small screens\n tablet: 0.75, // Moderate spacing for tablets\n desktop: 1.0, // Standard reference spacing\n large: 1.25, // Spacious for large displays\n xlarge: 1.5, // Maximum spacing for 4K\n} as const;\n\n/**\n * Default transition configuration for smooth resizing\n * Optimized for 60fps performance\n * \n * @constant\n * @category Animation\n */\nexport const DEFAULT_RESIZE_TRANSITION: ResizeTransitionConfig = {\n duration: '300ms',\n easing: 'ease-in-out',\n properties: ['font-size', 'padding', 'margin', 'width', 'height'] as const,\n enabled: true,\n} as const;\n\n/**\n * Font size constraints for Korean and English text\n * Ensures readability across all screen sizes\n * \n * @constant\n * @category Typography\n */\nexport const FONT_SIZE_CONSTRAINTS = {\n /** Minimum body text size for readability */\n MIN_BODY_SIZE: 14,\n /** Maximum size before text becomes too large */\n MAX_SIZE: 24,\n /** Base reference size (desktop) */\n BASE_SIZE: 16,\n} as const;\n\n/**\n * Determine screen size category from viewport width\n * \n * Categories:\n * - mobile: < 768px (phones)\n * - tablet: 768-1024px (tablets)\n * - desktop: 1024-1440px (standard monitors)\n * - large: 1440-1920px (HD/2K displays)\n * - xlarge: ≥1920px (4K/ultra-wide)\n * \n * @param width - Viewport width in pixels\n * @returns Screen size category\n * \n * @example\n * ```typescript\n * getScreenSize(375); // 'mobile'\n * getScreenSize(768); // 'tablet'\n * getScreenSize(1920); // 'xlarge'\n * ```\n * \n * @korean 화면크기얻기\n */\nexport function getScreenSize(width: number): ScreenSize {\n if (width < RESPONSIVE_BREAKPOINTS.MOBILE) return 'mobile';\n if (width < RESPONSIVE_BREAKPOINTS.TABLET) return 'tablet';\n if (width < RESPONSIVE_BREAKPOINTS.DESKTOP) return 'desktop';\n if (width < RESPONSIVE_BREAKPOINTS.LARGE) return 'large';\n return 'xlarge';\n}\n\n/**\n * Calculate scaled font size with readability constraints\n * \n * Formula: baseSize * scale\n * Clamped: max(minSize, min(maxSize, calculated))\n * \n * Ensures Korean and English text remain readable at all sizes\n * \n * @param baseSize - Base font size in pixels (typically 16px)\n * @param screenSize - Current screen size category\n * @param minSize - Minimum allowed size (default: 14px)\n * @param maxSize - Maximum allowed size (default: 24px)\n * @returns Calculated font size in pixels\n * \n * @example\n * ```typescript\n * calculateFontSize(16, 'mobile'); // 14 (clamped from 12.8)\n * calculateFontSize(16, 'desktop'); // 16\n * calculateFontSize(16, 'xlarge'); // 22.4\n * calculateFontSize(20, 'xlarge', 14, 24); // 24 (clamped from 28)\n * ```\n * \n * @korean 글꼴크기계산\n */\nexport function calculateFontSize(\n baseSize: number,\n screenSize: ScreenSize,\n minSize: number = FONT_SIZE_CONSTRAINTS.MIN_BODY_SIZE,\n maxSize: number = FONT_SIZE_CONSTRAINTS.MAX_SIZE\n): number {\n const scale = FONT_SCALE_MAP[screenSize];\n const scaled = baseSize * scale;\n \n // Clamp to readable range\n return Math.max(minSize, Math.min(maxSize, scaled));\n}\n\n/**\n * Calculate scaled spacing value\n * \n * Formula: baseSpacing * scale\n * Rounded to nearest integer for crisp rendering\n * \n * @param baseSpacing - Base spacing value in pixels\n * @param screenSize - Current screen size category\n * @returns Calculated spacing in pixels (rounded)\n * \n * @example\n * ```typescript\n * calculateSpacing(20, 'mobile'); // 10 (20 * 0.5)\n * calculateSpacing(20, 'desktop'); // 20\n * calculateSpacing(20, 'xlarge'); // 30 (20 * 1.5)\n * ```\n * \n * @korean 간격계산\n */\nexport function calculateSpacing(\n baseSpacing: number,\n screenSize: ScreenSize\n): number {\n const scale = SPACING_SCALE_MAP[screenSize];\n return Math.round(baseSpacing * scale);\n}\n\n/**\n * Get font scale multiplier for screen size\n * \n * @param screenSize - Screen size category\n * @returns Scale multiplier (0.8 - 1.4)\n * \n * @example\n * ```typescript\n * getFontScale('mobile'); // 0.8\n * getFontScale('desktop'); // 1.0\n * getFontScale('xlarge'); // 1.4\n * ```\n * \n * @korean 글꼴스케일얻기\n */\nexport function getFontScale(screenSize: ScreenSize): number {\n return FONT_SCALE_MAP[screenSize];\n}\n\n/**\n * Get spacing scale multiplier for screen size\n * \n * @param screenSize - Screen size category\n * @returns Scale multiplier (0.5 - 1.5)\n * \n * @example\n * ```typescript\n * getSpacingScale('mobile'); // 0.5\n * getSpacingScale('desktop'); // 1.0\n * getSpacingScale('xlarge'); // 1.5\n * ```\n * \n * @korean 간격스케일얻기\n */\nexport function getSpacingScale(screenSize: ScreenSize): number {\n return SPACING_SCALE_MAP[screenSize];\n}\n\n/**\n * Create CSS transition string for smooth resizing\n * \n * @param config - Transition configuration (optional)\n * @returns CSS transition string\n * \n * @example\n * ```typescript\n * createTransitionString();\n * // 'font-size 300ms ease-in-out, padding 300ms ease-in-out, ...'\n * \n * createTransitionString({ duration: '200ms', easing: 'linear' });\n * // 'font-size 200ms linear, padding 200ms linear, ...'\n * ```\n * \n * @korean 전환문자열생성\n */\nexport function createTransitionString(\n config: Partial<ResizeTransitionConfig> = {}\n): string {\n const {\n duration = DEFAULT_RESIZE_TRANSITION.duration,\n easing = DEFAULT_RESIZE_TRANSITION.easing,\n properties = DEFAULT_RESIZE_TRANSITION.properties,\n enabled = DEFAULT_RESIZE_TRANSITION.enabled,\n } = config;\n\n if (!enabled) {\n return 'none';\n }\n\n return properties\n .map((prop) => `${prop} ${duration} ${easing}`)\n .join(', ');\n}\n\n/**\n * Create complete responsive scale configuration\n * \n * @param width - Viewport width\n * @param height - Viewport height\n * @returns Complete responsive configuration\n * \n * @example\n * ```typescript\n * const config = createResponsiveConfig(375, 667);\n * console.log(config.screenSize); // 'mobile'\n * console.log(config.fontScale); // 0.8\n * console.log(config.spacingScale); // 0.5\n * ```\n * \n * @korean 반응형설정생성\n */\nexport function createResponsiveConfig(\n width: number,\n height: number\n): ResponsiveScaleConfig {\n const screenSize = getScreenSize(width);\n const fontScale = getFontScale(screenSize);\n const spacingScale = getSpacingScale(screenSize);\n\n return {\n screenSize,\n fontScale,\n spacingScale,\n viewport: { width, height },\n };\n}\n\n/**\n * Calculate all responsive values for a component\n * \n * Computes font sizes, spacing, and transitions based on screen size\n * Ready-to-use values for component styling\n * \n * @param width - Viewport width\n * @param baseFontSize - Base font size (default: 16px)\n * @param baseSpacing - Base spacing unit (default: 16px)\n * @returns Complete responsive values\n * \n * @example\n * ```typescript\n * const values = calculateResponsiveValues(375);\n * \n * <div style={{\n * fontSize: values.fontSize.body,\n * padding: values.spacing.md,\n * transition: values.transition,\n * }}>\n * Responsive content\n * </div>\n * ```\n * \n * @korean 반응형값계산\n */\nexport function calculateResponsiveValues(\n width: number,\n baseFontSize: number = FONT_SIZE_CONSTRAINTS.BASE_SIZE,\n baseSpacing: number = 16\n): ResponsiveValues {\n const screenSize = getScreenSize(width);\n \n // Calculate font sizes for all text levels\n const fontSize = {\n small: calculateFontSize(baseFontSize * 0.75, screenSize, 12, 18),\n body: calculateFontSize(baseFontSize, screenSize),\n title: calculateFontSize(baseFontSize * 1.5, screenSize, 18, 28),\n hero: calculateFontSize(baseFontSize * 2.25, screenSize, 24, 36),\n hud: calculateFontSize(baseFontSize * 1.25, screenSize, 16, 24),\n };\n\n // Calculate spacing scale\n const spacing = {\n xs: calculateSpacing(baseSpacing * 0.5, screenSize),\n sm: calculateSpacing(baseSpacing * 0.75, screenSize),\n md: calculateSpacing(baseSpacing, screenSize),\n lg: calculateSpacing(baseSpacing * 1.5, screenSize),\n xl: calculateSpacing(baseSpacing * 2, screenSize),\n };\n\n // Create transition string\n const transition = createTransitionString();\n\n return {\n fontSize,\n spacing,\n transition,\n };\n}\n\n/**\n * Test screen size determination for validation\n * \n * Useful for testing and debugging responsive breakpoints.\n * Screen size is determined by width (breakpoints), but height is included\n * in the result for testing portrait/landscape orientations.\n * \n * @param width - Viewport width to test\n * @param height - Viewport height to test\n * @returns Test result with screen size and device type flags\n * \n * @example\n * ```typescript\n * const result = testScreenSize(768, 1024);\n * console.log(result.screenSize); // 'tablet'\n * console.log(result.isTablet); // true\n * console.log(result.isMobile); // false\n * ```\n * \n * @korean 화면크기테스트\n */\nexport function testScreenSize(\n width: number,\n height: number\n): ScreenSizeTestResult {\n const screenSize = getScreenSize(width);\n const isLandscape = width > height;\n \n return {\n width,\n height,\n screenSize,\n isMobile: screenSize === 'mobile',\n isTablet: screenSize === 'tablet',\n isDesktop: screenSize === 'desktop' || screenSize === 'large' || screenSize === 'xlarge',\n // Include landscape in test result for completeness\n isLandscape,\n };\n}\n\n/**\n * Check if screen size is mobile\n * \n * @param width - Viewport width\n * @returns True if mobile screen size\n * \n * @korean 모바일확인\n */\nexport function isMobileSize(width: number): boolean {\n return getScreenSize(width) === 'mobile';\n}\n\n/**\n * Check if screen size is tablet\n * \n * @param width - Viewport width\n * @returns True if tablet screen size\n * \n * @korean 태블릿확인\n */\nexport function isTabletSize(width: number): boolean {\n return getScreenSize(width) === 'tablet';\n}\n\n/**\n * Check if screen size is desktop or larger\n * \n * @param width - Viewport width\n * @returns True if desktop, large, or xlarge screen size\n * \n * @korean 데스크톱확인\n */\nexport function isDesktopSize(width: number): boolean {\n const size = getScreenSize(width);\n return size === 'desktop' || size === 'large' || size === 'xlarge';\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TrigramSystem.js","names":[],"sources":["../../src/systems/TrigramSystem.ts"],"sourcesContent":["import { KoreanText, TrigramStance } from \"../types/common\";\nimport { PlayerState } from \"./player\";\n\nimport { TRIGRAM_STANCES_ORDER, TrigramTransitionCost } from \"./trigram\";\nimport { TrigramCalculator } from \"./trigram/TrigramCalculator\";\nimport { PLAYER_ARCHETYPES_DATA } from \"./types\";\n\n/**\n * Stance counter relationships based on I Ching philosophy\n * \n * Each stance has a counter stance that provides tactical advantage:\n * - **GEON (Heaven)** countered by **GAM (Water)** - Water flows around Heaven's force\n * - **TAE (Lake)** countered by **GON (Earth)** - Earth contains and grounds Lake\n * - **LI (Fire)** countered by **SON (Wind)** - Wind disperses Fire's intensity\n * - **JIN (Thunder)** countered by **GAN (Mountain)** - Mountain absorbs Thunder's impact\n * - **SON (Wind)** countered by **GEON (Heaven)** - Heaven's force overpowers Wind\n * - **GAM (Water)** countered by **TAE (Lake)** - Lake contains and channels Water\n * - **GAN (Mountain)** countered by **LI (Fire)** - Fire melts Mountain's solidity\n * - **GON (Earth)** countered by **JIN (Thunder)** - Thunder breaks Earth's stability\n * \n * Using a counter stance provides a 1.2x damage multiplier in combat.\n * \n * @korean 팔괘 상극 관계 (Eight Trigram Counter Relationships)\n */\nexport const STANCE_COUNTERS: Record<TrigramStance, TrigramStance> = {\n [TrigramStance.GEON]: TrigramStance.GAM, // Water flows around Heaven\n [TrigramStance.TAE]: TrigramStance.GON, // Earth grounds Lake\n [TrigramStance.LI]: TrigramStance.SON, // Wind disperses Fire\n [TrigramStance.JIN]: TrigramStance.GAN, // Mountain absorbs Thunder\n [TrigramStance.SON]: TrigramStance.GEON, // Heaven overpowers Wind\n [TrigramStance.GAM]: TrigramStance.TAE, // Lake contains Water\n [TrigramStance.GAN]: TrigramStance.LI, // Fire melts Mountain\n [TrigramStance.GON]: TrigramStance.JIN, // Thunder breaks Earth\n};\n\n/**\n * Counter stance damage multiplier\n * Applied when using a counter stance against opponent's stance\n * \n * @korean 상극 자세 피해 배율\n */\nexport const COUNTER_STANCE_DAMAGE_MULTIPLIER = 1.2;\n\n/**\n * Apply counter stance damage bonus when appropriate.\n *\n * This helper should be used by combat damage calculation code after it has\n * determined whether the current stance matchup is a counter stance\n * (for example, via an `isCounterStance` check elsewhere in the system).\n *\n * When `isCounterStance` is `true`, the base damage is multiplied by\n * {@link COUNTER_STANCE_DAMAGE_MULTIPLIER}. Non-positive damage values are\n * returned unchanged to avoid introducing invalid negative or zero scaling.\n *\n * @param baseDamage - The pre-modifier damage value.\n * @param isCounterStance - Whether the attacker is using a counter stance.\n * @returns The adjusted damage value with counter stance bonus applied when relevant.\n *\n * @example\n * ```ts\n * const isCounter = trigramSystem.isCounterStance(attackerStance, defenderStance);\n * const finalDamage = applyCounterStanceDamage(baseDamage, isCounter);\n * ```\n *\n * @korean\n * 반격 자세(상극 자세)일 때만 피해 배율(1.2배)을 적용합니다.\n */\nexport function applyCounterStanceDamage(\n baseDamage: number,\n isCounterStance: boolean\n): number {\n if (!isCounterStance || baseDamage <= 0) {\n return baseDamage;\n }\n\n return baseDamage * COUNTER_STANCE_DAMAGE_MULTIPLIER;\n}\n\n/**\n * System for managing Eight Trigram (팔괘) stance transitions and combat calculations.\n *\n * **Korean**: 팔괘 시스템 (Eight Trigram System)\n *\n * The TrigramSystem implements the core mechanics of the Eight Trigram martial arts system,\n * managing stance transitions, calculating effectiveness, and determining resource costs.\n * Based on I Ching (易經) philosophy adapted for tactical combat.\n *\n * ## Key Responsibilities\n *\n * - Validate stance transitions based on Ki and Stamina costs\n * - Calculate transition difficulty between stances\n * - Recommend optimal stance choices\n * - Determine stance effectiveness in combat matchups\n * - Apply archetype-specific modifiers to transitions\n *\n * @example\n * ```typescript\n * const trigramSystem = new TrigramSystem();\n *\n * // Check if transition is possible\n * const canTransition = trigramSystem.canTransitionTo(\n * TrigramStance.GEON,\n * TrigramStance.GAM,\n * playerState\n * );\n *\n * // Get recommended stance\n * const recommendedStance = trigramSystem.recommendStance(playerState);\n * ```\n *\n * @category Trigram System\n * @korean 팔괘시스템\n */\nexport class TrigramSystem {\n private calculator: TrigramCalculator;\n\n /**\n * Creates a new TrigramSystem instance.\n *\n * Initializes the internal calculator for stance effectiveness and transition difficulty.\n */\n constructor() {\n this.calculator = new TrigramCalculator();\n }\n\n /**\n * Gets the defensive/offensive characteristic of a stance.\n *\n * **Korean**: 자세 특성 조회 (Stance Characteristic Query)\n *\n * Returns whether a stance is primarily defensive, offensive, or balanced.\n * This information is useful for UI display and tactical decision-making.\n *\n * ## Stance Classifications\n *\n * - **Defensive**: 간 (GAN/Mountain), 곤 (GON/Earth) - Protect vital areas\n * - **Offensive**: 건 (GEON/Heaven), 진 (JIN/Thunder) - Expose for power\n * - **Balanced**: 태 (TAE/Lake), 리 (LI/Fire), 손 (SON/Wind), 감 (GAM/Water)\n *\n * @param stance - Trigram stance to query\n * @returns \"defensive\", \"offensive\", or \"balanced\"\n *\n * @example\n * ```typescript\n * const characteristic = trigramSystem.getStanceCharacteristic(TrigramStance.GAN);\n * console.log(characteristic); // \"defensive\"\n *\n * const offensive = trigramSystem.getStanceCharacteristic(TrigramStance.GEON);\n * console.log(offensive); // \"offensive\"\n * ```\n *\n * @korean 자세특성조회\n */\n getStanceCharacteristic(\n stance: TrigramStance\n ): \"defensive\" | \"offensive\" | \"balanced\" {\n switch (stance) {\n case TrigramStance.GAN: // Mountain - Immovable defense\n case TrigramStance.GON: // Earth - Grounding and stability\n return \"defensive\";\n\n case TrigramStance.GEON: // Heaven - Direct force and aggression\n case TrigramStance.JIN: // Thunder - Explosive power\n return \"offensive\";\n\n default:\n return \"balanced\";\n }\n }\n\n /**\n * Checks if a stance provides defensive advantages.\n *\n * **Korean**: 방어 자세 확인 (Check Defensive Stance)\n *\n * @param stance - Trigram stance to check\n * @returns true if stance is defensive, false otherwise\n *\n * @example\n * ```typescript\n * if (trigramSystem.isDefensiveStance(player.currentStance)) {\n * console.log(\"Player is in defensive posture\");\n * }\n * ```\n *\n * @korean 방어자세확인\n */\n isDefensiveStance(stance: TrigramStance): boolean {\n return this.getStanceCharacteristic(stance) === \"defensive\";\n }\n\n /**\n * Checks if a stance provides offensive advantages.\n *\n * **Korean**: 공격 자세 확인 (Check Offensive Stance)\n *\n * @param stance - Trigram stance to check\n * @returns true if stance is offensive, false otherwise\n *\n * @example\n * ```typescript\n * if (trigramSystem.isOffensiveStance(player.currentStance)) {\n * console.log(\"Player is in offensive posture\");\n * }\n * ```\n *\n * @korean 공격자세확인\n */\n isOffensiveStance(stance: TrigramStance): boolean {\n return this.getStanceCharacteristic(stance) === \"offensive\";\n }\n\n /**\n * Checks if a player can transition from one stance to another.\n *\n * Validates that the player has sufficient Ki (氣) and Stamina resources\n * to perform the stance transition. Same-stance transitions are always valid.\n *\n * @param fromStance - Current stance\n * @param toStance - Target stance\n * @param player - Player state with current Ki and Stamina\n * @returns true if transition is possible, false otherwise\n *\n * @example\n * ```typescript\n * const canChange = trigramSystem.canTransitionTo(\n * TrigramStance.GEON, // From Heaven\n * TrigramStance.GON, // To Earth\n * player\n * );\n * ```\n *\n * @korean 자세전환가능확인\n */\n canTransitionTo(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n player: PlayerState\n ): boolean {\n if (fromStance === toStance) return true;\n\n const cost = this.getTransitionCost(fromStance, toStance, player);\n\n // Check if player has sufficient resources\n const hasEnoughKi = player.ki >= cost.ki;\n const hasEnoughStamina = player.stamina >= cost.stamina;\n\n return hasEnoughKi && hasEnoughStamina;\n }\n\n /**\n * Recommends the optimal stance for current combat situation.\n *\n * Calculates the least-cost stance transition from the player's current position.\n * Uses combined cost of Ki, Stamina, and transition time to determine best option.\n *\n * **Algorithm**: Evaluates all eight stances and selects the one with minimum\n * total cost (Ki + Stamina + Time).\n *\n * @param player - Player state with current stance\n * @returns Recommended stance to transition to\n *\n * @example\n * ```typescript\n * const recommended = trigramSystem.recommendStance(player);\n * console.log(`Consider switching to ${recommended}`);\n * ```\n *\n * @korean 최적자세추천\n */\n recommendStance(player: PlayerState): TrigramStance {\n const from = player.currentStance;\n let best = from;\n let bestScore = Infinity;\n\n for (const to of TRIGRAM_STANCES_ORDER) {\n const costObj: TrigramTransitionCost = this.getTransitionCost(from, to);\n const score = costObj.ki + costObj.stamina + costObj.timeMilliseconds;\n if (score < bestScore) {\n bestScore = score;\n best = to;\n }\n }\n\n return best;\n }\n\n /**\n * Calculates the resource cost for transitioning between stances.\n *\n * Determines Ki, Stamina, and time costs based on the I Ching philosophical\n * distance between trigrams. Applies archetype-specific modifiers for favored stances.\n *\n * ## Cost Calculation\n *\n * - **Base Cost**: 10 Ki, 15 Stamina per difficulty point\n * - **Base Time**: 500ms per difficulty point\n * - **Archetype Modifier**: 0.8x for favored stances, 1.0x otherwise\n * - **Same Stance**: Zero cost\n *\n * @param from - Starting stance\n * @param to - Target stance\n * @param player - Optional player for archetype modifiers\n * @returns Transition cost breakdown\n *\n * @example\n * ```typescript\n * const cost = trigramSystem.getTransitionCost(\n * TrigramStance.GEON,\n * TrigramStance.TAE,\n * player\n * );\n * console.log(`Cost: ${cost.ki} Ki, ${cost.stamina} Stamina`);\n * ```\n *\n * @korean 자세전환비용\n */\n public getTransitionCost(\n from: TrigramStance,\n to: TrigramStance,\n player?: PlayerState\n ): TrigramTransitionCost {\n if (from === to) {\n return {\n ki: 0,\n stamina: 0,\n timeMilliseconds: 0, // neutral\n };\n }\n\n const difficulty = TrigramCalculator.calculateTransitionDifficulty(\n from,\n to\n );\n const baseCost = 10;\n const baseTime = 500;\n\n let ki = Math.ceil(baseCost * difficulty);\n let stamina = Math.ceil(baseCost * difficulty * 1.5);\n\n // apply archetype stance‐change cost modifier if player provided\n if (player) {\n const archData = PLAYER_ARCHETYPES_DATA[player.archetype];\n const favs = archData.favoredStances || [];\n const mod = favs.includes(to) ? 0.8 : 1.0;\n ki = Math.ceil(ki * mod);\n stamina = Math.ceil(stamina * mod);\n }\n\n return {\n ki,\n stamina,\n timeMilliseconds: Math.ceil(baseTime * difficulty),\n };\n }\n\n /**\n * Calculates stance effectiveness in combat matchup.\n *\n * Determines the multiplier advantage/disadvantage when one stance attacks another.\n * Based on I Ching elemental relationships (e.g., Water extinguishes Fire).\n *\n * @param attackerStance - Attacking player's stance\n * @param defenderStance - Defending player's stance\n * @returns Effectiveness multiplier (0.5 = disadvantage, 1.0 = neutral, 1.5 = advantage)\n *\n * @example\n * ```typescript\n * const effectiveness = trigramSystem.calculateStanceEffectiveness(\n * TrigramStance.GAM, // Water\n * TrigramStance.LI // Fire\n * ); // Returns > 1.0 (Water beats Fire)\n * ```\n *\n * @korean 자세효과성계산\n */\n calculateStanceEffectiveness(\n attackerStance: TrigramStance,\n defenderStance: TrigramStance\n ): number {\n return this.calculator.calculateStanceEffectiveness(\n attackerStance,\n defenderStance\n );\n }\n\n /**\n * Gets bilingual name for a stance.\n *\n * Returns Korean (Hangul) and English names for display purposes.\n *\n * @param stance - Stance to get name for\n * @returns Object with korean and english name properties\n *\n * @example\n * ```typescript\n * const name = trigramSystem.getStanceName(TrigramStance.GEON);\n * console.log(`${name.korean} (${name.english})`); // \"건 (Heaven)\"\n * ```\n *\n * @korean 자세이름조회\n */\n getStanceName(stance: TrigramStance): { korean: string; english: string } {\n const stanceNames = {\n [TrigramStance.GEON]: { korean: \"건\", english: \"Heaven\" },\n [TrigramStance.TAE]: { korean: \"태\", english: \"Lake\" },\n [TrigramStance.LI]: { korean: \"리\", english: \"Fire\" },\n [TrigramStance.JIN]: { korean: \"진\", english: \"Thunder\" },\n [TrigramStance.SON]: { korean: \"손\", english: \"Wind\" },\n [TrigramStance.GAM]: { korean: \"감\", english: \"Water\" },\n [TrigramStance.GAN]: { korean: \"간\", english: \"Mountain\" },\n [TrigramStance.GON]: { korean: \"곤\", english: \"Earth\" },\n };\n\n return stanceNames[stance] || { korean: \"Unknown\", english: \"Unknown\" };\n }\n\n /**\n * Gets the counter stance for opponent's current stance.\n * \n * Returns the stance that provides tactical advantage against the opponent's stance,\n * based on I Ching elemental relationships. Using a counter stance provides a 1.2x\n * damage multiplier in combat.\n * \n * **Korean Philosophy (상극 자세)**:\n * - Water counters Heaven (flows around force)\n * - Earth counters Lake (grounds and contains)\n * - Wind counters Fire (disperses intensity)\n * - Mountain counters Thunder (absorbs impact)\n * \n * @param opponentStance - Opponent's current stance\n * @returns Counter stance that provides advantage\n * \n * @example\n * ```typescript\n * const counterStance = trigramSystem.getCounterStance(TrigramStance.GEON);\n * console.log(counterStance); // TrigramStance.GAM (Water counters Heaven)\n * ```\n * \n * @korean 상극자세조회\n */\n getCounterStance(opponentStance: TrigramStance): TrigramStance {\n return STANCE_COUNTERS[opponentStance];\n }\n\n /**\n * Checks if player's stance counters opponent's stance.\n * \n * Determines if the player has a tactical advantage through stance matchup.\n * When true, player should receive a 1.2x damage multiplier for attacks.\n * \n * @param myStance - Player's current stance\n * @param opponentStance - Opponent's current stance\n * @returns True if player's stance counters opponent's stance\n * \n * @example\n * ```typescript\n * const hasAdvantage = trigramSystem.isCounterStance(\n * TrigramStance.GAM, // My stance: Water\n * TrigramStance.GEON // Opponent: Heaven\n * ); // Returns true - Water counters Heaven\n * \n * if (hasAdvantage) {\n * damage *= 1.2; // Apply counter bonus\n * }\n * ```\n * \n * @korean 상극자세확인\n */\n isCounterStance(myStance: TrigramStance, opponentStance: TrigramStance): boolean {\n return this.getCounterStance(opponentStance) === myStance;\n }\n\n /**\n * Gets complete stance data for UI display.\n *\n * Returns structured data object containing stance ID and bilingual names.\n *\n * @param stance - Stance to get data for\n * @returns Stance data object\n *\n * @korean 자세데이터조회\n */\n getCurrentStanceData(stance: TrigramStance): {\n id: TrigramStance;\n name: KoreanText;\n korean: string;\n english: string;\n } {\n const stanceName = this.getStanceName(stance);\n return {\n id: stance,\n name: stanceName,\n korean: stanceName.korean,\n english: stanceName.english,\n };\n }\n\n /**\n * Validates a stance transition with detailed feedback.\n *\n * Checks if transition is valid and provides reason if not.\n * More detailed than {@link canTransitionTo}, includes specific failure reasons.\n *\n * @param fromStance - Current stance\n * @param toStance - Target stance\n * @param player - Player state\n * @returns Validation result with optional failure reason\n *\n * @example\n * ```typescript\n * const validation = trigramSystem.validateTransition(\n * TrigramStance.GEON,\n * TrigramStance.GON,\n * player\n * );\n * if (!validation.valid) {\n * console.error(validation.reason);\n * }\n * ```\n *\n * @korean 자세전환검증\n */\n validateTransition(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n player: PlayerState\n ): { valid: boolean; reason?: string } {\n if (fromStance === toStance) {\n return { valid: true };\n }\n\n const cost = this.getTransitionCost(fromStance, toStance, player);\n\n if (player.ki < cost.ki) {\n return {\n valid: false,\n reason: `Insufficient Ki: need ${cost.ki}, have ${player.ki}`,\n };\n }\n\n if (player.stamina < cost.stamina) {\n return {\n valid: false,\n reason: `Insufficient Stamina: need ${cost.stamina}, have ${player.stamina}`,\n };\n }\n\n return { valid: true };\n }\n}\n\nexport default TrigramSystem;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TrigramSystem.js","names":[],"sources":["../../src/systems/TrigramSystem.ts"],"sourcesContent":["import { KoreanText, TrigramStance } from \"../types/common\";\nimport { PlayerState } from \"./player\";\n\nimport { TRIGRAM_STANCES_ORDER, TrigramTransitionCost } from \"./trigram\";\nimport { TrigramCalculator } from \"./trigram/TrigramCalculator\";\nimport { PLAYER_ARCHETYPES_DATA } from \"./types\";\n\n/**\n * Stance counter relationships based on I Ching philosophy\n * \n * Each stance has a counter stance that provides tactical advantage:\n * - **GEON (Heaven)** countered by **GAM (Water)** - Water flows around Heaven's force\n * - **TAE (Lake)** countered by **GON (Earth)** - Earth contains and grounds Lake\n * - **LI (Fire)** countered by **SON (Wind)** - Wind disperses Fire's intensity\n * - **JIN (Thunder)** countered by **GAN (Mountain)** - Mountain absorbs Thunder's impact\n * - **SON (Wind)** countered by **GEON (Heaven)** - Heaven's force overpowers Wind\n * - **GAM (Water)** countered by **TAE (Lake)** - Lake contains and channels Water\n * - **GAN (Mountain)** countered by **LI (Fire)** - Fire melts Mountain's solidity\n * - **GON (Earth)** countered by **JIN (Thunder)** - Thunder breaks Earth's stability\n * \n * Using a counter stance provides a 1.2x damage multiplier in combat.\n * \n * @korean 팔괘 상극 관계 (Eight Trigram Counter Relationships)\n */\nexport const STANCE_COUNTERS: Record<TrigramStance, TrigramStance> = {\n [TrigramStance.GEON]: TrigramStance.GAM, // Water flows around Heaven\n [TrigramStance.TAE]: TrigramStance.GON, // Earth grounds Lake\n [TrigramStance.LI]: TrigramStance.SON, // Wind disperses Fire\n [TrigramStance.JIN]: TrigramStance.GAN, // Mountain absorbs Thunder\n [TrigramStance.SON]: TrigramStance.GEON, // Heaven overpowers Wind\n [TrigramStance.GAM]: TrigramStance.TAE, // Lake contains Water\n [TrigramStance.GAN]: TrigramStance.LI, // Fire melts Mountain\n [TrigramStance.GON]: TrigramStance.JIN, // Thunder breaks Earth\n};\n\n/**\n * Counter stance damage multiplier\n * Applied when using a counter stance against opponent's stance\n * \n * @korean 상극 자세 피해 배율\n */\nexport const COUNTER_STANCE_DAMAGE_MULTIPLIER = 1.2;\n\n/**\n * Apply counter stance damage bonus when appropriate.\n *\n * This helper should be used by combat damage calculation code after it has\n * determined whether the current stance matchup is a counter stance\n * (for example, via an `isCounterStance` check elsewhere in the system).\n *\n * When `isCounterStance` is `true`, the base damage is multiplied by\n * {@link COUNTER_STANCE_DAMAGE_MULTIPLIER}. Non-positive damage values are\n * returned unchanged to avoid introducing invalid negative or zero scaling.\n *\n * @param baseDamage - The pre-modifier damage value.\n * @param isCounterStance - Whether the attacker is using a counter stance.\n * @returns The adjusted damage value with counter stance bonus applied when relevant.\n *\n * @example\n * ```ts\n * const isCounter = trigramSystem.isCounterStance(attackerStance, defenderStance);\n * const finalDamage = applyCounterStanceDamage(baseDamage, isCounter);\n * ```\n *\n * @korean\n * 반격 자세(상극 자세)일 때만 피해 배율(1.2배)을 적용합니다.\n */\nexport function applyCounterStanceDamage(\n baseDamage: number,\n isCounterStance: boolean\n): number {\n if (!isCounterStance || baseDamage <= 0) {\n return baseDamage;\n }\n\n return baseDamage * COUNTER_STANCE_DAMAGE_MULTIPLIER;\n}\n\n/**\n * System for managing Eight Trigram (팔괘) stance transitions and combat calculations.\n *\n * **Korean**: 팔괘 시스템 (Eight Trigram System)\n *\n * The TrigramSystem implements the core mechanics of the Eight Trigram martial arts system,\n * managing stance transitions, calculating effectiveness, and determining resource costs.\n * Based on I Ching (易經) philosophy adapted for tactical combat.\n *\n * ## Key Responsibilities\n *\n * - Validate stance transitions based on Ki and Stamina costs\n * - Calculate transition difficulty between stances\n * - Recommend optimal stance choices\n * - Determine stance effectiveness in combat matchups\n * - Apply archetype-specific modifiers to transitions\n *\n * @example\n * ```typescript\n * const trigramSystem = new TrigramSystem();\n *\n * // Check if transition is possible\n * const canTransition = trigramSystem.canTransitionTo(\n * TrigramStance.GEON,\n * TrigramStance.GAM,\n * playerState\n * );\n *\n * // Get recommended stance\n * const recommendedStance = trigramSystem.recommendStance(playerState);\n * ```\n *\n * @category Trigram System\n * @korean 팔괘시스템\n */\nexport class TrigramSystem {\n private calculator: TrigramCalculator;\n\n /**\n * Creates a new TrigramSystem instance.\n *\n * Initializes the internal calculator for stance effectiveness and transition difficulty.\n */\n constructor() {\n this.calculator = new TrigramCalculator();\n }\n\n /**\n * Gets the defensive/offensive characteristic of a stance.\n *\n * **Korean**: 자세 특성 조회 (Stance Characteristic Query)\n *\n * Returns whether a stance is primarily defensive, offensive, or balanced.\n * This information is useful for UI display and tactical decision-making.\n *\n * ## Stance Classifications\n *\n * - **Defensive**: 간 (GAN/Mountain), 곤 (GON/Earth) - Protect vital areas\n * - **Offensive**: 건 (GEON/Heaven), 진 (JIN/Thunder) - Expose for power\n * - **Balanced**: 태 (TAE/Lake), 리 (LI/Fire), 손 (SON/Wind), 감 (GAM/Water)\n *\n * @param stance - Trigram stance to query\n * @returns \"defensive\", \"offensive\", or \"balanced\"\n *\n * @example\n * ```typescript\n * const characteristic = trigramSystem.getStanceCharacteristic(TrigramStance.GAN);\n * console.log(characteristic); // \"defensive\"\n *\n * const offensive = trigramSystem.getStanceCharacteristic(TrigramStance.GEON);\n * console.log(offensive); // \"offensive\"\n * ```\n *\n * @korean 자세특성조회\n */\n getStanceCharacteristic(\n stance: TrigramStance\n ): \"defensive\" | \"offensive\" | \"balanced\" {\n switch (stance) {\n case TrigramStance.GAN: // Mountain - Immovable defense\n case TrigramStance.GON: // Earth - Grounding and stability\n return \"defensive\";\n\n case TrigramStance.GEON: // Heaven - Direct force and aggression\n case TrigramStance.JIN: // Thunder - Explosive power\n return \"offensive\";\n\n default:\n return \"balanced\";\n }\n }\n\n /**\n * Checks if a stance provides defensive advantages.\n *\n * **Korean**: 방어 자세 확인 (Check Defensive Stance)\n *\n * @param stance - Trigram stance to check\n * @returns true if stance is defensive, false otherwise\n *\n * @example\n * ```typescript\n * if (trigramSystem.isDefensiveStance(player.currentStance)) {\n * console.log(\"Player is in defensive posture\");\n * }\n * ```\n *\n * @korean 방어자세확인\n */\n isDefensiveStance(stance: TrigramStance): boolean {\n return this.getStanceCharacteristic(stance) === \"defensive\";\n }\n\n /**\n * Checks if a stance provides offensive advantages.\n *\n * **Korean**: 공격 자세 확인 (Check Offensive Stance)\n *\n * @param stance - Trigram stance to check\n * @returns true if stance is offensive, false otherwise\n *\n * @example\n * ```typescript\n * if (trigramSystem.isOffensiveStance(player.currentStance)) {\n * console.log(\"Player is in offensive posture\");\n * }\n * ```\n *\n * @korean 공격자세확인\n */\n isOffensiveStance(stance: TrigramStance): boolean {\n return this.getStanceCharacteristic(stance) === \"offensive\";\n }\n\n /**\n * Checks if a player can transition from one stance to another.\n *\n * Validates that the player has sufficient Ki (氣) and Stamina resources\n * to perform the stance transition. Same-stance transitions are always valid.\n *\n * @param fromStance - Current stance\n * @param toStance - Target stance\n * @param player - Player state with current Ki and Stamina\n * @returns true if transition is possible, false otherwise\n *\n * @example\n * ```typescript\n * const canChange = trigramSystem.canTransitionTo(\n * TrigramStance.GEON, // From Heaven\n * TrigramStance.GON, // To Earth\n * player\n * );\n * ```\n *\n * @korean 자세전환가능확인\n */\n canTransitionTo(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n player: PlayerState\n ): boolean {\n if (fromStance === toStance) return true;\n\n const cost = this.getTransitionCost(fromStance, toStance, player);\n\n // Check if player has sufficient resources\n const hasEnoughKi = player.ki >= cost.ki;\n const hasEnoughStamina = player.stamina >= cost.stamina;\n\n return hasEnoughKi && hasEnoughStamina;\n }\n\n /**\n * Recommends the optimal stance for current combat situation.\n *\n * Calculates the least-cost stance transition from the player's current position.\n * Uses combined cost of Ki, Stamina, and transition time to determine best option.\n *\n * **Algorithm**: Evaluates all eight stances and selects the one with minimum\n * total cost (Ki + Stamina + Time).\n *\n * @param player - Player state with current stance\n * @returns Recommended stance to transition to\n *\n * @example\n * ```typescript\n * const recommended = trigramSystem.recommendStance(player);\n * console.log(`Consider switching to ${recommended}`);\n * ```\n *\n * @korean 최적자세추천\n */\n recommendStance(player: PlayerState): TrigramStance {\n const from = player.currentStance;\n let best = from;\n let bestScore = Infinity;\n\n for (const to of TRIGRAM_STANCES_ORDER) {\n const costObj: TrigramTransitionCost = this.getTransitionCost(from, to);\n const score = costObj.ki + costObj.stamina + costObj.timeMilliseconds;\n if (score < bestScore) {\n bestScore = score;\n best = to;\n }\n }\n\n return best;\n }\n\n /**\n * Calculates the resource cost for transitioning between stances.\n *\n * Determines Ki, Stamina, and time costs based on the I Ching philosophical\n * distance between trigrams. Applies archetype-specific modifiers for favored stances.\n *\n * ## Cost Calculation\n *\n * - **Base Cost**: 10 Ki, 15 Stamina per difficulty point\n * - **Base Time**: 500ms per difficulty point\n * - **Archetype Modifier**: 0.8x for favored stances, 1.0x otherwise\n * - **Same Stance**: Zero cost\n *\n * @param from - Starting stance\n * @param to - Target stance\n * @param player - Optional player for archetype modifiers\n * @returns Transition cost breakdown\n *\n * @example\n * ```typescript\n * const cost = trigramSystem.getTransitionCost(\n * TrigramStance.GEON,\n * TrigramStance.TAE,\n * player\n * );\n * console.log(`Cost: ${cost.ki} Ki, ${cost.stamina} Stamina`);\n * ```\n *\n * @korean 자세전환비용\n */\n public getTransitionCost(\n from: TrigramStance,\n to: TrigramStance,\n player?: PlayerState\n ): TrigramTransitionCost {\n if (from === to) {\n return {\n ki: 0,\n stamina: 0,\n timeMilliseconds: 0, // neutral\n };\n }\n\n const difficulty = TrigramCalculator.calculateTransitionDifficulty(\n from,\n to\n );\n const baseCost = 10;\n const baseTime = 500;\n\n let ki = Math.ceil(baseCost * difficulty);\n let stamina = Math.ceil(baseCost * difficulty * 1.5);\n\n // apply archetype stance‐change cost modifier if player provided\n if (player) {\n const archData = PLAYER_ARCHETYPES_DATA[player.archetype];\n const favs = archData.favoredStances || [];\n const mod = favs.includes(to) ? 0.8 : 1.0;\n ki = Math.ceil(ki * mod);\n stamina = Math.ceil(stamina * mod);\n }\n\n return {\n ki,\n stamina,\n timeMilliseconds: Math.ceil(baseTime * difficulty),\n };\n }\n\n /**\n * Calculates stance effectiveness in combat matchup.\n *\n * Determines the multiplier advantage/disadvantage when one stance attacks another.\n * Based on I Ching elemental relationships (e.g., Water extinguishes Fire).\n *\n * @param attackerStance - Attacking player's stance\n * @param defenderStance - Defending player's stance\n * @returns Effectiveness multiplier (0.5 = disadvantage, 1.0 = neutral, 1.5 = advantage)\n *\n * @example\n * ```typescript\n * const effectiveness = trigramSystem.calculateStanceEffectiveness(\n * TrigramStance.GAM, // Water\n * TrigramStance.LI // Fire\n * ); // Returns > 1.0 (Water beats Fire)\n * ```\n *\n * @korean 자세효과성계산\n */\n calculateStanceEffectiveness(\n attackerStance: TrigramStance,\n defenderStance: TrigramStance\n ): number {\n return this.calculator.calculateStanceEffectiveness(\n attackerStance,\n defenderStance\n );\n }\n\n /**\n * Gets bilingual name for a stance.\n *\n * Returns Korean (Hangul) and English names for display purposes.\n *\n * @param stance - Stance to get name for\n * @returns Object with korean and english name properties\n *\n * @example\n * ```typescript\n * const name = trigramSystem.getStanceName(TrigramStance.GEON);\n * console.log(`${name.korean} (${name.english})`); // \"건 (Heaven)\"\n * ```\n *\n * @korean 자세이름조회\n */\n getStanceName(stance: TrigramStance): { korean: string; english: string } {\n const stanceNames = {\n [TrigramStance.GEON]: { korean: \"건\", english: \"Heaven\" },\n [TrigramStance.TAE]: { korean: \"태\", english: \"Lake\" },\n [TrigramStance.LI]: { korean: \"리\", english: \"Fire\" },\n [TrigramStance.JIN]: { korean: \"진\", english: \"Thunder\" },\n [TrigramStance.SON]: { korean: \"손\", english: \"Wind\" },\n [TrigramStance.GAM]: { korean: \"감\", english: \"Water\" },\n [TrigramStance.GAN]: { korean: \"간\", english: \"Mountain\" },\n [TrigramStance.GON]: { korean: \"곤\", english: \"Earth\" },\n };\n\n return stanceNames[stance] || { korean: \"Unknown\", english: \"Unknown\" };\n }\n\n /**\n * Gets the counter stance for opponent's current stance.\n * \n * Returns the stance that provides tactical advantage against the opponent's stance,\n * based on I Ching elemental relationships. Using a counter stance provides a 1.2x\n * damage multiplier in combat.\n * \n * **Korean Philosophy (상극 자세)**:\n * - Water counters Heaven (flows around force)\n * - Earth counters Lake (grounds and contains)\n * - Wind counters Fire (disperses intensity)\n * - Mountain counters Thunder (absorbs impact)\n * \n * @param opponentStance - Opponent's current stance\n * @returns Counter stance that provides advantage\n * \n * @example\n * ```typescript\n * const counterStance = trigramSystem.getCounterStance(TrigramStance.GEON);\n * console.log(counterStance); // TrigramStance.GAM (Water counters Heaven)\n * ```\n * \n * @korean 상극자세조회\n */\n getCounterStance(opponentStance: TrigramStance): TrigramStance {\n return STANCE_COUNTERS[opponentStance];\n }\n\n /**\n * Checks if player's stance counters opponent's stance.\n * \n * Determines if the player has a tactical advantage through stance matchup.\n * When true, player should receive a 1.2x damage multiplier for attacks.\n * \n * @param myStance - Player's current stance\n * @param opponentStance - Opponent's current stance\n * @returns True if player's stance counters opponent's stance\n * \n * @example\n * ```typescript\n * const hasAdvantage = trigramSystem.isCounterStance(\n * TrigramStance.GAM, // My stance: Water\n * TrigramStance.GEON // Opponent: Heaven\n * ); // Returns true - Water counters Heaven\n * \n * if (hasAdvantage) {\n * damage *= 1.2; // Apply counter bonus\n * }\n * ```\n * \n * @korean 상극자세확인\n */\n isCounterStance(myStance: TrigramStance, opponentStance: TrigramStance): boolean {\n return this.getCounterStance(opponentStance) === myStance;\n }\n\n /**\n * Gets complete stance data for UI display.\n *\n * Returns structured data object containing stance ID and bilingual names.\n *\n * @param stance - Stance to get data for\n * @returns Stance data object\n *\n * @korean 자세데이터조회\n */\n getCurrentStanceData(stance: TrigramStance): {\n id: TrigramStance;\n name: KoreanText;\n korean: string;\n english: string;\n } {\n const stanceName = this.getStanceName(stance);\n return {\n id: stance,\n name: stanceName,\n korean: stanceName.korean,\n english: stanceName.english,\n };\n }\n\n /**\n * Validates a stance transition with detailed feedback.\n *\n * Checks if transition is valid and provides reason if not.\n * More detailed than {@link canTransitionTo}, includes specific failure reasons.\n *\n * @param fromStance - Current stance\n * @param toStance - Target stance\n * @param player - Player state\n * @returns Validation result with optional failure reason\n *\n * @example\n * ```typescript\n * const validation = trigramSystem.validateTransition(\n * TrigramStance.GEON,\n * TrigramStance.GON,\n * player\n * );\n * if (!validation.valid) {\n * console.error(validation.reason);\n * }\n * ```\n *\n * @korean 자세전환검증\n */\n validateTransition(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n player: PlayerState\n ): { valid: boolean; reason?: string } {\n if (fromStance === toStance) {\n return { valid: true };\n }\n\n const cost = this.getTransitionCost(fromStance, toStance, player);\n\n if (player.ki < cost.ki) {\n return {\n valid: false,\n reason: `Insufficient Ki: need ${cost.ki}, have ${player.ki}`,\n };\n }\n\n if (player.stamina < cost.stamina) {\n return {\n valid: false,\n reason: `Insufficient Stamina: need ${cost.stamina}, have ${player.stamina}`,\n };\n }\n\n return { valid: true };\n }\n}\n\nexport default TrigramSystem;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAa,kBAAwD;EAClE,cAAc,OAAO,cAAc;EACnC,cAAc,MAAM,cAAc;EAClC,cAAc,KAAK,cAAc;EACjC,cAAc,MAAM,cAAc;EAClC,cAAc,MAAM,cAAc;EAClC,cAAc,MAAM,cAAc;EAClC,cAAc,MAAM,cAAc;EAClC,cAAc,MAAM,cAAc;AACrC;;;;;;;AAQA,IAAa,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BhD,SAAgB,yBACd,YACA,iBACQ;CACR,IAAI,CAAC,mBAAmB,cAAc,GACpC,OAAO;CAGT,OAAO,aAAa;AACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,IAAa,gBAAb,MAA2B;CACzB;;;;;;CAOA,cAAc;EACZ,KAAK,aAAa,IAAI,kBAAkB;CAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BA,wBACE,QACwC;EACxC,QAAQ,QAAR;GACE,KAAK,cAAc;GACnB,KAAK,cAAc,KACjB,OAAO;GAET,KAAK,cAAc;GACnB,KAAK,cAAc,KACjB,OAAO;GAET,SACE,OAAO;EACX;CACF;;;;;;;;;;;;;;;;;;CAmBA,kBAAkB,QAAgC;EAChD,OAAO,KAAK,wBAAwB,MAAM,MAAM;CAClD;;;;;;;;;;;;;;;;;;CAmBA,kBAAkB,QAAgC;EAChD,OAAO,KAAK,wBAAwB,MAAM,MAAM;CAClD;;;;;;;;;;;;;;;;;;;;;;;CAwBA,gBACE,YACA,UACA,QACS;EACT,IAAI,eAAe,UAAU,OAAO;EAEpC,MAAM,OAAO,KAAK,kBAAkB,YAAY,UAAU,MAAM;EAGhE,MAAM,cAAc,OAAO,MAAM,KAAK;EACtC,MAAM,mBAAmB,OAAO,WAAW,KAAK;EAEhD,OAAO,eAAe;CACxB;;;;;;;;;;;;;;;;;;;;;CAsBA,gBAAgB,QAAoC;EAClD,MAAM,OAAO,OAAO;EACpB,IAAI,OAAO;EACX,IAAI,YAAY;EAEhB,KAAK,MAAM,MAAM,uBAAuB;GACtC,MAAM,UAAiC,KAAK,kBAAkB,MAAM,EAAE;GACtE,MAAM,QAAQ,QAAQ,KAAK,QAAQ,UAAU,QAAQ;GACrD,IAAI,QAAQ,WAAW;IACrB,YAAY;IACZ,OAAO;GACT;EACF;EAEA,OAAO;CACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCA,kBACE,MACA,IACA,QACuB;EACvB,IAAI,SAAS,IACX,OAAO;GACL,IAAI;GACJ,SAAS;GACT,kBAAkB;EACpB;EAGF,MAAM,aAAa,kBAAkB,8BACnC,MACA,EACF;EACA,MAAM,WAAW;EACjB,MAAM,WAAW;EAEjB,IAAI,KAAK,KAAK,KAAK,WAAW,UAAU;EACxC,IAAI,UAAU,KAAK,KAAK,WAAW,aAAa,GAAG;EAGnD,IAAI,QAAQ;GAGV,MAAM,OAFW,uBAAuB,OAAO,WACzB,kBAAkB,CAAC,GACxB,SAAS,EAAE,IAAI,KAAM;GACtC,KAAK,KAAK,KAAK,KAAK,GAAG;GACvB,UAAU,KAAK,KAAK,UAAU,GAAG;EACnC;EAEA,OAAO;GACL;GACA;GACA,kBAAkB,KAAK,KAAK,WAAW,UAAU;EACnD;CACF;;;;;;;;;;;;;;;;;;;;;CAsBA,6BACE,gBACA,gBACQ;EACR,OAAO,KAAK,WAAW,6BACrB,gBACA,cACF;CACF;;;;;;;;;;;;;;;;;CAkBA,cAAc,QAA4D;EAYxE,OAAO;IAVJ,cAAc,OAAO;IAAE,QAAQ;IAAK,SAAS;GAAS;IACtD,cAAc,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAO;IACnD,cAAc,KAAK;IAAE,QAAQ;IAAK,SAAS;GAAO;IAClD,cAAc,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAU;IACtD,cAAc,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAO;IACnD,cAAc,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAQ;IACpD,cAAc,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAW;IACvD,cAAc,MAAM;IAAE,QAAQ;IAAK,SAAS;GAAQ;EAGhD,EAAY,WAAW;GAAE,QAAQ;GAAW,SAAS;EAAU;CACxE;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,iBAAiB,gBAA8C;EAC7D,OAAO,gBAAgB;CACzB;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,gBAAgB,UAAyB,gBAAwC;EAC/E,OAAO,KAAK,iBAAiB,cAAc,MAAM;CACnD;;;;;;;;;;;CAYA,qBAAqB,QAKnB;EACA,MAAM,aAAa,KAAK,cAAc,MAAM;EAC5C,OAAO;GACL,IAAI;GACJ,MAAM;GACN,QAAQ,WAAW;GACnB,SAAS,WAAW;EACtB;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BA,mBACE,YACA,UACA,QACqC;EACrC,IAAI,eAAe,UACjB,OAAO,EAAE,OAAO,KAAK;EAGvB,MAAM,OAAO,KAAK,kBAAkB,YAAY,UAAU,MAAM;EAEhE,IAAI,OAAO,KAAK,KAAK,IACnB,OAAO;GACL,OAAO;GACP,QAAQ,yBAAyB,KAAK,GAAG,SAAS,OAAO;EAC3D;EAGF,IAAI,OAAO,UAAU,KAAK,SACxB,OAAO;GACL,OAAO;GACP,QAAQ,8BAA8B,KAAK,QAAQ,SAAS,OAAO;EACrE;EAGF,OAAO,EAAE,OAAO,KAAK;CACvB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"VitalPointSystem.js","names":[],"sources":["../../src/systems/VitalPointSystem.ts"],"sourcesContent":["/**\n * System for managing Korean martial arts vital point (급소) targeting and damage calculation.\n *\n * **Korean**: 급소 시스템 (Vital Point System)\n *\n * The VitalPointSystem implements anatomical targeting mechanics based on traditional\n * Korean martial arts knowledge of 70 vital points (급소). It handles hit detection,\n * damage calculation, and status effect application for precise strikes.\n *\n * ## Vital Point Philosophy\n *\n * Korean martial arts identify specific anatomical locations that, when struck precisely,\n * can cause disproportionate effects. The system categorizes points by:\n *\n * - **Location**: Head, neck, torso, limbs, and core\n * - **Category**: Neurological, vascular, respiratory, muscular, skeletal, etc.\n * - **Severity**: Minor, moderate, major, critical, lethal\n * - **Effects**: Unconsciousness, paralysis, pain, stunning, etc.\n *\n * ## Meridian Integration (경락 통합)\n *\n * The system integrates Traditional Korean Medicine (TKM) meridian theory:\n * - **Time-of-Day Flow**: +30% effectiveness at meridian peak hours\n * - **Meridian Disruption**: Status effects from energy flow blockage\n * - **Elemental Relationships**: 五行 (Wu Xing) elemental advantages\n *\n * ## Key Features\n *\n * - Distance-based hit detection with accuracy falloff\n * - Severity multipliers for damage calculation\n * - Targeted vs. proximity-based strikes\n * - Bilingual Korean-English vital point names\n * - Realistic anatomical positioning\n * - Meridian state tracking and flow calculation\n *\n * @example\n * ```typescript\n * const vitalPointSystem = new VitalPointSystem();\n *\n * // Process a strike at specific position with time-of-day\n * const result = vitalPointSystem.processHit(\n * { x: 100, y: 50 }, // Target position\n * { width: 10, height: 10 }, // Hit box\n * \"GB-20\", // Optional: target specific vital point\n * 14 // Optional: hour of day for meridian flow\n * );\n *\n * if (result.hit && result.vitalPointHit) {\n * console.log(`Hit ${result.vitalPointHit.names.english}!`);\n * console.log(`Damage: ${result.damage}, Severity: ${result.severity}`);\n * console.log(`Meridian bonus: ${result.meridianMultiplier}x`);\n * }\n * ```\n *\n * @category Vital Point System\n * @korean 급소시스템\n */\nimport {\n PlayerArchetype,\n Position,\n TrigramStance,\n VitalPointSeverity,\n} from \"../types/common\";\nimport { convertToStatusEffect } from \"./EffectCalculator\";\nimport { StatusEffect } from \"./types\";\nimport {\n calculateEnhancedVulnerability,\n calculateMeridianFlow,\n generateMeridianEffects,\n} from \"./vitalpoint/KoreanAnatomy\";\nimport { getMeridiansForVitalPoint } from \"./vitalpoint/MeridianVitalPointMapping\";\nimport { VitalPoint, VitalPointHitResult } from \"./vitalpoint/types\";\nimport { VITAL_POINTS_DATA } from \"./vitalpoint/VitalPointsData\";\n\n/**\n * Amount of meridian disruption added per vital point hit (15%)\n */\nconst DISRUPTION_INCREMENT_PER_HIT = 0.15;\n\nexport class VitalPointSystem {\n private vitalPoints: VitalPoint[] = [];\n private meridianStates: Map<string, number> = new Map(); // Tracks disruption level per meridian\n private currentHour: number = 12; // Default to noon\n\n /**\n * Creates a new VitalPointSystem instance.\n *\n * Initializes the system with comprehensive Korean vital points database\n * and meridian state tracking.\n *\n * @param initialHour - Optional initial hour of day (0-23) for meridian flow calculations\n */\n constructor(initialHour: number = 12) {\n this.initializeVitalPoints();\n this.currentHour = initialHour;\n }\n\n /**\n * Sets the current hour of day for meridian flow calculations.\n *\n * **Korean**: 시간 설정\n *\n * @param hour - Hour of day (0-23)\n * @throws Error if hour is not a finite number\n *\n * @example\n * ```typescript\n * vitalPointSystem.setCurrentHour(20); // 8 PM - Pericardium peak time\n * ```\n *\n * @korean 시간설정\n */\n setCurrentHour(hour: number): void {\n if (!Number.isFinite(hour)) {\n throw new Error(\"Hour must be a finite number\");\n }\n this.currentHour = Math.max(0, Math.min(23, Math.floor(hour)));\n }\n\n /**\n * Gets the current hour of day used for meridian calculations.\n *\n * **Korean**: 현재 시간 조회\n *\n * @returns Current hour (0-23)\n *\n * @korean 시간조회\n */\n getCurrentHour(): number {\n return this.currentHour;\n }\n\n /**\n * Updates meridian disruption state for a specific meridian.\n *\n * **Korean**: 경락 차단 상태 업데이트\n *\n * @param meridianId - ID of the meridian\n * @param disruptionLevel - Disruption level (0-1, where 1 is fully blocked)\n *\n * @korean 경락차단업데이트\n */\n setMeridianDisruption(meridianId: string, disruptionLevel: number): void {\n this.meridianStates.set(\n meridianId,\n Math.max(0, Math.min(1, disruptionLevel)),\n );\n }\n\n /**\n * Gets the current disruption level for a meridian.\n *\n * **Korean**: 경락 차단 수준 조회\n *\n * @param meridianId - ID of the meridian\n * @returns Disruption level (0-1)\n *\n * @korean 경락차단조회\n */\n getMeridianDisruption(meridianId: string): number {\n return this.meridianStates.get(meridianId) ?? 0;\n }\n\n /**\n * Clears all meridian disruption states (e.g., after rest or healing).\n *\n * **Korean**: 경락 상태 초기화\n *\n * @korean 경락초기화\n */\n clearMeridianDisruptions(): void {\n this.meridianStates.clear();\n }\n\n /**\n * Processes a hit at a specific position to determine vital point impact.\n *\n * Evaluates whether a strike lands on or near a vital point, calculating\n * damage and effects based on accuracy, severity, and meridian flow.\n * Supports both targeted strikes (specific vital point ID) and proximity-based detection.\n *\n * Enhanced with archetype-specific modifiers for realistic combat simulation.\n *\n * ## Hit Detection Algorithm\n *\n * 1. If targetedVitalPointId provided, validate that specific point\n * 2. Otherwise, find closest vital point to target position\n * 3. Calculate distance from strike to vital point\n * 4. Apply accuracy falloff based on distance (max 50px)\n * 5. Calculate meridian flow bonus based on time of day\n * 6. Apply meridian disruption if applicable\n * 7. Apply archetype offensive/defensive modifiers\n * 8. Apply enhanced vulnerability with stance and anatomical zone\n * 9. Return hit result with damage multipliers and effects\n *\n * @param targetPosition - Position where strike lands\n * @param _hitBox - Size of hit box (currently unused, reserved for future)\n * @param targetedVitalPointId - Optional specific vital point being targeted\n * @param hour - Optional hour of day (0-23) for meridian flow calculation\n * @param attackerArchetype - Optional attacker's archetype (default: MUSA)\n * @param defenderArchetype - Optional defender's archetype (default: MUSA)\n * @param defenderStance - Optional defender's trigram stance (default: GEON)\n * @returns Hit result with damage, effects, severity, and meridian multiplier\n *\n * @example\n * ```typescript\n * // Proximity-based strike\n * const result1 = vitalPointSystem.processHit(\n * { x: 100, y: 50 },\n * { width: 10, height: 10 }\n * );\n *\n * // Targeted strike with archetype modifiers and stance\n * const result2 = vitalPointSystem.processHit(\n * { x: 100, y: 50 },\n * { width: 10, height: 10 },\n * \"head_temple\",\n * 2, // Liver meridian peak hour\n * PlayerArchetype.AMSALJA, // Assassin attacker (+30% effect)\n * PlayerArchetype.MUSA, // Warrior defender (+20% resistance)\n * TrigramStance.GEON // Heaven stance (exposes head +20%)\n * );\n * ```\n *\n * @korean 타격처리\n */\n processHit(\n targetPosition: Position,\n _hitBox: { width: number; height: number }, // Prefixed with underscore to indicate intentionally unused\n targetedVitalPointId?: string | null,\n hour?: number,\n attackerArchetype?: PlayerArchetype,\n defenderArchetype?: PlayerArchetype,\n defenderStance?: TrigramStance,\n ): VitalPointHitResult {\n const effectiveHour = hour ?? this.currentHour;\n const effectiveAttackerArchetype =\n attackerArchetype ?? PlayerArchetype.MUSA;\n const effectiveDefenderArchetype =\n defenderArchetype ?? PlayerArchetype.MUSA;\n const effectiveDefenderStance = defenderStance ?? TrigramStance.GEON;\n\n // If a specific vital point is targeted, check that one\n if (targetedVitalPointId) {\n const targetVitalPoint = this.getVitalPointById(targetedVitalPointId);\n if (targetVitalPoint) {\n return this.calculateVitalPointHit(\n targetVitalPoint,\n targetPosition,\n effectiveHour,\n effectiveAttackerArchetype,\n effectiveDefenderArchetype,\n effectiveDefenderStance,\n );\n }\n }\n\n // Otherwise, find the closest vital point\n const closestVitalPoint = this.findClosestVitalPoint(targetPosition);\n if (!closestVitalPoint) {\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n const distance = this.calculateDistance(\n targetPosition,\n closestVitalPoint.position,\n );\n const maxHitDistance = 50; // pixels\n\n if (distance <= maxHitDistance) {\n return this.calculateVitalPointHit(\n closestVitalPoint,\n targetPosition,\n effectiveHour,\n effectiveAttackerArchetype,\n effectiveDefenderArchetype,\n effectiveDefenderStance,\n );\n }\n\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n /**\n * Retrieves a vital point by its unique identifier.\n *\n * @param id - Vital point identifier (e.g., \"GB-20\", \"head_temple\")\n * @returns Vital point if found, null otherwise\n *\n * @example\n * ```typescript\n * const temple = vitalPointSystem.getVitalPointById(\"head_temple\");\n * if (temple) {\n * console.log(temple.names.korean); // \"태양혈\"\n * }\n * ```\n *\n * @korean 급소조회\n */\n getVitalPointById(id: string): VitalPoint | null {\n return this.vitalPoints.find((vp) => vp.id === id) ?? null;\n }\n\n /**\n * Gets all registered vital points in the system.\n *\n * @returns Read-only array of all vital points\n *\n * @example\n * ```typescript\n * const allPoints = vitalPointSystem.getVitalPoints();\n * console.log(`${allPoints.length} vital points registered`);\n * ```\n *\n * @korean 급소목록조회\n */\n getVitalPoints(): readonly VitalPoint[] {\n return this.vitalPoints;\n }\n\n /**\n * Calculates hit result for a technique-based attack.\n *\n * Determines whether a technique successfully lands on a vital point,\n * factoring in technique accuracy, attacker position, and randomness.\n * Used for AI and player technique execution.\n *\n * @param technique - Technique being executed with accuracy property\n * @param attackerPosition - Position where attack originates\n * @param _defenderPosition - Defender position (reserved for future use)\n * @param _defenderStance - Defender stance (reserved for future use)\n * @returns Hit result with damage and effects\n *\n * @example\n * ```typescript\n * const technique = {\n * id: \"geon-thunder-strike\",\n * accuracy: 0.85\n * };\n *\n * const result = vitalPointSystem.calculateHit(\n * technique,\n * { x: 100, y: 50 },\n * { x: 120, y: 50 },\n * TrigramStance.GEON\n * );\n * ```\n *\n * @korean 기술타격계산\n */\n calculateHit(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- technique type is dynamically determined by combat system\n technique: any,\n attackerPosition: Position,\n _defenderPosition: Position, // Prefixed with underscore to indicate intentionally unused\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- stance type is dynamically determined by combat system\n _defenderStance: any, // Prefixed with underscore to indicate intentionally unused\n ): VitalPointHitResult {\n const closestVitalPoint = this.findClosestVitalPoint(attackerPosition);\n\n if (!closestVitalPoint) {\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n const distance = this.calculateDistance(\n attackerPosition,\n closestVitalPoint.position,\n );\n const hitChance = technique.accuracy * (1 - distance / 100);\n\n if (Math.random() < hitChance) {\n return {\n hit: true,\n vitalPointHit: closestVitalPoint,\n damage: this.calculateBaseDamage(closestVitalPoint, distance),\n effects: [],\n severity: closestVitalPoint.severity,\n };\n }\n\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n /**\n * Finds the closest vital point to a given position.\n *\n * Uses Euclidean distance to determine proximity.\n *\n * @param position - Target position\n * @returns Closest vital point or null if none registered\n *\n * @private\n * @korean 최근접급소검색\n */\n private findClosestVitalPoint(position: Position): VitalPoint | null {\n if (this.vitalPoints.length === 0) return null;\n\n let closest = this.vitalPoints[0];\n let minDistance = this.calculateDistance(position, closest.position);\n\n for (const vitalPoint of this.vitalPoints) {\n const distance = this.calculateDistance(position, vitalPoint.position);\n if (distance < minDistance) {\n minDistance = distance;\n closest = vitalPoint;\n }\n }\n\n return closest;\n }\n\n /**\n * Calculates Euclidean distance between two positions.\n *\n * @param pos1 - First position\n * @param pos2 - Second position\n * @returns Distance in pixels\n *\n * @private\n * @korean 거리계산\n */\n private calculateDistance(pos1: Position, pos2: Position): number {\n const dx = pos1.x - pos2.x;\n const dy = pos1.y - pos2.y;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Calculates vital point hit result with accuracy, damage, and meridian effects.\n *\n * **Korean**: 급소타격결과계산\n *\n * Enhanced with comprehensive effect calculation including:\n * - Duration based on accuracy, severity, and archetype modifiers\n * - Intensity scaling with hit accuracy\n * - Critical hit bonuses for accuracy >= 0.9\n * - Archetype offensive/defensive modifiers\n *\n * @param vitalPoint - Vital point being struck\n * @param hitPosition - Exact position of strike\n * @param hour - Hour of day for meridian flow calculation\n * @param attackerArchetype - Attacker's archetype (default: MUSA)\n * @param defenderArchetype - Defender's archetype (default: MUSA)\n * @returns Hit result with calculated damage, accuracy, and meridian bonuses\n *\n * @private\n * @korean 급소타격결과계산\n */\n private calculateVitalPointHit(\n vitalPoint: VitalPoint,\n hitPosition: Position,\n hour: number,\n attackerArchetype: PlayerArchetype = PlayerArchetype.MUSA,\n defenderArchetype: PlayerArchetype = PlayerArchetype.MUSA,\n defenderStance: TrigramStance = TrigramStance.GEON,\n ): VitalPointHitResult {\n const distance = this.calculateDistance(hitPosition, vitalPoint.position);\n const baseDamage = this.calculateBaseDamage(vitalPoint, distance);\n const now = Date.now(); // Single timestamp for all effects\n\n const accuracy = Math.max(0, 1 - distance / 50);\n\n const meridians = getMeridiansForVitalPoint(vitalPoint.id);\n\n let meridianMultiplier = 1.0;\n const allMeridianEffects: StatusEffect[] = [];\n\n if (meridians.length > 0) {\n // Use the best meridian flow multiplier\n meridianMultiplier = Math.max(\n ...meridians.map((meridianId) =>\n calculateMeridianFlow(meridianId, hour),\n ),\n );\n\n // Generate meridian disruption effects for each affected meridian\n meridians.forEach((meridianId) => {\n const currentDisruption = this.getMeridianDisruption(meridianId);\n const newDisruption = Math.min(\n 1,\n currentDisruption + DISRUPTION_INCREMENT_PER_HIT,\n );\n this.setMeridianDisruption(meridianId, newDisruption);\n\n const effects = generateMeridianEffects(meridianId, newDisruption, now);\n allMeridianEffects.push(...effects);\n });\n }\n\n const meridianStates: Record<string, number> = {};\n meridians.forEach((meridianId) => {\n // Convert disruption (0=normal, 1=blocked) to flow state (1=normal, 0=blocked)\n const disruption = this.getMeridianDisruption(meridianId);\n meridianStates[meridianId] = 1.0 - disruption;\n });\n\n const vulnerabilityMultiplier = calculateEnhancedVulnerability(\n vitalPoint.position,\n hour,\n defenderStance,\n meridianStates,\n );\n\n // Apply all multipliers to damage: base × meridian flow × vulnerability\n const finalDamage = Math.floor(\n baseDamage * meridianMultiplier * vulnerabilityMultiplier,\n );\n\n const vitalPointStatusEffects: StatusEffect[] = vitalPoint.effects.map(\n (effect) =>\n convertToStatusEffect(\n effect,\n accuracy,\n vitalPoint.severity,\n attackerArchetype,\n defenderArchetype,\n vitalPoint.id,\n now,\n ),\n );\n\n const combinedEffects = [...vitalPointStatusEffects, ...allMeridianEffects];\n\n return {\n hit: true,\n vitalPointHit: vitalPoint,\n damage: finalDamage,\n effects: combinedEffects,\n severity: vitalPoint.severity,\n accuracy,\n meridianMultiplier,\n meridianEffects: allMeridianEffects,\n multiplier: vulnerabilityMultiplier,\n };\n }\n\n /**\n * Calculates base damage for a vital point strike.\n *\n * Applies distance-based falloff to vital point's base damage value.\n * Closer strikes deal more damage up to maximum base damage.\n *\n * @param vitalPoint - Vital point with base damage property\n * @param distance - Distance from strike to vital point center\n * @returns Calculated damage value\n *\n * @private\n * @korean 기본피해계산\n */\n private calculateBaseDamage(\n vitalPoint: VitalPoint,\n distance: number,\n ): number {\n const baseDamage = vitalPoint.baseDamage ?? 10;\n const distanceModifier = Math.max(0.1, 1 - distance / 100);\n return Math.floor(baseDamage * distanceModifier);\n }\n\n /**\n * Initializes the system with comprehensive Korean vital points.\n *\n * Loads all 70 Korean vital points from the comprehensive database\n * covering head, torso, arms, and legs with proper categorization.\n *\n * @private\n * @korean 급소초기화\n */\n private initializeVitalPoints(): void {\n this.vitalPoints = [...VITAL_POINTS_DATA];\n }\n}\n\nexport default VitalPointSystem;\n"],"mappings":"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"}
1
+ {"version":3,"file":"VitalPointSystem.js","names":[],"sources":["../../src/systems/VitalPointSystem.ts"],"sourcesContent":["/**\n * System for managing Korean martial arts vital point (급소) targeting and damage calculation.\n *\n * **Korean**: 급소 시스템 (Vital Point System)\n *\n * The VitalPointSystem implements anatomical targeting mechanics based on traditional\n * Korean martial arts knowledge of 70 vital points (급소). It handles hit detection,\n * damage calculation, and status effect application for precise strikes.\n *\n * ## Vital Point Philosophy\n *\n * Korean martial arts identify specific anatomical locations that, when struck precisely,\n * can cause disproportionate effects. The system categorizes points by:\n *\n * - **Location**: Head, neck, torso, limbs, and core\n * - **Category**: Neurological, vascular, respiratory, muscular, skeletal, etc.\n * - **Severity**: Minor, moderate, major, critical, lethal\n * - **Effects**: Unconsciousness, paralysis, pain, stunning, etc.\n *\n * ## Meridian Integration (경락 통합)\n *\n * The system integrates Traditional Korean Medicine (TKM) meridian theory:\n * - **Time-of-Day Flow**: +30% effectiveness at meridian peak hours\n * - **Meridian Disruption**: Status effects from energy flow blockage\n * - **Elemental Relationships**: 五行 (Wu Xing) elemental advantages\n *\n * ## Key Features\n *\n * - Distance-based hit detection with accuracy falloff\n * - Severity multipliers for damage calculation\n * - Targeted vs. proximity-based strikes\n * - Bilingual Korean-English vital point names\n * - Realistic anatomical positioning\n * - Meridian state tracking and flow calculation\n *\n * @example\n * ```typescript\n * const vitalPointSystem = new VitalPointSystem();\n *\n * // Process a strike at specific position with time-of-day\n * const result = vitalPointSystem.processHit(\n * { x: 100, y: 50 }, // Target position\n * { width: 10, height: 10 }, // Hit box\n * \"GB-20\", // Optional: target specific vital point\n * 14 // Optional: hour of day for meridian flow\n * );\n *\n * if (result.hit && result.vitalPointHit) {\n * console.log(`Hit ${result.vitalPointHit.names.english}!`);\n * console.log(`Damage: ${result.damage}, Severity: ${result.severity}`);\n * console.log(`Meridian bonus: ${result.meridianMultiplier}x`);\n * }\n * ```\n *\n * @category Vital Point System\n * @korean 급소시스템\n */\nimport {\n PlayerArchetype,\n Position,\n TrigramStance,\n VitalPointSeverity,\n} from \"../types/common\";\nimport { convertToStatusEffect } from \"./EffectCalculator\";\nimport { StatusEffect } from \"./types\";\nimport {\n calculateEnhancedVulnerability,\n calculateMeridianFlow,\n generateMeridianEffects,\n} from \"./vitalpoint/KoreanAnatomy\";\nimport { getMeridiansForVitalPoint } from \"./vitalpoint/MeridianVitalPointMapping\";\nimport { VitalPoint, VitalPointHitResult } from \"./vitalpoint/types\";\nimport { VITAL_POINTS_DATA } from \"./vitalpoint/VitalPointsData\";\n\n/**\n * Amount of meridian disruption added per vital point hit (15%)\n */\nconst DISRUPTION_INCREMENT_PER_HIT = 0.15;\n\nexport class VitalPointSystem {\n private vitalPoints: VitalPoint[] = [];\n private meridianStates: Map<string, number> = new Map(); // Tracks disruption level per meridian\n private currentHour: number = 12; // Default to noon\n\n /**\n * Creates a new VitalPointSystem instance.\n *\n * Initializes the system with comprehensive Korean vital points database\n * and meridian state tracking.\n *\n * @param initialHour - Optional initial hour of day (0-23) for meridian flow calculations\n */\n constructor(initialHour: number = 12) {\n this.initializeVitalPoints();\n this.currentHour = initialHour;\n }\n\n /**\n * Sets the current hour of day for meridian flow calculations.\n *\n * **Korean**: 시간 설정\n *\n * @param hour - Hour of day (0-23)\n * @throws Error if hour is not a finite number\n *\n * @example\n * ```typescript\n * vitalPointSystem.setCurrentHour(20); // 8 PM - Pericardium peak time\n * ```\n *\n * @korean 시간설정\n */\n setCurrentHour(hour: number): void {\n if (!Number.isFinite(hour)) {\n throw new Error(\"Hour must be a finite number\");\n }\n this.currentHour = Math.max(0, Math.min(23, Math.floor(hour)));\n }\n\n /**\n * Gets the current hour of day used for meridian calculations.\n *\n * **Korean**: 현재 시간 조회\n *\n * @returns Current hour (0-23)\n *\n * @korean 시간조회\n */\n getCurrentHour(): number {\n return this.currentHour;\n }\n\n /**\n * Updates meridian disruption state for a specific meridian.\n *\n * **Korean**: 경락 차단 상태 업데이트\n *\n * @param meridianId - ID of the meridian\n * @param disruptionLevel - Disruption level (0-1, where 1 is fully blocked)\n *\n * @korean 경락차단업데이트\n */\n setMeridianDisruption(meridianId: string, disruptionLevel: number): void {\n this.meridianStates.set(\n meridianId,\n Math.max(0, Math.min(1, disruptionLevel)),\n );\n }\n\n /**\n * Gets the current disruption level for a meridian.\n *\n * **Korean**: 경락 차단 수준 조회\n *\n * @param meridianId - ID of the meridian\n * @returns Disruption level (0-1)\n *\n * @korean 경락차단조회\n */\n getMeridianDisruption(meridianId: string): number {\n return this.meridianStates.get(meridianId) ?? 0;\n }\n\n /**\n * Clears all meridian disruption states (e.g., after rest or healing).\n *\n * **Korean**: 경락 상태 초기화\n *\n * @korean 경락초기화\n */\n clearMeridianDisruptions(): void {\n this.meridianStates.clear();\n }\n\n /**\n * Processes a hit at a specific position to determine vital point impact.\n *\n * Evaluates whether a strike lands on or near a vital point, calculating\n * damage and effects based on accuracy, severity, and meridian flow.\n * Supports both targeted strikes (specific vital point ID) and proximity-based detection.\n *\n * Enhanced with archetype-specific modifiers for realistic combat simulation.\n *\n * ## Hit Detection Algorithm\n *\n * 1. If targetedVitalPointId provided, validate that specific point\n * 2. Otherwise, find closest vital point to target position\n * 3. Calculate distance from strike to vital point\n * 4. Apply accuracy falloff based on distance (max 50px)\n * 5. Calculate meridian flow bonus based on time of day\n * 6. Apply meridian disruption if applicable\n * 7. Apply archetype offensive/defensive modifiers\n * 8. Apply enhanced vulnerability with stance and anatomical zone\n * 9. Return hit result with damage multipliers and effects\n *\n * @param targetPosition - Position where strike lands\n * @param _hitBox - Size of hit box (currently unused, reserved for future)\n * @param targetedVitalPointId - Optional specific vital point being targeted\n * @param hour - Optional hour of day (0-23) for meridian flow calculation\n * @param attackerArchetype - Optional attacker's archetype (default: MUSA)\n * @param defenderArchetype - Optional defender's archetype (default: MUSA)\n * @param defenderStance - Optional defender's trigram stance (default: GEON)\n * @returns Hit result with damage, effects, severity, and meridian multiplier\n *\n * @example\n * ```typescript\n * // Proximity-based strike\n * const result1 = vitalPointSystem.processHit(\n * { x: 100, y: 50 },\n * { width: 10, height: 10 }\n * );\n *\n * // Targeted strike with archetype modifiers and stance\n * const result2 = vitalPointSystem.processHit(\n * { x: 100, y: 50 },\n * { width: 10, height: 10 },\n * \"head_temple\",\n * 2, // Liver meridian peak hour\n * PlayerArchetype.AMSALJA, // Assassin attacker (+30% effect)\n * PlayerArchetype.MUSA, // Warrior defender (+20% resistance)\n * TrigramStance.GEON // Heaven stance (exposes head +20%)\n * );\n * ```\n *\n * @korean 타격처리\n */\n processHit(\n targetPosition: Position,\n _hitBox: { width: number; height: number }, // Prefixed with underscore to indicate intentionally unused\n targetedVitalPointId?: string | null,\n hour?: number,\n attackerArchetype?: PlayerArchetype,\n defenderArchetype?: PlayerArchetype,\n defenderStance?: TrigramStance,\n ): VitalPointHitResult {\n const effectiveHour = hour ?? this.currentHour;\n const effectiveAttackerArchetype =\n attackerArchetype ?? PlayerArchetype.MUSA;\n const effectiveDefenderArchetype =\n defenderArchetype ?? PlayerArchetype.MUSA;\n const effectiveDefenderStance = defenderStance ?? TrigramStance.GEON;\n\n // If a specific vital point is targeted, check that one\n if (targetedVitalPointId) {\n const targetVitalPoint = this.getVitalPointById(targetedVitalPointId);\n if (targetVitalPoint) {\n return this.calculateVitalPointHit(\n targetVitalPoint,\n targetPosition,\n effectiveHour,\n effectiveAttackerArchetype,\n effectiveDefenderArchetype,\n effectiveDefenderStance,\n );\n }\n }\n\n // Otherwise, find the closest vital point\n const closestVitalPoint = this.findClosestVitalPoint(targetPosition);\n if (!closestVitalPoint) {\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n const distance = this.calculateDistance(\n targetPosition,\n closestVitalPoint.position,\n );\n const maxHitDistance = 50; // pixels\n\n if (distance <= maxHitDistance) {\n return this.calculateVitalPointHit(\n closestVitalPoint,\n targetPosition,\n effectiveHour,\n effectiveAttackerArchetype,\n effectiveDefenderArchetype,\n effectiveDefenderStance,\n );\n }\n\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n /**\n * Retrieves a vital point by its unique identifier.\n *\n * @param id - Vital point identifier (e.g., \"GB-20\", \"head_temple\")\n * @returns Vital point if found, null otherwise\n *\n * @example\n * ```typescript\n * const temple = vitalPointSystem.getVitalPointById(\"head_temple\");\n * if (temple) {\n * console.log(temple.names.korean); // \"태양혈\"\n * }\n * ```\n *\n * @korean 급소조회\n */\n getVitalPointById(id: string): VitalPoint | null {\n return this.vitalPoints.find((vp) => vp.id === id) ?? null;\n }\n\n /**\n * Gets all registered vital points in the system.\n *\n * @returns Read-only array of all vital points\n *\n * @example\n * ```typescript\n * const allPoints = vitalPointSystem.getVitalPoints();\n * console.log(`${allPoints.length} vital points registered`);\n * ```\n *\n * @korean 급소목록조회\n */\n getVitalPoints(): readonly VitalPoint[] {\n return this.vitalPoints;\n }\n\n /**\n * Calculates hit result for a technique-based attack.\n *\n * Determines whether a technique successfully lands on a vital point,\n * factoring in technique accuracy, attacker position, and randomness.\n * Used for AI and player technique execution.\n *\n * @param technique - Technique being executed with accuracy property\n * @param attackerPosition - Position where attack originates\n * @param _defenderPosition - Defender position (reserved for future use)\n * @param _defenderStance - Defender stance (reserved for future use)\n * @returns Hit result with damage and effects\n *\n * @example\n * ```typescript\n * const technique = {\n * id: \"geon-thunder-strike\",\n * accuracy: 0.85\n * };\n *\n * const result = vitalPointSystem.calculateHit(\n * technique,\n * { x: 100, y: 50 },\n * { x: 120, y: 50 },\n * TrigramStance.GEON\n * );\n * ```\n *\n * @korean 기술타격계산\n */\n calculateHit(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- technique type is dynamically determined by combat system\n technique: any,\n attackerPosition: Position,\n _defenderPosition: Position, // Prefixed with underscore to indicate intentionally unused\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- stance type is dynamically determined by combat system\n _defenderStance: any, // Prefixed with underscore to indicate intentionally unused\n ): VitalPointHitResult {\n const closestVitalPoint = this.findClosestVitalPoint(attackerPosition);\n\n if (!closestVitalPoint) {\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n const distance = this.calculateDistance(\n attackerPosition,\n closestVitalPoint.position,\n );\n const hitChance = technique.accuracy * (1 - distance / 100);\n\n if (Math.random() < hitChance) {\n return {\n hit: true,\n vitalPointHit: closestVitalPoint,\n damage: this.calculateBaseDamage(closestVitalPoint, distance),\n effects: [],\n severity: closestVitalPoint.severity,\n };\n }\n\n return {\n hit: false,\n damage: 0,\n effects: [],\n severity: VitalPointSeverity.MINOR,\n };\n }\n\n /**\n * Finds the closest vital point to a given position.\n *\n * Uses Euclidean distance to determine proximity.\n *\n * @param position - Target position\n * @returns Closest vital point or null if none registered\n *\n * @private\n * @korean 최근접급소검색\n */\n private findClosestVitalPoint(position: Position): VitalPoint | null {\n if (this.vitalPoints.length === 0) return null;\n\n let closest = this.vitalPoints[0];\n let minDistance = this.calculateDistance(position, closest.position);\n\n for (const vitalPoint of this.vitalPoints) {\n const distance = this.calculateDistance(position, vitalPoint.position);\n if (distance < minDistance) {\n minDistance = distance;\n closest = vitalPoint;\n }\n }\n\n return closest;\n }\n\n /**\n * Calculates Euclidean distance between two positions.\n *\n * @param pos1 - First position\n * @param pos2 - Second position\n * @returns Distance in pixels\n *\n * @private\n * @korean 거리계산\n */\n private calculateDistance(pos1: Position, pos2: Position): number {\n const dx = pos1.x - pos2.x;\n const dy = pos1.y - pos2.y;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Calculates vital point hit result with accuracy, damage, and meridian effects.\n *\n * **Korean**: 급소타격결과계산\n *\n * Enhanced with comprehensive effect calculation including:\n * - Duration based on accuracy, severity, and archetype modifiers\n * - Intensity scaling with hit accuracy\n * - Critical hit bonuses for accuracy >= 0.9\n * - Archetype offensive/defensive modifiers\n *\n * @param vitalPoint - Vital point being struck\n * @param hitPosition - Exact position of strike\n * @param hour - Hour of day for meridian flow calculation\n * @param attackerArchetype - Attacker's archetype (default: MUSA)\n * @param defenderArchetype - Defender's archetype (default: MUSA)\n * @returns Hit result with calculated damage, accuracy, and meridian bonuses\n *\n * @private\n * @korean 급소타격결과계산\n */\n private calculateVitalPointHit(\n vitalPoint: VitalPoint,\n hitPosition: Position,\n hour: number,\n attackerArchetype: PlayerArchetype = PlayerArchetype.MUSA,\n defenderArchetype: PlayerArchetype = PlayerArchetype.MUSA,\n defenderStance: TrigramStance = TrigramStance.GEON,\n ): VitalPointHitResult {\n const distance = this.calculateDistance(hitPosition, vitalPoint.position);\n const baseDamage = this.calculateBaseDamage(vitalPoint, distance);\n const now = Date.now(); // Single timestamp for all effects\n\n const accuracy = Math.max(0, 1 - distance / 50);\n\n const meridians = getMeridiansForVitalPoint(vitalPoint.id);\n\n let meridianMultiplier = 1.0;\n const allMeridianEffects: StatusEffect[] = [];\n\n if (meridians.length > 0) {\n // Use the best meridian flow multiplier\n meridianMultiplier = Math.max(\n ...meridians.map((meridianId) =>\n calculateMeridianFlow(meridianId, hour),\n ),\n );\n\n // Generate meridian disruption effects for each affected meridian\n meridians.forEach((meridianId) => {\n const currentDisruption = this.getMeridianDisruption(meridianId);\n const newDisruption = Math.min(\n 1,\n currentDisruption + DISRUPTION_INCREMENT_PER_HIT,\n );\n this.setMeridianDisruption(meridianId, newDisruption);\n\n const effects = generateMeridianEffects(meridianId, newDisruption, now);\n allMeridianEffects.push(...effects);\n });\n }\n\n const meridianStates: Record<string, number> = {};\n meridians.forEach((meridianId) => {\n // Convert disruption (0=normal, 1=blocked) to flow state (1=normal, 0=blocked)\n const disruption = this.getMeridianDisruption(meridianId);\n meridianStates[meridianId] = 1.0 - disruption;\n });\n\n const vulnerabilityMultiplier = calculateEnhancedVulnerability(\n vitalPoint.position,\n hour,\n defenderStance,\n meridianStates,\n );\n\n // Apply all multipliers to damage: base × meridian flow × vulnerability\n const finalDamage = Math.floor(\n baseDamage * meridianMultiplier * vulnerabilityMultiplier,\n );\n\n const vitalPointStatusEffects: StatusEffect[] = vitalPoint.effects.map(\n (effect) =>\n convertToStatusEffect(\n effect,\n accuracy,\n vitalPoint.severity,\n attackerArchetype,\n defenderArchetype,\n vitalPoint.id,\n now,\n ),\n );\n\n const combinedEffects = [...vitalPointStatusEffects, ...allMeridianEffects];\n\n return {\n hit: true,\n vitalPointHit: vitalPoint,\n damage: finalDamage,\n effects: combinedEffects,\n severity: vitalPoint.severity,\n accuracy,\n meridianMultiplier,\n meridianEffects: allMeridianEffects,\n multiplier: vulnerabilityMultiplier,\n };\n }\n\n /**\n * Calculates base damage for a vital point strike.\n *\n * Applies distance-based falloff to vital point's base damage value.\n * Closer strikes deal more damage up to maximum base damage.\n *\n * @param vitalPoint - Vital point with base damage property\n * @param distance - Distance from strike to vital point center\n * @returns Calculated damage value\n *\n * @private\n * @korean 기본피해계산\n */\n private calculateBaseDamage(\n vitalPoint: VitalPoint,\n distance: number,\n ): number {\n const baseDamage = vitalPoint.baseDamage ?? 10;\n const distanceModifier = Math.max(0.1, 1 - distance / 100);\n return Math.floor(baseDamage * distanceModifier);\n }\n\n /**\n * Initializes the system with comprehensive Korean vital points.\n *\n * Loads all 70 Korean vital points from the comprehensive database\n * covering head, torso, arms, and legs with proper categorization.\n *\n * @private\n * @korean 급소초기화\n */\n private initializeVitalPoints(): void {\n this.vitalPoints = [...VITAL_POINTS_DATA];\n }\n}\n\nexport default VitalPointSystem;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AIPersonality.js","names":[],"sources":["../../../src/systems/ai/AIPersonality.ts"],"sourcesContent":["/**\n * AI Personality System for Korean Martial Arts Combat\n * Defines behavioral archetypes that guide AI decision-making\n */\n\nimport { PlayerArchetype, TrigramStance } from \"@/types\";\n\n/**\n * Movement pattern types for archetype behavior\n *\n * @korean 이동 패턴 타입\n */\nexport type MovementPattern =\n | \"aggressive\"\n | \"evasive\"\n | \"analytical\"\n | \"unpredictable\";\n\n/**\n * Vital target priority for archetype-specific combat strategies\n *\n * @korean 급소 우선순위\n */\nexport type VitalTargetPriority =\n | \"health\"\n | \"pain\"\n | \"consciousness\"\n | \"balanced\";\n\n/**\n * Technique category types for archetype preferences\n *\n * @korean 기술 범주\n */\nexport type TechniqueCategory =\n | \"joint_manipulation\"\n | \"bone_strikes\"\n | \"nerve_strikes\"\n | \"silent_takedowns\"\n | \"anatomical_analysis\"\n | \"calculated_strikes\"\n | \"psychological_pressure\"\n | \"submission_induction\"\n | \"dirty_techniques\"\n | \"environmental_usage\";\n\n/**\n * Archetype-specific behavior profile\n *\n * Defines combat preferences, movement patterns, and tactical decision-making\n * unique to each of the 5 player archetypes.\n *\n * @korean 원형별 행동 프로필\n */\nexport interface ArchetypeBehavior {\n /** Preferred trigram stances for this archetype */\n readonly preferredStances: readonly TrigramStance[];\n /** Optimal combat range in grid cells (1 cell = ~40px) */\n readonly optimalRange: number;\n /** Health percentage threshold to trigger retreat behavior */\n readonly retreatThreshold: number;\n /** Technique categories this archetype favors */\n readonly techniqueSelectionBias: readonly TechniqueCategory[];\n /** Movement pattern characteristic of this archetype */\n readonly movementPattern: MovementPattern;\n /** Whether archetype follows honor code (affects retreat behavior) */\n readonly honorCode: boolean;\n /** Priority system for vital point targeting */\n readonly vitalTargetPriority: VitalTargetPriority;\n}\n\n/**\n * AI personality profile defining combat behavior\n */\nexport interface AIPersonality {\n readonly name: string;\n readonly koreanName: string;\n readonly archetype: PlayerArchetype;\n readonly aggressionLevel: number; // 0.0-1.0: How often AI attacks\n readonly defensePreference: number; // 0.0-1.0: Tendency to block/counter\n readonly comboTendency: number; // 0.0-1.0: Likelihood to continue combos\n readonly stanceSwitchFrequency: number; // 0.0-1.0: How often changes stance\n readonly feintChance: number; // 0.0-1.0: Probability of fake attacks\n readonly tacticalRetreatThreshold: number; // Health % to retreat\n readonly favoredStances: readonly TrigramStance[];\n readonly description: {\n readonly korean: string;\n readonly english: string;\n };\n}\n\n/**\n * Archetype-specific behavior profiles\n *\n * Maps each of the 5 player archetypes to their unique combat behaviors,\n * movement patterns, and tactical preferences based on Korean martial arts\n * traditions and game design philosophy.\n *\n * @korean 원형별 행동 프로필\n */\nexport const ARCHETYPE_BEHAVIORS: Record<PlayerArchetype, ArchetypeBehavior> = {\n [PlayerArchetype.MUSA]: {\n preferredStances: [\n TrigramStance.GEON,\n TrigramStance.JIN,\n TrigramStance.GAN,\n ], // Heaven, Thunder, Mountain\n optimalRange: 1, // Close quarters (1 cell = ~40px)\n retreatThreshold: 5, // Enhanced: fights to near-death (honor code)\n techniqueSelectionBias: [\"joint_manipulation\", \"bone_strikes\"],\n movementPattern: \"aggressive\",\n honorCode: true, // Never retreats above threshold\n vitalTargetPriority: \"balanced\",\n },\n [PlayerArchetype.AMSALJA]: {\n preferredStances: [TrigramStance.SON, TrigramStance.GAM], // Wind, Water\n optimalRange: 1, // Stealth melee (1 cell)\n retreatThreshold: 20, // Enhanced: tactical retreat, not cowardice\n techniqueSelectionBias: [\"nerve_strikes\", \"silent_takedowns\"],\n movementPattern: \"evasive\",\n honorCode: false,\n vitalTargetPriority: \"consciousness\",\n },\n [PlayerArchetype.HACKER]: {\n preferredStances: [TrigramStance.LI, TrigramStance.TAE], // Fire, Lake\n optimalRange: 3, // Mid-range analysis (3 cells = ~120px)\n retreatThreshold: 50,\n techniqueSelectionBias: [\"anatomical_analysis\", \"calculated_strikes\"],\n movementPattern: \"analytical\",\n honorCode: false,\n vitalTargetPriority: \"balanced\",\n },\n [PlayerArchetype.JEONGBO_YOWON]: {\n preferredStances: [TrigramStance.GAN, TrigramStance.GON], // Mountain, Earth\n optimalRange: 2, // Tactical mid-range (2 cells = ~80px)\n retreatThreshold: 40,\n techniqueSelectionBias: [\"psychological_pressure\", \"submission_induction\"],\n movementPattern: \"analytical\",\n honorCode: false,\n vitalTargetPriority: \"pain\",\n },\n [PlayerArchetype.JOJIK_POKRYEOKBAE]: {\n preferredStances: [TrigramStance.JIN, TrigramStance.GAM], // Thunder, Water (adaptable)\n optimalRange: 1, // Close brutal combat (1 cell)\n retreatThreshold: 70, // Retreats pragmatically\n techniqueSelectionBias: [\"dirty_techniques\", \"environmental_usage\"],\n movementPattern: \"unpredictable\",\n honorCode: false,\n vitalTargetPriority: \"health\",\n },\n};\n\n/**\n * Five AI personality archetypes inspired by Korean martial arts philosophy\n */\nexport const AI_PERSONALITIES: Record<string, AIPersonality> = {\n /**\n * 맹공자 (Maenggongja) - Fierce Attacker\n * Aggressive pressure fighter using Musa archetype\n *\n * **Enhanced Aggression (Issue #enhance-ai-aggression)**:\n * - Increased aggression: 0.85 → 0.95 (overwhelming force)\n * - Reduced defense: 0.2 → 0.1 (all-in offensive)\n * - Increased combo tendency: 0.7 → 0.8 (sustained pressure)\n * - Reduced retreat threshold: 0.15 → 0.05 (honor code: fights to near-death)\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.3 → 0.5 (more tactical flexibility)\n */\n AGGRESSIVE_STRIKER: {\n name: \"Aggressive Striker\",\n koreanName: \"맹공자\",\n archetype: PlayerArchetype.MUSA,\n aggressionLevel: 0.95, // Enhanced from 0.85\n defensePreference: 0.1, // Reduced from 0.2\n comboTendency: 0.8, // Increased from 0.7\n stanceSwitchFrequency: 0.15, // Reduced: Musa focuses on overwhelming force, not stance dancing\n feintChance: 0.15,\n tacticalRetreatThreshold: 0.05, // Reduced from 0.15\n favoredStances: [\n TrigramStance.GEON, // Heaven - Direct force\n TrigramStance.JIN, // Thunder - Explosive power\n TrigramStance.LI, // Fire - Precision strikes\n ],\n description: {\n korean: \"정면 돌파를 선호하는 공격적인 전사\",\n english: \"Aggressive warrior who prefers frontal assault\",\n },\n },\n\n /**\n * 기술가 (Gisulga) - Technical Master\n * Precision fighter using Amsalja archetype\n *\n * **Enhanced Aggression (Issue #enhance-ai-aggression)**:\n * - Increased aggression: 0.5 → 0.85 (instant takedown focus)\n * - Reduced defense: 0.6 → 0.3 (opportunistic aggression)\n * - Increased combo tendency: 0.4 → 0.6 (lethal sequences)\n * - Reduced retreat threshold: 0.35 → 0.20 (tactical retreat, not cowardice)\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.7 → 0.85 (highly adaptive)\n */\n TECHNICAL_MASTER: {\n name: \"Technical Master\",\n koreanName: \"기술가\",\n archetype: PlayerArchetype.AMSALJA,\n aggressionLevel: 0.95, // Enhanced for fatal precision strikes\n defensePreference: 0.2, // Reduced: assassins attack, don't defend\n comboTendency: 0.7, // Increased for lethal combinations\n stanceSwitchFrequency: 0.2, // Reduced: precision strikers commit to their stance\n feintChance: 0.35,\n tacticalRetreatThreshold: 0.15, // Reduced: assassins press the attack\n favoredStances: [\n TrigramStance.SON, // Wind - Continuous pressure\n TrigramStance.GAM, // Water - Flow and adaptation\n TrigramStance.TAE, // Lake - Fluid manipulation\n ],\n description: {\n korean: \"정밀한 기술로 약점을 노리는 달인\",\n english: \"Master who targets weaknesses with precise techniques\",\n },\n },\n\n /**\n * 균형 잡힌 자 (Gyunhyeong Jabin-ja) - Balanced Fighter\n * All-around fighter using Jeongbo Yowon archetype\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.5 → 0.7 (strategic switching)\n */\n BALANCED_FIGHTER: {\n name: \"Balanced Fighter\",\n koreanName: \"균형 잡힌 자\",\n archetype: PlayerArchetype.JEONGBO_YOWON,\n aggressionLevel: 0.75, // Enhanced: intelligence operatives are decisive\n defensePreference: 0.4, // Slightly reduced for more aggression\n comboTendency: 0.6, // Increased for calculated sequences\n stanceSwitchFrequency: 0.25, // Reduced: strategic, not reactive\n feintChance: 0.3, // Increased: psychological warfare\n tacticalRetreatThreshold: 0.2, // Slightly reduced\n favoredStances: [\n TrigramStance.GEON, // Heaven\n TrigramStance.GAM, // Water\n TrigramStance.GAN, // Mountain\n TrigramStance.GON, // Earth\n ],\n description: {\n korean: \"공격과 방어의 조화를 추구하는 전략가\",\n english: \"Strategist seeking harmony between offense and defense\",\n },\n },\n\n /**\n * 방어의 달인 (Bangeo-ui Dallin) - Defensive Specialist\n * Counter-attack focused using Hacker archetype\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.4 → 0.6 (analytical adaptation)\n */\n DEFENSIVE_SPECIALIST: {\n name: \"Defensive Specialist\",\n koreanName: \"방어의 달인\",\n archetype: PlayerArchetype.HACKER,\n aggressionLevel: 0.55, // Enhanced: hackers exploit vulnerabilities aggressively\n defensePreference: 0.6, // Reduced: still defensive but not passive\n comboTendency: 0.5, // Increased for analytical attack chains\n stanceSwitchFrequency: 0.2, // Reduced: analytical fighters don't fidget\n feintChance: 0.45, // Increased: data-driven misdirection\n tacticalRetreatThreshold: 0.3, // Reduced: hackers are more confident\n favoredStances: [\n TrigramStance.GAN, // Mountain - Defensive mastery\n TrigramStance.GON, // Earth - Grounding\n TrigramStance.GAM, // Water - Adaptation\n ],\n description: {\n korean: \"방어에서 반격의 기회를 찾는 전문가\",\n english: \"Expert who finds counter-attack opportunities through defense\",\n },\n },\n\n /**\n * 혼돈의 전사 (Hondon-ui Jeonsa) - Chaos Warrior\n * Unpredictable fighter using Jojik Pokryeokbae archetype\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.8 → 0.95 (unpredictable chaos)\n */\n CHAOS_WARRIOR: {\n name: \"Chaos Warrior\",\n koreanName: \"혼돈의 전사\",\n archetype: PlayerArchetype.JOJIK_POKRYEOKBAE,\n aggressionLevel: 0.9, // Enhanced: brutal pragmatists attack relentlessly\n defensePreference: 0.2, // Reduced: dirty fighters don't retreat\n comboTendency: 0.7, // Increased for vicious combinations\n stanceSwitchFrequency: 0.3, // Reduced: chaos is in attacks, not stance dancing\n feintChance: 0.5,\n tacticalRetreatThreshold: 0.05, // Reduced: fights to the bitter end\n favoredStances: [\n TrigramStance.LI, // Fire - Unpredictable\n TrigramStance.SON, // Wind - Constant motion\n TrigramStance.JIN, // Thunder - Explosive\n TrigramStance.TAE, // Lake - Fluid\n ],\n description: {\n korean: \"예측 불가능한 패턴으로 상대를 혼란시키는 전사\",\n english: \"Warrior who confuses opponents with unpredictable patterns\",\n },\n },\n};\n\n/**\n * Get a random AI personality\n */\nexport function getRandomPersonality(): AIPersonality {\n const personalities = Object.values(AI_PERSONALITIES);\n return personalities[Math.floor(Math.random() * personalities.length)];\n}\n\n/**\n * Get personality by archetype\n */\nexport function getPersonalityByArchetype(\n archetype: PlayerArchetype,\n): AIPersonality {\n const personality = Object.values(AI_PERSONALITIES).find(\n (p) => p.archetype === archetype,\n );\n return personality ?? AI_PERSONALITIES.BALANCED_FIGHTER;\n}\n\n/**\n * Get personality by name key\n */\nexport function getPersonalityByName(name: string): AIPersonality {\n return AI_PERSONALITIES[name] ?? AI_PERSONALITIES.BALANCED_FIGHTER;\n}\n\n/**\n * List all available personalities\n */\nexport function getAllPersonalities(): readonly AIPersonality[] {\n return Object.values(AI_PERSONALITIES);\n}\n\n/**\n * Get archetype-specific behavior profile\n *\n * Retrieves the unique combat behavior configuration for a given archetype,\n * including movement patterns, optimal ranges, and tactical preferences.\n *\n * @param archetype - Player archetype to get behavior for\n * @returns Archetype behavior profile\n *\n * @korean 원형별 행동 프로필 가져오기\n */\nexport function getArchetypeBehavior(\n archetype: PlayerArchetype,\n): ArchetypeBehavior {\n return ARCHETYPE_BEHAVIORS[archetype];\n}\n\n/**\n * Check if archetype follows honor code\n *\n * Honor code affects retreat behavior - honor-bound archetypes like Musa\n * will not retreat above their health threshold.\n *\n * @param archetype - Player archetype to check\n * @returns True if archetype follows honor code\n *\n * @korean 명예 규범 확인\n */\nexport function followsHonorCode(archetype: PlayerArchetype): boolean {\n return ARCHETYPE_BEHAVIORS[archetype].honorCode;\n}\n\n/**\n * Get optimal combat range for archetype\n *\n * Returns the preferred distance in grid cells (1 cell = ~40px) where\n * the archetype is most effective in combat.\n *\n * @param archetype - Player archetype\n * @returns Optimal range in grid cells\n *\n * @korean 최적 전투 거리 가져오기\n */\nexport function getOptimalRange(archetype: PlayerArchetype): number {\n return ARCHETYPE_BEHAVIORS[archetype].optimalRange;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AIPersonality.js","names":[],"sources":["../../../src/systems/ai/AIPersonality.ts"],"sourcesContent":["/**\n * AI Personality System for Korean Martial Arts Combat\n * Defines behavioral archetypes that guide AI decision-making\n */\n\nimport { PlayerArchetype, TrigramStance } from \"@/types\";\n\n/**\n * Movement pattern types for archetype behavior\n *\n * @korean 이동 패턴 타입\n */\nexport type MovementPattern =\n | \"aggressive\"\n | \"evasive\"\n | \"analytical\"\n | \"unpredictable\";\n\n/**\n * Vital target priority for archetype-specific combat strategies\n *\n * @korean 급소 우선순위\n */\nexport type VitalTargetPriority =\n | \"health\"\n | \"pain\"\n | \"consciousness\"\n | \"balanced\";\n\n/**\n * Technique category types for archetype preferences\n *\n * @korean 기술 범주\n */\nexport type TechniqueCategory =\n | \"joint_manipulation\"\n | \"bone_strikes\"\n | \"nerve_strikes\"\n | \"silent_takedowns\"\n | \"anatomical_analysis\"\n | \"calculated_strikes\"\n | \"psychological_pressure\"\n | \"submission_induction\"\n | \"dirty_techniques\"\n | \"environmental_usage\";\n\n/**\n * Archetype-specific behavior profile\n *\n * Defines combat preferences, movement patterns, and tactical decision-making\n * unique to each of the 5 player archetypes.\n *\n * @korean 원형별 행동 프로필\n */\nexport interface ArchetypeBehavior {\n /** Preferred trigram stances for this archetype */\n readonly preferredStances: readonly TrigramStance[];\n /** Optimal combat range in grid cells (1 cell = ~40px) */\n readonly optimalRange: number;\n /** Health percentage threshold to trigger retreat behavior */\n readonly retreatThreshold: number;\n /** Technique categories this archetype favors */\n readonly techniqueSelectionBias: readonly TechniqueCategory[];\n /** Movement pattern characteristic of this archetype */\n readonly movementPattern: MovementPattern;\n /** Whether archetype follows honor code (affects retreat behavior) */\n readonly honorCode: boolean;\n /** Priority system for vital point targeting */\n readonly vitalTargetPriority: VitalTargetPriority;\n}\n\n/**\n * AI personality profile defining combat behavior\n */\nexport interface AIPersonality {\n readonly name: string;\n readonly koreanName: string;\n readonly archetype: PlayerArchetype;\n readonly aggressionLevel: number; // 0.0-1.0: How often AI attacks\n readonly defensePreference: number; // 0.0-1.0: Tendency to block/counter\n readonly comboTendency: number; // 0.0-1.0: Likelihood to continue combos\n readonly stanceSwitchFrequency: number; // 0.0-1.0: How often changes stance\n readonly feintChance: number; // 0.0-1.0: Probability of fake attacks\n readonly tacticalRetreatThreshold: number; // Health % to retreat\n readonly favoredStances: readonly TrigramStance[];\n readonly description: {\n readonly korean: string;\n readonly english: string;\n };\n}\n\n/**\n * Archetype-specific behavior profiles\n *\n * Maps each of the 5 player archetypes to their unique combat behaviors,\n * movement patterns, and tactical preferences based on Korean martial arts\n * traditions and game design philosophy.\n *\n * @korean 원형별 행동 프로필\n */\nexport const ARCHETYPE_BEHAVIORS: Record<PlayerArchetype, ArchetypeBehavior> = {\n [PlayerArchetype.MUSA]: {\n preferredStances: [\n TrigramStance.GEON,\n TrigramStance.JIN,\n TrigramStance.GAN,\n ], // Heaven, Thunder, Mountain\n optimalRange: 1, // Close quarters (1 cell = ~40px)\n retreatThreshold: 5, // Enhanced: fights to near-death (honor code)\n techniqueSelectionBias: [\"joint_manipulation\", \"bone_strikes\"],\n movementPattern: \"aggressive\",\n honorCode: true, // Never retreats above threshold\n vitalTargetPriority: \"balanced\",\n },\n [PlayerArchetype.AMSALJA]: {\n preferredStances: [TrigramStance.SON, TrigramStance.GAM], // Wind, Water\n optimalRange: 1, // Stealth melee (1 cell)\n retreatThreshold: 20, // Enhanced: tactical retreat, not cowardice\n techniqueSelectionBias: [\"nerve_strikes\", \"silent_takedowns\"],\n movementPattern: \"evasive\",\n honorCode: false,\n vitalTargetPriority: \"consciousness\",\n },\n [PlayerArchetype.HACKER]: {\n preferredStances: [TrigramStance.LI, TrigramStance.TAE], // Fire, Lake\n optimalRange: 3, // Mid-range analysis (3 cells = ~120px)\n retreatThreshold: 50,\n techniqueSelectionBias: [\"anatomical_analysis\", \"calculated_strikes\"],\n movementPattern: \"analytical\",\n honorCode: false,\n vitalTargetPriority: \"balanced\",\n },\n [PlayerArchetype.JEONGBO_YOWON]: {\n preferredStances: [TrigramStance.GAN, TrigramStance.GON], // Mountain, Earth\n optimalRange: 2, // Tactical mid-range (2 cells = ~80px)\n retreatThreshold: 40,\n techniqueSelectionBias: [\"psychological_pressure\", \"submission_induction\"],\n movementPattern: \"analytical\",\n honorCode: false,\n vitalTargetPriority: \"pain\",\n },\n [PlayerArchetype.JOJIK_POKRYEOKBAE]: {\n preferredStances: [TrigramStance.JIN, TrigramStance.GAM], // Thunder, Water (adaptable)\n optimalRange: 1, // Close brutal combat (1 cell)\n retreatThreshold: 70, // Retreats pragmatically\n techniqueSelectionBias: [\"dirty_techniques\", \"environmental_usage\"],\n movementPattern: \"unpredictable\",\n honorCode: false,\n vitalTargetPriority: \"health\",\n },\n};\n\n/**\n * Five AI personality archetypes inspired by Korean martial arts philosophy\n */\nexport const AI_PERSONALITIES: Record<string, AIPersonality> = {\n /**\n * 맹공자 (Maenggongja) - Fierce Attacker\n * Aggressive pressure fighter using Musa archetype\n *\n * **Enhanced Aggression (Issue #enhance-ai-aggression)**:\n * - Increased aggression: 0.85 → 0.95 (overwhelming force)\n * - Reduced defense: 0.2 → 0.1 (all-in offensive)\n * - Increased combo tendency: 0.7 → 0.8 (sustained pressure)\n * - Reduced retreat threshold: 0.15 → 0.05 (honor code: fights to near-death)\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.3 → 0.5 (more tactical flexibility)\n */\n AGGRESSIVE_STRIKER: {\n name: \"Aggressive Striker\",\n koreanName: \"맹공자\",\n archetype: PlayerArchetype.MUSA,\n aggressionLevel: 0.95, // Enhanced from 0.85\n defensePreference: 0.1, // Reduced from 0.2\n comboTendency: 0.8, // Increased from 0.7\n stanceSwitchFrequency: 0.15, // Reduced: Musa focuses on overwhelming force, not stance dancing\n feintChance: 0.15,\n tacticalRetreatThreshold: 0.05, // Reduced from 0.15\n favoredStances: [\n TrigramStance.GEON, // Heaven - Direct force\n TrigramStance.JIN, // Thunder - Explosive power\n TrigramStance.LI, // Fire - Precision strikes\n ],\n description: {\n korean: \"정면 돌파를 선호하는 공격적인 전사\",\n english: \"Aggressive warrior who prefers frontal assault\",\n },\n },\n\n /**\n * 기술가 (Gisulga) - Technical Master\n * Precision fighter using Amsalja archetype\n *\n * **Enhanced Aggression (Issue #enhance-ai-aggression)**:\n * - Increased aggression: 0.5 → 0.85 (instant takedown focus)\n * - Reduced defense: 0.6 → 0.3 (opportunistic aggression)\n * - Increased combo tendency: 0.4 → 0.6 (lethal sequences)\n * - Reduced retreat threshold: 0.35 → 0.20 (tactical retreat, not cowardice)\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.7 → 0.85 (highly adaptive)\n */\n TECHNICAL_MASTER: {\n name: \"Technical Master\",\n koreanName: \"기술가\",\n archetype: PlayerArchetype.AMSALJA,\n aggressionLevel: 0.95, // Enhanced for fatal precision strikes\n defensePreference: 0.2, // Reduced: assassins attack, don't defend\n comboTendency: 0.7, // Increased for lethal combinations\n stanceSwitchFrequency: 0.2, // Reduced: precision strikers commit to their stance\n feintChance: 0.35,\n tacticalRetreatThreshold: 0.15, // Reduced: assassins press the attack\n favoredStances: [\n TrigramStance.SON, // Wind - Continuous pressure\n TrigramStance.GAM, // Water - Flow and adaptation\n TrigramStance.TAE, // Lake - Fluid manipulation\n ],\n description: {\n korean: \"정밀한 기술로 약점을 노리는 달인\",\n english: \"Master who targets weaknesses with precise techniques\",\n },\n },\n\n /**\n * 균형 잡힌 자 (Gyunhyeong Jabin-ja) - Balanced Fighter\n * All-around fighter using Jeongbo Yowon archetype\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.5 → 0.7 (strategic switching)\n */\n BALANCED_FIGHTER: {\n name: \"Balanced Fighter\",\n koreanName: \"균형 잡힌 자\",\n archetype: PlayerArchetype.JEONGBO_YOWON,\n aggressionLevel: 0.75, // Enhanced: intelligence operatives are decisive\n defensePreference: 0.4, // Slightly reduced for more aggression\n comboTendency: 0.6, // Increased for calculated sequences\n stanceSwitchFrequency: 0.25, // Reduced: strategic, not reactive\n feintChance: 0.3, // Increased: psychological warfare\n tacticalRetreatThreshold: 0.2, // Slightly reduced\n favoredStances: [\n TrigramStance.GEON, // Heaven\n TrigramStance.GAM, // Water\n TrigramStance.GAN, // Mountain\n TrigramStance.GON, // Earth\n ],\n description: {\n korean: \"공격과 방어의 조화를 추구하는 전략가\",\n english: \"Strategist seeking harmony between offense and defense\",\n },\n },\n\n /**\n * 방어의 달인 (Bangeo-ui Dallin) - Defensive Specialist\n * Counter-attack focused using Hacker archetype\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.4 → 0.6 (analytical adaptation)\n */\n DEFENSIVE_SPECIALIST: {\n name: \"Defensive Specialist\",\n koreanName: \"방어의 달인\",\n archetype: PlayerArchetype.HACKER,\n aggressionLevel: 0.55, // Enhanced: hackers exploit vulnerabilities aggressively\n defensePreference: 0.6, // Reduced: still defensive but not passive\n comboTendency: 0.5, // Increased for analytical attack chains\n stanceSwitchFrequency: 0.2, // Reduced: analytical fighters don't fidget\n feintChance: 0.45, // Increased: data-driven misdirection\n tacticalRetreatThreshold: 0.3, // Reduced: hackers are more confident\n favoredStances: [\n TrigramStance.GAN, // Mountain - Defensive mastery\n TrigramStance.GON, // Earth - Grounding\n TrigramStance.GAM, // Water - Adaptation\n ],\n description: {\n korean: \"방어에서 반격의 기회를 찾는 전문가\",\n english: \"Expert who finds counter-attack opportunities through defense\",\n },\n },\n\n /**\n * 혼돈의 전사 (Hondon-ui Jeonsa) - Chaos Warrior\n * Unpredictable fighter using Jojik Pokryeokbae archetype\n *\n * **Dynamic Stance Rotation (Issue #dynamic-ai-stance-rotation)**:\n * - Increased stance switch frequency: 0.8 → 0.95 (unpredictable chaos)\n */\n CHAOS_WARRIOR: {\n name: \"Chaos Warrior\",\n koreanName: \"혼돈의 전사\",\n archetype: PlayerArchetype.JOJIK_POKRYEOKBAE,\n aggressionLevel: 0.9, // Enhanced: brutal pragmatists attack relentlessly\n defensePreference: 0.2, // Reduced: dirty fighters don't retreat\n comboTendency: 0.7, // Increased for vicious combinations\n stanceSwitchFrequency: 0.3, // Reduced: chaos is in attacks, not stance dancing\n feintChance: 0.5,\n tacticalRetreatThreshold: 0.05, // Reduced: fights to the bitter end\n favoredStances: [\n TrigramStance.LI, // Fire - Unpredictable\n TrigramStance.SON, // Wind - Constant motion\n TrigramStance.JIN, // Thunder - Explosive\n TrigramStance.TAE, // Lake - Fluid\n ],\n description: {\n korean: \"예측 불가능한 패턴으로 상대를 혼란시키는 전사\",\n english: \"Warrior who confuses opponents with unpredictable patterns\",\n },\n },\n};\n\n/**\n * Get a random AI personality\n */\nexport function getRandomPersonality(): AIPersonality {\n const personalities = Object.values(AI_PERSONALITIES);\n return personalities[Math.floor(Math.random() * personalities.length)];\n}\n\n/**\n * Get personality by archetype\n */\nexport function getPersonalityByArchetype(\n archetype: PlayerArchetype,\n): AIPersonality {\n const personality = Object.values(AI_PERSONALITIES).find(\n (p) => p.archetype === archetype,\n );\n return personality ?? AI_PERSONALITIES.BALANCED_FIGHTER;\n}\n\n/**\n * Get personality by name key\n */\nexport function getPersonalityByName(name: string): AIPersonality {\n return AI_PERSONALITIES[name] ?? AI_PERSONALITIES.BALANCED_FIGHTER;\n}\n\n/**\n * List all available personalities\n */\nexport function getAllPersonalities(): readonly AIPersonality[] {\n return Object.values(AI_PERSONALITIES);\n}\n\n/**\n * Get archetype-specific behavior profile\n *\n * Retrieves the unique combat behavior configuration for a given archetype,\n * including movement patterns, optimal ranges, and tactical preferences.\n *\n * @param archetype - Player archetype to get behavior for\n * @returns Archetype behavior profile\n *\n * @korean 원형별 행동 프로필 가져오기\n */\nexport function getArchetypeBehavior(\n archetype: PlayerArchetype,\n): ArchetypeBehavior {\n return ARCHETYPE_BEHAVIORS[archetype];\n}\n\n/**\n * Check if archetype follows honor code\n *\n * Honor code affects retreat behavior - honor-bound archetypes like Musa\n * will not retreat above their health threshold.\n *\n * @param archetype - Player archetype to check\n * @returns True if archetype follows honor code\n *\n * @korean 명예 규범 확인\n */\nexport function followsHonorCode(archetype: PlayerArchetype): boolean {\n return ARCHETYPE_BEHAVIORS[archetype].honorCode;\n}\n\n/**\n * Get optimal combat range for archetype\n *\n * Returns the preferred distance in grid cells (1 cell = ~40px) where\n * the archetype is most effective in combat.\n *\n * @param archetype - Player archetype\n * @returns Optimal range in grid cells\n *\n * @korean 최적 전투 거리 가져오기\n */\nexport function getOptimalRange(archetype: PlayerArchetype): number {\n return ARCHETYPE_BEHAVIORS[archetype].optimalRange;\n}\n"],"mappings":"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"}
@@ -17,7 +17,7 @@ var DifficultyTier = /* @__PURE__ */ function(DifficultyTier) {
17
17
  * @korean 각 난이도 단계별 매개변수 설정
18
18
  */
19
19
  var DIFFICULTY_PARAMETERS = {
20
- [DifficultyTier.BEGINNER]: {
20
+ [1]: {
21
21
  reactionTimeMs: {
22
22
  min: 800,
23
23
  max: 1200
@@ -29,7 +29,7 @@ var DIFFICULTY_PARAMETERS = {
29
29
  aggressionModifier: .7,
30
30
  comboChance: .2
31
31
  },
32
- [DifficultyTier.NOVICE]: {
32
+ [2]: {
33
33
  reactionTimeMs: {
34
34
  min: 500,
35
35
  max: 800
@@ -41,7 +41,7 @@ var DIFFICULTY_PARAMETERS = {
41
41
  aggressionModifier: .9,
42
42
  comboChance: .35
43
43
  },
44
- [DifficultyTier.INTERMEDIATE]: {
44
+ [3]: {
45
45
  reactionTimeMs: {
46
46
  min: 300,
47
47
  max: 500
@@ -53,7 +53,7 @@ var DIFFICULTY_PARAMETERS = {
53
53
  aggressionModifier: 1.1,
54
54
  comboChance: .5
55
55
  },
56
- [DifficultyTier.ADVANCED]: {
56
+ [4]: {
57
57
  reactionTimeMs: {
58
58
  min: 150,
59
59
  max: 300
@@ -65,7 +65,7 @@ var DIFFICULTY_PARAMETERS = {
65
65
  aggressionModifier: 1.3,
66
66
  comboChance: .6
67
67
  },
68
- [DifficultyTier.EXPERT]: {
68
+ [5]: {
69
69
  reactionTimeMs: {
70
70
  min: 50,
71
71
  max: 150
@@ -88,11 +88,11 @@ var DIFFICULTY_PARAMETERS = {
88
88
  * @returns Corresponding difficulty tier
89
89
  */
90
90
  function skillScoreToTier(score) {
91
- if (score < .2) return DifficultyTier.BEGINNER;
92
- if (score < .4) return DifficultyTier.NOVICE;
93
- if (score < .6) return DifficultyTier.INTERMEDIATE;
94
- if (score < .8) return DifficultyTier.ADVANCED;
95
- return DifficultyTier.EXPERT;
91
+ if (score < .2) return 1;
92
+ if (score < .4) return 2;
93
+ if (score < .6) return 3;
94
+ if (score < .8) return 4;
95
+ return 5;
96
96
  }
97
97
  /**
98
98
  * Linear interpolation helper
@@ -247,13 +247,13 @@ var AdaptiveDifficulty = class {
247
247
  getDifficultyRecommendation() {
248
248
  const skillLevel = this.calculatePlayerSkill();
249
249
  const tier = this.getDifficultyTier();
250
- const shouldIncrease = skillLevel > .7 && tier < DifficultyTier.EXPERT;
250
+ const shouldIncrease = skillLevel > .7 && tier < 5;
251
251
  const tierNames = {
252
- [DifficultyTier.BEGINNER]: "Beginner (초보)",
253
- [DifficultyTier.NOVICE]: "Novice (입문)",
254
- [DifficultyTier.INTERMEDIATE]: "Intermediate (중급)",
255
- [DifficultyTier.ADVANCED]: "Advanced (고급)",
256
- [DifficultyTier.EXPERT]: "Expert (전문)"
252
+ [1]: "Beginner (초보)",
253
+ [2]: "Novice (입문)",
254
+ [3]: "Intermediate (중급)",
255
+ [4]: "Advanced (고급)",
256
+ [5]: "Expert (전문)"
257
257
  };
258
258
  let message;
259
259
  if (shouldIncrease) message = "Player shows mastery - increasing difficulty";
@@ -1 +1 @@
1
- {"version":3,"file":"AdaptiveDifficulty.js","names":[],"sources":["../../../src/systems/ai/AdaptiveDifficulty.ts"],"sourcesContent":["/**\n * Adaptive Difficulty System for Korean Martial Arts Combat\n * Tracks player skill metrics and adjusts AI difficulty dynamically\n */\n\nimport { AIPersonality } from \"./AIPersonality\";\n\n/**\n * Player skill metrics tracked for adaptive difficulty\n */\nexport interface PlayerSkillMetrics {\n averageAccuracy: number; // 0.0-1.0: Hit rate\n comboCount: number; // Total combos executed\n perfectBlocks: number; // Perfect timing blocks\n reactionTime: number; // Average reaction time in ms\n vitalPointHits: number; // Successful vital point strikes\n stanceTransitions: number; // Effective stance changes\n damageEfficiency: number; // 0.0-1.0: Damage dealt vs taken ratio\n matchesPlayed: number; // Total matches for scaling\n}\n\n/**\n * Difficulty tier levels (5 tiers for adaptive system)\n */\nexport enum DifficultyTier {\n BEGINNER = 1,\n NOVICE = 2,\n INTERMEDIATE = 3,\n ADVANCED = 4,\n EXPERT = 5,\n}\n\n/**\n * Difficulty parameters that control AI behavior\n * Applied dynamically based on player skill level\n * \n * @korean 난이도 매개변수 - 플레이어 실력에 따라 AI 행동 제어\n */\nexport interface DifficultyParameters {\n /** AI reaction time range in milliseconds */\n readonly reactionTimeMs: { readonly min: number; readonly max: number };\n /** Accuracy for vital point strikes (0.0-1.0) */\n readonly vitalPointAccuracy: number;\n /** Accuracy for basic attacks (0.0-1.0) */\n readonly basicAttackAccuracy: number;\n /** Block timing window in milliseconds (smaller = harder to block) */\n readonly blockTimingWindow: number;\n /** Decision quality affects technique selection optimality (0.0-1.0) */\n readonly decisionQuality: number;\n /** Aggression modifier multiplier (0.5-2.0) */\n readonly aggressionModifier: number;\n /** Chance to attempt combo sequences (0.0-1.0) */\n readonly comboChance: number;\n}\n\n/**\n * Difficulty parameter sets for each skill tier\n * Defines AI behavior characteristics at each difficulty level\n * \n * @korean 각 난이도 단계별 매개변수 설정\n */\nexport const DIFFICULTY_PARAMETERS: Record<DifficultyTier, DifficultyParameters> = {\n [DifficultyTier.BEGINNER]: {\n reactionTimeMs: { min: 800, max: 1200 },\n vitalPointAccuracy: 0.40,\n basicAttackAccuracy: 0.70,\n blockTimingWindow: 150,\n decisionQuality: 0.50,\n aggressionModifier: 0.7,\n comboChance: 0.20,\n },\n [DifficultyTier.NOVICE]: {\n reactionTimeMs: { min: 500, max: 800 },\n vitalPointAccuracy: 0.55,\n basicAttackAccuracy: 0.78,\n blockTimingWindow: 120,\n decisionQuality: 0.65,\n aggressionModifier: 0.9,\n comboChance: 0.35,\n },\n [DifficultyTier.INTERMEDIATE]: {\n reactionTimeMs: { min: 300, max: 500 },\n vitalPointAccuracy: 0.65,\n basicAttackAccuracy: 0.85,\n blockTimingWindow: 90,\n decisionQuality: 0.75,\n aggressionModifier: 1.1,\n comboChance: 0.50,\n },\n [DifficultyTier.ADVANCED]: {\n reactionTimeMs: { min: 150, max: 300 },\n vitalPointAccuracy: 0.75,\n basicAttackAccuracy: 0.90,\n blockTimingWindow: 70,\n decisionQuality: 0.85,\n aggressionModifier: 1.3,\n comboChance: 0.60,\n },\n [DifficultyTier.EXPERT]: {\n reactionTimeMs: { min: 50, max: 150 },\n vitalPointAccuracy: 0.85,\n basicAttackAccuracy: 0.95,\n blockTimingWindow: 50,\n decisionQuality: 0.95,\n aggressionModifier: 1.5,\n comboChance: 0.70,\n },\n};\n\n/**\n * Map skill score (0.0-1.0) to difficulty tier\n * Uses fixed thresholds for consistent tier assignment\n * \n * @korean 실력 점수를 난이도 단계로 변환\n * \n * @param score - Player skill score (0.0-1.0)\n * @returns Corresponding difficulty tier\n */\nexport function skillScoreToTier(score: number): DifficultyTier {\n if (score < 0.2) return DifficultyTier.BEGINNER;\n if (score < 0.4) return DifficultyTier.NOVICE;\n if (score < 0.6) return DifficultyTier.INTERMEDIATE;\n if (score < 0.8) return DifficultyTier.ADVANCED;\n return DifficultyTier.EXPERT;\n}\n\n/**\n * Linear interpolation helper\n * @param a - Start value\n * @param b - End value\n * @param t - Interpolation factor (0.0-1.0)\n * @returns Interpolated value\n */\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * Math.max(0, Math.min(1, t));\n}\n\n/**\n * Interpolate between two difficulty parameter sets\n * Used for smooth difficulty transitions over time\n * \n * @korean 난이도 매개변수 간 부드러운 전환\n * \n * @param from - Starting difficulty parameters\n * @param to - Target difficulty parameters\n * @param progress - Interpolation progress (0.0-1.0)\n * @returns Interpolated difficulty parameters\n */\nexport function interpolateDifficultyParameters(\n from: DifficultyParameters,\n to: DifficultyParameters,\n progress: number\n): DifficultyParameters {\n const t = Math.max(0, Math.min(1, progress));\n \n return {\n reactionTimeMs: {\n min: lerp(from.reactionTimeMs.min, to.reactionTimeMs.min, t),\n max: lerp(from.reactionTimeMs.max, to.reactionTimeMs.max, t),\n },\n vitalPointAccuracy: lerp(from.vitalPointAccuracy, to.vitalPointAccuracy, t),\n basicAttackAccuracy: lerp(from.basicAttackAccuracy, to.basicAttackAccuracy, t),\n blockTimingWindow: lerp(from.blockTimingWindow, to.blockTimingWindow, t),\n decisionQuality: lerp(from.decisionQuality, to.decisionQuality, t),\n aggressionModifier: lerp(from.aggressionModifier, to.aggressionModifier, t),\n comboChance: lerp(from.comboChance, to.comboChance, t),\n };\n}\n\n/**\n * Adaptive Difficulty System\n */\nexport class AdaptiveDifficulty {\n private playerSkillMetrics: PlayerSkillMetrics;\n private readonly skillDecay = 0.95; // Gradual skill decay between matches\n private readonly learningRate = 0.1; // How quickly to adapt\n\n constructor() {\n this.playerSkillMetrics = {\n averageAccuracy: 0.5,\n comboCount: 0,\n perfectBlocks: 0,\n reactionTime: 800,\n vitalPointHits: 0,\n stanceTransitions: 0,\n damageEfficiency: 0.5,\n matchesPlayed: 0,\n };\n }\n\n /**\n * Update player skill metrics based on match performance\n */\n updateSkillMetrics(matchData: {\n hitsLanded: number;\n totalAttacks: number;\n combosExecuted: number;\n perfectBlockCount: number;\n avgReactionTimeMs: number;\n vitalPointsHit: number;\n effectiveStanceChanges: number;\n damageDealt: number;\n damageTaken: number;\n }): void {\n const { metrics } = this;\n\n // Update accuracy with learning rate\n const matchAccuracy =\n matchData.totalAttacks > 0\n ? matchData.hitsLanded / matchData.totalAttacks\n : 0.5;\n metrics.averageAccuracy =\n metrics.averageAccuracy * (1 - this.learningRate) +\n matchAccuracy * this.learningRate;\n\n // Update combo count\n metrics.comboCount += matchData.combosExecuted;\n\n // Update perfect blocks\n metrics.perfectBlocks += matchData.perfectBlockCount;\n\n // Update reaction time\n if (matchData.avgReactionTimeMs > 0) {\n metrics.reactionTime =\n metrics.reactionTime * (1 - this.learningRate) +\n matchData.avgReactionTimeMs * this.learningRate;\n }\n\n // Update vital point hits\n metrics.vitalPointHits += matchData.vitalPointsHit;\n\n // Update stance transitions\n metrics.stanceTransitions += matchData.effectiveStanceChanges;\n\n // Update damage efficiency\n const matchEfficiency =\n matchData.damageTaken > 0\n ? Math.min(1, matchData.damageDealt / matchData.damageTaken)\n : matchData.damageDealt > 0\n ? 1.0 // Perfect defense with damage dealt\n : 0.5; // No damage on either side\n metrics.damageEfficiency =\n metrics.damageEfficiency * (1 - this.learningRate) +\n matchEfficiency * this.learningRate;\n\n // Increment matches played\n metrics.matchesPlayed += 1;\n\n // Apply skill decay to prevent over-adjustment\n this.applySkillDecay();\n }\n\n /**\n * Apply gradual skill decay to prevent over-adjustment\n */\n private applySkillDecay(): void {\n const { metrics } = this;\n metrics.averageAccuracy =\n metrics.averageAccuracy * this.skillDecay +\n 0.5 * (1 - this.skillDecay);\n metrics.damageEfficiency =\n metrics.damageEfficiency * this.skillDecay +\n 0.5 * (1 - this.skillDecay);\n }\n\n /**\n * Calculate overall player skill level (0.0 - 1.0)\n */\n calculatePlayerSkill(): number {\n const { metrics } = this;\n\n // Weight different skill components\n const accuracyScore = metrics.averageAccuracy * 0.3;\n const comboScore = Math.min(1, metrics.comboCount / 20) * 0.2;\n const blockScore = Math.min(1, metrics.perfectBlocks / 10) * 0.2;\n const reactionScore = Math.max(0, 1 - metrics.reactionTime / 1000) * 0.15;\n const vitalScore = Math.min(1, metrics.vitalPointHits / 15) * 0.15;\n\n return accuracyScore + comboScore + blockScore + reactionScore + vitalScore;\n }\n\n /**\n * Get current difficulty tier based on skill level\n */\n getDifficultyTier(): DifficultyTier {\n const skillLevel = this.calculatePlayerSkill();\n return skillScoreToTier(skillLevel);\n }\n\n /**\n * Get difficulty parameters for current skill tier\n * Returns the appropriate DifficultyParameters based on player skill\n * \n * @korean 현재 실력 단계에 맞는 난이도 매개변수 반환\n */\n getDifficultyParameters(): DifficultyParameters {\n const tier = this.getDifficultyTier();\n return DIFFICULTY_PARAMETERS[tier];\n }\n\n /**\n * Adjust AI personality based on player skill\n */\n adjustAIPersonality(personality: AIPersonality): AIPersonality {\n const skillLevel = this.calculatePlayerSkill();\n const tier = this.getDifficultyTier();\n\n // Scale factors based on difficulty tier\n const aggressionScale = 1 + tier * 0.1; // +10% per tier\n const feintScale = 1 + tier * 0.15; // +15% per tier\n const comboScale = 1 + tier * 0.12; // +12% per tier\n const stanceScale = 1 + tier * 0.08; // +8% per tier\n\n return {\n ...personality,\n aggressionLevel: Math.min(\n 0.95,\n personality.aggressionLevel * aggressionScale\n ),\n feintChance: Math.min(0.6, personality.feintChance * feintScale),\n comboTendency: Math.min(0.85, personality.comboTendency * comboScale),\n stanceSwitchFrequency: Math.min(\n 0.9,\n personality.stanceSwitchFrequency * stanceScale\n ),\n // Adjust retreat threshold - better players face more aggressive AI\n tacticalRetreatThreshold: Math.max(\n 0.1,\n personality.tacticalRetreatThreshold * (1 - skillLevel * 0.3)\n ),\n };\n }\n\n /**\n * Get skill metrics\n */\n getMetrics(): Readonly<PlayerSkillMetrics> {\n return { ...this.playerSkillMetrics };\n }\n\n /**\n * Reset skill metrics\n */\n reset(): void {\n this.playerSkillMetrics = {\n averageAccuracy: 0.5,\n comboCount: 0,\n perfectBlocks: 0,\n reactionTime: 800,\n vitalPointHits: 0,\n stanceTransitions: 0,\n damageEfficiency: 0.5,\n matchesPlayed: 0,\n };\n }\n\n /**\n * Get difficulty adjustment recommendation\n */\n getDifficultyRecommendation(): {\n tier: DifficultyTier;\n tierName: string;\n skillLevel: number;\n shouldIncrease: boolean;\n message: string;\n } {\n const skillLevel = this.calculatePlayerSkill();\n const tier = this.getDifficultyTier();\n const shouldIncrease = skillLevel > 0.7 && tier < DifficultyTier.EXPERT;\n\n const tierNames: Record<DifficultyTier, string> = {\n [DifficultyTier.BEGINNER]: \"Beginner (초보)\",\n [DifficultyTier.NOVICE]: \"Novice (입문)\",\n [DifficultyTier.INTERMEDIATE]: \"Intermediate (중급)\",\n [DifficultyTier.ADVANCED]: \"Advanced (고급)\",\n [DifficultyTier.EXPERT]: \"Expert (전문)\",\n };\n\n let message: string;\n if (shouldIncrease) {\n message = \"Player shows mastery - increasing difficulty\";\n } else if (skillLevel < 0.3) {\n message = \"Player struggling - maintaining current difficulty\";\n } else {\n message = \"Player performing well - difficulty appropriate\";\n }\n\n return {\n tier,\n tierName: tierNames[tier],\n skillLevel,\n shouldIncrease,\n message,\n };\n }\n\n /**\n * Export metrics for persistence\n */\n exportMetrics(): string {\n return JSON.stringify(this.playerSkillMetrics);\n }\n\n /**\n * Import metrics from persistence\n */\n importMetrics(data: string): boolean {\n try {\n const metrics = JSON.parse(data) as PlayerSkillMetrics;\n this.playerSkillMetrics = metrics;\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get reference to metrics (for internal use)\n */\n private get metrics(): PlayerSkillMetrics {\n return this.playerSkillMetrics;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdaptiveDifficulty.js","names":[],"sources":["../../../src/systems/ai/AdaptiveDifficulty.ts"],"sourcesContent":["/**\n * Adaptive Difficulty System for Korean Martial Arts Combat\n * Tracks player skill metrics and adjusts AI difficulty dynamically\n */\n\nimport { AIPersonality } from \"./AIPersonality\";\n\n/**\n * Player skill metrics tracked for adaptive difficulty\n */\nexport interface PlayerSkillMetrics {\n averageAccuracy: number; // 0.0-1.0: Hit rate\n comboCount: number; // Total combos executed\n perfectBlocks: number; // Perfect timing blocks\n reactionTime: number; // Average reaction time in ms\n vitalPointHits: number; // Successful vital point strikes\n stanceTransitions: number; // Effective stance changes\n damageEfficiency: number; // 0.0-1.0: Damage dealt vs taken ratio\n matchesPlayed: number; // Total matches for scaling\n}\n\n/**\n * Difficulty tier levels (5 tiers for adaptive system)\n */\nexport enum DifficultyTier {\n BEGINNER = 1,\n NOVICE = 2,\n INTERMEDIATE = 3,\n ADVANCED = 4,\n EXPERT = 5,\n}\n\n/**\n * Difficulty parameters that control AI behavior\n * Applied dynamically based on player skill level\n * \n * @korean 난이도 매개변수 - 플레이어 실력에 따라 AI 행동 제어\n */\nexport interface DifficultyParameters {\n /** AI reaction time range in milliseconds */\n readonly reactionTimeMs: { readonly min: number; readonly max: number };\n /** Accuracy for vital point strikes (0.0-1.0) */\n readonly vitalPointAccuracy: number;\n /** Accuracy for basic attacks (0.0-1.0) */\n readonly basicAttackAccuracy: number;\n /** Block timing window in milliseconds (smaller = harder to block) */\n readonly blockTimingWindow: number;\n /** Decision quality affects technique selection optimality (0.0-1.0) */\n readonly decisionQuality: number;\n /** Aggression modifier multiplier (0.5-2.0) */\n readonly aggressionModifier: number;\n /** Chance to attempt combo sequences (0.0-1.0) */\n readonly comboChance: number;\n}\n\n/**\n * Difficulty parameter sets for each skill tier\n * Defines AI behavior characteristics at each difficulty level\n * \n * @korean 각 난이도 단계별 매개변수 설정\n */\nexport const DIFFICULTY_PARAMETERS: Record<DifficultyTier, DifficultyParameters> = {\n [DifficultyTier.BEGINNER]: {\n reactionTimeMs: { min: 800, max: 1200 },\n vitalPointAccuracy: 0.40,\n basicAttackAccuracy: 0.70,\n blockTimingWindow: 150,\n decisionQuality: 0.50,\n aggressionModifier: 0.7,\n comboChance: 0.20,\n },\n [DifficultyTier.NOVICE]: {\n reactionTimeMs: { min: 500, max: 800 },\n vitalPointAccuracy: 0.55,\n basicAttackAccuracy: 0.78,\n blockTimingWindow: 120,\n decisionQuality: 0.65,\n aggressionModifier: 0.9,\n comboChance: 0.35,\n },\n [DifficultyTier.INTERMEDIATE]: {\n reactionTimeMs: { min: 300, max: 500 },\n vitalPointAccuracy: 0.65,\n basicAttackAccuracy: 0.85,\n blockTimingWindow: 90,\n decisionQuality: 0.75,\n aggressionModifier: 1.1,\n comboChance: 0.50,\n },\n [DifficultyTier.ADVANCED]: {\n reactionTimeMs: { min: 150, max: 300 },\n vitalPointAccuracy: 0.75,\n basicAttackAccuracy: 0.90,\n blockTimingWindow: 70,\n decisionQuality: 0.85,\n aggressionModifier: 1.3,\n comboChance: 0.60,\n },\n [DifficultyTier.EXPERT]: {\n reactionTimeMs: { min: 50, max: 150 },\n vitalPointAccuracy: 0.85,\n basicAttackAccuracy: 0.95,\n blockTimingWindow: 50,\n decisionQuality: 0.95,\n aggressionModifier: 1.5,\n comboChance: 0.70,\n },\n};\n\n/**\n * Map skill score (0.0-1.0) to difficulty tier\n * Uses fixed thresholds for consistent tier assignment\n * \n * @korean 실력 점수를 난이도 단계로 변환\n * \n * @param score - Player skill score (0.0-1.0)\n * @returns Corresponding difficulty tier\n */\nexport function skillScoreToTier(score: number): DifficultyTier {\n if (score < 0.2) return DifficultyTier.BEGINNER;\n if (score < 0.4) return DifficultyTier.NOVICE;\n if (score < 0.6) return DifficultyTier.INTERMEDIATE;\n if (score < 0.8) return DifficultyTier.ADVANCED;\n return DifficultyTier.EXPERT;\n}\n\n/**\n * Linear interpolation helper\n * @param a - Start value\n * @param b - End value\n * @param t - Interpolation factor (0.0-1.0)\n * @returns Interpolated value\n */\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * Math.max(0, Math.min(1, t));\n}\n\n/**\n * Interpolate between two difficulty parameter sets\n * Used for smooth difficulty transitions over time\n * \n * @korean 난이도 매개변수 간 부드러운 전환\n * \n * @param from - Starting difficulty parameters\n * @param to - Target difficulty parameters\n * @param progress - Interpolation progress (0.0-1.0)\n * @returns Interpolated difficulty parameters\n */\nexport function interpolateDifficultyParameters(\n from: DifficultyParameters,\n to: DifficultyParameters,\n progress: number\n): DifficultyParameters {\n const t = Math.max(0, Math.min(1, progress));\n \n return {\n reactionTimeMs: {\n min: lerp(from.reactionTimeMs.min, to.reactionTimeMs.min, t),\n max: lerp(from.reactionTimeMs.max, to.reactionTimeMs.max, t),\n },\n vitalPointAccuracy: lerp(from.vitalPointAccuracy, to.vitalPointAccuracy, t),\n basicAttackAccuracy: lerp(from.basicAttackAccuracy, to.basicAttackAccuracy, t),\n blockTimingWindow: lerp(from.blockTimingWindow, to.blockTimingWindow, t),\n decisionQuality: lerp(from.decisionQuality, to.decisionQuality, t),\n aggressionModifier: lerp(from.aggressionModifier, to.aggressionModifier, t),\n comboChance: lerp(from.comboChance, to.comboChance, t),\n };\n}\n\n/**\n * Adaptive Difficulty System\n */\nexport class AdaptiveDifficulty {\n private playerSkillMetrics: PlayerSkillMetrics;\n private readonly skillDecay = 0.95; // Gradual skill decay between matches\n private readonly learningRate = 0.1; // How quickly to adapt\n\n constructor() {\n this.playerSkillMetrics = {\n averageAccuracy: 0.5,\n comboCount: 0,\n perfectBlocks: 0,\n reactionTime: 800,\n vitalPointHits: 0,\n stanceTransitions: 0,\n damageEfficiency: 0.5,\n matchesPlayed: 0,\n };\n }\n\n /**\n * Update player skill metrics based on match performance\n */\n updateSkillMetrics(matchData: {\n hitsLanded: number;\n totalAttacks: number;\n combosExecuted: number;\n perfectBlockCount: number;\n avgReactionTimeMs: number;\n vitalPointsHit: number;\n effectiveStanceChanges: number;\n damageDealt: number;\n damageTaken: number;\n }): void {\n const { metrics } = this;\n\n // Update accuracy with learning rate\n const matchAccuracy =\n matchData.totalAttacks > 0\n ? matchData.hitsLanded / matchData.totalAttacks\n : 0.5;\n metrics.averageAccuracy =\n metrics.averageAccuracy * (1 - this.learningRate) +\n matchAccuracy * this.learningRate;\n\n // Update combo count\n metrics.comboCount += matchData.combosExecuted;\n\n // Update perfect blocks\n metrics.perfectBlocks += matchData.perfectBlockCount;\n\n // Update reaction time\n if (matchData.avgReactionTimeMs > 0) {\n metrics.reactionTime =\n metrics.reactionTime * (1 - this.learningRate) +\n matchData.avgReactionTimeMs * this.learningRate;\n }\n\n // Update vital point hits\n metrics.vitalPointHits += matchData.vitalPointsHit;\n\n // Update stance transitions\n metrics.stanceTransitions += matchData.effectiveStanceChanges;\n\n // Update damage efficiency\n const matchEfficiency =\n matchData.damageTaken > 0\n ? Math.min(1, matchData.damageDealt / matchData.damageTaken)\n : matchData.damageDealt > 0\n ? 1.0 // Perfect defense with damage dealt\n : 0.5; // No damage on either side\n metrics.damageEfficiency =\n metrics.damageEfficiency * (1 - this.learningRate) +\n matchEfficiency * this.learningRate;\n\n // Increment matches played\n metrics.matchesPlayed += 1;\n\n // Apply skill decay to prevent over-adjustment\n this.applySkillDecay();\n }\n\n /**\n * Apply gradual skill decay to prevent over-adjustment\n */\n private applySkillDecay(): void {\n const { metrics } = this;\n metrics.averageAccuracy =\n metrics.averageAccuracy * this.skillDecay +\n 0.5 * (1 - this.skillDecay);\n metrics.damageEfficiency =\n metrics.damageEfficiency * this.skillDecay +\n 0.5 * (1 - this.skillDecay);\n }\n\n /**\n * Calculate overall player skill level (0.0 - 1.0)\n */\n calculatePlayerSkill(): number {\n const { metrics } = this;\n\n // Weight different skill components\n const accuracyScore = metrics.averageAccuracy * 0.3;\n const comboScore = Math.min(1, metrics.comboCount / 20) * 0.2;\n const blockScore = Math.min(1, metrics.perfectBlocks / 10) * 0.2;\n const reactionScore = Math.max(0, 1 - metrics.reactionTime / 1000) * 0.15;\n const vitalScore = Math.min(1, metrics.vitalPointHits / 15) * 0.15;\n\n return accuracyScore + comboScore + blockScore + reactionScore + vitalScore;\n }\n\n /**\n * Get current difficulty tier based on skill level\n */\n getDifficultyTier(): DifficultyTier {\n const skillLevel = this.calculatePlayerSkill();\n return skillScoreToTier(skillLevel);\n }\n\n /**\n * Get difficulty parameters for current skill tier\n * Returns the appropriate DifficultyParameters based on player skill\n * \n * @korean 현재 실력 단계에 맞는 난이도 매개변수 반환\n */\n getDifficultyParameters(): DifficultyParameters {\n const tier = this.getDifficultyTier();\n return DIFFICULTY_PARAMETERS[tier];\n }\n\n /**\n * Adjust AI personality based on player skill\n */\n adjustAIPersonality(personality: AIPersonality): AIPersonality {\n const skillLevel = this.calculatePlayerSkill();\n const tier = this.getDifficultyTier();\n\n // Scale factors based on difficulty tier\n const aggressionScale = 1 + tier * 0.1; // +10% per tier\n const feintScale = 1 + tier * 0.15; // +15% per tier\n const comboScale = 1 + tier * 0.12; // +12% per tier\n const stanceScale = 1 + tier * 0.08; // +8% per tier\n\n return {\n ...personality,\n aggressionLevel: Math.min(\n 0.95,\n personality.aggressionLevel * aggressionScale\n ),\n feintChance: Math.min(0.6, personality.feintChance * feintScale),\n comboTendency: Math.min(0.85, personality.comboTendency * comboScale),\n stanceSwitchFrequency: Math.min(\n 0.9,\n personality.stanceSwitchFrequency * stanceScale\n ),\n // Adjust retreat threshold - better players face more aggressive AI\n tacticalRetreatThreshold: Math.max(\n 0.1,\n personality.tacticalRetreatThreshold * (1 - skillLevel * 0.3)\n ),\n };\n }\n\n /**\n * Get skill metrics\n */\n getMetrics(): Readonly<PlayerSkillMetrics> {\n return { ...this.playerSkillMetrics };\n }\n\n /**\n * Reset skill metrics\n */\n reset(): void {\n this.playerSkillMetrics = {\n averageAccuracy: 0.5,\n comboCount: 0,\n perfectBlocks: 0,\n reactionTime: 800,\n vitalPointHits: 0,\n stanceTransitions: 0,\n damageEfficiency: 0.5,\n matchesPlayed: 0,\n };\n }\n\n /**\n * Get difficulty adjustment recommendation\n */\n getDifficultyRecommendation(): {\n tier: DifficultyTier;\n tierName: string;\n skillLevel: number;\n shouldIncrease: boolean;\n message: string;\n } {\n const skillLevel = this.calculatePlayerSkill();\n const tier = this.getDifficultyTier();\n const shouldIncrease = skillLevel > 0.7 && tier < DifficultyTier.EXPERT;\n\n const tierNames: Record<DifficultyTier, string> = {\n [DifficultyTier.BEGINNER]: \"Beginner (초보)\",\n [DifficultyTier.NOVICE]: \"Novice (입문)\",\n [DifficultyTier.INTERMEDIATE]: \"Intermediate (중급)\",\n [DifficultyTier.ADVANCED]: \"Advanced (고급)\",\n [DifficultyTier.EXPERT]: \"Expert (전문)\",\n };\n\n let message: string;\n if (shouldIncrease) {\n message = \"Player shows mastery - increasing difficulty\";\n } else if (skillLevel < 0.3) {\n message = \"Player struggling - maintaining current difficulty\";\n } else {\n message = \"Player performing well - difficulty appropriate\";\n }\n\n return {\n tier,\n tierName: tierNames[tier],\n skillLevel,\n shouldIncrease,\n message,\n };\n }\n\n /**\n * Export metrics for persistence\n */\n exportMetrics(): string {\n return JSON.stringify(this.playerSkillMetrics);\n }\n\n /**\n * Import metrics from persistence\n */\n importMetrics(data: string): boolean {\n try {\n const metrics = JSON.parse(data) as PlayerSkillMetrics;\n this.playerSkillMetrics = metrics;\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get reference to metrics (for internal use)\n */\n private get metrics(): PlayerSkillMetrics {\n return this.playerSkillMetrics;\n }\n}\n"],"mappings":"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"}