blacktrigram 0.7.44 → 0.7.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/audio/AudioManager.d.ts +26 -0
- package/lib/audio/AudioManager.d.ts.map +1 -1
- package/lib/audio/AudioManager.js +26 -0
- package/lib/audio/AudioManager.js.map +1 -1
- package/lib/audio/index.d.ts.map +1 -1
- package/lib/audio/index.js.map +1 -1
- package/lib/audio/types.d.ts +18 -2
- package/lib/audio/types.d.ts.map +1 -1
- package/lib/audio/types.js +1 -0
- package/lib/audio/types.js.map +1 -1
- package/lib/components/effects/WindParticles3D.d.ts.map +1 -1
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.d.ts +0 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.d.ts.map +1 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.js +0 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenu.d.ts.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ArterialSpray3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodDecals3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodParticles3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodViscosity3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BoneCrackParticles3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ConsciousnessBlur.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
- package/lib/components/screens/combat/components/effects/DustClouds3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/EarthCrackEffect3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/EarthHealingEffect3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/ImpactSparks3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/InternalDamage3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/LiPrecisionTargetingOverlay.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/NerveStrikeParticles3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/PainVignette.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ParticleAudio3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/TraumaOverlay3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/WaterRipple3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/WaterWave3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/index.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/MatchCountdown.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatLeftHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/DifficultyIndicator.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/hud/FPSMonitor.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
- package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/BalanceIndicator.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.d.ts +0 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js +0 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/StaminaWarning.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.d.ts +0 -2
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js +0 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
- package/lib/components/screens/combat/helpers/combatHelpers.d.ts.map +1 -1
- package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
- package/lib/components/screens/combat/hooks/useAICombat.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatActions.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAttackMovement.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAudio.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
- package/lib/components/screens/combat/hooks/useGrapplingAudio.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/usePreloadCombatAudio.d.ts.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.d.ts.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
- package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/GamepadVisualization3D.d.ts.map +1 -1
- package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
- package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/Key3D.d.ts.map +1 -1
- package/lib/components/screens/controls/components/Key3D.js.map +1 -1
- package/lib/components/screens/controls/components/VisualKeyboard3D.d.ts.map +1 -1
- package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
- package/lib/components/screens/controls/constants/ControlsConstants.d.ts.map +1 -1
- package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
- package/lib/components/screens/controls/hooks/useControlsState.d.ts.map +1 -1
- package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
- package/lib/components/screens/endscreen/EndScreen3D.d.ts.map +1 -1
- package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/DefeatAnimation3D.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/VictoryAnimation3D.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/index.d.ts.map +1 -1
- package/lib/components/screens/endscreen/index.d.ts.map +1 -1
- package/lib/components/screens/intro/IntroScreen3D.d.ts.map +1 -1
- package/lib/components/screens/intro/IntroScreen3D.js +1 -1
- package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
- package/lib/components/screens/intro/components/AbilityListOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuSectionOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/StatBarOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.d.ts.map +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
- package/lib/components/screens/philosophy/components/InteractiveTrigramGridOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/InteractiveTrigramGridOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/PhilosophyNavigationOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/PhilosophyNavigationOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/PhilosophySectionOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/PhilosophySectionOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/PhilosophyTextOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/PhilosophyTextOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/TrigramSymbol3D.d.ts +0 -1
- package/lib/components/screens/philosophy/components/TrigramSymbol3D.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/TrigramVisualization3D.d.ts +0 -1
- package/lib/components/screens/philosophy/components/TrigramVisualization3D.d.ts.map +1 -1
- package/lib/components/screens/philosophy/hooks/usePhilosophyState.d.ts +0 -1
- package/lib/components/screens/philosophy/hooks/usePhilosophyState.d.ts.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyOverlay3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
- package/lib/components/screens/training/components/DamageNumber3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/FootPlacementMarkers3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
- package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/HitFeedbackEffect3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingAICharacter3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingArena3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingControlsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingDummy3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingHitEffects3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingStatsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointMarker3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingLeftHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingRightHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingTopHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
- package/lib/components/screens/training/components/index.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useAttackMovement.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingState.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
- package/lib/components/shared/base/AccessibilityProvider.d.ts.map +1 -1
- package/lib/components/shared/base/BaseButton.d.ts.map +1 -1
- package/lib/components/shared/base/BaseButton.js.map +1 -1
- package/lib/components/shared/base/BaseButtonOverlayHtml.d.ts.map +1 -1
- package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
- package/lib/components/shared/base/BasePanel.d.ts.map +1 -1
- package/lib/components/shared/base/BasePanel.js.map +1 -1
- package/lib/components/shared/base/BaseText.d.ts.map +1 -1
- package/lib/components/shared/base/BaseText.js.map +1 -1
- package/lib/components/shared/base/ResponsiveContainer.d.ts.map +1 -1
- package/lib/components/shared/base/index.d.ts.map +1 -1
- package/lib/components/shared/base/useKoreanTheme.d.ts.map +1 -1
- package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
- package/lib/components/shared/debug/PerformanceDebugOverlayHtml.d.ts.map +1 -1
- package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
- package/lib/components/shared/effects/ScreenFlash.d.ts.map +1 -1
- package/lib/components/shared/mobile/ActionButtons.d.ts.map +1 -1
- package/lib/components/shared/mobile/ActionButtons.js +0 -1
- package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.d.ts +0 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.d.ts.map +1 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.js +0 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
- package/lib/components/shared/mobile/HapticController.d.ts +0 -13
- package/lib/components/shared/mobile/HapticController.d.ts.map +1 -1
- package/lib/components/shared/mobile/HapticController.js +0 -10
- package/lib/components/shared/mobile/HapticController.js.map +1 -1
- package/lib/components/shared/mobile/MobileControlsPure.d.ts.map +1 -1
- package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
- package/lib/components/shared/mobile/PerformanceMonitor.d.ts +0 -15
- package/lib/components/shared/mobile/PerformanceMonitor.d.ts.map +1 -1
- package/lib/components/shared/mobile/StanceWheelPure.d.ts +0 -1
- package/lib/components/shared/mobile/StanceWheelPure.d.ts.map +1 -1
- package/lib/components/shared/mobile/StanceWheelPure.js +0 -1
- package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
- package/lib/components/shared/mobile/TouchOptimizer.d.ts +0 -4
- package/lib/components/shared/mobile/TouchOptimizer.d.ts.map +1 -1
- package/lib/components/shared/mobile/TouchOptimizer.js +0 -3
- package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
- package/lib/components/shared/mobile/VirtualDPad.d.ts.map +1 -1
- package/lib/components/shared/mobile/VirtualDPad.js +0 -1
- package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
- package/lib/components/shared/mobile/index.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BodySurface.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneAttachedMuscles.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneClothing.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.d.ts +0 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
- package/lib/components/shared/three/anatomy/Face3D.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Foot3D.d.ts +0 -1
- package/lib/components/shared/three/anatomy/Foot3D.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Hand3D.d.ts +0 -1
- package/lib/components/shared/three/anatomy/Hand3D.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
- package/lib/components/shared/three/effects/ActionFeedback.d.ts.map +1 -1
- package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
- package/lib/components/shared/three/effects/DamageNumbers.d.ts.map +1 -1
- package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
- package/lib/components/shared/three/effects/ExplosiveBurstEffect3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/GrapplingIndicator3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/HitEffects3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
- package/lib/components/shared/three/effects/LimbExposureIndicator3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/NerveDisruptionEffect3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/PlayerStateIndicators.d.ts.map +1 -1
- package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
- package/lib/components/shared/three/effects/StanceSymbol3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
- package/lib/components/shared/three/effects/StanceTransitionEffect.d.ts.map +1 -1
- package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
- package/lib/components/shared/three/effects/ThunderEffect3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/VitalPointMarkers3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
- package/lib/components/shared/three/index.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/ElementalColorSystem.d.ts +0 -6
- package/lib/components/shared/three/indicators/ElementalColorSystem.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/ElementalColorSystem.js +0 -4
- package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
- package/lib/components/shared/three/indicators/GuardIndicator.d.ts +0 -1
- package/lib/components/shared/three/indicators/GuardIndicator.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/GuardIndicator.js +0 -1
- package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
- package/lib/components/shared/three/indicators/HapticFeedback.d.ts +0 -7
- package/lib/components/shared/three/indicators/HapticFeedback.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/HapticFeedback.js +0 -2
- package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.d.ts +0 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.js +0 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
- package/lib/components/shared/three/indicators/TrigramSymbol3D.d.ts +0 -1
- package/lib/components/shared/three/indicators/TrigramSymbol3D.d.ts.map +1 -1
- package/lib/components/shared/three/models/Player3DWithTransitions.d.ts.map +1 -1
- package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
- package/lib/components/shared/three/optimization/AdaptiveQuality.d.ts.map +1 -1
- package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
- package/lib/components/shared/three/optimization/InstancedGeometry.d.ts.map +1 -1
- package/lib/components/shared/three/optimization/LODSystem.d.ts.map +1 -1
- package/lib/components/shared/three/scene/AtmosphericParticles3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
- package/lib/components/shared/three/scene/BackgroundScene3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
- package/lib/components/shared/three/scene/CombatArena3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
- package/lib/components/shared/three/scene/DebugCollision.d.ts +0 -2
- package/lib/components/shared/three/scene/DebugCollision.d.ts.map +1 -1
- package/lib/components/shared/three/scene/KoreanSignage3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
- package/lib/components/shared/three/ui/ArchetypeCard.d.ts.map +1 -1
- package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
- package/lib/components/shared/three/ui/BodyPartHealthDisplay.d.ts.map +1 -1
- package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
- package/lib/components/shared/three/ui/BreathingIndicator.d.ts.map +1 -1
- package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
- package/lib/components/shared/three/ui/CombatReadinessBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
- package/lib/components/shared/three/ui/ComboCounter.d.ts.map +1 -1
- package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
- package/lib/components/shared/three/ui/HealthBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanButton.d.ts.map +1 -1
- package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanPanel.d.ts.map +1 -1
- package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanText.d.ts.map +1 -1
- package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
- package/lib/components/shared/three/ui/MenuList.d.ts.map +1 -1
- package/lib/components/shared/three/ui/MenuList.js.map +1 -1
- package/lib/components/shared/three/ui/PlayerHUD.d.ts.map +1 -1
- package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
- package/lib/components/shared/three/ui/ProgressBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.d.ts +0 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.d.ts.map +1 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.js +0 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
- package/lib/components/shared/three/ui/StaminaBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBarContainer.d.ts.map +1 -1
- package/lib/components/shared/three/ui/TechniqueCard.d.ts.map +1 -1
- package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
- package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.d.ts.map +1 -1
- package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
- package/lib/components/shared/three/ui/VulnerabilityWindowHUD.d.ts.map +1 -1
- package/lib/components/shared/ui/BaseHUDContainer.d.ts.map +1 -1
- package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
- package/lib/components/shared/ui/CombatTimer.d.ts.map +1 -1
- package/lib/components/shared/ui/CombatTimer.js.map +1 -1
- package/lib/components/shared/ui/ErrorBoundary.d.ts.map +1 -1
- package/lib/components/shared/ui/ErrorModal.d.ts.map +1 -1
- package/lib/components/shared/ui/ErrorModal.js.map +1 -1
- package/lib/components/shared/ui/HUDSection.d.ts.map +1 -1
- package/lib/components/shared/ui/LoadingState.d.ts.map +1 -1
- package/lib/components/shared/ui/LoadingState.js.map +1 -1
- package/lib/components/shared/ui/MobileHUDLayout.d.ts +0 -1
- package/lib/components/shared/ui/MobileHUDLayout.d.ts.map +1 -1
- package/lib/components/shared/ui/ResponsiveContainer.d.ts +0 -1
- package/lib/components/shared/ui/ResponsiveContainer.d.ts.map +1 -1
- package/lib/components/shared/ui/SplashScreen.d.ts.map +1 -1
- package/lib/components/shared/ui/SplashScreen.js +2 -2
- package/lib/components/shared/ui/SplashScreen.js.map +1 -1
- package/lib/components/shared/ui/StyledHUDPanel.d.ts.map +1 -1
- package/lib/components/shared/ui/VitalPointOverlayControlsPure.d.ts.map +1 -1
- package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
- package/lib/components/shared/ui/VolumeControl.d.ts.map +1 -1
- package/lib/components/shared/ui/VolumeControl.js.map +1 -1
- package/lib/components/shared/ui/shared/ConfirmDialog.d.ts.map +1 -1
- package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
- package/lib/components/test/Hello3D.d.ts.map +1 -1
- package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.d.ts.map +1 -1
- package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
- package/lib/components/ui/combat/ComboCounter.d.ts.map +1 -1
- package/lib/components/ui/combat/PressureMeter.d.ts.map +1 -1
- package/lib/systems/CombatSystem.d.ts +0 -6
- package/lib/systems/CombatSystem.d.ts.map +1 -1
- package/lib/systems/CombatSystem.js +0 -6
- package/lib/systems/CombatSystem.js.map +1 -1
- package/lib/systems/EffectCalculator.d.ts +0 -7
- package/lib/systems/EffectCalculator.d.ts.map +1 -1
- package/lib/systems/EffectCalculator.js +0 -4
- package/lib/systems/EffectCalculator.js.map +1 -1
- package/lib/systems/LayoutSystem.d.ts +0 -1
- package/lib/systems/LayoutSystem.d.ts.map +1 -1
- package/lib/systems/LayoutSystem.js +0 -1
- package/lib/systems/LayoutSystem.js.map +1 -1
- package/lib/systems/PlayerEffectManager.d.ts +0 -10
- package/lib/systems/PlayerEffectManager.d.ts.map +1 -1
- package/lib/systems/PlayerEffectManager.js +0 -3
- package/lib/systems/PlayerEffectManager.js.map +1 -1
- package/lib/systems/ResponsiveScaling.d.ts +0 -12
- package/lib/systems/ResponsiveScaling.d.ts.map +1 -1
- package/lib/systems/ResponsiveScaling.js +0 -12
- package/lib/systems/ResponsiveScaling.js.map +1 -1
- package/lib/systems/TrigramSystem.d.ts +0 -13
- package/lib/systems/TrigramSystem.d.ts.map +1 -1
- package/lib/systems/TrigramSystem.js +0 -13
- package/lib/systems/TrigramSystem.js.map +1 -1
- package/lib/systems/VitalPointSystem.d.ts +0 -10
- package/lib/systems/VitalPointSystem.d.ts.map +1 -1
- package/lib/systems/VitalPointSystem.js +0 -10
- package/lib/systems/VitalPointSystem.js.map +1 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.d.ts +0 -4
- package/lib/systems/animation/builders/KeyframeInterpolation.d.ts.map +1 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.js +0 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
- package/lib/systems/animation/builders/SkeletonRig.d.ts +0 -4
- package/lib/systems/animation/builders/SkeletonRig.d.ts.map +1 -1
- package/lib/systems/animation/builders/SkeletonRig.js +0 -3
- package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.d.ts +0 -5
- package/lib/systems/animation/catalogs/RecoveryAnimations.d.ts.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.js +0 -5
- package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
- package/lib/systems/animation/core/AnimationHitTiming.d.ts +0 -6
- package/lib/systems/animation/core/AnimationHitTiming.d.ts.map +1 -1
- package/lib/systems/animation/core/AnimationHitTiming.js +0 -4
- package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.d.ts +0 -3
- package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
- package/lib/systems/animation/core/LateralityTransform.d.ts +0 -3
- package/lib/systems/animation/core/LateralityTransform.d.ts.map +1 -1
- package/lib/systems/animation/core/LateralityTransform.js +0 -1
- package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.d.ts +0 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.d.ts.map +1 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapper.d.ts +0 -10
- package/lib/systems/animation/core/TechniqueAnimationMapper.d.ts.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapper.js +0 -8
- package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
- package/lib/systems/animation/core/TrigramAnimationMapping.d.ts +0 -10
- package/lib/systems/animation/core/TrigramAnimationMapping.d.ts.map +1 -1
- package/lib/systems/animation/core/TrigramStanceTransitions.d.ts +0 -2
- package/lib/systems/animation/core/TrigramStanceTransitions.d.ts.map +1 -1
- package/lib/systems/animation/core/types.d.ts +0 -39
- package/lib/systems/animation/core/types.d.ts.map +1 -1
- package/lib/systems/animation/core/types.js +0 -9
- package/lib/systems/animation/core/types.js.map +1 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.d.ts +0 -27
- package/lib/systems/animation/systems/AdvancedJointMovements.d.ts.map +1 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.js +0 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
- package/lib/systems/animation/systems/BodyFacingSystem.d.ts +0 -19
- package/lib/systems/animation/systems/BodyFacingSystem.d.ts.map +1 -1
- package/lib/systems/animation/systems/BodyFacingSystem.js +0 -14
- package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
- package/lib/systems/animation/systems/FacialExpressions.d.ts +0 -10
- package/lib/systems/animation/systems/FacialExpressions.d.ts.map +1 -1
- package/lib/systems/animation/systems/FacialExpressions.js +0 -2
- package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
- package/lib/systems/animation/systems/FallAnimations.d.ts +0 -4
- package/lib/systems/animation/systems/FallAnimations.d.ts.map +1 -1
- package/lib/systems/animation/systems/FallAnimations.js +0 -2
- package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
- package/lib/systems/animation/systems/HeadMovements.d.ts +0 -10
- package/lib/systems/animation/systems/HeadMovements.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartDamageIntegration.d.ts +0 -7
- package/lib/systems/bodypart/BodyPartDamageIntegration.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartDamageIntegration.js +0 -7
- package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
- package/lib/systems/bodypart/BodyPartHealthSystem.d.ts +0 -13
- package/lib/systems/bodypart/BodyPartHealthSystem.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartHealthSystem.js +0 -13
- package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
- package/lib/systems/bodypart/BodyPartPositionMapping.d.ts +0 -6
- package/lib/systems/bodypart/BodyPartPositionMapping.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartPositionMapping.js +0 -6
- package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
- package/lib/systems/bodypart/CombatInjuryIntegration.d.ts +0 -10
- package/lib/systems/bodypart/CombatInjuryIntegration.d.ts.map +1 -1
- package/lib/systems/bodypart/CombatInjuryIntegration.js +0 -8
- package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryIntegration.d.ts +0 -2
- package/lib/systems/bodypart/InjuryIntegration.d.ts.map +1 -1
- package/lib/systems/bodypart/InjuryIntegration.js +0 -2
- package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryTracker.d.ts +0 -14
- package/lib/systems/bodypart/InjuryTracker.d.ts.map +1 -1
- package/lib/systems/bodypart/InjuryTracker.js +0 -12
- package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
- package/lib/systems/bodypart/MovementPenaltySystem.d.ts +0 -8
- package/lib/systems/bodypart/MovementPenaltySystem.d.ts.map +1 -1
- package/lib/systems/bodypart/MovementPenaltySystem.js +0 -8
- package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.d.ts +0 -8
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.d.ts.map +1 -1
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.js +0 -8
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
- package/lib/systems/bodypart/types.d.ts +0 -13
- package/lib/systems/bodypart/types.d.ts.map +1 -1
- package/lib/systems/bodypart/types.js +0 -5
- package/lib/systems/bodypart/types.js.map +1 -1
- package/lib/systems/breathing/BreathingDisruptionSystem.d.ts +0 -3
- package/lib/systems/breathing/BreathingDisruptionSystem.d.ts.map +1 -1
- package/lib/systems/breathing/BreathingDisruptionSystem.js +0 -2
- package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
- package/lib/systems/combat/BalanceSystem.d.ts +0 -25
- package/lib/systems/combat/BalanceSystem.d.ts.map +1 -1
- package/lib/systems/combat/BalanceSystem.js +0 -25
- package/lib/systems/combat/BalanceSystem.js.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.d.ts +0 -4
- package/lib/systems/combat/BreakingStatusEffects.d.ts.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.js +0 -3
- package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
- package/lib/systems/combat/CombatStateSystem.d.ts +0 -9
- package/lib/systems/combat/CombatStateSystem.d.ts.map +1 -1
- package/lib/systems/combat/CombatStateSystem.js +0 -9
- package/lib/systems/combat/CombatStateSystem.js.map +1 -1
- package/lib/systems/combat/ConsciousnessSystem.d.ts +0 -16
- package/lib/systems/combat/ConsciousnessSystem.d.ts.map +1 -1
- package/lib/systems/combat/ConsciousnessSystem.js +0 -16
- package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
- package/lib/systems/combat/FallIntegration.d.ts +0 -3
- package/lib/systems/combat/FallIntegration.d.ts.map +1 -1
- package/lib/systems/combat/FallIntegration.js +0 -3
- package/lib/systems/combat/FallIntegration.js.map +1 -1
- package/lib/systems/combat/GrappleSystem.d.ts +0 -2
- package/lib/systems/combat/GrappleSystem.d.ts.map +1 -1
- package/lib/systems/combat/GrappleSystem.js +0 -2
- package/lib/systems/combat/GrappleSystem.js.map +1 -1
- package/lib/systems/combat/LimbExposureSystem.d.ts +0 -7
- package/lib/systems/combat/LimbExposureSystem.d.ts.map +1 -1
- package/lib/systems/combat/LimbExposureSystem.js +0 -7
- package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
- package/lib/systems/combat/PainResponseSystem.d.ts +0 -11
- package/lib/systems/combat/PainResponseSystem.d.ts.map +1 -1
- package/lib/systems/combat/PainResponseSystem.js +0 -11
- package/lib/systems/combat/PainResponseSystem.js.map +1 -1
- package/lib/systems/combat/painConsciousnessUtils.d.ts +0 -7
- package/lib/systems/combat/painConsciousnessUtils.d.ts.map +1 -1
- package/lib/systems/combat/painConsciousnessUtils.js +0 -7
- package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
- package/lib/systems/effects.d.ts +11 -0
- package/lib/systems/effects.d.ts.map +1 -1
- package/lib/systems/effects.js +10 -0
- package/lib/systems/effects.js.map +1 -1
- package/lib/systems/game.d.ts +16 -0
- package/lib/systems/game.d.ts.map +1 -1
- package/lib/systems/game.js +1 -0
- package/lib/systems/game.js.map +1 -1
- package/lib/systems/index.d.ts +5 -1
- package/lib/systems/index.d.ts.map +1 -1
- package/lib/systems/index.js.map +1 -1
- package/lib/systems/movement/InjuryMovementModifier.d.ts +0 -10
- package/lib/systems/movement/InjuryMovementModifier.d.ts.map +1 -1
- package/lib/systems/movement/InjuryMovementModifier.js +0 -7
- package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
- package/lib/systems/movement/integration.d.ts +0 -3
- package/lib/systems/movement/integration.d.ts.map +1 -1
- package/lib/systems/movement/integration.js +0 -3
- package/lib/systems/movement/integration.js.map +1 -1
- package/lib/systems/physics/AttackMovementPhysics.d.ts +0 -9
- package/lib/systems/physics/AttackMovementPhysics.d.ts.map +1 -1
- package/lib/systems/physics/AttackMovementPhysics.js +0 -7
- package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
- package/lib/systems/physics/CollisionDetection.d.ts +0 -6
- package/lib/systems/physics/CollisionDetection.d.ts.map +1 -1
- package/lib/systems/physics/CollisionDetection.js +0 -6
- package/lib/systems/physics/CollisionDetection.js.map +1 -1
- package/lib/systems/physics/CoordinateMapper.d.ts +0 -1
- package/lib/systems/physics/CoordinateMapper.d.ts.map +1 -1
- package/lib/systems/physics/CoordinateMapper.js +0 -1
- package/lib/systems/physics/CoordinateMapper.js.map +1 -1
- package/lib/systems/physics/KnockbackPhysics.d.ts +0 -11
- package/lib/systems/physics/KnockbackPhysics.d.ts.map +1 -1
- package/lib/systems/physics/KnockbackPhysics.js +0 -8
- package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
- package/lib/systems/physics/MovementPhysics.d.ts +0 -10
- package/lib/systems/physics/MovementPhysics.d.ts.map +1 -1
- package/lib/systems/physics/MovementPhysics.js +0 -8
- package/lib/systems/physics/MovementPhysics.js.map +1 -1
- package/lib/systems/physics/PhysicalReachCalculator.d.ts +0 -6
- package/lib/systems/physics/PhysicalReachCalculator.d.ts.map +1 -1
- package/lib/systems/physics/PhysicalReachCalculator.js +0 -5
- package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
- package/lib/systems/physics/SpeedModifierSystem.d.ts +0 -5
- package/lib/systems/physics/SpeedModifierSystem.d.ts.map +1 -1
- package/lib/systems/physics/SpeedModifierSystem.js +0 -4
- package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
- package/lib/systems/player.d.ts +0 -5
- package/lib/systems/player.d.ts.map +1 -1
- package/lib/systems/trigram/TrigramCalculator.d.ts +0 -1
- package/lib/systems/trigram/TrigramCalculator.d.ts.map +1 -1
- package/lib/systems/trigram/TrigramCalculator.js +0 -1
- package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
- package/lib/systems/trigram/types.d.ts +0 -4
- package/lib/systems/trigram/types.d.ts.map +1 -1
- package/lib/systems/trigram/types.js +0 -2
- package/lib/systems/trigram/types.js.map +1 -1
- package/lib/systems/types.d.ts +7 -2
- package/lib/systems/types.d.ts.map +1 -1
- package/lib/systems/types.js.map +1 -1
- package/lib/systems/vitalpoint/DamageCalculator.d.ts +0 -3
- package/lib/systems/vitalpoint/DamageCalculator.d.ts.map +1 -1
- package/lib/systems/vitalpoint/DamageCalculator.js +0 -3
- package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
- package/lib/systems/vitalpoint/KoreanVitalPoints.d.ts +0 -8
- package/lib/systems/vitalpoint/KoreanVitalPoints.d.ts.map +1 -1
- package/lib/systems/vitalpoint/KoreanVitalPoints.js +0 -8
- package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
- package/lib/systems/vitalpoint/VitalPointsData.d.ts +0 -3
- package/lib/systems/vitalpoint/VitalPointsData.d.ts.map +1 -1
- package/lib/systems/vitalpoint/VitalPointsData.js +0 -1
- package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
- package/lib/types/PhysicsTypes.d.ts +21 -78
- package/lib/types/PhysicsTypes.d.ts.map +1 -1
- package/lib/types/PhysicsTypes.js +17 -63
- package/lib/types/PhysicsTypes.js.map +1 -1
- package/lib/types/clothing.d.ts +0 -9
- package/lib/types/clothing.d.ts.map +1 -1
- package/lib/types/constants/animations.d.ts +35 -1
- package/lib/types/constants/animations.d.ts.map +1 -1
- package/lib/types/constants/animations.js +12 -1
- package/lib/types/constants/animations.js.map +1 -1
- package/lib/types/constants/colors.d.ts +28 -2
- package/lib/types/constants/colors.d.ts.map +1 -1
- package/lib/types/constants/colors.js +30 -4
- package/lib/types/constants/colors.js.map +1 -1
- package/lib/types/constants/index.d.ts +5 -1
- package/lib/types/constants/index.d.ts.map +1 -1
- package/lib/types/constants/index.js.map +1 -1
- package/lib/types/constants/performance.d.ts +0 -2
- package/lib/types/constants/performance.d.ts.map +1 -1
- package/lib/types/constants/performance.js +0 -2
- package/lib/types/constants/performance.js.map +1 -1
- package/lib/types/constants/typography.d.ts +40 -2
- package/lib/types/constants/typography.d.ts.map +1 -1
- package/lib/types/constants/typography.js +40 -2
- package/lib/types/constants/typography.js.map +1 -1
- package/lib/types/constants/ui.d.ts +89 -1
- package/lib/types/constants/ui.d.ts.map +1 -1
- package/lib/types/constants/ui.js +33 -1
- package/lib/types/constants/ui.js.map +1 -1
- package/lib/types/facial.d.ts +0 -15
- package/lib/types/facial.d.ts.map +1 -1
- package/lib/types/facial.js +0 -8
- package/lib/types/facial.js.map +1 -1
- package/lib/types/hand-animation.d.ts +34 -147
- package/lib/types/hand-animation.d.ts.map +1 -1
- package/lib/types/hand-animation.js +0 -2
- package/lib/types/hand-animation.js.map +1 -1
- package/lib/types/injury.d.ts +0 -2
- package/lib/types/injury.d.ts.map +1 -1
- package/lib/types/injury.js +0 -1
- package/lib/types/injury.js.map +1 -1
- package/lib/types/physics.d.ts +0 -21
- package/lib/types/physics.d.ts.map +1 -1
- package/lib/types/physics.js +0 -6
- package/lib/types/physics.js.map +1 -1
- package/lib/types/physicsConstants.d.ts +0 -12
- package/lib/types/physicsConstants.d.ts.map +1 -1
- package/lib/types/physicsConstants.js +0 -12
- package/lib/types/physicsConstants.js.map +1 -1
- package/lib/types/player-visual.d.ts +45 -189
- package/lib/types/player-visual.d.ts.map +1 -1
- package/lib/types/technique.d.ts +1 -5
- package/lib/types/technique.d.ts.map +1 -1
- package/lib/types/techniqueId.d.ts +0 -1
- package/lib/types/techniqueId.d.ts.map +1 -1
- package/lib/types/techniqueId.js +0 -1
- package/lib/types/techniqueId.js.map +1 -1
- package/lib/utils/arenaWorldDimensions.d.ts +0 -11
- package/lib/utils/arenaWorldDimensions.d.ts.map +1 -1
- package/lib/utils/arenaWorldDimensions.js +0 -6
- package/lib/utils/arenaWorldDimensions.js.map +1 -1
- package/lib/utils/controlMapping.d.ts +3 -4
- package/lib/utils/controlMapping.d.ts.map +1 -1
- package/lib/utils/controlMapping.js +1 -2
- package/lib/utils/controlMapping.js.map +1 -1
- package/lib/utils/deviceDetection.d.ts +0 -5
- package/lib/utils/deviceDetection.d.ts.map +1 -1
- package/lib/utils/deviceDetection.js +0 -5
- package/lib/utils/deviceDetection.js.map +1 -1
- package/lib/utils/hapticFeedback.d.ts +23 -95
- package/lib/utils/hapticFeedback.d.ts.map +1 -1
- package/lib/utils/hapticFeedback.js +9 -39
- package/lib/utils/hapticFeedback.js.map +1 -1
- package/lib/utils/haptics.d.ts +0 -3
- package/lib/utils/haptics.d.ts.map +1 -1
- package/lib/utils/haptics.js +0 -1
- package/lib/utils/haptics.js.map +1 -1
- package/lib/utils/math.d.ts +0 -3
- package/lib/utils/math.d.ts.map +1 -1
- package/lib/utils/math.js +0 -2
- package/lib/utils/math.js.map +1 -1
- package/lib/utils/mobileLayoutHelpers.d.ts +0 -3
- package/lib/utils/mobileLayoutHelpers.d.ts.map +1 -1
- package/lib/utils/mobileLayoutHelpers.js +0 -1
- package/lib/utils/mobileLayoutHelpers.js.map +1 -1
- package/lib/utils/mobileUIUtils.d.ts +5 -100
- package/lib/utils/mobileUIUtils.d.ts.map +1 -1
- package/lib/utils/mobileUIUtils.js +0 -9
- package/lib/utils/mobileUIUtils.js.map +1 -1
- package/lib/utils/physicalAttributeValidation.d.ts.map +1 -1
- package/lib/utils/player3DHelpers.d.ts.map +1 -1
- package/lib/utils/player3DHelpers.js.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.d.ts +0 -65
- package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.js +0 -65
- package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
- package/lib/utils/responsiveOrientationConstants.d.ts +0 -7
- package/lib/utils/responsiveOrientationConstants.d.ts.map +1 -1
- package/lib/utils/responsiveOrientationConstants.js +0 -7
- package/lib/utils/responsiveOrientationConstants.js.map +1 -1
- package/lib/utils/safeAreaUtils.d.ts +0 -6
- package/lib/utils/safeAreaUtils.d.ts.map +1 -1
- package/lib/utils/safeAreaUtils.js +0 -2
- package/lib/utils/safeAreaUtils.js.map +1 -1
- package/lib/utils/sharedPhysicsConfig.d.ts +0 -4
- package/lib/utils/sharedPhysicsConfig.d.ts.map +1 -1
- package/lib/utils/sharedPhysicsConfig.js +0 -2
- package/lib/utils/sharedPhysicsConfig.js.map +1 -1
- package/lib/utils/skeletonScaling.d.ts +0 -9
- package/lib/utils/skeletonScaling.d.ts.map +1 -1
- package/lib/utils/skeletonScaling.js +0 -1
- package/lib/utils/skeletonScaling.js.map +1 -1
- package/package.json +7 -7
|
@@ -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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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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"}
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
* }
|
|
53
53
|
* ```
|
|
54
54
|
*
|
|
55
|
-
* @public
|
|
56
55
|
* @category Vital Point System
|
|
57
56
|
* @korean 급소시스템
|
|
58
57
|
*/
|
|
@@ -84,7 +83,6 @@ export declare class VitalPointSystem {
|
|
|
84
83
|
* vitalPointSystem.setCurrentHour(20); // 8 PM - Pericardium peak time
|
|
85
84
|
* ```
|
|
86
85
|
*
|
|
87
|
-
* @public
|
|
88
86
|
* @korean 시간설정
|
|
89
87
|
*/
|
|
90
88
|
setCurrentHour(hour: number): void;
|
|
@@ -95,7 +93,6 @@ export declare class VitalPointSystem {
|
|
|
95
93
|
*
|
|
96
94
|
* @returns Current hour (0-23)
|
|
97
95
|
*
|
|
98
|
-
* @public
|
|
99
96
|
* @korean 시간조회
|
|
100
97
|
*/
|
|
101
98
|
getCurrentHour(): number;
|
|
@@ -107,7 +104,6 @@ export declare class VitalPointSystem {
|
|
|
107
104
|
* @param meridianId - ID of the meridian
|
|
108
105
|
* @param disruptionLevel - Disruption level (0-1, where 1 is fully blocked)
|
|
109
106
|
*
|
|
110
|
-
* @public
|
|
111
107
|
* @korean 경락차단업데이트
|
|
112
108
|
*/
|
|
113
109
|
setMeridianDisruption(meridianId: string, disruptionLevel: number): void;
|
|
@@ -119,7 +115,6 @@ export declare class VitalPointSystem {
|
|
|
119
115
|
* @param meridianId - ID of the meridian
|
|
120
116
|
* @returns Disruption level (0-1)
|
|
121
117
|
*
|
|
122
|
-
* @public
|
|
123
118
|
* @korean 경락차단조회
|
|
124
119
|
*/
|
|
125
120
|
getMeridianDisruption(meridianId: string): number;
|
|
@@ -128,7 +123,6 @@ export declare class VitalPointSystem {
|
|
|
128
123
|
*
|
|
129
124
|
* **Korean**: 경락 상태 초기화
|
|
130
125
|
*
|
|
131
|
-
* @public
|
|
132
126
|
* @korean 경락초기화
|
|
133
127
|
*/
|
|
134
128
|
clearMeridianDisruptions(): void;
|
|
@@ -182,7 +176,6 @@ export declare class VitalPointSystem {
|
|
|
182
176
|
* );
|
|
183
177
|
* ```
|
|
184
178
|
*
|
|
185
|
-
* @public
|
|
186
179
|
* @korean 타격처리
|
|
187
180
|
*/
|
|
188
181
|
processHit(targetPosition: Position, _hitBox: {
|
|
@@ -204,7 +197,6 @@ export declare class VitalPointSystem {
|
|
|
204
197
|
* }
|
|
205
198
|
* ```
|
|
206
199
|
*
|
|
207
|
-
* @public
|
|
208
200
|
* @korean 급소조회
|
|
209
201
|
*/
|
|
210
202
|
getVitalPointById(id: string): VitalPoint | null;
|
|
@@ -219,7 +211,6 @@ export declare class VitalPointSystem {
|
|
|
219
211
|
* console.log(`${allPoints.length} vital points registered`);
|
|
220
212
|
* ```
|
|
221
213
|
*
|
|
222
|
-
* @public
|
|
223
214
|
* @korean 급소목록조회
|
|
224
215
|
*/
|
|
225
216
|
getVitalPoints(): readonly VitalPoint[];
|
|
@@ -251,7 +242,6 @@ export declare class VitalPointSystem {
|
|
|
251
242
|
* );
|
|
252
243
|
* ```
|
|
253
244
|
*
|
|
254
|
-
* @public
|
|
255
245
|
* @korean 기술타격계산
|
|
256
246
|
*/
|
|
257
247
|
calculateHit(technique: any, attackerPosition: Position, _defenderPosition: Position, // Prefixed with underscore to indicate intentionally unused
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VitalPointSystem.d.ts","sourceRoot":"","sources":["../../src/systems/VitalPointSystem.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"VitalPointSystem.d.ts","sourceRoot":"","sources":["../../src/systems/VitalPointSystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,OAAO,EACL,eAAe,EACf,QAAQ,EACR,aAAa,EAEd,MAAM,iBAAiB,CAAC;AASzB,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAQrE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,WAAW,CAAc;IAEjC;;;;;;;OAOG;gBACS,WAAW,GAAE,MAAW;IAKpC;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOlC;;;;;;;;OAQG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;;;;;;OASG;IACH,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI;IAOxE;;;;;;;;;OASG;IACH,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIjD;;;;;;OAMG;IACH,wBAAwB,IAAI,IAAI;IAIhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmDG;IACH,UAAU,CACR,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,4DAA4D;IACxG,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,EACpC,IAAI,CAAC,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,eAAe,EACnC,iBAAiB,CAAC,EAAE,eAAe,EACnC,cAAc,CAAC,EAAE,aAAa,GAC7B,mBAAmB;IA2DtB;;;;;;;;;;;;;;;OAeG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAIhD;;;;;;;;;;;;OAYG;IACH,cAAc,IAAI,SAAS,UAAU,EAAE;IAIvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,YAAY,CAEV,SAAS,EAAE,GAAG,EACd,gBAAgB,EAAE,QAAQ,EAC1B,iBAAiB,EAAE,QAAQ,EAAE,4DAA4D;IAEzF,eAAe,EAAE,GAAG,GACnB,mBAAmB;IAoCtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,qBAAqB;IAiB7B;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,sBAAsB;IAwF9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;CAG9B;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -58,7 +58,6 @@ import { calculateEnhancedVulnerability, calculateMeridianFlow, generateMeridian
|
|
|
58
58
|
* }
|
|
59
59
|
* ```
|
|
60
60
|
*
|
|
61
|
-
* @public
|
|
62
61
|
* @category Vital Point System
|
|
63
62
|
* @korean 급소시스템
|
|
64
63
|
*/
|
|
@@ -95,7 +94,6 @@ var VitalPointSystem = class {
|
|
|
95
94
|
* vitalPointSystem.setCurrentHour(20); // 8 PM - Pericardium peak time
|
|
96
95
|
* ```
|
|
97
96
|
*
|
|
98
|
-
* @public
|
|
99
97
|
* @korean 시간설정
|
|
100
98
|
*/
|
|
101
99
|
setCurrentHour(hour) {
|
|
@@ -109,7 +107,6 @@ var VitalPointSystem = class {
|
|
|
109
107
|
*
|
|
110
108
|
* @returns Current hour (0-23)
|
|
111
109
|
*
|
|
112
|
-
* @public
|
|
113
110
|
* @korean 시간조회
|
|
114
111
|
*/
|
|
115
112
|
getCurrentHour() {
|
|
@@ -123,7 +120,6 @@ var VitalPointSystem = class {
|
|
|
123
120
|
* @param meridianId - ID of the meridian
|
|
124
121
|
* @param disruptionLevel - Disruption level (0-1, where 1 is fully blocked)
|
|
125
122
|
*
|
|
126
|
-
* @public
|
|
127
123
|
* @korean 경락차단업데이트
|
|
128
124
|
*/
|
|
129
125
|
setMeridianDisruption(meridianId, disruptionLevel) {
|
|
@@ -137,7 +133,6 @@ var VitalPointSystem = class {
|
|
|
137
133
|
* @param meridianId - ID of the meridian
|
|
138
134
|
* @returns Disruption level (0-1)
|
|
139
135
|
*
|
|
140
|
-
* @public
|
|
141
136
|
* @korean 경락차단조회
|
|
142
137
|
*/
|
|
143
138
|
getMeridianDisruption(meridianId) {
|
|
@@ -148,7 +143,6 @@ var VitalPointSystem = class {
|
|
|
148
143
|
*
|
|
149
144
|
* **Korean**: 경락 상태 초기화
|
|
150
145
|
*
|
|
151
|
-
* @public
|
|
152
146
|
* @korean 경락초기화
|
|
153
147
|
*/
|
|
154
148
|
clearMeridianDisruptions() {
|
|
@@ -204,7 +198,6 @@ var VitalPointSystem = class {
|
|
|
204
198
|
* );
|
|
205
199
|
* ```
|
|
206
200
|
*
|
|
207
|
-
* @public
|
|
208
201
|
* @korean 타격처리
|
|
209
202
|
*/
|
|
210
203
|
processHit(targetPosition, _hitBox, targetedVitalPointId, hour, attackerArchetype, defenderArchetype, defenderStance) {
|
|
@@ -245,7 +238,6 @@ var VitalPointSystem = class {
|
|
|
245
238
|
* }
|
|
246
239
|
* ```
|
|
247
240
|
*
|
|
248
|
-
* @public
|
|
249
241
|
* @korean 급소조회
|
|
250
242
|
*/
|
|
251
243
|
getVitalPointById(id) {
|
|
@@ -262,7 +254,6 @@ var VitalPointSystem = class {
|
|
|
262
254
|
* console.log(`${allPoints.length} vital points registered`);
|
|
263
255
|
* ```
|
|
264
256
|
*
|
|
265
|
-
* @public
|
|
266
257
|
* @korean 급소목록조회
|
|
267
258
|
*/
|
|
268
259
|
getVitalPoints() {
|
|
@@ -296,7 +287,6 @@ var VitalPointSystem = class {
|
|
|
296
287
|
* );
|
|
297
288
|
* ```
|
|
298
289
|
*
|
|
299
|
-
* @public
|
|
300
290
|
* @korean 기술타격계산
|
|
301
291
|
*/
|
|
302
292
|
calculateHit(technique, attackerPosition, _defenderPosition, _defenderStance) {
|
|
@@ -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 * @public\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 // Initialize with comprehensive Korean vital points database\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 // Use provided hour or current system hour\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 // Calculate distance to determine hit accuracy\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 * @public\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 * @public\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 * @public\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 // Find closest vital point to attack\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 // Calculate hit based on technique accuracy and distance\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 // Calculate hit accuracy (0-1 scale based on distance)\n const accuracy = Math.max(0, 1 - distance / 50);\n\n // Get meridians for this vital point\n const meridians = getMeridiansForVitalPoint(vitalPoint.id);\n\n // Calculate meridian flow effectiveness (highest value if multiple meridians)\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 // Generate effects if disruption is significant (using shared timestamp)\n const effects = generateMeridianEffects(meridianId, newDisruption, now);\n allMeridianEffects.push(...effects);\n });\n }\n\n // Calculate enhanced vulnerability based on anatomical zone, stance, meridian flow, and time\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 // Convert VitalPointEffect to StatusEffect with comprehensive calculations\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 // Combine vital point effects with meridian effects\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 // Load all 70 vital points from the comprehensive database\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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"}
|
|
@@ -24,7 +24,6 @@ type EasingFunction = (t: number) => number;
|
|
|
24
24
|
*
|
|
25
25
|
* **Korean**: 3차 베지어 제어점
|
|
26
26
|
*
|
|
27
|
-
* @public
|
|
28
27
|
* @category Animation
|
|
29
28
|
* @korean 베지어제어점
|
|
30
29
|
*/
|
|
@@ -122,7 +121,6 @@ export declare function createBezierEasing(points: BezierControlPoints): EasingF
|
|
|
122
121
|
*
|
|
123
122
|
* **Korean**: 무도 동작 이징 곡선
|
|
124
123
|
*
|
|
125
|
-
* @public
|
|
126
124
|
* @category Animation
|
|
127
125
|
* @korean 무도동작이징곡선
|
|
128
126
|
*/
|
|
@@ -263,7 +261,6 @@ export declare const easeExplosivePower: EasingFunction;
|
|
|
263
261
|
*
|
|
264
262
|
* **Korean**: 확장된 이징 함수 이름
|
|
265
263
|
*
|
|
266
|
-
* @public
|
|
267
264
|
* @category Animation
|
|
268
265
|
* @korean 확장이징함수이름
|
|
269
266
|
*/
|
|
@@ -423,7 +420,6 @@ export declare const crossFadeAnimations: (animation1: SkeletalAnimation, time1:
|
|
|
423
420
|
*
|
|
424
421
|
* Stores recent animation velocities for motion prediction.
|
|
425
422
|
*
|
|
426
|
-
* @public
|
|
427
423
|
* @category Animation
|
|
428
424
|
* @korean 동작예측상태
|
|
429
425
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyframeInterpolation.d.ts","sourceRoot":"","sources":["../../../../src/systems/animation/builders/KeyframeInterpolation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;GAOG;AACH,KAAK,cAAc,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"KeyframeInterpolation.d.ts","sourceRoot":"","sources":["../../../../src/systems/animation/builders/KeyframeInterpolation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyframeInterpolation.js","names":[],"sources":["../../../../src/systems/animation/builders/KeyframeInterpolation.ts"],"sourcesContent":["/**\n * Keyframe interpolation for smooth skeletal animations\n * \n * Provides interpolation between animation keyframes for smooth 60fps playback.\n * Supports linear, ease-in, ease-out, and ease-in-out easing functions.\n * \n * @module systems/animation/KeyframeInterpolation\n * @category Animation System\n * @korean 키프레임보간\n */\n\nimport * as THREE from \"three\";\nimport type {\n AnimationKeyframe,\n SkeletalAnimation,\n SkeletalRig,\n} from \"@/types/skeletal\";\n\n/**\n * Easing function type\n * \n * @param t - Time value between 0 and 1\n * @returns Eased value between 0 and 1\n * \n * @korean 이징함수타입\n */\ntype EasingFunction = (t: number) => number;\n\n/**\n * Cubic bezier control points for easing curves\n * \n * **Korean**: 3차 베지어 제어점\n * \n * @public\n * @category Animation\n * @korean 베지어제어점\n */\nexport interface BezierControlPoints {\n /** First control point x (0-1) */\n readonly p1x: number;\n /** First control point y (0-1) */\n readonly p1y: number;\n /** Second control point x (0-1) */\n readonly p2x: number;\n /** Second control point y (0-1) */\n readonly p2y: number;\n /** \n * Enable precision mode for exact bezier curve calculation\n * \n * **Reserved for future implementation.**\n * \n * When false (default), uses simplified approximation assuming x progresses linearly with t.\n * This is standard for CSS cubic-bezier() and provides good results with minimal overhead.\n * \n * When true (future), will perform iterative solving for accurate x-t mapping (higher CPU cost).\n * This would enable non-linear time progression for more complex easing curves.\n * \n * Currently unused - kept in interface for forward compatibility without breaking API changes.\n * \n * @korean 정밀모드\n */\n readonly precisionMode?: boolean;\n}\n\n/**\n * Cubic bezier easing for natural movement\n * \n * **Korean**: 3차 베지어 이징\n * \n * Implements cubic bezier curve interpolation for smooth, natural motion.\n * Based on CSS cubic-bezier() function specification.\n * \n * This function uses a configuration object approach for better API clarity.\n * By default, uses simplified approximation (x progresses linearly with t) which\n * provides good results for animation with minimal overhead. Enable precisionMode\n * for exact calculations when needed.\n * \n * @param t - Input time (0-1)\n * @param options - Bezier control points and configuration\n * @returns Eased value\n * \n * @example\n * ```typescript\n * // Natural Korean martial arts movement (physics-based)\n * const eased = cubicBezierWithOptions(0.5, { \n * p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 \n * });\n * \n * // With precision mode for exact calculation\n * const precise = cubicBezierWithOptions(0.5, {\n * p1x: 0.42, p1y: 0, p2x: 0.58, p2y: 1.0,\n * precisionMode: true\n * });\n * ```\n * \n * @korean 3차베지어이징옵션\n */\nexport function cubicBezierWithOptions(\n t: number,\n options: BezierControlPoints\n): number {\n // Clamp t to [0, 1]\n const clampedT = Math.max(0, Math.min(1, t));\n \n // For performance, use direct calculation (standard for CSS cubic-bezier)\n // Note: options.precisionMode is currently unused and reserved for future implementation\n // where we could add iterative solving for exact x-t mapping\n const u = 1 - clampedT;\n \n // Cubic bezier formula: B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃\n // For easing, P₀ = (0,0) and P₃ = (1,1), so:\n // y(t) = 3(1-t)²t*p1y + 3(1-t)t²*p2y + t³\n const result = 3 * u * u * clampedT * options.p1y + \n 3 * u * clampedT * clampedT * options.p2y + \n clampedT * clampedT * clampedT;\n \n return result;\n}\n\n/**\n * Cubic bezier easing (legacy function signature for backward compatibility)\n * \n * **Korean**: 3차 베지어 이징 (레거시)\n * \n * @param t - Input time (0-1)\n * @param p1x - First control point x (0-1) - currently unused, reserved for precision mode\n * @param p1y - First control point y (can exceed 0-1 for overshoot)\n * @param p2x - Second control point x (0-1) - currently unused, reserved for precision mode\n * @param p2y - Second control point y (can exceed 0-1 for overshoot)\n * @returns Eased value\n * \n * @deprecated Use cubicBezierWithOptions for clearer API\n * @korean 3차베지어이징레거시\n */\nexport function cubicBezier(\n t: number,\n p1x: number,\n p1y: number,\n p2x: number,\n p2y: number\n): number {\n return cubicBezierWithOptions(t, { p1x, p1y, p2x, p2y });\n}\n\n/**\n * Create a cubic bezier easing function with control points\n * \n * **Korean**: 베지어 이징 함수 생성\n * \n * Factory function to create reusable bezier easing functions.\n * \n * @param points - Bezier control points\n * @returns Easing function\n * \n * @korean 베지어이징함수생성\n */\nexport function createBezierEasing(points: BezierControlPoints): EasingFunction {\n return (t: number) => cubicBezier(t, points.p1x, points.p1y, points.p2x, points.p2y);\n}\n\n/**\n * Preset bezier easing curves for Korean martial arts movements\n * \n * **Korean**: 무도 동작 이징 곡선\n * \n * @public\n * @category Animation\n * @korean 무도동작이징곡선\n */\nexport const BEZIER_PRESETS = {\n /**\n * Natural motion with physics-based acceleration/deceleration\n * Ideal for: Stance transitions, body rotations, weight shifts\n * **Korean**: 자연스러운 물리 기반 동작\n */\n naturalMotion: { p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Smooth S-curve for fluid transitions\n * Ideal for: Attack wind-ups, defensive positioning, footwork\n * **Korean**: 부드러운 S곡선 전환\n */\n smoothTransition: { p1x: 0.42, p1y: 0.0, p2x: 0.58, p2y: 1.0 },\n \n /**\n * Quick start with gentle landing\n * Ideal for: Strike recoil, guard recovery, step completion\n * **Korean**: 빠른 시작과 부드러운 착지\n */\n quickStart: { p1x: 0.1, p1y: 0.8, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Explosive power curve\n * Ideal for: Explosive strikes, power techniques, ki projection\n * **Korean**: 폭발적 힘 곡선\n */\n explosivePower: { p1x: 0.05, p1y: 0.9, p2x: 0.2, p2y: 1.0 },\n \n /**\n * Controlled deceleration\n * Ideal for: Defensive withdrawals, cautious movements, guard stance\n * **Korean**: 제어된 감속\n */\n controlledSlow: { p1x: 0.6, p1y: 0.0, p2x: 0.9, p2y: 0.4 },\n} as const;\n\n/**\n * Linear easing (no easing)\n * \n * @param t - Input time (0-1)\n * @returns Same as input\n * \n * @korean 선형이징\n */\nexport const easeLinear: EasingFunction = (t: number): number => t;\n\n/**\n * Ease-in (slow start, fast end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인\n */\nexport const easeIn: EasingFunction = (t: number): number => t * t;\n\n/**\n * Ease-out (fast start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈아웃\n */\nexport const easeOut: EasingFunction = (t: number): number => t * (2 - t);\n\n/**\n * Ease-in-out (slow start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인아웃\n */\nexport const easeInOut: EasingFunction = (t: number): number => {\n if (t < 0.5) {\n return 2 * t * t;\n }\n return -1 + (4 - 2 * t) * t;\n};\n\n/**\n * Natural motion bezier easing (preset)\n * \n * **Korean**: 자연스러운 동작 이징\n * \n * Physics-based movement ideal for Korean martial arts.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 자연동작이징\n */\nexport const easeNaturalMotion: EasingFunction = createBezierEasing(BEZIER_PRESETS.naturalMotion);\n\n/**\n * Smooth transition bezier easing (preset)\n * \n * **Korean**: 부드러운 전환 이징\n * \n * S-curve for fluid stance transitions.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 부드러운전환이징\n */\nexport const easeSmoothTransition: EasingFunction = createBezierEasing(BEZIER_PRESETS.smoothTransition);\n\n/**\n * Explosive power bezier easing (preset)\n * \n * **Korean**: 폭발적 힘 이징\n * \n * Explosive acceleration for power strikes.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 폭발적힘이징\n */\nexport const easeExplosivePower: EasingFunction = createBezierEasing(BEZIER_PRESETS.explosivePower);\n\n/**\n * Extended easing function names including bezier presets\n * \n * **Korean**: 확장된 이징 함수 이름\n * \n * @public\n * @category Animation\n * @korean 확장이징함수이름\n */\nexport type EasingName = \n | \"linear\"\n | \"ease-in\" \n | \"ease-out\" \n | \"ease-in-out\"\n | \"natural-motion\"\n | \"smooth-transition\"\n | \"quick-start\"\n | \"explosive-power\"\n | \"controlled-slow\";\n\n/**\n * Get easing function by name\n * \n * **Korean**: 이름으로 이징 함수 구하기\n * \n * @param name - Easing function name (supports bezier presets)\n * @returns Easing function\n * \n * @example\n * ```typescript\n * // Get natural motion easing for Korean martial arts\n * const easing = getEasingFunction(\"natural-motion\");\n * const easedValue = easing(0.5); // Smooth physics-based interpolation\n * \n * // Get explosive power for strike animations\n * const powerEasing = getEasingFunction(\"explosive-power\");\n * ```\n * \n * @korean 이징함수구하기\n */\nexport const getEasingFunction = (\n name: EasingName = \"linear\"\n): EasingFunction => {\n switch (name) {\n case \"ease-in\":\n return easeIn;\n case \"ease-out\":\n return easeOut;\n case \"ease-in-out\":\n return easeInOut;\n case \"natural-motion\":\n return easeNaturalMotion;\n case \"smooth-transition\":\n return easeSmoothTransition;\n case \"quick-start\":\n return createBezierEasing(BEZIER_PRESETS.quickStart);\n case \"explosive-power\":\n return easeExplosivePower;\n case \"controlled-slow\":\n return createBezierEasing(BEZIER_PRESETS.controlledSlow);\n default:\n return easeLinear;\n }\n};\n\n/**\n * Find keyframes surrounding current time\n * \n * Returns the two keyframes to interpolate between for current animation time.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Tuple of [previousKeyframe, nextKeyframe, interpolationFactor]\n * \n * @korean 주변키프레임찾기\n */\nexport const findSurroundingKeyframes = (\n animation: SkeletalAnimation,\n currentTime: number\n): [AnimationKeyframe, AnimationKeyframe, number] => {\n const { keyframes } = animation;\n\n // Clamp time to animation duration\n const clampedTime = Math.max(\n 0,\n Math.min(currentTime, animation.duration)\n );\n\n // Find keyframes\n let prevKeyframe = keyframes[0];\n let nextKeyframe = keyframes[keyframes.length - 1];\n let interpolationFactor = 0;\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n const current = keyframes[i];\n const next = keyframes[i + 1];\n\n if (clampedTime >= current.time && clampedTime <= next.time) {\n prevKeyframe = current;\n nextKeyframe = next;\n\n // Calculate interpolation factor (0 to 1)\n const timeDelta = next.time - current.time;\n if (timeDelta > 0) {\n interpolationFactor = (clampedTime - current.time) / timeDelta;\n }\n break;\n }\n }\n\n return [prevKeyframe, nextKeyframe, interpolationFactor];\n};\n\n/**\n * Interpolate between two Euler rotations\n * \n * Performs spherical linear interpolation (slerp) for smooth rotation.\n * \n * @param from - Start rotation\n * @param to - End rotation\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated rotation\n * \n * @korean 회전보간\n */\nexport const interpolateRotation = (\n from: THREE.Euler,\n to: THREE.Euler,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Euler => {\n const easedT = easingFn(t);\n\n // Convert Euler to Quaternion for proper slerp\n const fromQuat = new THREE.Quaternion().setFromEuler(from);\n const toQuat = new THREE.Quaternion().setFromEuler(to);\n\n // Slerp between quaternions\n const result = new THREE.Quaternion().slerpQuaternions(\n fromQuat,\n toQuat,\n easedT\n );\n\n // Convert back to Euler\n const resultEuler = new THREE.Euler().setFromQuaternion(result);\n return resultEuler;\n};\n\n/**\n * Interpolate between two Vector3 positions\n * \n * Performs linear interpolation for smooth position changes.\n * \n * @param from - Start position\n * @param to - End position\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated position\n * \n * @korean 위치보간\n */\nexport const interpolatePosition = (\n from: THREE.Vector3,\n to: THREE.Vector3,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Vector3 => {\n const easedT = easingFn(t);\n return new THREE.Vector3().lerpVectors(from, to, easedT);\n};\n\n/**\n * Get interpolated keyframe at current time\n * \n * Calculates bone transformations by interpolating between keyframes.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Interpolated keyframe\n * \n * @korean 보간된키프레임구하기\n */\nexport const getInterpolatedKeyframe = (\n animation: SkeletalAnimation,\n currentTime: number\n): AnimationKeyframe => {\n const [prevKeyframe, nextKeyframe, t] =\n findSurroundingKeyframes(animation, currentTime);\n\n // Get easing function from next keyframe\n const easingFn = getEasingFunction(nextKeyframe.easing);\n\n // Interpolate bone rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBoneNames = new Set([\n ...prevKeyframe.boneRotations.keys(),\n ...nextKeyframe.boneRotations.keys(),\n ]);\n\n for (const boneName of allBoneNames) {\n const prevRotation =\n prevKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n const nextRotation =\n nextKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n\n const interpolated = interpolateRotation(\n prevRotation,\n nextRotation,\n t,\n easingFn\n );\n boneRotations.set(boneName, interpolated);\n }\n\n // Interpolate bone positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...prevKeyframe.bonePositions.keys(),\n ...nextKeyframe.bonePositions.keys(),\n ]);\n\n for (const boneName of allPositionBones) {\n const prevPosition =\n prevKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n const nextPosition =\n nextKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n\n const interpolated = interpolatePosition(\n prevPosition,\n nextPosition,\n t,\n easingFn\n );\n bonePositions.set(boneName, interpolated);\n }\n\n return {\n time: currentTime,\n boneRotations,\n bonePositions,\n easing: nextKeyframe.easing,\n };\n};\n\n/**\n * Apply keyframe to skeletal rig\n * \n * Updates all bone transformations based on keyframe data.\n * \n * @param rig - Skeletal rig to update\n * @param keyframe - Keyframe to apply\n * \n * @korean 키프레임적용\n */\nexport const applyKeyframeToRig = (\n rig: SkeletalRig,\n keyframe: AnimationKeyframe\n): void => {\n // Apply bone rotations\n keyframe.boneRotations.forEach((rotation, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n bone.rotation.copy(rotation);\n }\n });\n\n // Apply bone positions (offset from rest pose)\n keyframe.bonePositions.forEach((position, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n // Add position offset to rest position\n bone.position.copy(bone.restPosition).add(position);\n }\n });\n};\n\n/**\n * Blend between two keyframes\n * \n * Creates smooth transition between two animations for animation blending.\n * Useful for transitioning between stance change and attack, etc.\n * \n * @param keyframe1 - First keyframe\n * @param keyframe2 - Second keyframe\n * @param blendFactor - Blend amount (0 = keyframe1, 1 = keyframe2)\n * @returns Blended keyframe\n * \n * @korean 키프레임블렌드\n */\nexport const blendKeyframes = (\n keyframe1: AnimationKeyframe,\n keyframe2: AnimationKeyframe,\n blendFactor: number\n): AnimationKeyframe => {\n const clampedBlend = Math.max(0, Math.min(1, blendFactor));\n\n // Blend rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBones = new Set([\n ...keyframe1.boneRotations.keys(),\n ...keyframe2.boneRotations.keys(),\n ]);\n\n allBones.forEach((boneName) => {\n const rot1 = keyframe1.boneRotations.get(boneName) ?? new THREE.Euler();\n const rot2 = keyframe2.boneRotations.get(boneName) ?? new THREE.Euler();\n const blended = interpolateRotation(rot1, rot2, clampedBlend);\n boneRotations.set(boneName, blended);\n });\n\n // Blend positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...keyframe1.bonePositions.keys(),\n ...keyframe2.bonePositions.keys(),\n ]);\n\n allPositionBones.forEach((boneName) => {\n const pos1 = keyframe1.bonePositions.get(boneName) ?? new THREE.Vector3();\n const pos2 = keyframe2.bonePositions.get(boneName) ?? new THREE.Vector3();\n const blended = interpolatePosition(pos1, pos2, clampedBlend);\n bonePositions.set(boneName, blended);\n });\n\n return {\n time: 0,\n boneRotations,\n bonePositions,\n easing: \"linear\",\n };\n};\n\n/**\n * Update animation state\n * \n * Advances animation time and returns current interpolated keyframe.\n * Handles looping animations automatically.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation\n * @param deltaTime - Time since last update (seconds)\n * @param playbackSpeed - Speed multiplier (1.0 = normal)\n * @returns Updated time and current keyframe\n * \n * @korean 애니메이션상태업데이트\n */\nexport const updateAnimation = (\n animation: SkeletalAnimation,\n currentTime: number,\n deltaTime: number,\n playbackSpeed = 1.0\n): { time: number; keyframe: AnimationKeyframe; completed: boolean } => {\n // Advance time\n let newTime = currentTime + deltaTime * playbackSpeed;\n let completed = false;\n\n // Handle looping or completion\n if (newTime >= animation.duration) {\n if (animation.loop) {\n newTime = newTime % animation.duration;\n } else {\n newTime = animation.duration;\n completed = true;\n }\n }\n\n // Get interpolated keyframe\n const keyframe = getInterpolatedKeyframe(animation, newTime);\n\n return {\n time: newTime,\n keyframe,\n completed,\n };\n};\n\n/**\n * Cross-fade blend between two animations\n * \n * **Korean**: 크로스페이드 블렌드\n * \n * Smoothly blends between two overlapping animations to prevent popping.\n * Uses cubic bezier easing for natural transitions.\n * \n * @param animation1 - First animation\n * @param time1 - Current time in first animation\n * @param animation2 - Second animation\n * @param time2 - Current time in second animation\n * @param blendFactor - Blend weight (0 = animation1, 1 = animation2)\n * @param easingName - Easing curve for blend transition\n * @returns Blended keyframe\n * \n * @example\n * ```typescript\n * // Cross-fade from idle to attack over 100ms\n * const blended = crossFadeAnimations(\n * idleAnim, idleTime,\n * attackAnim, attackTime,\n * 0.5, // 50% blend\n * \"smooth-transition\"\n * );\n * applyKeyframeToRig(rig, blended);\n * ```\n * \n * @korean 크로스페이드블렌드\n */\nexport const crossFadeAnimations = (\n animation1: SkeletalAnimation,\n time1: number,\n animation2: SkeletalAnimation,\n time2: number,\n blendFactor: number,\n easingName: EasingName = \"smooth-transition\"\n): AnimationKeyframe => {\n const keyframe1 = getInterpolatedKeyframe(animation1, time1);\n const keyframe2 = getInterpolatedKeyframe(animation2, time2);\n \n // Apply easing to blend factor\n const easingFn = getEasingFunction(easingName);\n const easedBlend = easingFn(Math.max(0, Math.min(1, blendFactor)));\n \n return blendKeyframes(keyframe1, keyframe2, easedBlend);\n};\n\n/**\n * Motion prediction state for latency reduction\n * \n * **Korean**: 동작 예측 상태\n * \n * Stores recent animation velocities for motion prediction.\n * \n * @public\n * @category Animation\n * @korean 동작예측상태\n */\nexport interface MotionPredictionState {\n /** Recent position velocities per bone */\n readonly velocities: Map<string, THREE.Vector3>;\n /** Recent rotation velocities per bone */\n readonly angularVelocities: Map<string, THREE.Euler>;\n /** Last update timestamp */\n readonly lastUpdateTime: number;\n}\n\n/**\n * Create motion prediction state\n * \n * **Korean**: 동작 예측 상태 생성\n * \n * @returns Initial motion prediction state\n * @korean 동작예측상태생성\n */\nexport const createMotionPredictionState = (): MotionPredictionState => ({\n velocities: new Map(),\n angularVelocities: new Map(),\n lastUpdateTime: 0,\n});\n\n/**\n * Update motion prediction state with new keyframe\n * \n * **Korean**: 동작 예측 상태 업데이트\n * \n * Calculates velocities from keyframe differences for motion prediction.\n * \n * @param state - Current prediction state\n * @param previousKeyframe - Previous animation keyframe\n * @param currentKeyframe - Current animation keyframe\n * @param deltaTime - Time elapsed between keyframes\n * @returns Updated prediction state\n * \n * @korean 동작예측상태업데이트\n */\nexport const updateMotionPrediction = (\n state: MotionPredictionState,\n previousKeyframe: AnimationKeyframe,\n currentKeyframe: AnimationKeyframe,\n deltaTime: number\n): MotionPredictionState => {\n if (deltaTime <= 0) return state;\n \n const newVelocities = new Map<string, THREE.Vector3>();\n const newAngularVelocities = new Map<string, THREE.Euler>();\n \n // Calculate position velocities\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const prevPos = previousKeyframe.bonePositions.get(boneName);\n if (prevPos) {\n const velocity = new THREE.Vector3()\n .subVectors(currentPos, prevPos)\n .divideScalar(deltaTime);\n newVelocities.set(boneName, velocity);\n }\n });\n \n // Calculate angular velocities using quaternion-based rotation differences\n // This avoids gimbal lock and angle wrapping issues with Euler angle differences\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const prevRot = previousKeyframe.boneRotations.get(boneName);\n if (prevRot) {\n // Convert Euler rotations to quaternions\n const qCurrent = new THREE.Quaternion().setFromEuler(currentRot);\n const qPrev = new THREE.Quaternion().setFromEuler(prevRot);\n \n // Calculate relative rotation: qDiff = qCurrent * qPrev^(-1)\n const qDiff = qCurrent.clone().multiply(qPrev.clone().invert());\n \n // Extract axis-angle representation for angular velocity\n const axis = new THREE.Vector3();\n const wClamped = THREE.MathUtils.clamp(qDiff.w, -1, 1);\n let angle = 2 * Math.acos(wClamped);\n const sinHalfAngle = Math.sqrt(1 - wClamped * wClamped);\n \n if (sinHalfAngle < 0.0001) {\n // If sinHalfAngle is too small, rotation is negligible - use zero velocity\n axis.set(0, 0, 0);\n angle = 0;\n } else {\n // Extract normalized axis from quaternion\n axis.set(\n qDiff.x / sinHalfAngle,\n qDiff.y / sinHalfAngle,\n qDiff.z / sinHalfAngle\n );\n }\n \n // Use shortest rotation path\n if (angle > Math.PI) {\n angle -= 2 * Math.PI;\n }\n \n // Angular velocity vector = axis * (angle / deltaTime)\n const angularVelocityVec = axis.multiplyScalar(angle / deltaTime);\n \n // Store as Euler for consistency with existing API\n const angularVel = new THREE.Euler(\n angularVelocityVec.x,\n angularVelocityVec.y,\n angularVelocityVec.z,\n currentRot.order\n );\n newAngularVelocities.set(boneName, angularVel);\n }\n });\n \n return {\n velocities: newVelocities,\n angularVelocities: newAngularVelocities,\n lastUpdateTime: performance.now(),\n };\n};\n\n/**\n * Predict future keyframe using motion prediction\n * \n * **Korean**: 동작 예측으로 미래 키프레임 예측\n * \n * Reduces perceived latency by predicting future bone positions/rotations\n * based on current velocities. Typical prediction: 16-33ms (1-2 frames at 60fps).\n * \n * @param currentKeyframe - Current animation keyframe\n * @param predictionState - Motion prediction state\n * @param predictionTime - Time ahead to predict (seconds, typically 0.016-0.033)\n * @returns Predicted keyframe\n * \n * @example\n * ```typescript\n * // Predict 1 frame ahead (16.67ms at 60fps) for <50ms total latency\n * const predicted = predictFutureKeyframe(\n * currentKeyframe,\n * motionState,\n * 0.01667\n * );\n * applyKeyframeToRig(rig, predicted);\n * ```\n * \n * @korean 미래키프레임예측\n */\nexport const predictFutureKeyframe = (\n currentKeyframe: AnimationKeyframe,\n predictionState: MotionPredictionState,\n predictionTime: number\n): AnimationKeyframe => {\n // Clamp prediction time to reasonable bounds (max 50ms)\n const clampedPrediction = Math.min(predictionTime, 0.05);\n \n // Predict bone positions\n const predictedPositions = new Map<string, THREE.Vector3>();\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const velocity = predictionState.velocities.get(boneName);\n if (velocity) {\n // Apply damping to prevent overshoot (0.8 factor for natural motion)\n const predicted = currentPos.clone().add(\n velocity.clone().multiplyScalar(clampedPrediction * 0.8)\n );\n predictedPositions.set(boneName, predicted);\n } else {\n predictedPositions.set(boneName, currentPos.clone());\n }\n });\n \n // Predict bone rotations\n const predictedRotations = new Map<string, THREE.Euler>();\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const angularVel = predictionState.angularVelocities.get(boneName);\n if (angularVel) {\n // Apply damping to prevent overshoot\n const predicted = new THREE.Euler(\n currentRot.x + angularVel.x * clampedPrediction * 0.8,\n currentRot.y + angularVel.y * clampedPrediction * 0.8,\n currentRot.z + angularVel.z * clampedPrediction * 0.8,\n currentRot.order\n );\n predictedRotations.set(boneName, predicted);\n } else {\n predictedRotations.set(boneName, currentRot.clone());\n }\n });\n \n return {\n time: currentKeyframe.time + clampedPrediction,\n boneRotations: predictedRotations,\n bonePositions: predictedPositions,\n easing: currentKeyframe.easing,\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KeyframeInterpolation.js","names":[],"sources":["../../../../src/systems/animation/builders/KeyframeInterpolation.ts"],"sourcesContent":["/**\n * Keyframe interpolation for smooth skeletal animations\n * \n * Provides interpolation between animation keyframes for smooth 60fps playback.\n * Supports linear, ease-in, ease-out, and ease-in-out easing functions.\n * \n * @module systems/animation/KeyframeInterpolation\n * @category Animation System\n * @korean 키프레임보간\n */\n\nimport * as THREE from \"three\";\nimport type {\n AnimationKeyframe,\n SkeletalAnimation,\n SkeletalRig,\n} from \"@/types/skeletal\";\n\n/**\n * Easing function type\n * \n * @param t - Time value between 0 and 1\n * @returns Eased value between 0 and 1\n * \n * @korean 이징함수타입\n */\ntype EasingFunction = (t: number) => number;\n\n/**\n * Cubic bezier control points for easing curves\n * \n * **Korean**: 3차 베지어 제어점\n * \n * @category Animation\n * @korean 베지어제어점\n */\nexport interface BezierControlPoints {\n /** First control point x (0-1) */\n readonly p1x: number;\n /** First control point y (0-1) */\n readonly p1y: number;\n /** Second control point x (0-1) */\n readonly p2x: number;\n /** Second control point y (0-1) */\n readonly p2y: number;\n /** \n * Enable precision mode for exact bezier curve calculation\n * \n * **Reserved for future implementation.**\n * \n * When false (default), uses simplified approximation assuming x progresses linearly with t.\n * This is standard for CSS cubic-bezier() and provides good results with minimal overhead.\n * \n * When true (future), will perform iterative solving for accurate x-t mapping (higher CPU cost).\n * This would enable non-linear time progression for more complex easing curves.\n * \n * Currently unused - kept in interface for forward compatibility without breaking API changes.\n * \n * @korean 정밀모드\n */\n readonly precisionMode?: boolean;\n}\n\n/**\n * Cubic bezier easing for natural movement\n * \n * **Korean**: 3차 베지어 이징\n * \n * Implements cubic bezier curve interpolation for smooth, natural motion.\n * Based on CSS cubic-bezier() function specification.\n * \n * This function uses a configuration object approach for better API clarity.\n * By default, uses simplified approximation (x progresses linearly with t) which\n * provides good results for animation with minimal overhead. Enable precisionMode\n * for exact calculations when needed.\n * \n * @param t - Input time (0-1)\n * @param options - Bezier control points and configuration\n * @returns Eased value\n * \n * @example\n * ```typescript\n * // Natural Korean martial arts movement (physics-based)\n * const eased = cubicBezierWithOptions(0.5, { \n * p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 \n * });\n * \n * // With precision mode for exact calculation\n * const precise = cubicBezierWithOptions(0.5, {\n * p1x: 0.42, p1y: 0, p2x: 0.58, p2y: 1.0,\n * precisionMode: true\n * });\n * ```\n * \n * @korean 3차베지어이징옵션\n */\nexport function cubicBezierWithOptions(\n t: number,\n options: BezierControlPoints\n): number {\n // Clamp t to [0, 1]\n const clampedT = Math.max(0, Math.min(1, t));\n \n // For performance, use direct calculation (standard for CSS cubic-bezier)\n // Note: options.precisionMode is currently unused and reserved for future implementation\n // where we could add iterative solving for exact x-t mapping\n const u = 1 - clampedT;\n \n // Cubic bezier formula: B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃\n // For easing, P₀ = (0,0) and P₃ = (1,1), so:\n // y(t) = 3(1-t)²t*p1y + 3(1-t)t²*p2y + t³\n const result = 3 * u * u * clampedT * options.p1y + \n 3 * u * clampedT * clampedT * options.p2y + \n clampedT * clampedT * clampedT;\n \n return result;\n}\n\n/**\n * Cubic bezier easing (legacy function signature for backward compatibility)\n * \n * **Korean**: 3차 베지어 이징 (레거시)\n * \n * @param t - Input time (0-1)\n * @param p1x - First control point x (0-1) - currently unused, reserved for precision mode\n * @param p1y - First control point y (can exceed 0-1 for overshoot)\n * @param p2x - Second control point x (0-1) - currently unused, reserved for precision mode\n * @param p2y - Second control point y (can exceed 0-1 for overshoot)\n * @returns Eased value\n * \n * @deprecated Use cubicBezierWithOptions for clearer API\n * @korean 3차베지어이징레거시\n */\nexport function cubicBezier(\n t: number,\n p1x: number,\n p1y: number,\n p2x: number,\n p2y: number\n): number {\n return cubicBezierWithOptions(t, { p1x, p1y, p2x, p2y });\n}\n\n/**\n * Create a cubic bezier easing function with control points\n * \n * **Korean**: 베지어 이징 함수 생성\n * \n * Factory function to create reusable bezier easing functions.\n * \n * @param points - Bezier control points\n * @returns Easing function\n * \n * @korean 베지어이징함수생성\n */\nexport function createBezierEasing(points: BezierControlPoints): EasingFunction {\n return (t: number) => cubicBezier(t, points.p1x, points.p1y, points.p2x, points.p2y);\n}\n\n/**\n * Preset bezier easing curves for Korean martial arts movements\n * \n * **Korean**: 무도 동작 이징 곡선\n * \n * @category Animation\n * @korean 무도동작이징곡선\n */\nexport const BEZIER_PRESETS = {\n /**\n * Natural motion with physics-based acceleration/deceleration\n * Ideal for: Stance transitions, body rotations, weight shifts\n * **Korean**: 자연스러운 물리 기반 동작\n */\n naturalMotion: { p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Smooth S-curve for fluid transitions\n * Ideal for: Attack wind-ups, defensive positioning, footwork\n * **Korean**: 부드러운 S곡선 전환\n */\n smoothTransition: { p1x: 0.42, p1y: 0.0, p2x: 0.58, p2y: 1.0 },\n \n /**\n * Quick start with gentle landing\n * Ideal for: Strike recoil, guard recovery, step completion\n * **Korean**: 빠른 시작과 부드러운 착지\n */\n quickStart: { p1x: 0.1, p1y: 0.8, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Explosive power curve\n * Ideal for: Explosive strikes, power techniques, ki projection\n * **Korean**: 폭발적 힘 곡선\n */\n explosivePower: { p1x: 0.05, p1y: 0.9, p2x: 0.2, p2y: 1.0 },\n \n /**\n * Controlled deceleration\n * Ideal for: Defensive withdrawals, cautious movements, guard stance\n * **Korean**: 제어된 감속\n */\n controlledSlow: { p1x: 0.6, p1y: 0.0, p2x: 0.9, p2y: 0.4 },\n} as const;\n\n/**\n * Linear easing (no easing)\n * \n * @param t - Input time (0-1)\n * @returns Same as input\n * \n * @korean 선형이징\n */\nexport const easeLinear: EasingFunction = (t: number): number => t;\n\n/**\n * Ease-in (slow start, fast end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인\n */\nexport const easeIn: EasingFunction = (t: number): number => t * t;\n\n/**\n * Ease-out (fast start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈아웃\n */\nexport const easeOut: EasingFunction = (t: number): number => t * (2 - t);\n\n/**\n * Ease-in-out (slow start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인아웃\n */\nexport const easeInOut: EasingFunction = (t: number): number => {\n if (t < 0.5) {\n return 2 * t * t;\n }\n return -1 + (4 - 2 * t) * t;\n};\n\n/**\n * Natural motion bezier easing (preset)\n * \n * **Korean**: 자연스러운 동작 이징\n * \n * Physics-based movement ideal for Korean martial arts.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 자연동작이징\n */\nexport const easeNaturalMotion: EasingFunction = createBezierEasing(BEZIER_PRESETS.naturalMotion);\n\n/**\n * Smooth transition bezier easing (preset)\n * \n * **Korean**: 부드러운 전환 이징\n * \n * S-curve for fluid stance transitions.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 부드러운전환이징\n */\nexport const easeSmoothTransition: EasingFunction = createBezierEasing(BEZIER_PRESETS.smoothTransition);\n\n/**\n * Explosive power bezier easing (preset)\n * \n * **Korean**: 폭발적 힘 이징\n * \n * Explosive acceleration for power strikes.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 폭발적힘이징\n */\nexport const easeExplosivePower: EasingFunction = createBezierEasing(BEZIER_PRESETS.explosivePower);\n\n/**\n * Extended easing function names including bezier presets\n * \n * **Korean**: 확장된 이징 함수 이름\n * \n * @category Animation\n * @korean 확장이징함수이름\n */\nexport type EasingName = \n | \"linear\"\n | \"ease-in\" \n | \"ease-out\" \n | \"ease-in-out\"\n | \"natural-motion\"\n | \"smooth-transition\"\n | \"quick-start\"\n | \"explosive-power\"\n | \"controlled-slow\";\n\n/**\n * Get easing function by name\n * \n * **Korean**: 이름으로 이징 함수 구하기\n * \n * @param name - Easing function name (supports bezier presets)\n * @returns Easing function\n * \n * @example\n * ```typescript\n * // Get natural motion easing for Korean martial arts\n * const easing = getEasingFunction(\"natural-motion\");\n * const easedValue = easing(0.5); // Smooth physics-based interpolation\n * \n * // Get explosive power for strike animations\n * const powerEasing = getEasingFunction(\"explosive-power\");\n * ```\n * \n * @korean 이징함수구하기\n */\nexport const getEasingFunction = (\n name: EasingName = \"linear\"\n): EasingFunction => {\n switch (name) {\n case \"ease-in\":\n return easeIn;\n case \"ease-out\":\n return easeOut;\n case \"ease-in-out\":\n return easeInOut;\n case \"natural-motion\":\n return easeNaturalMotion;\n case \"smooth-transition\":\n return easeSmoothTransition;\n case \"quick-start\":\n return createBezierEasing(BEZIER_PRESETS.quickStart);\n case \"explosive-power\":\n return easeExplosivePower;\n case \"controlled-slow\":\n return createBezierEasing(BEZIER_PRESETS.controlledSlow);\n default:\n return easeLinear;\n }\n};\n\n/**\n * Find keyframes surrounding current time\n * \n * Returns the two keyframes to interpolate between for current animation time.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Tuple of [previousKeyframe, nextKeyframe, interpolationFactor]\n * \n * @korean 주변키프레임찾기\n */\nexport const findSurroundingKeyframes = (\n animation: SkeletalAnimation,\n currentTime: number\n): [AnimationKeyframe, AnimationKeyframe, number] => {\n const { keyframes } = animation;\n\n // Clamp time to animation duration\n const clampedTime = Math.max(\n 0,\n Math.min(currentTime, animation.duration)\n );\n\n // Find keyframes\n let prevKeyframe = keyframes[0];\n let nextKeyframe = keyframes[keyframes.length - 1];\n let interpolationFactor = 0;\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n const current = keyframes[i];\n const next = keyframes[i + 1];\n\n if (clampedTime >= current.time && clampedTime <= next.time) {\n prevKeyframe = current;\n nextKeyframe = next;\n\n // Calculate interpolation factor (0 to 1)\n const timeDelta = next.time - current.time;\n if (timeDelta > 0) {\n interpolationFactor = (clampedTime - current.time) / timeDelta;\n }\n break;\n }\n }\n\n return [prevKeyframe, nextKeyframe, interpolationFactor];\n};\n\n/**\n * Interpolate between two Euler rotations\n * \n * Performs spherical linear interpolation (slerp) for smooth rotation.\n * \n * @param from - Start rotation\n * @param to - End rotation\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated rotation\n * \n * @korean 회전보간\n */\nexport const interpolateRotation = (\n from: THREE.Euler,\n to: THREE.Euler,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Euler => {\n const easedT = easingFn(t);\n\n // Convert Euler to Quaternion for proper slerp\n const fromQuat = new THREE.Quaternion().setFromEuler(from);\n const toQuat = new THREE.Quaternion().setFromEuler(to);\n\n // Slerp between quaternions\n const result = new THREE.Quaternion().slerpQuaternions(\n fromQuat,\n toQuat,\n easedT\n );\n\n // Convert back to Euler\n const resultEuler = new THREE.Euler().setFromQuaternion(result);\n return resultEuler;\n};\n\n/**\n * Interpolate between two Vector3 positions\n * \n * Performs linear interpolation for smooth position changes.\n * \n * @param from - Start position\n * @param to - End position\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated position\n * \n * @korean 위치보간\n */\nexport const interpolatePosition = (\n from: THREE.Vector3,\n to: THREE.Vector3,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Vector3 => {\n const easedT = easingFn(t);\n return new THREE.Vector3().lerpVectors(from, to, easedT);\n};\n\n/**\n * Get interpolated keyframe at current time\n * \n * Calculates bone transformations by interpolating between keyframes.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Interpolated keyframe\n * \n * @korean 보간된키프레임구하기\n */\nexport const getInterpolatedKeyframe = (\n animation: SkeletalAnimation,\n currentTime: number\n): AnimationKeyframe => {\n const [prevKeyframe, nextKeyframe, t] =\n findSurroundingKeyframes(animation, currentTime);\n\n // Get easing function from next keyframe\n const easingFn = getEasingFunction(nextKeyframe.easing);\n\n // Interpolate bone rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBoneNames = new Set([\n ...prevKeyframe.boneRotations.keys(),\n ...nextKeyframe.boneRotations.keys(),\n ]);\n\n for (const boneName of allBoneNames) {\n const prevRotation =\n prevKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n const nextRotation =\n nextKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n\n const interpolated = interpolateRotation(\n prevRotation,\n nextRotation,\n t,\n easingFn\n );\n boneRotations.set(boneName, interpolated);\n }\n\n // Interpolate bone positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...prevKeyframe.bonePositions.keys(),\n ...nextKeyframe.bonePositions.keys(),\n ]);\n\n for (const boneName of allPositionBones) {\n const prevPosition =\n prevKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n const nextPosition =\n nextKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n\n const interpolated = interpolatePosition(\n prevPosition,\n nextPosition,\n t,\n easingFn\n );\n bonePositions.set(boneName, interpolated);\n }\n\n return {\n time: currentTime,\n boneRotations,\n bonePositions,\n easing: nextKeyframe.easing,\n };\n};\n\n/**\n * Apply keyframe to skeletal rig\n * \n * Updates all bone transformations based on keyframe data.\n * \n * @param rig - Skeletal rig to update\n * @param keyframe - Keyframe to apply\n * \n * @korean 키프레임적용\n */\nexport const applyKeyframeToRig = (\n rig: SkeletalRig,\n keyframe: AnimationKeyframe\n): void => {\n // Apply bone rotations\n keyframe.boneRotations.forEach((rotation, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n bone.rotation.copy(rotation);\n }\n });\n\n // Apply bone positions (offset from rest pose)\n keyframe.bonePositions.forEach((position, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n // Add position offset to rest position\n bone.position.copy(bone.restPosition).add(position);\n }\n });\n};\n\n/**\n * Blend between two keyframes\n * \n * Creates smooth transition between two animations for animation blending.\n * Useful for transitioning between stance change and attack, etc.\n * \n * @param keyframe1 - First keyframe\n * @param keyframe2 - Second keyframe\n * @param blendFactor - Blend amount (0 = keyframe1, 1 = keyframe2)\n * @returns Blended keyframe\n * \n * @korean 키프레임블렌드\n */\nexport const blendKeyframes = (\n keyframe1: AnimationKeyframe,\n keyframe2: AnimationKeyframe,\n blendFactor: number\n): AnimationKeyframe => {\n const clampedBlend = Math.max(0, Math.min(1, blendFactor));\n\n // Blend rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBones = new Set([\n ...keyframe1.boneRotations.keys(),\n ...keyframe2.boneRotations.keys(),\n ]);\n\n allBones.forEach((boneName) => {\n const rot1 = keyframe1.boneRotations.get(boneName) ?? new THREE.Euler();\n const rot2 = keyframe2.boneRotations.get(boneName) ?? new THREE.Euler();\n const blended = interpolateRotation(rot1, rot2, clampedBlend);\n boneRotations.set(boneName, blended);\n });\n\n // Blend positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...keyframe1.bonePositions.keys(),\n ...keyframe2.bonePositions.keys(),\n ]);\n\n allPositionBones.forEach((boneName) => {\n const pos1 = keyframe1.bonePositions.get(boneName) ?? new THREE.Vector3();\n const pos2 = keyframe2.bonePositions.get(boneName) ?? new THREE.Vector3();\n const blended = interpolatePosition(pos1, pos2, clampedBlend);\n bonePositions.set(boneName, blended);\n });\n\n return {\n time: 0,\n boneRotations,\n bonePositions,\n easing: \"linear\",\n };\n};\n\n/**\n * Update animation state\n * \n * Advances animation time and returns current interpolated keyframe.\n * Handles looping animations automatically.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation\n * @param deltaTime - Time since last update (seconds)\n * @param playbackSpeed - Speed multiplier (1.0 = normal)\n * @returns Updated time and current keyframe\n * \n * @korean 애니메이션상태업데이트\n */\nexport const updateAnimation = (\n animation: SkeletalAnimation,\n currentTime: number,\n deltaTime: number,\n playbackSpeed = 1.0\n): { time: number; keyframe: AnimationKeyframe; completed: boolean } => {\n // Advance time\n let newTime = currentTime + deltaTime * playbackSpeed;\n let completed = false;\n\n // Handle looping or completion\n if (newTime >= animation.duration) {\n if (animation.loop) {\n newTime = newTime % animation.duration;\n } else {\n newTime = animation.duration;\n completed = true;\n }\n }\n\n // Get interpolated keyframe\n const keyframe = getInterpolatedKeyframe(animation, newTime);\n\n return {\n time: newTime,\n keyframe,\n completed,\n };\n};\n\n/**\n * Cross-fade blend between two animations\n * \n * **Korean**: 크로스페이드 블렌드\n * \n * Smoothly blends between two overlapping animations to prevent popping.\n * Uses cubic bezier easing for natural transitions.\n * \n * @param animation1 - First animation\n * @param time1 - Current time in first animation\n * @param animation2 - Second animation\n * @param time2 - Current time in second animation\n * @param blendFactor - Blend weight (0 = animation1, 1 = animation2)\n * @param easingName - Easing curve for blend transition\n * @returns Blended keyframe\n * \n * @example\n * ```typescript\n * // Cross-fade from idle to attack over 100ms\n * const blended = crossFadeAnimations(\n * idleAnim, idleTime,\n * attackAnim, attackTime,\n * 0.5, // 50% blend\n * \"smooth-transition\"\n * );\n * applyKeyframeToRig(rig, blended);\n * ```\n * \n * @korean 크로스페이드블렌드\n */\nexport const crossFadeAnimations = (\n animation1: SkeletalAnimation,\n time1: number,\n animation2: SkeletalAnimation,\n time2: number,\n blendFactor: number,\n easingName: EasingName = \"smooth-transition\"\n): AnimationKeyframe => {\n const keyframe1 = getInterpolatedKeyframe(animation1, time1);\n const keyframe2 = getInterpolatedKeyframe(animation2, time2);\n \n // Apply easing to blend factor\n const easingFn = getEasingFunction(easingName);\n const easedBlend = easingFn(Math.max(0, Math.min(1, blendFactor)));\n \n return blendKeyframes(keyframe1, keyframe2, easedBlend);\n};\n\n/**\n * Motion prediction state for latency reduction\n * \n * **Korean**: 동작 예측 상태\n * \n * Stores recent animation velocities for motion prediction.\n * \n * @category Animation\n * @korean 동작예측상태\n */\nexport interface MotionPredictionState {\n /** Recent position velocities per bone */\n readonly velocities: Map<string, THREE.Vector3>;\n /** Recent rotation velocities per bone */\n readonly angularVelocities: Map<string, THREE.Euler>;\n /** Last update timestamp */\n readonly lastUpdateTime: number;\n}\n\n/**\n * Create motion prediction state\n * \n * **Korean**: 동작 예측 상태 생성\n * \n * @returns Initial motion prediction state\n * @korean 동작예측상태생성\n */\nexport const createMotionPredictionState = (): MotionPredictionState => ({\n velocities: new Map(),\n angularVelocities: new Map(),\n lastUpdateTime: 0,\n});\n\n/**\n * Update motion prediction state with new keyframe\n * \n * **Korean**: 동작 예측 상태 업데이트\n * \n * Calculates velocities from keyframe differences for motion prediction.\n * \n * @param state - Current prediction state\n * @param previousKeyframe - Previous animation keyframe\n * @param currentKeyframe - Current animation keyframe\n * @param deltaTime - Time elapsed between keyframes\n * @returns Updated prediction state\n * \n * @korean 동작예측상태업데이트\n */\nexport const updateMotionPrediction = (\n state: MotionPredictionState,\n previousKeyframe: AnimationKeyframe,\n currentKeyframe: AnimationKeyframe,\n deltaTime: number\n): MotionPredictionState => {\n if (deltaTime <= 0) return state;\n \n const newVelocities = new Map<string, THREE.Vector3>();\n const newAngularVelocities = new Map<string, THREE.Euler>();\n \n // Calculate position velocities\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const prevPos = previousKeyframe.bonePositions.get(boneName);\n if (prevPos) {\n const velocity = new THREE.Vector3()\n .subVectors(currentPos, prevPos)\n .divideScalar(deltaTime);\n newVelocities.set(boneName, velocity);\n }\n });\n \n // Calculate angular velocities using quaternion-based rotation differences\n // This avoids gimbal lock and angle wrapping issues with Euler angle differences\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const prevRot = previousKeyframe.boneRotations.get(boneName);\n if (prevRot) {\n // Convert Euler rotations to quaternions\n const qCurrent = new THREE.Quaternion().setFromEuler(currentRot);\n const qPrev = new THREE.Quaternion().setFromEuler(prevRot);\n \n // Calculate relative rotation: qDiff = qCurrent * qPrev^(-1)\n const qDiff = qCurrent.clone().multiply(qPrev.clone().invert());\n \n // Extract axis-angle representation for angular velocity\n const axis = new THREE.Vector3();\n const wClamped = THREE.MathUtils.clamp(qDiff.w, -1, 1);\n let angle = 2 * Math.acos(wClamped);\n const sinHalfAngle = Math.sqrt(1 - wClamped * wClamped);\n \n if (sinHalfAngle < 0.0001) {\n // If sinHalfAngle is too small, rotation is negligible - use zero velocity\n axis.set(0, 0, 0);\n angle = 0;\n } else {\n // Extract normalized axis from quaternion\n axis.set(\n qDiff.x / sinHalfAngle,\n qDiff.y / sinHalfAngle,\n qDiff.z / sinHalfAngle\n );\n }\n \n // Use shortest rotation path\n if (angle > Math.PI) {\n angle -= 2 * Math.PI;\n }\n \n // Angular velocity vector = axis * (angle / deltaTime)\n const angularVelocityVec = axis.multiplyScalar(angle / deltaTime);\n \n // Store as Euler for consistency with existing API\n const angularVel = new THREE.Euler(\n angularVelocityVec.x,\n angularVelocityVec.y,\n angularVelocityVec.z,\n currentRot.order\n );\n newAngularVelocities.set(boneName, angularVel);\n }\n });\n \n return {\n velocities: newVelocities,\n angularVelocities: newAngularVelocities,\n lastUpdateTime: performance.now(),\n };\n};\n\n/**\n * Predict future keyframe using motion prediction\n * \n * **Korean**: 동작 예측으로 미래 키프레임 예측\n * \n * Reduces perceived latency by predicting future bone positions/rotations\n * based on current velocities. Typical prediction: 16-33ms (1-2 frames at 60fps).\n * \n * @param currentKeyframe - Current animation keyframe\n * @param predictionState - Motion prediction state\n * @param predictionTime - Time ahead to predict (seconds, typically 0.016-0.033)\n * @returns Predicted keyframe\n * \n * @example\n * ```typescript\n * // Predict 1 frame ahead (16.67ms at 60fps) for <50ms total latency\n * const predicted = predictFutureKeyframe(\n * currentKeyframe,\n * motionState,\n * 0.01667\n * );\n * applyKeyframeToRig(rig, predicted);\n * ```\n * \n * @korean 미래키프레임예측\n */\nexport const predictFutureKeyframe = (\n currentKeyframe: AnimationKeyframe,\n predictionState: MotionPredictionState,\n predictionTime: number\n): AnimationKeyframe => {\n // Clamp prediction time to reasonable bounds (max 50ms)\n const clampedPrediction = Math.min(predictionTime, 0.05);\n \n // Predict bone positions\n const predictedPositions = new Map<string, THREE.Vector3>();\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const velocity = predictionState.velocities.get(boneName);\n if (velocity) {\n // Apply damping to prevent overshoot (0.8 factor for natural motion)\n const predicted = currentPos.clone().add(\n velocity.clone().multiplyScalar(clampedPrediction * 0.8)\n );\n predictedPositions.set(boneName, predicted);\n } else {\n predictedPositions.set(boneName, currentPos.clone());\n }\n });\n \n // Predict bone rotations\n const predictedRotations = new Map<string, THREE.Euler>();\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const angularVel = predictionState.angularVelocities.get(boneName);\n if (angularVel) {\n // Apply damping to prevent overshoot\n const predicted = new THREE.Euler(\n currentRot.x + angularVel.x * clampedPrediction * 0.8,\n currentRot.y + angularVel.y * clampedPrediction * 0.8,\n currentRot.z + angularVel.z * clampedPrediction * 0.8,\n currentRot.order\n );\n predictedRotations.set(boneName, predicted);\n } else {\n predictedRotations.set(boneName, currentRot.clone());\n }\n });\n \n return {\n time: currentKeyframe.time + clampedPrediction,\n boneRotations: predictedRotations,\n bonePositions: predictedPositions,\n easing: currentKeyframe.easing,\n };\n};\n"],"mappings":"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"}
|
|
@@ -109,7 +109,6 @@ export declare const createHumanoidRig: () => SkeletalRig;
|
|
|
109
109
|
* // Height: 188cm, Legs: 100cm, Arms: 84cm, Shoulders: 54cm (25% wider!)
|
|
110
110
|
* ```
|
|
111
111
|
*
|
|
112
|
-
* @public
|
|
113
112
|
* @korean 크기조정된인간형골격생성
|
|
114
113
|
*/
|
|
115
114
|
export declare const createScaledHumanoidRig: (attributes: PhysicalAttributes) => SkeletalRig;
|
|
@@ -231,7 +230,6 @@ export declare const createHumanoidRigWithHands: (includeHandBones?: boolean) =>
|
|
|
231
230
|
* - 허리회전 (Heorhwoejeon) - Torso rotation
|
|
232
231
|
* - 해부학적제약 (Haebuhakjeok Jeyak) - Anatomical constraints
|
|
233
232
|
*
|
|
234
|
-
* @public
|
|
235
233
|
* @korean 허리회전제약조건
|
|
236
234
|
*/
|
|
237
235
|
export declare const TORSO_CONSTRAINTS: {
|
|
@@ -288,7 +286,6 @@ export declare const TORSO_CONSTRAINTS: {
|
|
|
288
286
|
* // Returns 0 (opponent is already aligned with hips)
|
|
289
287
|
* ```
|
|
290
288
|
*
|
|
291
|
-
* @public
|
|
292
289
|
* @korean 상대를향한허리회전계산
|
|
293
290
|
*/
|
|
294
291
|
export declare function calculateTorsoRotation(currentPosition: THREE.Vector3, opponentPosition: THREE.Vector3, _movementDirection: THREE.Vector3, hipRotation: number): number;
|
|
@@ -314,7 +311,6 @@ export declare function calculateTorsoRotation(currentPosition: THREE.Vector3, o
|
|
|
314
311
|
* // Returns 1.05 (5% damage bonus)
|
|
315
312
|
* ```
|
|
316
313
|
*
|
|
317
|
-
* @public
|
|
318
314
|
* @korean 허리회전으로인한데미지배율계산
|
|
319
315
|
*/
|
|
320
316
|
export declare function calculateHipRotationPowerModifier(hipRotationAngle: number, techniqueType: "strike" | "throw" | "joint"): number;
|