blacktrigram 0.7.47 → 0.7.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (471) hide show
  1. package/lib/App2.js.map +1 -1
  2. package/lib/audio/AudioAssetLoader.js.map +1 -1
  3. package/lib/audio/AudioAssetRegistry.js.map +1 -1
  4. package/lib/audio/AudioCache.js.map +1 -1
  5. package/lib/audio/AudioManager.js.map +1 -1
  6. package/lib/audio/AudioMonitor.js.map +1 -1
  7. package/lib/audio/AudioPool.js.map +1 -1
  8. package/lib/audio/AudioProvider.js.map +1 -1
  9. package/lib/audio/AudioUtils.js.map +1 -1
  10. package/lib/audio/BoneImpactAudioMap.js.map +1 -1
  11. package/lib/audio/VariantSelector.js.map +1 -1
  12. package/lib/audio/types.js.map +1 -1
  13. package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
  14. package/lib/components/screens/combat/CombatScreen3D.js +29 -25
  15. package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
  16. package/lib/components/screens/combat/components/controls/CombatButtons.js.map +1 -1
  17. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
  18. package/lib/components/screens/combat/components/controls/ControlsGuide.js.map +1 -1
  19. package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
  20. package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
  21. package/lib/components/screens/combat/components/controls/PauseMenuButton.js.map +1 -1
  22. package/lib/components/screens/combat/components/controls/QuickSettings.js.map +1 -1
  23. package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
  24. package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
  25. package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
  26. package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
  27. package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
  28. package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
  29. package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
  30. package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
  31. package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
  32. package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
  33. package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
  34. package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
  35. package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js.map +1 -1
  36. package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
  37. package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
  38. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js +2 -2
  39. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
  40. package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
  41. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js +1 -1
  42. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
  43. package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
  44. package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
  45. package/lib/components/screens/combat/components/hud/CombatTopHUD.js +2 -1
  46. package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
  47. package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
  48. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  49. package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
  50. package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
  51. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  52. package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
  53. package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
  54. package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
  55. package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
  56. package/lib/components/screens/combat/helpers/AnimationUpdater.js +4 -2
  57. package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
  58. package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
  59. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  60. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  61. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  62. package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
  63. package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
  64. package/lib/components/screens/combat/hooks/useCombatLayout.js +11 -5
  65. package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
  66. package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
  67. package/lib/components/screens/controls/ControlsScreen3D.js +1 -1
  68. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  69. package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
  70. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  71. package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
  72. package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
  73. package/lib/components/screens/controls/components/Key3D.js.map +1 -1
  74. package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
  75. package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
  76. package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
  77. package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
  78. package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
  79. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  80. package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
  81. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  82. package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
  83. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  84. package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
  85. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  86. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  87. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  88. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  89. package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
  90. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  91. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  92. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  93. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  94. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  95. package/lib/components/screens/philosophy/PhilosophyScreen3D.js +1 -1
  96. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  97. package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
  98. package/lib/components/screens/training/TrainingScreen3D.js +3 -11
  99. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  100. package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
  101. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  102. package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
  103. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  104. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  105. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  106. package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
  107. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  108. package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
  109. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  110. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  111. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  112. package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
  113. package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
  114. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js +2 -2
  115. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
  116. package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
  117. package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
  118. package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
  119. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  120. package/lib/components/screens/training/hooks/useTrainingActions.d.ts +1 -0
  121. package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
  122. package/lib/components/screens/training/hooks/useTrainingActions.js +6 -4
  123. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  124. package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
  125. package/lib/components/screens/training/hooks/useTrainingLayout.js +11 -5
  126. package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
  127. package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
  128. package/lib/components/shared/base/BaseButton.js.map +1 -1
  129. package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
  130. package/lib/components/shared/base/BasePanel.js.map +1 -1
  131. package/lib/components/shared/base/BaseText.js.map +1 -1
  132. package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
  133. package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
  134. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  135. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  136. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  137. package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
  138. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  139. package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
  140. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  141. package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
  142. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  143. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  144. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  145. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  146. package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
  147. package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
  148. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  149. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  150. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  151. package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
  152. package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
  153. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  154. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  155. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  156. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  157. package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
  158. package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
  159. package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
  160. package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
  161. package/lib/components/shared/three/models/SkeletalPlayer3D.js +7 -5
  162. package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
  163. package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
  164. package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
  165. package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
  166. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  167. package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
  168. package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
  169. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  170. package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
  171. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  172. package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
  173. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  174. package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
  175. package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
  176. package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
  177. package/lib/components/shared/three/ui/MenuList.js.map +1 -1
  178. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  179. package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
  180. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  181. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  182. package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
  183. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  184. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  185. package/lib/components/shared/ui/BackButton.js.map +1 -1
  186. package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
  187. package/lib/components/shared/ui/CombatTimer.js.map +1 -1
  188. package/lib/components/shared/ui/ErrorModal.js.map +1 -1
  189. package/lib/components/shared/ui/LoadingState.js.map +1 -1
  190. package/lib/components/shared/ui/SplashScreen.js +2 -2
  191. package/lib/components/shared/ui/SplashScreen.js.map +1 -1
  192. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  193. package/lib/components/shared/ui/VolumeControl.js.map +1 -1
  194. package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
  195. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  196. package/lib/constants/bodyDimensions.js.map +1 -1
  197. package/lib/constants/bodyRenderingConstants.js.map +1 -1
  198. package/lib/data/archetypeClothing.js.map +1 -1
  199. package/lib/data/archetypePhysicalAttributes.js.map +1 -1
  200. package/lib/data/techniqueMappings.js.map +1 -1
  201. package/lib/data/techniques.js.map +1 -1
  202. package/lib/hooks/useActionFeedback.js.map +1 -1
  203. package/lib/hooks/useBalanceAnimations.js.map +1 -1
  204. package/lib/hooks/useCombatTimer.js.map +1 -1
  205. package/lib/hooks/useDebounce.js.map +1 -1
  206. package/lib/hooks/useHUDLayout.d.ts.map +1 -1
  207. package/lib/hooks/useHUDLayout.js +3 -2
  208. package/lib/hooks/useHUDLayout.js.map +1 -1
  209. package/lib/hooks/useHandPoseTransitions.js.map +1 -1
  210. package/lib/hooks/useKeyboardControls.js.map +1 -1
  211. package/lib/hooks/useMatchCountdown.js.map +1 -1
  212. package/lib/hooks/useMuscleActivation.js.map +1 -1
  213. package/lib/hooks/usePauseMenu.js.map +1 -1
  214. package/lib/hooks/usePlayerAnimation.js.map +1 -1
  215. package/lib/hooks/useResponsiveLayout.js.map +1 -1
  216. package/lib/hooks/useRoundTransition.js.map +1 -1
  217. package/lib/hooks/useSkeletalAnimation.d.ts.map +1 -1
  218. package/lib/hooks/useSkeletalAnimation.js +1 -1
  219. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  220. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  221. package/lib/hooks/useThrottle.js.map +1 -1
  222. package/lib/hooks/useTouchControls.js.map +1 -1
  223. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  224. package/lib/hooks/useWindowSize.js.map +1 -1
  225. package/lib/systems/CombatSystem.js.map +1 -1
  226. package/lib/systems/EffectCalculator.js.map +1 -1
  227. package/lib/systems/LayoutSystem.js.map +1 -1
  228. package/lib/systems/PlayerEffectManager.js.map +1 -1
  229. package/lib/systems/ResponsiveScaling.js.map +1 -1
  230. package/lib/systems/TrigramSystem.js.map +1 -1
  231. package/lib/systems/VitalPointSystem.js.map +1 -1
  232. package/lib/systems/ai/AIPersonality.js.map +1 -1
  233. package/lib/systems/ai/AdaptiveDifficulty.js +16 -16
  234. package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
  235. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  236. package/lib/systems/ai/ComboSystem.js.map +1 -1
  237. package/lib/systems/ai/DecisionTree.js.map +1 -1
  238. package/lib/systems/ai/TrainingAI.js.map +1 -1
  239. package/lib/systems/ai/types.js.map +1 -1
  240. package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
  241. package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
  242. package/lib/systems/animation/builders/HandPoses.js.map +1 -1
  243. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  244. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  245. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts +6 -0
  246. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts.map +1 -1
  247. package/lib/systems/animation/builders/KickPhaseApplicator.js +16 -9
  248. package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
  249. package/lib/systems/animation/builders/KoreanGuardPositions.d.ts +4 -4
  250. package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
  251. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts +1 -1
  252. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts.map +1 -1
  253. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js +5 -5
  254. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  255. package/lib/systems/animation/builders/MartialArtsConstants.d.ts +112 -71
  256. package/lib/systems/animation/builders/MartialArtsConstants.d.ts.map +1 -1
  257. package/lib/systems/animation/builders/MartialArtsConstants.js +113 -72
  258. package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
  259. package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
  260. package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
  261. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  262. package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
  263. package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
  264. package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
  265. package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
  266. package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
  267. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  268. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
  269. package/lib/systems/animation/catalogs/EnhancedAttackAnimations.js.map +1 -1
  270. package/lib/systems/animation/catalogs/EnhancedElbowKneeAnimations.js.map +1 -1
  271. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  272. package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
  273. package/lib/systems/animation/catalogs/GamStanceAnimations.js +21 -0
  274. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -0
  275. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js +34 -2
  276. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
  277. package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
  278. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
  279. package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
  280. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts +9 -0
  281. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts.map +1 -1
  282. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +288 -0
  283. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -0
  284. package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
  285. package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
  286. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
  287. package/lib/systems/animation/catalogs/KickAnimations.d.ts +2 -2
  288. package/lib/systems/animation/catalogs/KickAnimations.js +2 -2
  289. package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
  290. package/lib/systems/animation/catalogs/LiStanceAnimations.js +14 -1
  291. package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
  292. package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
  293. package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
  294. package/lib/systems/animation/catalogs/PunchAnimations.d.ts +1 -1
  295. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  296. package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
  297. package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
  298. package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
  299. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
  300. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
  301. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  302. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  303. package/lib/systems/animation/catalogs/StanceGuardPoses.d.ts +6 -6
  304. package/lib/systems/animation/catalogs/StanceGuardPoses.js +36 -36
  305. package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
  306. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  307. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  308. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  309. package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
  310. package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
  311. package/lib/systems/animation/constants/AnatomicalLimits.js.map +1 -1
  312. package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
  313. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  314. package/lib/systems/animation/core/AnimationPriority.js +15 -15
  315. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  316. package/lib/systems/animation/core/AnimationRegistry.d.ts +30 -0
  317. package/lib/systems/animation/core/AnimationRegistry.d.ts.map +1 -1
  318. package/lib/systems/animation/core/AnimationRegistry.js +74 -12
  319. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  320. package/lib/systems/animation/core/AnimationStateMachine.js +16 -16
  321. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  322. package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
  323. package/lib/systems/animation/core/AnimationTransitions.js +34 -0
  324. package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
  325. package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
  326. package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
  327. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  328. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  329. package/lib/systems/animation/core/index.d.ts +1 -1
  330. package/lib/systems/animation/core/index.d.ts.map +1 -1
  331. package/lib/systems/animation/core/types.d.ts +24 -0
  332. package/lib/systems/animation/core/types.d.ts.map +1 -1
  333. package/lib/systems/animation/core/types.js +27 -11
  334. package/lib/systems/animation/core/types.js.map +1 -1
  335. package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
  336. package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
  337. package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
  338. package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
  339. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  340. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  341. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  342. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  343. package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
  344. package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
  345. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  346. package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
  347. package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
  348. package/lib/systems/bodypart/types.js.map +1 -1
  349. package/lib/systems/breathing/BreathingDisruptionSystem.js +19 -19
  350. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  351. package/lib/systems/breathing/feedback.js.map +1 -1
  352. package/lib/systems/breathing/integration.js.map +1 -1
  353. package/lib/systems/combat/BalanceSystem.js +19 -19
  354. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  355. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  356. package/lib/systems/combat/CombatStateSystem.js +17 -17
  357. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  358. package/lib/systems/combat/ConsciousnessSystem.js +24 -24
  359. package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
  360. package/lib/systems/combat/FallIntegration.js.map +1 -1
  361. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  362. package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
  363. package/lib/systems/combat/PainResponseSystem.js +21 -21
  364. package/lib/systems/combat/PainResponseSystem.js.map +1 -1
  365. package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
  366. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  367. package/lib/systems/combat/typeGuards.js.map +1 -1
  368. package/lib/systems/effects.js.map +1 -1
  369. package/lib/systems/game.js.map +1 -1
  370. package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
  371. package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
  372. package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
  373. package/lib/systems/movement/integration.js.map +1 -1
  374. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  375. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  376. package/lib/systems/physics/CoordinateMapper.js.map +1 -1
  377. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  378. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  379. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  380. package/lib/systems/physics/SpeedModifierSystem.js +6 -6
  381. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  382. package/lib/systems/trigram/KoreanCulture.js.map +1 -1
  383. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  384. package/lib/systems/trigram/StanceManager.js.map +1 -1
  385. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  386. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  387. package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
  388. package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
  389. package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
  390. package/lib/systems/trigram/techniques/GeonTechniques.js.map +1 -1
  391. package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
  392. package/lib/systems/trigram/techniques/JinTechniques.js.map +1 -1
  393. package/lib/systems/trigram/techniques/LiTechniques.js.map +1 -1
  394. package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
  395. package/lib/systems/trigram/techniques/TaeTechniques.js.map +1 -1
  396. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  397. package/lib/systems/trigram/techniques/index.js.map +1 -1
  398. package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
  399. package/lib/systems/trigram/types.js.map +1 -1
  400. package/lib/systems/types.js.map +1 -1
  401. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  402. package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
  403. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  404. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  405. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  406. package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
  407. package/lib/types/AccessibilityTypes.js.map +1 -1
  408. package/lib/types/LayoutTypes.js.map +1 -1
  409. package/lib/types/PhysicsTypes.js.map +1 -1
  410. package/lib/types/common.js.map +1 -1
  411. package/lib/types/constants/animations.js.map +1 -1
  412. package/lib/types/constants/colors.js.map +1 -1
  413. package/lib/types/constants/designSystem.js.map +1 -1
  414. package/lib/types/constants/index.js.map +1 -1
  415. package/lib/types/constants/layout.d.ts +21 -0
  416. package/lib/types/constants/layout.d.ts.map +1 -1
  417. package/lib/types/constants/layout.js +22 -1
  418. package/lib/types/constants/layout.js.map +1 -1
  419. package/lib/types/constants/performance.js.map +1 -1
  420. package/lib/types/constants/typography.js.map +1 -1
  421. package/lib/types/constants/ui.js.map +1 -1
  422. package/lib/types/facial.js +19 -19
  423. package/lib/types/facial.js.map +1 -1
  424. package/lib/types/hand-animation.js.map +1 -1
  425. package/lib/types/injury.js.map +1 -1
  426. package/lib/types/muscle.js.map +1 -1
  427. package/lib/types/physics.js.map +1 -1
  428. package/lib/types/physicsConstants.js.map +1 -1
  429. package/lib/types/player-visual.d.ts +1 -1
  430. package/lib/types/player-visual.d.ts.map +1 -1
  431. package/lib/types/skeletal.js.map +1 -1
  432. package/lib/types/techniqueId.js.map +1 -1
  433. package/lib/utils/accessibility.js.map +1 -1
  434. package/lib/utils/arenaWorldDimensions.js.map +1 -1
  435. package/lib/utils/assetConfig.js.map +1 -1
  436. package/lib/utils/characterScaling.js.map +1 -1
  437. package/lib/utils/colorHelpers.js.map +1 -1
  438. package/lib/utils/colorUtils.js.map +1 -1
  439. package/lib/utils/combatReadiness.js.map +1 -1
  440. package/lib/utils/controlMapping.js.map +1 -1
  441. package/lib/utils/deviceDetection.js +6 -7
  442. package/lib/utils/deviceDetection.js.map +1 -1
  443. package/lib/utils/effectUtils.js.map +1 -1
  444. package/lib/utils/fabricTextures.js.map +1 -1
  445. package/lib/utils/hapticFeedback.js.map +1 -1
  446. package/lib/utils/haptics.js.map +1 -1
  447. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  448. package/lib/utils/inputSystem.js.map +1 -1
  449. package/lib/utils/koreanThemeHelpers.js.map +1 -1
  450. package/lib/utils/math.js.map +1 -1
  451. package/lib/utils/mobileLayoutHelpers.js.map +1 -1
  452. package/lib/utils/mobileUIUtils.js.map +1 -1
  453. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  454. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  455. package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
  456. package/lib/utils/performanceOptimization.js.map +1 -1
  457. package/lib/utils/player3DHelpers.js.map +1 -1
  458. package/lib/utils/playerUtils.js.map +1 -1
  459. package/lib/utils/responsiveLayout.js.map +1 -1
  460. package/lib/utils/responsiveLayoutHelpers.d.ts +7 -0
  461. package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
  462. package/lib/utils/responsiveLayoutHelpers.js +16 -2
  463. package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
  464. package/lib/utils/responsiveOrientationConstants.js.map +1 -1
  465. package/lib/utils/safeAreaUtils.js.map +1 -1
  466. package/lib/utils/sharedPhysicsConfig.js.map +1 -1
  467. package/lib/utils/skeletonScaling.js.map +1 -1
  468. package/lib/utils/stanceHelpers.js.map +1 -1
  469. package/lib/utils/threeObjectPool.js.map +1 -1
  470. package/lib/utils/visualEffects.js.map +1 -1
  471. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"PlayerEffectManager.js","names":[],"sources":["../../src/systems/PlayerEffectManager.ts"],"sourcesContent":["/**\n * Player Effect Manager for tracking and applying status effects.\n * \n * **Korean**: 플레이어 효과 관리자 (Player Effect Manager)\n * \n * This module provides utilities for managing status effects on player state,\n * including adding effects with stacking logic, removing expired effects,\n * and applying effect-based combat modifiers.\n * \n * ## Key Features\n * \n * - **Effect Tracking**: Add, remove, and update status effects\n * - **Stacking Logic**: Manage concurrent effects (max 5)\n * - **Expiration Handling**: Auto-remove expired effects\n * - **Combat Modifiers**: Calculate effect-based stat changes\n * \n * @module systems/PlayerEffectManager\n * @category Player Management\n * @korean 플레이어효과관리\n */\n\nimport { VitalPointEffectType } from \"../types/common\";\nimport { StatusEffect } from \"./types\";\nimport { PlayerState } from \"./player\";\nimport { applyEffectStacking, MAX_CONCURRENT_EFFECTS } from \"./EffectCalculator\";\n\n/**\n * Adds status effects to a player's active effects list.\n * \n * **Korean**: 플레이어에 효과 추가 (Add Effects to Player)\n * \n * Applies stacking logic and respects the max concurrent effects limit.\n * \n * @param player - Current player state\n * @param effects - New effects to add\n * @returns Updated player state with new effects\n * \n * @example\n * ```typescript\n * const updatedPlayer = addEffectsToPlayer(\n * player,\n * [paralyze, bleed, stun]\n * );\n * ```\n * \n * @korean 효과추가\n */\nexport function addEffectsToPlayer(\n player: PlayerState,\n effects: readonly StatusEffect[]\n): PlayerState {\n const currentTime = Date.now();\n\n const updatedEffects = applyEffectStacking(\n player.statusEffects,\n effects,\n currentTime\n );\n\n const activeEffectIds = updatedEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: updatedEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Removes expired status effects from player.\n * \n * **Korean**: 만료 효과 제거 (Remove Expired Effects)\n * \n * Filters out effects whose endTime has passed.\n * \n * @param player - Current player state\n * @param currentTime - Current timestamp (default: Date.now())\n * @returns Updated player state with expired effects removed\n * \n * @example\n * ```typescript\n * const updatedPlayer = removeExpiredEffects(player, Date.now());\n * ```\n * \n * @korean 만료효과제거\n */\nexport function removeExpiredEffects(\n player: PlayerState,\n currentTime: number = Date.now()\n): PlayerState {\n const activeEffects = player.statusEffects.filter(\n (effect) => effect.endTime > currentTime\n );\n\n const activeEffectIds = activeEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: activeEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Removes a specific status effect by ID.\n * \n * **Korean**: 특정 효과 제거 (Remove Specific Effect)\n * \n * @param player - Current player state\n * @param effectId - ID of effect to remove\n * @returns Updated player state with effect removed\n * \n * @example\n * ```typescript\n * const updatedPlayer = removeEffectById(player, \"stun_12345\");\n * ```\n * \n * @korean 효과제거\n */\nexport function removeEffectById(\n player: PlayerState,\n effectId: string\n): PlayerState {\n const activeEffects = player.statusEffects.filter(\n (effect) => effect.id !== effectId\n );\n\n const activeEffectIds = activeEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: activeEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Removes all status effects of a specific type.\n * \n * **Korean**: 특정 유형 효과 모두 제거 (Remove All Effects of Type)\n * \n * @param player - Current player state\n * @param effectType - Type of effects to remove\n * @returns Updated player state with effects removed\n * \n * @example\n * ```typescript\n * const updatedPlayer = removeEffectsByType(\n * player,\n * VitalPointEffectType.PARALYSIS\n * );\n * ```\n * \n * @korean 유형별효과제거\n */\nexport function removeEffectsByType(\n player: PlayerState,\n effectType: VitalPointEffectType\n): PlayerState {\n const activeEffects = player.statusEffects.filter(\n (effect) => effect.type !== effectType\n );\n\n const activeEffectIds = activeEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: activeEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Clears all status effects from player.\n * \n * **Korean**: 모든 효과 제거 (Clear All Effects)\n * \n * Useful for healing items, rest periods, or match resets.\n * \n * @param player - Current player state\n * @returns Updated player state with no effects\n * \n * @example\n * ```typescript\n * const clearedPlayer = clearAllEffects(player);\n * ```\n * \n * @korean 전체효과제거\n */\nexport function clearAllEffects(player: PlayerState): PlayerState {\n return {\n ...player,\n statusEffects: [],\n activeEffects: [],\n };\n}\n\n/**\n * Calculates combat stat modifiers based on active status effects.\n * \n * **Korean**: 효과 기반 전투 배율 계산 (Calculate Effect-Based Combat Modifiers)\n * \n * Returns multipliers for various combat attributes affected by status effects.\n * \n * @param player - Current player state\n * @returns Object with stat multipliers (1.0 = no change)\n * \n * @example\n * ```typescript\n * const modifiers = getEffectModifiers(player);\n * const effectiveDamage = baseDamage * modifiers.attackPower;\n * const effectiveSpeed = baseSpeed * modifiers.speed;\n * ```\n * \n * @korean 효과배율계산\n */\nexport function getEffectModifiers(player: PlayerState): {\n attackPower: number;\n defense: number;\n speed: number;\n technique: number;\n staminaRegen: number;\n kiRegen: number;\n} {\n let attackPower = 1.0;\n let defense = 1.0;\n let speed = 1.0;\n let technique = 1.0;\n let staminaRegen = 1.0;\n let kiRegen = 1.0;\n\n for (const effect of player.statusEffects) {\n // UNCONSCIOUSNESS takes precedence - early return with complete incapacitation\n if (effect.type === VitalPointEffectType.UNCONSCIOUSNESS) {\n return {\n attackPower: 0,\n defense: 0,\n speed: 0,\n technique: 0,\n staminaRegen: 0,\n kiRegen: 0,\n };\n }\n\n // Apply other effect modifiers multiplicatively\n switch (effect.type) {\n case VitalPointEffectType.PARALYSIS:\n // Severe movement and action impairment\n attackPower *= 0.3;\n speed *= 0.2;\n technique *= 0.4;\n break;\n\n case VitalPointEffectType.STUN:\n // Moderate impairment\n attackPower *= 0.5;\n defense *= 0.6;\n speed *= 0.5;\n technique *= 0.6;\n break;\n\n case VitalPointEffectType.PAIN:\n // Reduces effectiveness across the board\n attackPower *= 0.7;\n defense *= 0.8;\n speed *= 0.8;\n technique *= 0.7;\n break;\n\n case VitalPointEffectType.BLOOD_FLOW_RESTRICTION:\n // Gradual weakening from reduced circulation\n attackPower *= 0.85;\n staminaRegen *= 0.5;\n break;\n\n case VitalPointEffectType.BREATHLESSNESS:\n // NOTE: Stamina regen is handled by BreathingDisruptionSystem.calculateStaminaRegen()\n // which applies severity-specific multipliers (25%-75% depending on disruption level).\n // DO NOT apply a flat multiplier here as it would compound with the breathing system.\n // Only apply secondary effects here.\n speed *= 0.7; // Reduced movement speed due to breathing difficulty\n break;\n\n case VitalPointEffectType.DISORIENTATION:\n // Accuracy and technique affected\n technique *= 0.6;\n defense *= 0.7;\n break;\n\n case VitalPointEffectType.WEAKNESS:\n // Overall power reduction\n attackPower *= 0.7;\n defense *= 0.8;\n break;\n\n case VitalPointEffectType.NERVE_DISRUPTION:\n // Ki system and coordination impaired\n kiRegen *= 0.5;\n attackPower *= 0.8;\n technique *= 0.7;\n break;\n\n case VitalPointEffectType.ORGAN_DISRUPTION:\n // Internal damage affecting all systems\n attackPower *= 0.6;\n defense *= 0.7;\n staminaRegen *= 0.4;\n kiRegen *= 0.4;\n break;\n }\n }\n\n return {\n attackPower,\n defense,\n speed,\n technique,\n staminaRegen,\n kiRegen,\n };\n}\n\n/**\n * Checks if player has a specific effect type active.\n * \n * **Korean**: 효과 활성 여부 확인 (Check Effect Active)\n * \n * @param player - Current player state\n * @param effectType - Type to check for\n * @returns True if effect type is active\n * \n * @example\n * ```typescript\n * if (hasEffect(player, VitalPointEffectType.PARALYSIS)) {\n * console.log(\"Player is paralyzed!\");\n * }\n * ```\n * \n * @korean 효과확인\n */\nexport function hasEffect(\n player: PlayerState,\n effectType: VitalPointEffectType\n): boolean {\n return player.statusEffects.some((effect) => effect.type === effectType);\n}\n\n/**\n * Gets all active effects of a specific type.\n * \n * **Korean**: 유형별 활성 효과 조회 (Get Effects by Type)\n * \n * @param player - Current player state\n * @param effectType - Type to retrieve\n * @returns Array of matching effects\n * \n * @korean 유형별효과조회\n */\nexport function getEffectsByType(\n player: PlayerState,\n effectType: VitalPointEffectType\n): StatusEffect[] {\n return player.statusEffects.filter((effect) => effect.type === effectType);\n}\n\n/**\n * Gets the total number of active status effects.\n * \n * **Korean**: 활성 효과 개수 조회 (Get Active Effect Count)\n * \n * @param player - Current player state\n * @returns Number of active effects\n * \n * @korean 효과개수조회\n */\nexport function getActiveEffectCount(player: PlayerState): number {\n return player.statusEffects.length;\n}\n\n/**\n * Checks if player can accept new status effects.\n * \n * **Korean**: 효과 추가 가능 여부 확인 (Can Add More Effects)\n * \n * @param player - Current player state\n * @returns True if under MAX_CONCURRENT_EFFECTS limit\n * \n * @korean 효과추가가능확인\n */\nexport function canAddMoreEffects(player: PlayerState): boolean {\n return player.statusEffects.length < MAX_CONCURRENT_EFFECTS;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,mBACd,QACA,SACa;CACb,MAAM,cAAc,KAAK,KAAK;CAE9B,MAAM,iBAAiB,oBACrB,OAAO,eACP,SACA,YACD;CAED,MAAM,kBAAkB,eAAe,KAAK,WAAW,OAAO,GAAG;CAEjE,OAAO;EACL,GAAG;EACH,eAAe;EACf,eAAe;EAChB;;;;;;;;;;;;;;;;;;;;AAqBH,SAAgB,qBACd,QACA,cAAsB,KAAK,KAAK,EACnB;CACb,MAAM,gBAAgB,OAAO,cAAc,QACxC,WAAW,OAAO,UAAU,YAC9B;CAED,MAAM,kBAAkB,cAAc,KAAK,WAAW,OAAO,GAAG;CAEhE,OAAO;EACL,GAAG;EACH,eAAe;EACf,eAAe;EAChB;;;;;;;;;;;;;;;;;;;;;AAoHH,SAAgB,mBAAmB,QAOjC;CACA,IAAI,cAAc;CAClB,IAAI,UAAU;CACd,IAAI,QAAQ;CACZ,IAAI,YAAY;CAChB,IAAI,eAAe;CACnB,IAAI,UAAU;CAEd,KAAK,MAAM,UAAU,OAAO,eAAe;EAEzC,IAAI,OAAO,SAAS,qBAAqB,iBACvC,OAAO;GACL,aAAa;GACb,SAAS;GACT,OAAO;GACP,WAAW;GACX,cAAc;GACd,SAAS;GACV;EAIH,QAAQ,OAAO,MAAf;GACE,KAAK,qBAAqB;IAExB,eAAe;IACf,SAAS;IACT,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX,SAAS;IACT,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX,SAAS;IACT,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,gBAAgB;IAChB;GAEF,KAAK,qBAAqB;IAKxB,SAAS;IACT;GAEF,KAAK,qBAAqB;IAExB,aAAa;IACb,WAAW;IACX;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX;GAEF,KAAK,qBAAqB;IAExB,WAAW;IACX,eAAe;IACf,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX,gBAAgB;IAChB,WAAW;IACX;;;CAIN,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD"}
1
+ {"version":3,"file":"PlayerEffectManager.js","names":[],"sources":["../../src/systems/PlayerEffectManager.ts"],"sourcesContent":["/**\n * Player Effect Manager for tracking and applying status effects.\n * \n * **Korean**: 플레이어 효과 관리자 (Player Effect Manager)\n * \n * This module provides utilities for managing status effects on player state,\n * including adding effects with stacking logic, removing expired effects,\n * and applying effect-based combat modifiers.\n * \n * ## Key Features\n * \n * - **Effect Tracking**: Add, remove, and update status effects\n * - **Stacking Logic**: Manage concurrent effects (max 5)\n * - **Expiration Handling**: Auto-remove expired effects\n * - **Combat Modifiers**: Calculate effect-based stat changes\n * \n * @module systems/PlayerEffectManager\n * @category Player Management\n * @korean 플레이어효과관리\n */\n\nimport { VitalPointEffectType } from \"../types/common\";\nimport { StatusEffect } from \"./types\";\nimport { PlayerState } from \"./player\";\nimport { applyEffectStacking, MAX_CONCURRENT_EFFECTS } from \"./EffectCalculator\";\n\n/**\n * Adds status effects to a player's active effects list.\n * \n * **Korean**: 플레이어에 효과 추가 (Add Effects to Player)\n * \n * Applies stacking logic and respects the max concurrent effects limit.\n * \n * @param player - Current player state\n * @param effects - New effects to add\n * @returns Updated player state with new effects\n * \n * @example\n * ```typescript\n * const updatedPlayer = addEffectsToPlayer(\n * player,\n * [paralyze, bleed, stun]\n * );\n * ```\n * \n * @korean 효과추가\n */\nexport function addEffectsToPlayer(\n player: PlayerState,\n effects: readonly StatusEffect[]\n): PlayerState {\n const currentTime = Date.now();\n\n const updatedEffects = applyEffectStacking(\n player.statusEffects,\n effects,\n currentTime\n );\n\n const activeEffectIds = updatedEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: updatedEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Removes expired status effects from player.\n * \n * **Korean**: 만료 효과 제거 (Remove Expired Effects)\n * \n * Filters out effects whose endTime has passed.\n * \n * @param player - Current player state\n * @param currentTime - Current timestamp (default: Date.now())\n * @returns Updated player state with expired effects removed\n * \n * @example\n * ```typescript\n * const updatedPlayer = removeExpiredEffects(player, Date.now());\n * ```\n * \n * @korean 만료효과제거\n */\nexport function removeExpiredEffects(\n player: PlayerState,\n currentTime: number = Date.now()\n): PlayerState {\n const activeEffects = player.statusEffects.filter(\n (effect) => effect.endTime > currentTime\n );\n\n const activeEffectIds = activeEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: activeEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Removes a specific status effect by ID.\n * \n * **Korean**: 특정 효과 제거 (Remove Specific Effect)\n * \n * @param player - Current player state\n * @param effectId - ID of effect to remove\n * @returns Updated player state with effect removed\n * \n * @example\n * ```typescript\n * const updatedPlayer = removeEffectById(player, \"stun_12345\");\n * ```\n * \n * @korean 효과제거\n */\nexport function removeEffectById(\n player: PlayerState,\n effectId: string\n): PlayerState {\n const activeEffects = player.statusEffects.filter(\n (effect) => effect.id !== effectId\n );\n\n const activeEffectIds = activeEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: activeEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Removes all status effects of a specific type.\n * \n * **Korean**: 특정 유형 효과 모두 제거 (Remove All Effects of Type)\n * \n * @param player - Current player state\n * @param effectType - Type of effects to remove\n * @returns Updated player state with effects removed\n * \n * @example\n * ```typescript\n * const updatedPlayer = removeEffectsByType(\n * player,\n * VitalPointEffectType.PARALYSIS\n * );\n * ```\n * \n * @korean 유형별효과제거\n */\nexport function removeEffectsByType(\n player: PlayerState,\n effectType: VitalPointEffectType\n): PlayerState {\n const activeEffects = player.statusEffects.filter(\n (effect) => effect.type !== effectType\n );\n\n const activeEffectIds = activeEffects.map((effect) => effect.id);\n\n return {\n ...player,\n statusEffects: activeEffects,\n activeEffects: activeEffectIds,\n };\n}\n\n/**\n * Clears all status effects from player.\n * \n * **Korean**: 모든 효과 제거 (Clear All Effects)\n * \n * Useful for healing items, rest periods, or match resets.\n * \n * @param player - Current player state\n * @returns Updated player state with no effects\n * \n * @example\n * ```typescript\n * const clearedPlayer = clearAllEffects(player);\n * ```\n * \n * @korean 전체효과제거\n */\nexport function clearAllEffects(player: PlayerState): PlayerState {\n return {\n ...player,\n statusEffects: [],\n activeEffects: [],\n };\n}\n\n/**\n * Calculates combat stat modifiers based on active status effects.\n * \n * **Korean**: 효과 기반 전투 배율 계산 (Calculate Effect-Based Combat Modifiers)\n * \n * Returns multipliers for various combat attributes affected by status effects.\n * \n * @param player - Current player state\n * @returns Object with stat multipliers (1.0 = no change)\n * \n * @example\n * ```typescript\n * const modifiers = getEffectModifiers(player);\n * const effectiveDamage = baseDamage * modifiers.attackPower;\n * const effectiveSpeed = baseSpeed * modifiers.speed;\n * ```\n * \n * @korean 효과배율계산\n */\nexport function getEffectModifiers(player: PlayerState): {\n attackPower: number;\n defense: number;\n speed: number;\n technique: number;\n staminaRegen: number;\n kiRegen: number;\n} {\n let attackPower = 1.0;\n let defense = 1.0;\n let speed = 1.0;\n let technique = 1.0;\n let staminaRegen = 1.0;\n let kiRegen = 1.0;\n\n for (const effect of player.statusEffects) {\n // UNCONSCIOUSNESS takes precedence - early return with complete incapacitation\n if (effect.type === VitalPointEffectType.UNCONSCIOUSNESS) {\n return {\n attackPower: 0,\n defense: 0,\n speed: 0,\n technique: 0,\n staminaRegen: 0,\n kiRegen: 0,\n };\n }\n\n // Apply other effect modifiers multiplicatively\n switch (effect.type) {\n case VitalPointEffectType.PARALYSIS:\n // Severe movement and action impairment\n attackPower *= 0.3;\n speed *= 0.2;\n technique *= 0.4;\n break;\n\n case VitalPointEffectType.STUN:\n // Moderate impairment\n attackPower *= 0.5;\n defense *= 0.6;\n speed *= 0.5;\n technique *= 0.6;\n break;\n\n case VitalPointEffectType.PAIN:\n // Reduces effectiveness across the board\n attackPower *= 0.7;\n defense *= 0.8;\n speed *= 0.8;\n technique *= 0.7;\n break;\n\n case VitalPointEffectType.BLOOD_FLOW_RESTRICTION:\n // Gradual weakening from reduced circulation\n attackPower *= 0.85;\n staminaRegen *= 0.5;\n break;\n\n case VitalPointEffectType.BREATHLESSNESS:\n // NOTE: Stamina regen is handled by BreathingDisruptionSystem.calculateStaminaRegen()\n // which applies severity-specific multipliers (25%-75% depending on disruption level).\n // DO NOT apply a flat multiplier here as it would compound with the breathing system.\n // Only apply secondary effects here.\n speed *= 0.7; // Reduced movement speed due to breathing difficulty\n break;\n\n case VitalPointEffectType.DISORIENTATION:\n // Accuracy and technique affected\n technique *= 0.6;\n defense *= 0.7;\n break;\n\n case VitalPointEffectType.WEAKNESS:\n // Overall power reduction\n attackPower *= 0.7;\n defense *= 0.8;\n break;\n\n case VitalPointEffectType.NERVE_DISRUPTION:\n // Ki system and coordination impaired\n kiRegen *= 0.5;\n attackPower *= 0.8;\n technique *= 0.7;\n break;\n\n case VitalPointEffectType.ORGAN_DISRUPTION:\n // Internal damage affecting all systems\n attackPower *= 0.6;\n defense *= 0.7;\n staminaRegen *= 0.4;\n kiRegen *= 0.4;\n break;\n }\n }\n\n return {\n attackPower,\n defense,\n speed,\n technique,\n staminaRegen,\n kiRegen,\n };\n}\n\n/**\n * Checks if player has a specific effect type active.\n * \n * **Korean**: 효과 활성 여부 확인 (Check Effect Active)\n * \n * @param player - Current player state\n * @param effectType - Type to check for\n * @returns True if effect type is active\n * \n * @example\n * ```typescript\n * if (hasEffect(player, VitalPointEffectType.PARALYSIS)) {\n * console.log(\"Player is paralyzed!\");\n * }\n * ```\n * \n * @korean 효과확인\n */\nexport function hasEffect(\n player: PlayerState,\n effectType: VitalPointEffectType\n): boolean {\n return player.statusEffects.some((effect) => effect.type === effectType);\n}\n\n/**\n * Gets all active effects of a specific type.\n * \n * **Korean**: 유형별 활성 효과 조회 (Get Effects by Type)\n * \n * @param player - Current player state\n * @param effectType - Type to retrieve\n * @returns Array of matching effects\n * \n * @korean 유형별효과조회\n */\nexport function getEffectsByType(\n player: PlayerState,\n effectType: VitalPointEffectType\n): StatusEffect[] {\n return player.statusEffects.filter((effect) => effect.type === effectType);\n}\n\n/**\n * Gets the total number of active status effects.\n * \n * **Korean**: 활성 효과 개수 조회 (Get Active Effect Count)\n * \n * @param player - Current player state\n * @returns Number of active effects\n * \n * @korean 효과개수조회\n */\nexport function getActiveEffectCount(player: PlayerState): number {\n return player.statusEffects.length;\n}\n\n/**\n * Checks if player can accept new status effects.\n * \n * **Korean**: 효과 추가 가능 여부 확인 (Can Add More Effects)\n * \n * @param player - Current player state\n * @returns True if under MAX_CONCURRENT_EFFECTS limit\n * \n * @korean 효과추가가능확인\n */\nexport function canAddMoreEffects(player: PlayerState): boolean {\n return player.statusEffects.length < MAX_CONCURRENT_EFFECTS;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,mBACd,QACA,SACa;CACb,MAAM,cAAc,KAAK,IAAI;CAE7B,MAAM,iBAAiB,oBACrB,OAAO,eACP,SACA,WACF;CAEA,MAAM,kBAAkB,eAAe,KAAK,WAAW,OAAO,EAAE;CAEhE,OAAO;EACL,GAAG;EACH,eAAe;EACf,eAAe;CACjB;AACF;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,qBACd,QACA,cAAsB,KAAK,IAAI,GAClB;CACb,MAAM,gBAAgB,OAAO,cAAc,QACxC,WAAW,OAAO,UAAU,WAC/B;CAEA,MAAM,kBAAkB,cAAc,KAAK,WAAW,OAAO,EAAE;CAE/D,OAAO;EACL,GAAG;EACH,eAAe;EACf,eAAe;CACjB;AACF;;;;;;;;;;;;;;;;;;;;AAmHA,SAAgB,mBAAmB,QAOjC;CACA,IAAI,cAAc;CAClB,IAAI,UAAU;CACd,IAAI,QAAQ;CACZ,IAAI,YAAY;CAChB,IAAI,eAAe;CACnB,IAAI,UAAU;CAEd,KAAK,MAAM,UAAU,OAAO,eAAe;EAEzC,IAAI,OAAO,SAAS,qBAAqB,iBACvC,OAAO;GACL,aAAa;GACb,SAAS;GACT,OAAO;GACP,WAAW;GACX,cAAc;GACd,SAAS;EACX;EAIF,QAAQ,OAAO,MAAf;GACE,KAAK,qBAAqB;IAExB,eAAe;IACf,SAAS;IACT,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX,SAAS;IACT,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX,SAAS;IACT,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,gBAAgB;IAChB;GAEF,KAAK,qBAAqB;IAKxB,SAAS;IACT;GAEF,KAAK,qBAAqB;IAExB,aAAa;IACb,WAAW;IACX;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX;GAEF,KAAK,qBAAqB;IAExB,WAAW;IACX,eAAe;IACf,aAAa;IACb;GAEF,KAAK,qBAAqB;IAExB,eAAe;IACf,WAAW;IACX,gBAAgB;IAChB,WAAW;IACX;EACJ;CACF;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -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":"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"}
@@ -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";