blacktrigram 0.7.39 → 0.7.41
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/App2.js.map +1 -1
- package/lib/audio/AudioAssetLoader.js.map +1 -1
- package/lib/audio/AudioAssetRegistry.js.map +1 -1
- package/lib/audio/AudioCache.js.map +1 -1
- package/lib/audio/AudioManager.js.map +1 -1
- package/lib/audio/AudioMonitor.js.map +1 -1
- package/lib/audio/AudioPool.js.map +1 -1
- package/lib/audio/AudioProvider.js.map +1 -1
- package/lib/audio/AudioUtils.js.map +1 -1
- package/lib/audio/BoneImpactAudioMap.js.map +1 -1
- package/lib/audio/VariantSelector.js.map +1 -1
- package/lib/audio/types.js.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
- package/lib/components/screens/combat/components/controls/CombatButtons.js.map +1 -1
- package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
- package/lib/components/screens/combat/components/controls/ControlsGuide.js.map +1 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenuButton.js.map +1 -1
- package/lib/components/screens/combat/components/controls/QuickSettings.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
- package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
- package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
- package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
- package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
- package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
- package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
- package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/Key3D.js.map +1 -1
- package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
- package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
- package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
- package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.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.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
- package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
- package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
- package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
- package/lib/components/shared/base/BaseButton.js.map +1 -1
- package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
- package/lib/components/shared/base/BasePanel.js.map +1 -1
- package/lib/components/shared/base/BaseText.js.map +1 -1
- package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
- package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
- package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
- package/lib/components/shared/mobile/HapticController.js.map +1 -1
- package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
- package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
- package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
- package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
- package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
- package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
- package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
- package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
- package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
- package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
- package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
- package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
- package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
- package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
- package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
- package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
- package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
- package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
- package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
- package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
- package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
- package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
- package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
- package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
- package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
- package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
- package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
- package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
- package/lib/components/shared/three/ui/MenuList.js.map +1 -1
- package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
- package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
- package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
- package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
- package/lib/components/shared/ui/BackButton.js.map +1 -1
- package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
- package/lib/components/shared/ui/CombatTimer.js.map +1 -1
- package/lib/components/shared/ui/ErrorModal.js.map +1 -1
- package/lib/components/shared/ui/LoadingState.js.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/VitalPointOverlayControlsPure.js.map +1 -1
- package/lib/components/shared/ui/VolumeControl.js.map +1 -1
- package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
- package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
- package/lib/constants/bodyDimensions.js.map +1 -1
- package/lib/constants/bodyRenderingConstants.js.map +1 -1
- package/lib/data/archetypeClothing.js.map +1 -1
- package/lib/data/archetypePhysicalAttributes.js.map +1 -1
- package/lib/data/techniqueMappings.js.map +1 -1
- package/lib/data/techniques.js.map +1 -1
- package/lib/hooks/useActionFeedback.js.map +1 -1
- package/lib/hooks/useBalanceAnimations.js.map +1 -1
- package/lib/hooks/useCombatTimer.js.map +1 -1
- package/lib/hooks/useDebounce.js.map +1 -1
- package/lib/hooks/useHUDLayout.js.map +1 -1
- package/lib/hooks/useHandPoseTransitions.js.map +1 -1
- package/lib/hooks/useKeyboardControls.js.map +1 -1
- package/lib/hooks/useMatchCountdown.js.map +1 -1
- package/lib/hooks/useMuscleActivation.js.map +1 -1
- package/lib/hooks/usePauseMenu.js.map +1 -1
- package/lib/hooks/usePlayerAnimation.js.map +1 -1
- package/lib/hooks/useResponsiveLayout.js.map +1 -1
- package/lib/hooks/useRoundTransition.js.map +1 -1
- package/lib/hooks/useSkeletalAnimation.js.map +1 -1
- package/lib/hooks/useTechniqueSelection.js.map +1 -1
- package/lib/hooks/useThrottle.js.map +1 -1
- package/lib/hooks/useTouchControls.js.map +1 -1
- package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
- package/lib/hooks/useWindowSize.js.map +1 -1
- package/lib/systems/CombatSystem.js.map +1 -1
- package/lib/systems/EffectCalculator.js.map +1 -1
- package/lib/systems/LayoutSystem.js.map +1 -1
- package/lib/systems/PlayerEffectManager.js.map +1 -1
- package/lib/systems/ResponsiveScaling.js.map +1 -1
- package/lib/systems/TrigramSystem.js.map +1 -1
- package/lib/systems/VitalPointSystem.js.map +1 -1
- package/lib/systems/ai/AIPersonality.js.map +1 -1
- package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
- package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
- package/lib/systems/ai/ComboSystem.js.map +1 -1
- package/lib/systems/ai/DecisionTree.js.map +1 -1
- package/lib/systems/ai/TrainingAI.js.map +1 -1
- package/lib/systems/ai/types.js.map +1 -1
- package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
- package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/HandPoses.js.map +1 -1
- package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.js +3 -90
- package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
- package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
- package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
- package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
- package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
- package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
- package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
- package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
- package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
- package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
- package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
- package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
- package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
- package/lib/systems/animation/core/types.js.map +1 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
- package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
- package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
- package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
- package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
- package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
- package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
- package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
- package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
- package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
- package/lib/systems/bodypart/types.js.map +1 -1
- package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
- package/lib/systems/breathing/feedback.js.map +1 -1
- package/lib/systems/breathing/integration.js.map +1 -1
- package/lib/systems/combat/BalanceSystem.js.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
- package/lib/systems/combat/CombatStateSystem.js.map +1 -1
- package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
- package/lib/systems/combat/FallIntegration.js.map +1 -1
- package/lib/systems/combat/GrappleSystem.js.map +1 -1
- package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
- package/lib/systems/combat/PainResponseSystem.js.map +1 -1
- package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
- package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
- package/lib/systems/combat/typeGuards.js.map +1 -1
- package/lib/systems/effects.js.map +1 -1
- package/lib/systems/game.js.map +1 -1
- package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
- package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
- package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
- package/lib/systems/movement/integration.js.map +1 -1
- package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
- package/lib/systems/physics/CollisionDetection.js.map +1 -1
- package/lib/systems/physics/CoordinateMapper.js.map +1 -1
- package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
- package/lib/systems/physics/MovementPhysics.js.map +1 -1
- package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
- package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
- package/lib/systems/trigram/KoreanCulture.js.map +1 -1
- package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
- package/lib/systems/trigram/StanceManager.js.map +1 -1
- package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
- package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
- package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
- package/lib/systems/trigram/techniques/index.js.map +1 -1
- package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
- package/lib/systems/trigram/types.js.map +1 -1
- package/lib/systems/types.js.map +1 -1
- package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
- package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
- package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
- package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
- package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
- package/lib/types/AccessibilityTypes.js.map +1 -1
- package/lib/types/PhysicsTypes.js.map +1 -1
- package/lib/types/common.js.map +1 -1
- package/lib/types/constants/colors.js.map +1 -1
- package/lib/types/constants/designSystem.js.map +1 -1
- package/lib/types/constants/layout.js.map +1 -1
- package/lib/types/constants/performance.js.map +1 -1
- package/lib/types/constants/typography.js.map +1 -1
- package/lib/types/facial.js.map +1 -1
- package/lib/types/hand-animation.js.map +1 -1
- package/lib/types/injury.js.map +1 -1
- package/lib/types/physics.js.map +1 -1
- package/lib/types/skeletal.js.map +1 -1
- package/lib/types/techniqueId.js.map +1 -1
- package/lib/utils/accessibility.js.map +1 -1
- package/lib/utils/arenaWorldDimensions.js.map +1 -1
- package/lib/utils/assetConfig.js.map +1 -1
- package/lib/utils/characterScaling.js.map +1 -1
- package/lib/utils/colorHelpers.js.map +1 -1
- package/lib/utils/colorUtils.js.map +1 -1
- package/lib/utils/combatReadiness.js.map +1 -1
- package/lib/utils/controlMapping.js.map +1 -1
- package/lib/utils/deviceDetection.js.map +1 -1
- package/lib/utils/effectUtils.js.map +1 -1
- package/lib/utils/fabricTextures.js.map +1 -1
- package/lib/utils/hapticFeedback.js.map +1 -1
- package/lib/utils/haptics.js.map +1 -1
- package/lib/utils/htmlOverlayHelpers.js.map +1 -1
- package/lib/utils/inputSystem.js.map +1 -1
- package/lib/utils/koreanThemeHelpers.js.map +1 -1
- package/lib/utils/math.js.map +1 -1
- package/lib/utils/mobileLayoutHelpers.js.map +1 -1
- package/lib/utils/mobileUIUtils.js.map +1 -1
- package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
- package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
- package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
- package/lib/utils/performanceOptimization.js.map +1 -1
- package/lib/utils/player3DHelpers.js.map +1 -1
- package/lib/utils/playerUtils.js.map +1 -1
- package/lib/utils/responsiveLayout.js.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
- package/lib/utils/responsiveOrientationConstants.js.map +1 -1
- package/lib/utils/safeAreaUtils.js.map +1 -1
- package/lib/utils/sharedPhysicsConfig.js.map +1 -1
- package/lib/utils/skeletonScaling.js.map +1 -1
- package/lib/utils/stanceHelpers.js.map +1 -1
- package/lib/utils/threeObjectPool.js.map +1 -1
- package/lib/utils/visualEffects.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archetypeClothing.js","names":[],"sources":["../../src/data/archetypeClothing.ts"],"sourcesContent":["/**\n * Archetype-specific clothing configurations\n *\n * **Korean**: 원형별 의류 설정 (Archetype Clothing Configurations)\n *\n * Defines characteristic clothing sets for each of the five player archetypes,\n * combining traditional Korean martial arts attire with cyberpunk aesthetics.\n *\n * @module data/archetypeClothing\n * @category Player & Archetypes\n * @korean 원형의류데이터\n */\n\nimport { PlayerArchetype } from \"@/types\";\nimport { KOREAN_COLORS } from \"@/types/constants/colors\";\nimport type { ClothingSet, ClothingItem } from \"@/types/clothing\";\n\n/**\n * 무사 (Musa) - Traditional Warrior Clothing Set\n *\n * **Philosophy**: Honor through disciplined strength\n * **Style**: Military dobok with tactical enhancements\n * **Aesthetic**: Traditional Korean martial arts uniform modernized with military elements\n *\n * @korean 무사의류\n */\nconst MUSA_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"musa_torso_gi\",\n nameKorean: \"전투 도복 상의\",\n nameEnglish: \"Combat Dobok Top\",\n type: \"torso\",\n material: \"fabric\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM, // Dark gray base\n colorSecondary: KOREAN_COLORS.ACCENT_GOLD,\n colorEmissive: KOREAN_COLORS.ACCENT_GOLD,\n emissiveIntensity: 0.1,\n metalness: 0.1,\n roughness: 0.8,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"musa_pants\",\n nameKorean: \"전투 도복 하의\",\n nameEnglish: \"Combat Dobok Pants\",\n type: \"pants\",\n material: \"fabric\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n colorSecondary: KOREAN_COLORS.ACCENT_GOLD,\n metalness: 0.1,\n roughness: 0.8,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"musa_belt\",\n nameKorean: \"검은 띠\",\n nameEnglish: \"Black Belt\",\n type: \"belt\",\n material: \"fabric\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.ACCENT_GOLD,\n colorEmissive: KOREAN_COLORS.ACCENT_GOLD,\n emissiveIntensity: 0.2,\n metalness: 0.0,\n roughness: 0.9,\n attachedBones: [\"pelvis\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"musa_boots\",\n nameKorean: \"전투 부츠\",\n nameEnglish: \"Combat Boots\",\n type: \"boots\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n metalness: 0.3,\n roughness: 0.7,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const MUSA_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.MUSA,\n nameKorean: \"무사 군복\",\n nameEnglish: \"Military Warrior Uniform\",\n descriptionKorean: \"전통 도복과 현대 군복을 결합한 전사의 의상\",\n descriptionEnglish: \"Traditional dobok combined with modern military uniform\",\n items: MUSA_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n secondary: KOREAN_COLORS.ACCENT_GOLD,\n accent: KOREAN_COLORS.KOREAN_BLACK,\n },\n};\n\n/**\n * 암살자 (Amsalja) - Shadow Assassin Clothing Set\n *\n * **Philosophy**: Efficiency through invisibility\n * **Style**: Stealth bodysuit with cyber enhancements\n * **Aesthetic**: Sleek, form-fitting with neon cyan accents\n *\n * @korean 암살자의류\n */\nconst AMSALJA_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"amsalja_bodysuit\",\n nameKorean: \"스텔스 바디슈트\",\n nameEnglish: \"Stealth Bodysuit\",\n type: \"torso\",\n material: \"synthetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.PRIMARY_CYAN,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.3,\n metalness: 0.4,\n roughness: 0.5,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_lower_arm\", \"right_lower_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"amsalja_pants\",\n nameKorean: \"스텔스 팬츠\",\n nameEnglish: \"Stealth Pants\",\n type: \"pants\",\n material: \"synthetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.PRIMARY_CYAN,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.2,\n metalness: 0.4,\n roughness: 0.5,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"amsalja_vest\",\n nameKorean: \"사이버 조끼\",\n nameEnglish: \"Cyber Vest\",\n type: \"vest\",\n material: \"armored\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.PRIMARY_CYAN,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.4,\n metalness: 0.7,\n roughness: 0.3,\n attachedBones: [\"torso\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"amsalja_boots\",\n nameKorean: \"스텔스 부츠\",\n nameEnglish: \"Stealth Boots\",\n type: \"boots\",\n material: \"synthetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.15,\n metalness: 0.5,\n roughness: 0.4,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const AMSALJA_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.AMSALJA,\n nameKorean: \"암살자 전투복\",\n nameEnglish: \"Shadow Assassin Suit\",\n descriptionKorean: \"사이버 기술이 통합된 은밀한 암살자 복장\",\n descriptionEnglish: \"Stealthy assassin outfit with integrated cyber technology\",\n items: AMSALJA_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.KOREAN_BLACK,\n secondary: KOREAN_COLORS.PRIMARY_CYAN,\n accent: KOREAN_COLORS.UI_BACKGROUND_DARK,\n },\n};\n\n/**\n * 해커 (Hacker) - Cyber Warrior Clothing Set\n *\n * **Philosophy**: Information as power through technology\n * **Style**: Casual tech wear with augmented reality elements\n * **Aesthetic**: Street style with holographic accents\n *\n * @korean 해커의류\n */\nconst HACKER_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"hacker_hoodie\",\n nameKorean: \"사이버 후드티\",\n nameEnglish: \"Cyber Hoodie\",\n type: \"torso\",\n material: \"synthetic\",\n fit: \"loose\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.25,\n metalness: 0.2,\n roughness: 0.7,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"hacker_pants\",\n nameKorean: \"테크 팬츠\",\n nameEnglish: \"Tech Pants\",\n type: \"pants\",\n material: \"tactical\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.15,\n metalness: 0.3,\n roughness: 0.6,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"hacker_gloves\",\n nameKorean: \"데이터 글러브\",\n nameEnglish: \"Data Gloves\",\n type: \"gloves\",\n material: \"cybernetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.5,\n metalness: 0.8,\n roughness: 0.2,\n attachedBones: [\"left_hand\", \"right_hand\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"hacker_boots\",\n nameKorean: \"스마트 스니커즈\",\n nameEnglish: \"Smart Sneakers\",\n type: \"boots\",\n material: \"synthetic\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.2,\n metalness: 0.4,\n roughness: 0.5,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const HACKER_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.HACKER,\n nameKorean: \"해커 전투복\",\n nameEnglish: \"Hacker Combat Wear\",\n descriptionKorean: \"첨단 기술이 융합된 사이버 전사 복장\",\n descriptionEnglish: \"Cyber warrior outfit with cutting-edge technology\",\n items: HACKER_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n secondary: KOREAN_COLORS.SECONDARY_PURPLE,\n accent: KOREAN_COLORS.KOREAN_BLACK,\n },\n};\n\n/**\n * 정보요원 (Jeongbo Yowon) - Intelligence Operative Clothing Set\n *\n * **Philosophy**: Knowledge through observation and strategy\n * **Style**: Professional tactical suit\n * **Aesthetic**: Clean, functional, government operative\n *\n * @korean 정보요원의류\n */\nconst JEONGBO_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"jeongbo_jacket\",\n nameKorean: \"작전 재킷\",\n nameEnglish: \"Tactical Jacket\",\n type: \"torso\",\n material: \"tactical\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n colorEmissive: KOREAN_COLORS.ACCENT_BLUE,\n emissiveIntensity: 0.15,\n metalness: 0.2,\n roughness: 0.7,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_pants\",\n nameKorean: \"작전 팬츠\",\n nameEnglish: \"Tactical Pants\",\n type: \"pants\",\n material: \"tactical\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n metalness: 0.2,\n roughness: 0.7,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_vest\",\n nameKorean: \"작전 조끼\",\n nameEnglish: \"Tactical Vest\",\n type: \"vest\",\n material: \"armored\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n colorEmissive: KOREAN_COLORS.ACCENT_BLUE,\n emissiveIntensity: 0.2,\n metalness: 0.5,\n roughness: 0.5,\n attachedBones: [\"torso\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_belt\",\n nameKorean: \"전술 벨트\",\n nameEnglish: \"Tactical Belt\",\n type: \"belt\",\n material: \"tactical\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n metalness: 0.4,\n roughness: 0.6,\n attachedBones: [\"pelvis\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_boots\",\n nameKorean: \"작전 부츠\",\n nameEnglish: \"Tactical Boots\",\n type: \"boots\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n metalness: 0.3,\n roughness: 0.7,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const JEONGBO_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.JEONGBO_YOWON,\n nameKorean: \"정보요원 작전복\",\n nameEnglish: \"Intelligence Operative Gear\",\n descriptionKorean: \"정부 요원을 위한 전문 작전 장비\",\n descriptionEnglish: \"Professional tactical gear for government operatives\",\n items: JEONGBO_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n secondary: KOREAN_COLORS.ACCENT_BLUE,\n accent: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n },\n};\n\n/**\n * 조직폭력배 (Jojik Pokryeokbae) - Organized Crime Clothing Set\n *\n * **Philosophy**: Survival through ruthlessness and brutality\n * **Style**: Street gang attire with intimidating elements\n * **Aesthetic**: Heavy, brutal, street fighter\n *\n * @korean 조직폭력배의류\n */\nconst JOJIK_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"jojik_leather_jacket\",\n nameKorean: \"가죽 재킷\",\n nameEnglish: \"Leather Jacket\",\n type: \"torso\",\n material: \"leather\",\n fit: \"oversized\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.ACCENT_RED,\n colorEmissive: KOREAN_COLORS.ACCENT_RED,\n emissiveIntensity: 0.2,\n metalness: 0.6,\n roughness: 0.4,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_pants\",\n nameKorean: \"카고 팬츠\",\n nameEnglish: \"Cargo Pants\",\n type: \"pants\",\n material: \"fabric\",\n fit: \"loose\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_RED,\n metalness: 0.1,\n roughness: 0.8,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_belt\",\n nameKorean: \"체인 벨트\",\n nameEnglish: \"Chain Belt\",\n type: \"belt\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.UI_STEEL_GRAY,\n colorEmissive: KOREAN_COLORS.ACCENT_RED,\n emissiveIntensity: 0.15,\n metalness: 0.8,\n roughness: 0.3,\n attachedBones: [\"pelvis\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_gloves\",\n nameKorean: \"스터드 장갑\",\n nameEnglish: \"Studded Gloves\",\n type: \"gloves\",\n material: \"leather\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.UI_STEEL_GRAY,\n metalness: 0.7,\n roughness: 0.4,\n attachedBones: [\"left_hand\", \"right_hand\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_boots\",\n nameKorean: \"전투 부츠\",\n nameEnglish: \"Combat Boots\",\n type: \"boots\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n metalness: 0.4,\n roughness: 0.6,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const JOJIK_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.JOJIK_POKRYEOKBAE,\n nameKorean: \"조직폭력배 복장\",\n nameEnglish: \"Street Fighter Gear\",\n descriptionKorean: \"거리의 무법자를 위한 위협적인 복장\",\n descriptionEnglish: \"Intimidating outfit for street-hardened fighters\",\n items: JOJIK_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.KOREAN_BLACK,\n secondary: KOREAN_COLORS.ACCENT_RED,\n accent: KOREAN_COLORS.UI_BACKGROUND_DARK,\n },\n};\n\n/**\n * Archetype clothing lookup map\n *\n * **Korean**: 원형 의류 맵 (Archetype Clothing Map)\n *\n * @public\n * @korean 원형의류맵\n */\nexport const ARCHETYPE_CLOTHING: Record<PlayerArchetype, ClothingSet> = {\n [PlayerArchetype.MUSA]: MUSA_CLOTHING,\n [PlayerArchetype.AMSALJA]: AMSALJA_CLOTHING,\n [PlayerArchetype.HACKER]: HACKER_CLOTHING,\n [PlayerArchetype.JEONGBO_YOWON]: JEONGBO_CLOTHING,\n [PlayerArchetype.JOJIK_POKRYEOKBAE]: JOJIK_CLOTHING,\n};\n\n/**\n * Get clothing set for a specific archetype\n *\n * **Korean**: 원형 의류 가져오기 (Get Archetype Clothing)\n *\n * @param archetype - Player archetype\n * @returns Clothing set for the archetype\n * @public\n * @korean 원형의류가져오기\n */\nexport function getArchetypeClothing(archetype: PlayerArchetype): ClothingSet {\n return ARCHETYPE_CLOTHING[archetype];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"archetypeClothing.js","names":[],"sources":["../../src/data/archetypeClothing.ts"],"sourcesContent":["/**\n * Archetype-specific clothing configurations\n *\n * **Korean**: 원형별 의류 설정 (Archetype Clothing Configurations)\n *\n * Defines characteristic clothing sets for each of the five player archetypes,\n * combining traditional Korean martial arts attire with cyberpunk aesthetics.\n *\n * @module data/archetypeClothing\n * @category Player & Archetypes\n * @korean 원형의류데이터\n */\n\nimport { PlayerArchetype } from \"@/types\";\nimport { KOREAN_COLORS } from \"@/types/constants/colors\";\nimport type { ClothingSet, ClothingItem } from \"@/types/clothing\";\n\n/**\n * 무사 (Musa) - Traditional Warrior Clothing Set\n *\n * **Philosophy**: Honor through disciplined strength\n * **Style**: Military dobok with tactical enhancements\n * **Aesthetic**: Traditional Korean martial arts uniform modernized with military elements\n *\n * @korean 무사의류\n */\nconst MUSA_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"musa_torso_gi\",\n nameKorean: \"전투 도복 상의\",\n nameEnglish: \"Combat Dobok Top\",\n type: \"torso\",\n material: \"fabric\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM, // Dark gray base\n colorSecondary: KOREAN_COLORS.ACCENT_GOLD,\n colorEmissive: KOREAN_COLORS.ACCENT_GOLD,\n emissiveIntensity: 0.1,\n metalness: 0.1,\n roughness: 0.8,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"musa_pants\",\n nameKorean: \"전투 도복 하의\",\n nameEnglish: \"Combat Dobok Pants\",\n type: \"pants\",\n material: \"fabric\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n colorSecondary: KOREAN_COLORS.ACCENT_GOLD,\n metalness: 0.1,\n roughness: 0.8,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"musa_belt\",\n nameKorean: \"검은 띠\",\n nameEnglish: \"Black Belt\",\n type: \"belt\",\n material: \"fabric\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.ACCENT_GOLD,\n colorEmissive: KOREAN_COLORS.ACCENT_GOLD,\n emissiveIntensity: 0.2,\n metalness: 0.0,\n roughness: 0.9,\n attachedBones: [\"pelvis\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"musa_boots\",\n nameKorean: \"전투 부츠\",\n nameEnglish: \"Combat Boots\",\n type: \"boots\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n metalness: 0.3,\n roughness: 0.7,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const MUSA_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.MUSA,\n nameKorean: \"무사 군복\",\n nameEnglish: \"Military Warrior Uniform\",\n descriptionKorean: \"전통 도복과 현대 군복을 결합한 전사의 의상\",\n descriptionEnglish: \"Traditional dobok combined with modern military uniform\",\n items: MUSA_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n secondary: KOREAN_COLORS.ACCENT_GOLD,\n accent: KOREAN_COLORS.KOREAN_BLACK,\n },\n};\n\n/**\n * 암살자 (Amsalja) - Shadow Assassin Clothing Set\n *\n * **Philosophy**: Efficiency through invisibility\n * **Style**: Stealth bodysuit with cyber enhancements\n * **Aesthetic**: Sleek, form-fitting with neon cyan accents\n *\n * @korean 암살자의류\n */\nconst AMSALJA_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"amsalja_bodysuit\",\n nameKorean: \"스텔스 바디슈트\",\n nameEnglish: \"Stealth Bodysuit\",\n type: \"torso\",\n material: \"synthetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.PRIMARY_CYAN,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.3,\n metalness: 0.4,\n roughness: 0.5,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_lower_arm\", \"right_lower_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"amsalja_pants\",\n nameKorean: \"스텔스 팬츠\",\n nameEnglish: \"Stealth Pants\",\n type: \"pants\",\n material: \"synthetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.PRIMARY_CYAN,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.2,\n metalness: 0.4,\n roughness: 0.5,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"amsalja_vest\",\n nameKorean: \"사이버 조끼\",\n nameEnglish: \"Cyber Vest\",\n type: \"vest\",\n material: \"armored\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.PRIMARY_CYAN,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.4,\n metalness: 0.7,\n roughness: 0.3,\n attachedBones: [\"torso\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"amsalja_boots\",\n nameKorean: \"스텔스 부츠\",\n nameEnglish: \"Stealth Boots\",\n type: \"boots\",\n material: \"synthetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorEmissive: KOREAN_COLORS.PRIMARY_CYAN,\n emissiveIntensity: 0.15,\n metalness: 0.5,\n roughness: 0.4,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const AMSALJA_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.AMSALJA,\n nameKorean: \"암살자 전투복\",\n nameEnglish: \"Shadow Assassin Suit\",\n descriptionKorean: \"사이버 기술이 통합된 은밀한 암살자 복장\",\n descriptionEnglish: \"Stealthy assassin outfit with integrated cyber technology\",\n items: AMSALJA_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.KOREAN_BLACK,\n secondary: KOREAN_COLORS.PRIMARY_CYAN,\n accent: KOREAN_COLORS.UI_BACKGROUND_DARK,\n },\n};\n\n/**\n * 해커 (Hacker) - Cyber Warrior Clothing Set\n *\n * **Philosophy**: Information as power through technology\n * **Style**: Casual tech wear with augmented reality elements\n * **Aesthetic**: Street style with holographic accents\n *\n * @korean 해커의류\n */\nconst HACKER_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"hacker_hoodie\",\n nameKorean: \"사이버 후드티\",\n nameEnglish: \"Cyber Hoodie\",\n type: \"torso\",\n material: \"synthetic\",\n fit: \"loose\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.25,\n metalness: 0.2,\n roughness: 0.7,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"hacker_pants\",\n nameKorean: \"테크 팬츠\",\n nameEnglish: \"Tech Pants\",\n type: \"pants\",\n material: \"tactical\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.15,\n metalness: 0.3,\n roughness: 0.6,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"hacker_gloves\",\n nameKorean: \"데이터 글러브\",\n nameEnglish: \"Data Gloves\",\n type: \"gloves\",\n material: \"cybernetic\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.5,\n metalness: 0.8,\n roughness: 0.2,\n attachedBones: [\"left_hand\", \"right_hand\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"hacker_boots\",\n nameKorean: \"스마트 스니커즈\",\n nameEnglish: \"Smart Sneakers\",\n type: \"boots\",\n material: \"synthetic\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.SECONDARY_PURPLE,\n colorEmissive: KOREAN_COLORS.SECONDARY_PURPLE,\n emissiveIntensity: 0.2,\n metalness: 0.4,\n roughness: 0.5,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const HACKER_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.HACKER,\n nameKorean: \"해커 전투복\",\n nameEnglish: \"Hacker Combat Wear\",\n descriptionKorean: \"첨단 기술이 융합된 사이버 전사 복장\",\n descriptionEnglish: \"Cyber warrior outfit with cutting-edge technology\",\n items: HACKER_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n secondary: KOREAN_COLORS.SECONDARY_PURPLE,\n accent: KOREAN_COLORS.KOREAN_BLACK,\n },\n};\n\n/**\n * 정보요원 (Jeongbo Yowon) - Intelligence Operative Clothing Set\n *\n * **Philosophy**: Knowledge through observation and strategy\n * **Style**: Professional tactical suit\n * **Aesthetic**: Clean, functional, government operative\n *\n * @korean 정보요원의류\n */\nconst JEONGBO_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"jeongbo_jacket\",\n nameKorean: \"작전 재킷\",\n nameEnglish: \"Tactical Jacket\",\n type: \"torso\",\n material: \"tactical\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n colorEmissive: KOREAN_COLORS.ACCENT_BLUE,\n emissiveIntensity: 0.15,\n metalness: 0.2,\n roughness: 0.7,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_pants\",\n nameKorean: \"작전 팬츠\",\n nameEnglish: \"Tactical Pants\",\n type: \"pants\",\n material: \"tactical\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n metalness: 0.2,\n roughness: 0.7,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_vest\",\n nameKorean: \"작전 조끼\",\n nameEnglish: \"Tactical Vest\",\n type: \"vest\",\n material: \"armored\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n colorEmissive: KOREAN_COLORS.ACCENT_BLUE,\n emissiveIntensity: 0.2,\n metalness: 0.5,\n roughness: 0.5,\n attachedBones: [\"torso\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_belt\",\n nameKorean: \"전술 벨트\",\n nameEnglish: \"Tactical Belt\",\n type: \"belt\",\n material: \"tactical\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_BLUE,\n metalness: 0.4,\n roughness: 0.6,\n attachedBones: [\"pelvis\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jeongbo_boots\",\n nameKorean: \"작전 부츠\",\n nameEnglish: \"Tactical Boots\",\n type: \"boots\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n metalness: 0.3,\n roughness: 0.7,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const JEONGBO_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.JEONGBO_YOWON,\n nameKorean: \"정보요원 작전복\",\n nameEnglish: \"Intelligence Operative Gear\",\n descriptionKorean: \"정부 요원을 위한 전문 작전 장비\",\n descriptionEnglish: \"Professional tactical gear for government operatives\",\n items: JEONGBO_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n secondary: KOREAN_COLORS.ACCENT_BLUE,\n accent: KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n },\n};\n\n/**\n * 조직폭력배 (Jojik Pokryeokbae) - Organized Crime Clothing Set\n *\n * **Philosophy**: Survival through ruthlessness and brutality\n * **Style**: Street gang attire with intimidating elements\n * **Aesthetic**: Heavy, brutal, street fighter\n *\n * @korean 조직폭력배의류\n */\nconst JOJIK_CLOTHING_ITEMS: readonly ClothingItem[] = [\n {\n id: \"jojik_leather_jacket\",\n nameKorean: \"가죽 재킷\",\n nameEnglish: \"Leather Jacket\",\n type: \"torso\",\n material: \"leather\",\n fit: \"oversized\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.ACCENT_RED,\n colorEmissive: KOREAN_COLORS.ACCENT_RED,\n emissiveIntensity: 0.2,\n metalness: 0.6,\n roughness: 0.4,\n attachedBones: [\"torso\", \"left_upper_arm\", \"right_upper_arm\", \"left_shoulder\", \"right_shoulder\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_pants\",\n nameKorean: \"카고 팬츠\",\n nameEnglish: \"Cargo Pants\",\n type: \"pants\",\n material: \"fabric\",\n fit: \"loose\",\n colorPrimary: KOREAN_COLORS.UI_BACKGROUND_DARK,\n colorSecondary: KOREAN_COLORS.ACCENT_RED,\n metalness: 0.1,\n roughness: 0.8,\n attachedBones: [\"pelvis\", \"left_upper_leg\", \"right_upper_leg\", \"left_lower_leg\", \"right_lower_leg\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_belt\",\n nameKorean: \"체인 벨트\",\n nameEnglish: \"Chain Belt\",\n type: \"belt\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.UI_STEEL_GRAY,\n colorEmissive: KOREAN_COLORS.ACCENT_RED,\n emissiveIntensity: 0.15,\n metalness: 0.8,\n roughness: 0.3,\n attachedBones: [\"pelvis\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_gloves\",\n nameKorean: \"스터드 장갑\",\n nameEnglish: \"Studded Gloves\",\n type: \"gloves\",\n material: \"leather\",\n fit: \"tight\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n colorSecondary: KOREAN_COLORS.UI_STEEL_GRAY,\n metalness: 0.7,\n roughness: 0.4,\n attachedBones: [\"left_hand\", \"right_hand\"],\n castShadow: true,\n receiveShadow: true,\n },\n {\n id: \"jojik_boots\",\n nameKorean: \"전투 부츠\",\n nameEnglish: \"Combat Boots\",\n type: \"boots\",\n material: \"leather\",\n fit: \"fitted\",\n colorPrimary: KOREAN_COLORS.KOREAN_BLACK,\n metalness: 0.4,\n roughness: 0.6,\n attachedBones: [\"left_foot\", \"right_foot\"],\n castShadow: true,\n receiveShadow: true,\n },\n];\n\nexport const JOJIK_CLOTHING: ClothingSet = {\n archetype: PlayerArchetype.JOJIK_POKRYEOKBAE,\n nameKorean: \"조직폭력배 복장\",\n nameEnglish: \"Street Fighter Gear\",\n descriptionKorean: \"거리의 무법자를 위한 위협적인 복장\",\n descriptionEnglish: \"Intimidating outfit for street-hardened fighters\",\n items: JOJIK_CLOTHING_ITEMS,\n themeColors: {\n primary: KOREAN_COLORS.KOREAN_BLACK,\n secondary: KOREAN_COLORS.ACCENT_RED,\n accent: KOREAN_COLORS.UI_BACKGROUND_DARK,\n },\n};\n\n/**\n * Archetype clothing lookup map\n *\n * **Korean**: 원형 의류 맵 (Archetype Clothing Map)\n *\n * @public\n * @korean 원형의류맵\n */\nexport const ARCHETYPE_CLOTHING: Record<PlayerArchetype, ClothingSet> = {\n [PlayerArchetype.MUSA]: MUSA_CLOTHING,\n [PlayerArchetype.AMSALJA]: AMSALJA_CLOTHING,\n [PlayerArchetype.HACKER]: HACKER_CLOTHING,\n [PlayerArchetype.JEONGBO_YOWON]: JEONGBO_CLOTHING,\n [PlayerArchetype.JOJIK_POKRYEOKBAE]: JOJIK_CLOTHING,\n};\n\n/**\n * Get clothing set for a specific archetype\n *\n * **Korean**: 원형 의류 가져오기 (Get Archetype Clothing)\n *\n * @param archetype - Player archetype\n * @returns Clothing set for the archetype\n * @public\n * @korean 원형의류가져오기\n */\nexport function getArchetypeClothing(archetype: PlayerArchetype): ClothingSet {\n return ARCHETYPE_CLOTHING[archetype];\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archetypePhysicalAttributes.js","names":[],"sources":["../../src/data/archetypePhysicalAttributes.ts"],"sourcesContent":["/**\n * Physical attribute profiles for each player archetype.\n *\n * **Korean**: 원형별 신체 속성 (Archetype Physical Attributes)\n *\n * Defines realistic body dimensions and composition for each of the five\n * player archetypes based on their combat style and background. These\n * attributes directly affect combat calculations including reach, movement\n * speed, damage, and stamina.\n *\n * ## Design Philosophy\n *\n * Each archetype's physical profile reflects their training, lifestyle, and\n * combat specialization:\n *\n * - **무사 (Musa)**: Balanced warrior with traditional training\n * - **암살자 (Amsalja)**: Lean and agile for stealth operations\n * - **해커 (Hacker)**: Average build with tech enhancements\n * - **정보요원 (Jeongbo)**: Fit operative with intelligence background\n * - **조직폭력배 (Jojik)**: Heavy and brutal street fighter\n *\n * @module data/archetypePhysicalAttributes\n * @category Player & Archetypes\n * @korean 원형신체데이터\n */\n\nimport { PhysicalAttributes, PlayerArchetype } from \"@/types\";\n\n/**\n * 무사 (Musa) - Traditional Warrior Physical Profile\n *\n * **Philosophy**: Honor through disciplined strength\n * **Training**: Military special forces with traditional martial arts\n * **Build**: Balanced, athletic, well-conditioned warrior\n *\n * Physical characteristics reflect years of traditional Korean martial arts\n * training combined with modern military conditioning. Optimal balance between\n * strength, speed, and endurance for prolonged combat effectiveness.\n *\n * @korean 무사신체\n */\nexport const MUSA_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 82 kg\n * Athletic military build for strength and mobility\n * Korean Special Forces standard physique\n * Optimal power-to-weight ratio for combat\n */\n weight: 82,\n\n /**\n * Leg Length: 96 cm\n * Athletic leg length for powerful kicks\n * Trained for devastating Taekwondo kicks\n * Balanced reach and stability\n */\n legLength: 96,\n\n /**\n * Arm Length: 77 cm\n * Strong arm reach for disciplined striking\n * Conditioned for both precision and power\n * Effective grappling range\n */\n armLength: 77,\n\n /**\n * Muscle Mass: 35 kg (43% of body weight)\n * High muscle mass from military training\n * Realistic for trained special forces soldier\n * Excellent functional strength\n */\n muscleMass: 35,\n\n /**\n * Fat Mass: 13 kg (16% body fat)\n * Athletic body fat percentage\n * Maintains energy reserves for combat endurance\n * Optimal for sustained operations\n */\n fatMass: 13,\n\n /**\n * Age: 32 years\n * Prime combat age combining experience and physical capability\n * Peak of martial arts mastery and physical conditioning\n * Balanced wisdom and reflexes\n */\n age: 32,\n\n /**\n * Total Height: 180 cm\n * Solid military build height\n * Above average for imposing presence\n * Good proportions for all-around combat\n */\n totalHeight: 180,\n\n /**\n * Torso Length: 59 cm\n * Strong core providing stable base\n * Optimal for breath control and Ki cultivation\n * Protected vital points\n */\n torsoLength: 59,\n\n /**\n * Head Size: 22 cm\n * Average head diameter\n * Standard vital point target area\n * Balanced consciousness vulnerability\n */\n headSize: 22,\n\n /**\n * Neck Length: 11 cm\n * Strong, trained neck\n * Moderate vulnerability to chokes\n * Conditioned for impact resistance\n */\n neckLength: 11,\n\n /**\n * Shoulder Width: 46 cm\n * Broad military shoulders\n * Strong defense coverage\n * Excellent grappling control points\n */\n shoulderWidth: 46,\n\n /**\n * Walk Speed: 6.0 m/s\n * Balanced tactical movement\n * Military conditioning for sustained mobility\n * Optimal for disciplined combat approach\n */\n walkSpeed: 6.0,\n\n /**\n * Run Speed: 9.5 m/s\n * Strong sprint capability\n * Combat-ready rapid repositioning\n * Efficient for tactical advances\n */\n runSpeed: 9.5,\n\n /**\n * Acceleration: 12.0 m/s²\n * Balanced explosiveness\n * Military conditioning for quick reactions\n * Optimal muscle-to-weight ratio for combat\n */\n acceleration: 12.0,\n};\n\n/**\n * 암살자 (Amsalja) - Shadow Assassin Physical Profile\n *\n * **Philosophy**: Efficiency through invisibility\n * **Training**: Covert operations and silent elimination specialist\n * **Build**: Lean, agile, optimized for stealth and precision\n *\n * Physical characteristics emphasize low body mass for stealth movement,\n * exceptional reach for vital point targeting, and minimal fat for maximum\n * agility. Every attribute optimized for silent, deadly efficiency.\n *\n * @korean 암살자신체\n */\nexport const AMSALJA_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 75 kg\n * Lean athletic build like a kickboxer (Israel Adesanya type)\n * Optimized for speed, reach, and precision\n * Light enough for stealth, heavy enough for power\n */\n weight: 75,\n\n /**\n * Leg Length: 102 cm\n * Long legs for exceptional reach and stride\n * Enables precise high kicks to vital points\n * Excellent for maintaining distance\n */\n legLength: 102,\n\n /**\n * Arm Length: 82 cm\n * Extended reach for range advantage\n * Crucial for vital point precision strikes\n * Keeps opponents at safe distance\n */\n armLength: 82,\n\n /**\n * Muscle Mass: 30 kg (40% of body weight)\n * Lean, functional muscle for speed\n * Optimized for explosive movements\n * Sufficient for devastating precision strikes\n */\n muscleMass: 30,\n\n /**\n * Fat Mass: 10 kg (13% body fat)\n * Very low fat for maximum definition\n * Peak agility and flexibility\n * Athletic performance optimized\n */\n fatMass: 10,\n\n /**\n * Age: 28 years\n * Young and at peak physical agility\n * Optimal reflexes for split-second decisions\n * Experience balanced with peak conditioning\n */\n age: 28,\n\n /**\n * Total Height: 186 cm\n * Tall for exceptional reach advantage\n * Long limb ratios for vital point access\n * Intimidating presence while maintaining agility\n */\n totalHeight: 186,\n\n /**\n * Torso Length: 58 cm\n * Compact torso for lower center of gravity\n * Agile core for quick movement\n * Reduced vital point target area\n */\n torsoLength: 58,\n\n /**\n * Head Size: 22 cm\n * Normal head profile\n * Standard target area for head strikes\n * Balanced consciousness vulnerability\n */\n headSize: 22,\n\n /**\n * Neck Length: 11 cm\n * Longer neck for head movement evasion\n * Slightly increased choke vulnerability\n * Requires skilled guard positioning\n */\n neckLength: 11,\n\n /**\n * Shoulder Width: 44 cm\n * Lean but athletic shoulders\n * Good mobility with adequate coverage\n * Efficient for striking mechanics\n */\n shoulderWidth: 44,\n\n /**\n * Walk Speed: 6.5 m/s\n * FASTEST tactical movement\n * Optimized for silent, rapid repositioning\n * Assassin-level agility and speed\n */\n walkSpeed: 6.5,\n\n /**\n * Run Speed: 11.0 m/s\n * FASTEST sprint capability\n * Peak athletic conditioning for pursuit\n * Exceptional for closing distance quickly\n */\n runSpeed: 11.0,\n\n /**\n * Acceleration: 15.0 m/s²\n * HIGHEST explosiveness\n * Exceptional muscle-to-weight ratio\n * Lightning-fast direction changes\n */\n acceleration: 15.0,\n};\n\n/**\n * 해커 (Hacker) - Cyber Warrior Physical Profile\n *\n * **Philosophy**: Information as power through technology\n * **Training**: Digital native with supplemental physical training\n * **Build**: Average physique enhanced by technological augmentation\n *\n * Physical characteristics reflect a tech-focused lifestyle with functional\n * fitness rather than peak athletic conditioning. Attributes are average\n * but compensated by cybernetic enhancements and data-driven combat analysis.\n *\n * @korean 해커신체\n */\nexport const HACKER_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 72 kg\n * Average weight for height\n * Functional fitness from regular training\n * Tech worker who maintains fitness\n */\n weight: 72,\n\n /**\n * Leg Length: 92 cm\n * Standard leg proportions\n * Adequate for tech-assisted movement\n * Compensated by augmented targeting systems\n */\n legLength: 92,\n\n /**\n * Arm Length: 73 cm\n * Average arm reach\n * Sufficient when aided by cybernetic enhancements\n * Precision compensated by data analysis\n */\n armLength: 73,\n\n /**\n * Muscle Mass: 28 kg (39% of body weight)\n * Moderate muscle mass for tech worker\n * Maintained through efficient training\n * Relies more on tech than raw strength\n */\n muscleMass: 28,\n\n /**\n * Fat Mass: 15 kg (21% body fat)\n * Average body fat from desk work\n * Still functional for combat\n * Less emphasis on peak conditioning\n */\n fatMass: 15,\n\n /**\n * Age: 26 years\n * Young digital native\n * High neuroplasticity for tech integration\n * Peak learning and adaptation capabilities\n */\n age: 26,\n\n /**\n * Total Height: 175 cm\n * Average Korean male height\n * Standard proportions for tech integration\n * Balanced body type for augmentation\n */\n totalHeight: 175,\n\n /**\n * Torso Length: 57 cm\n * Average torso length\n * Standard core for cyber implants\n * Balanced Ki flow for tech-bio integration\n */\n torsoLength: 57,\n\n /**\n * Head Size: 22 cm\n * Average head size\n * Standard neural interface compatibility\n * Balanced for augmented reality overlays\n */\n headSize: 22,\n\n /**\n * Neck Length: 10 cm\n * Average neck length\n * Standard vulnerability to chokes\n * Adequate for neural interface cables\n */\n neckLength: 10,\n\n /**\n * Shoulder Width: 43 cm\n * Average shoulder span\n * Standard defense coverage\n * Balanced for wearable tech integration\n */\n shoulderWidth: 43,\n\n /**\n * Walk Speed: 5.5 m/s\n * Average tactical movement\n * Tech-focused rather than athletic\n * Compensated by cybernetic enhancements\n */\n walkSpeed: 5.5,\n\n /**\n * Run Speed: 8.5 m/s\n * Moderate sprint capability\n * Supplemental physical training\n * Relies on tech for combat advantage\n */\n runSpeed: 8.5,\n\n /**\n * Acceleration: 10.0 m/s²\n * Moderate explosiveness\n * Average physical conditioning\n * Compensated by tech-enhanced reactions\n */\n acceleration: 10.0,\n};\n\n/**\n * 정보요원 (Jeongbo Yowon) - Intelligence Operative Physical Profile\n *\n * **Philosophy**: Knowledge through observation and strategy\n * **Training**: Government intelligence agency with specialized combat\n * **Build**: Athletic operative with strategic fitness\n *\n * Physical characteristics reflect intelligence agency fitness standards\n * with emphasis on versatility, endurance, and adaptability. Balanced\n * attributes suitable for varied operational requirements.\n *\n * @korean 정보요원신체\n */\nexport const JEONGBO_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 78 kg\n * Fit intelligence operative build\n * Government agency fitness standard\n * Balance between capability and inconspicuousness\n */\n weight: 78,\n\n /**\n * Leg Length: 95 cm\n * Balanced leg length for varied terrain\n * Standard proportions for operational flexibility\n * Suitable for extended pursuit or evasion\n */\n legLength: 95,\n\n /**\n * Arm Length: 76 cm\n * Standard operative reach\n * Trained for weapon and hand-to-hand versatility\n * Balanced for multiple combat scenarios\n */\n armLength: 76,\n\n /**\n * Muscle Mass: 32 kg (41% of body weight)\n * Agency-required conditioning\n * Balanced strength for operational demands\n * Emphasis on functional fitness\n */\n muscleMass: 32,\n\n /**\n * Fat Mass: 12 kg (15% body fat)\n * Low but sustainable body fat\n * Maintains energy reserves for long operations\n * Within intelligence service standards\n */\n fatMass: 12,\n\n /**\n * Age: 34 years\n * Experienced operative\n * Peak of analytical and physical capability\n * Wisdom from field experience\n */\n age: 34,\n\n /**\n * Total Height: 179 cm\n * Standard government agency height\n * Balanced proportions for versatility\n * Neither imposing nor inconspicuous\n */\n totalHeight: 179,\n\n /**\n * Torso Length: 58 cm\n * Balanced torso for varied operations\n * Good breath control and stamina\n * Standard vital point distribution\n */\n torsoLength: 58,\n\n /**\n * Head Size: 22 cm\n * Average head size\n * Standard tactical gear compatibility\n * Balanced consciousness resilience\n */\n headSize: 22,\n\n /**\n * Neck Length: 10 cm\n * Average neck length\n * Trained resistance to chokes\n * Standard blood choke vulnerability\n */\n neckLength: 10,\n\n /**\n * Shoulder Width: 45 cm\n * Athletic shoulder width\n * Good defense coverage\n * Versatile grappling control\n */\n shoulderWidth: 45,\n\n /**\n * Walk Speed: 6.2 m/s\n * Fast tactical movement\n * Agency fitness standards\n * Excellent for varied operations\n */\n walkSpeed: 6.2,\n\n /**\n * Run Speed: 10.0 m/s\n * Strong sprint capability\n * Intelligence operative conditioning\n * Efficient pursuit and evasion\n */\n runSpeed: 10.0,\n\n /**\n * Acceleration: 14.0 m/s²\n * High explosiveness\n * Agency combat training\n * Quick response for tactical situations\n */\n acceleration: 14.0,\n};\n\n/**\n * 조직폭력배 (Jojik Pokryeokbae) - Organized Crime Physical Profile\n *\n * **Philosophy**: Survival through ruthlessness and brutality\n * **Training**: Street fighting and underground martial arts\n * **Build**: Heavy, powerful, intimidating presence\n *\n * Physical characteristics emphasize raw power and intimidation over\n * refined technique. Heavier build with high muscle mass for brutal\n * effectiveness and street-proven durability.\n *\n * @korean 조직폭력배신체\n */\nexport const JOJIK_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 105 kg\n * MASSIVE build for power and intimidation\n * Like a heavyweight MMA fighter or large taekwondo practitioner\n * Dominant mass advantage in any confrontation\n */\n weight: 105,\n\n /**\n * Leg Length: 100 cm\n * Long, powerful legs despite heavy build\n * Devastating kicks with massive power\n * Surprising mobility for size\n */\n legLength: 100,\n\n /**\n * Arm Length: 84 cm\n * Long, thick arms for crushing power\n * Exceptional reach for grappling and strikes\n * Street-fighting dominance\n */\n armLength: 84,\n\n /**\n * Muscle Mass: 48 kg (46% of body weight)\n * Highest muscle mass of all archetypes\n * Built through intense street combat and heavy training\n * Raw, overwhelming power\n */\n muscleMass: 48,\n\n /**\n * Fat Mass: 20 kg (19% body fat)\n * Functional body fat for damage absorption\n * Provides padding against strikes\n * Still very fit despite bulk\n */\n fatMass: 20,\n\n /**\n * Age: 36 years\n * Veteran of street conflicts\n * Battle-scarred and experienced\n * Peak brutality and survival instincts\n */\n age: 36,\n\n /**\n * Total Height: 188 cm\n * Tall AND massive build\n * Physically imposing presence\n * Dominates any confrontation visually\n */\n totalHeight: 188,\n\n /**\n * Torso Length: 64 cm\n * Thick, powerful torso\n * Massive core strength\n * Enhanced durability and power generation\n */\n torsoLength: 64,\n\n /**\n * Head Size: 24 cm\n * Large, thick skull\n * Significant head strike resistance\n * High consciousness resilience\n */\n headSize: 24,\n\n /**\n * Neck Length: 11 cm\n * Thick, muscular neck\n * Very difficult to choke\n * Protected blood vessels\n */\n neckLength: 11,\n\n /**\n * Shoulder Width: 54 cm\n * WIDEST shoulders - intimidating presence\n * Maximum defense coverage\n * Overwhelming physical dominance\n */\n shoulderWidth: 54,\n\n /**\n * Walk Speed: 5.0 m/s\n * Slower tactical movement\n * Heavy build reduces mobility\n * Compensated by raw power and reach\n */\n walkSpeed: 5.0,\n\n /**\n * Run Speed: 8.0 m/s\n * Moderate sprint capability\n * Mass limits top speed\n * Still intimidating when charging\n */\n runSpeed: 8.0,\n\n /**\n * Acceleration: 9.0 m/s²\n * Lower explosiveness\n * Heavy mass requires more force to move\n * Compensated by devastating power on contact\n */\n acceleration: 9.0,\n};\n\n/**\n * Archetype physical attributes lookup map.\n *\n * **Korean**: 원형 신체 속성 맵 (Archetype Physical Attributes Map)\n *\n * Provides quick access to physical attribute profiles by archetype.\n * Used by combat system to retrieve realistic body dimensions and\n * composition for calculations.\n *\n * @example\n * ```typescript\n * const playerArchetype = PlayerArchetype.MUSA;\n * const physicalAttrs = ARCHETYPE_PHYSICAL_ATTRIBUTES[playerArchetype];\n * const kickRange = calculateKickRange(physicalAttrs.legLength);\n * ```\n *\n * @public\n * @korean 원형신체맵\n */\nexport const ARCHETYPE_PHYSICAL_ATTRIBUTES: Record<\n PlayerArchetype,\n PhysicalAttributes\n> = {\n [PlayerArchetype.MUSA]: MUSA_PHYSICAL,\n [PlayerArchetype.AMSALJA]: AMSALJA_PHYSICAL,\n [PlayerArchetype.HACKER]: HACKER_PHYSICAL,\n [PlayerArchetype.JEONGBO_YOWON]: JEONGBO_PHYSICAL,\n [PlayerArchetype.JOJIK_POKRYEOKBAE]: JOJIK_PHYSICAL,\n};\n\n/**\n * Get physical attributes for a specific archetype.\n *\n * **Korean**: 원형 신체 속성 가져오기 (Get Archetype Physical Attributes)\n *\n * Retrieves the physical attribute profile for the specified player archetype.\n * Returns a readonly copy to prevent accidental mutations.\n *\n * @param archetype - The player archetype to get attributes for\n * @returns Physical attributes for the specified archetype\n *\n * @example\n * ```typescript\n * const musaAttrs = getArchetypePhysicalAttributes(PlayerArchetype.MUSA);\n * console.log(`Musa weight: ${musaAttrs.weight}kg`);\n * console.log(`Musa arm reach: ${musaAttrs.armLength}cm`);\n * ```\n *\n * @public\n * @korean 원형신체가져오기\n */\nexport function getArchetypePhysicalAttributes(\n archetype: PlayerArchetype,\n): Readonly<PhysicalAttributes> {\n return ARCHETYPE_PHYSICAL_ATTRIBUTES[archetype];\n}\n\n/**\n * Calculate effective reach based on limb length and stance.\n *\n * **Korean**: 유효 거리 계산 (Calculate Effective Reach)\n *\n * Computes the effective combat reach considering limb length and\n * body positioning. Different techniques use different limbs and\n * leverage different amounts of body extension.\n *\n * @param limbLength - Length of the limb in centimeters\n * @param extension - Percentage of full extension (0.0 to 1.0)\n * @returns Effective reach in centimeters\n *\n * @example\n * ```typescript\n * // Full extension punch\n * const punchReach = calculateEffectiveReach(75, 1.0); // 75cm\n *\n * // 70% extension kick (stable stance)\n * const kickReach = calculateEffectiveReach(95, 0.7); // 66.5cm\n * ```\n *\n * @public\n * @korean 유효거리계산\n */\nexport function calculateEffectiveReach(\n limbLength: number,\n extension: number = 1.0,\n): number {\n return limbLength * Math.max(0, Math.min(1, extension));\n}\n\n/**\n * Calculate movement speed modifier based on weight and leg length.\n *\n * **Korean**: 이동 속도 계산 (Calculate Movement Speed)\n *\n * Computes movement speed modifier based on body weight (inversely)\n * and leg length (positively). Heavier fighters move slower, while\n * longer legs provide faster base movement.\n *\n * Formula: baseSpeed * (legLength / 95) * (75 / weight)\n * - Normalized around 95cm legs and 75kg weight\n *\n * @param physical - Physical attributes of the fighter\n * @param baseSpeed - Base movement speed (default: 100)\n * @returns Modified movement speed\n *\n * @example\n * ```typescript\n * const musaSpeed = calculateMovementSpeed(MUSA_PHYSICAL);\n * // Result: 100 * (95/95) * (75/75) = 100\n *\n * const jojikSpeed = calculateMovementSpeed(JOJIK_PHYSICAL);\n * // Result: 100 * (90/95) * (75/85) = ~88.2 (slower)\n * ```\n *\n * @public\n * @korean 이동속도계산\n */\nexport function calculateMovementSpeed(\n physical: PhysicalAttributes,\n baseSpeed: number = 100,\n): number {\n const legFactor = physical.legLength / 95; // Normalized to 95cm average\n const weightFactor = 75 / physical.weight; // Normalized to 75kg average\n return baseSpeed * legFactor * weightFactor;\n}\n\n/**\n * Calculate damage modifier based on muscle mass.\n *\n * **Korean**: 공격력 계산 (Calculate Damage Output)\n *\n * Computes damage output modifier based on muscle mass. More muscle\n * means more power in strikes, but with diminishing returns.\n *\n * Formula: 1.0 + ((muscleMass - 35) / 35) * 0.3\n * - Normalized around 35kg muscle mass\n * - Maximum 30% bonus from muscle\n *\n * @param physical - Physical attributes of the fighter\n * @returns Damage multiplier (typically 0.7 to 1.3)\n *\n * @example\n * ```typescript\n * const musaDamage = calculateDamageModifier(MUSA_PHYSICAL);\n * // Result: 1.0 + ((38-35)/35)*0.3 = ~1.026\n *\n * const jojikDamage = calculateDamageModifier(JOJIK_PHYSICAL);\n * // Result: 1.0 + ((42-35)/35)*0.3 = ~1.06 (stronger)\n * ```\n *\n * @public\n * @korean 공격력계산\n */\nexport function calculateDamageModifier(physical: PhysicalAttributes): number {\n const normalizedMuscle = (physical.muscleMass - 35) / 35;\n return 1.0 + normalizedMuscle * 0.3;\n}\n\n/**\n * Calculate defense modifier based on fat mass and muscle mass.\n *\n * **Korean**: 방어력 계산 (Calculate Defense)\n *\n * Computes defense modifier based on fat mass (padding) and muscle mass\n * (structural integrity). Fat absorbs blunt damage, muscle protects\n * against impact.\n *\n * Formula: 1.0 + (fatMass / 100) + (muscleMass / 200)\n *\n * @param physical - Physical attributes of the fighter\n * @returns Defense multiplier (typically 1.0 to 1.3)\n *\n * @example\n * ```typescript\n * const amsaljaDefense = calculateDefenseModifier(AMSALJA_PHYSICAL);\n * // Result: 1.0 + (9/100) + (32/200) = 1.25\n *\n * const jojikDefense = calculateDefenseModifier(JOJIK_PHYSICAL);\n * // Result: 1.0 + (18/100) + (42/200) = 1.39 (tankier)\n * ```\n *\n * @public\n * @korean 방어력계산\n */\nexport function calculateDefenseModifier(physical: PhysicalAttributes): number {\n const fatPadding = physical.fatMass / 100;\n const muscleStructure = physical.muscleMass / 200;\n return 1.0 + fatPadding + muscleStructure;\n}\n\n/**\n * Calculate stamina regeneration rate based on age and fat mass.\n *\n * **Korean**: 체력 회복 속도 (Stamina Recovery Rate)\n *\n * Computes stamina recovery speed based on age (optimal 25-35) and\n * fat mass (lower is better for recovery). Younger fighters and leaner\n * builds recover faster.\n *\n * Formula: baseRate * ageFactor * fatFactor\n * - Age factor peaks at 30 years (1.0), decreases before and after\n * - Fat factor = 1.0 - (fatMass - 10) / 50\n *\n * @param physical - Physical attributes of the fighter\n * @param baseRate - Base recovery rate (default: 10 per second)\n * @returns Modified stamina recovery rate\n *\n * @example\n * ```typescript\n * const amsaljaRecovery = calculateStaminaRecovery(AMSALJA_PHYSICAL);\n * // Age 28, fat 9kg: ~10.2 per second\n *\n * const jojikRecovery = calculateStaminaRecovery(JOJIK_PHYSICAL);\n * // Age 36, fat 18kg: ~8.4 per second (slower)\n * ```\n *\n * @public\n * @korean 체력회복계산\n */\nexport function calculateStaminaRecovery(\n physical: PhysicalAttributes,\n baseRate: number = 10,\n): number {\n // Age factor: peaks at 30, decreases before and after\n const ageOptimal = 30;\n const ageDiff = Math.abs(physical.age - ageOptimal);\n const ageFactor = Math.max(0.7, 1.0 - ageDiff / 30);\n\n // Fat factor: lower fat = faster recovery\n const fatFactor = Math.max(0.7, 1.0 - (physical.fatMass - 10) / 50);\n\n return baseRate * ageFactor * fatFactor;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"archetypePhysicalAttributes.js","names":[],"sources":["../../src/data/archetypePhysicalAttributes.ts"],"sourcesContent":["/**\n * Physical attribute profiles for each player archetype.\n *\n * **Korean**: 원형별 신체 속성 (Archetype Physical Attributes)\n *\n * Defines realistic body dimensions and composition for each of the five\n * player archetypes based on their combat style and background. These\n * attributes directly affect combat calculations including reach, movement\n * speed, damage, and stamina.\n *\n * ## Design Philosophy\n *\n * Each archetype's physical profile reflects their training, lifestyle, and\n * combat specialization:\n *\n * - **무사 (Musa)**: Balanced warrior with traditional training\n * - **암살자 (Amsalja)**: Lean and agile for stealth operations\n * - **해커 (Hacker)**: Average build with tech enhancements\n * - **정보요원 (Jeongbo)**: Fit operative with intelligence background\n * - **조직폭력배 (Jojik)**: Heavy and brutal street fighter\n *\n * @module data/archetypePhysicalAttributes\n * @category Player & Archetypes\n * @korean 원형신체데이터\n */\n\nimport { PhysicalAttributes, PlayerArchetype } from \"@/types\";\n\n/**\n * 무사 (Musa) - Traditional Warrior Physical Profile\n *\n * **Philosophy**: Honor through disciplined strength\n * **Training**: Military special forces with traditional martial arts\n * **Build**: Balanced, athletic, well-conditioned warrior\n *\n * Physical characteristics reflect years of traditional Korean martial arts\n * training combined with modern military conditioning. Optimal balance between\n * strength, speed, and endurance for prolonged combat effectiveness.\n *\n * @korean 무사신체\n */\nexport const MUSA_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 82 kg\n * Athletic military build for strength and mobility\n * Korean Special Forces standard physique\n * Optimal power-to-weight ratio for combat\n */\n weight: 82,\n\n /**\n * Leg Length: 96 cm\n * Athletic leg length for powerful kicks\n * Trained for devastating Taekwondo kicks\n * Balanced reach and stability\n */\n legLength: 96,\n\n /**\n * Arm Length: 77 cm\n * Strong arm reach for disciplined striking\n * Conditioned for both precision and power\n * Effective grappling range\n */\n armLength: 77,\n\n /**\n * Muscle Mass: 35 kg (43% of body weight)\n * High muscle mass from military training\n * Realistic for trained special forces soldier\n * Excellent functional strength\n */\n muscleMass: 35,\n\n /**\n * Fat Mass: 13 kg (16% body fat)\n * Athletic body fat percentage\n * Maintains energy reserves for combat endurance\n * Optimal for sustained operations\n */\n fatMass: 13,\n\n /**\n * Age: 32 years\n * Prime combat age combining experience and physical capability\n * Peak of martial arts mastery and physical conditioning\n * Balanced wisdom and reflexes\n */\n age: 32,\n\n /**\n * Total Height: 180 cm\n * Solid military build height\n * Above average for imposing presence\n * Good proportions for all-around combat\n */\n totalHeight: 180,\n\n /**\n * Torso Length: 59 cm\n * Strong core providing stable base\n * Optimal for breath control and Ki cultivation\n * Protected vital points\n */\n torsoLength: 59,\n\n /**\n * Head Size: 22 cm\n * Average head diameter\n * Standard vital point target area\n * Balanced consciousness vulnerability\n */\n headSize: 22,\n\n /**\n * Neck Length: 11 cm\n * Strong, trained neck\n * Moderate vulnerability to chokes\n * Conditioned for impact resistance\n */\n neckLength: 11,\n\n /**\n * Shoulder Width: 46 cm\n * Broad military shoulders\n * Strong defense coverage\n * Excellent grappling control points\n */\n shoulderWidth: 46,\n\n /**\n * Walk Speed: 6.0 m/s\n * Balanced tactical movement\n * Military conditioning for sustained mobility\n * Optimal for disciplined combat approach\n */\n walkSpeed: 6.0,\n\n /**\n * Run Speed: 9.5 m/s\n * Strong sprint capability\n * Combat-ready rapid repositioning\n * Efficient for tactical advances\n */\n runSpeed: 9.5,\n\n /**\n * Acceleration: 12.0 m/s²\n * Balanced explosiveness\n * Military conditioning for quick reactions\n * Optimal muscle-to-weight ratio for combat\n */\n acceleration: 12.0,\n};\n\n/**\n * 암살자 (Amsalja) - Shadow Assassin Physical Profile\n *\n * **Philosophy**: Efficiency through invisibility\n * **Training**: Covert operations and silent elimination specialist\n * **Build**: Lean, agile, optimized for stealth and precision\n *\n * Physical characteristics emphasize low body mass for stealth movement,\n * exceptional reach for vital point targeting, and minimal fat for maximum\n * agility. Every attribute optimized for silent, deadly efficiency.\n *\n * @korean 암살자신체\n */\nexport const AMSALJA_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 75 kg\n * Lean athletic build like a kickboxer (Israel Adesanya type)\n * Optimized for speed, reach, and precision\n * Light enough for stealth, heavy enough for power\n */\n weight: 75,\n\n /**\n * Leg Length: 102 cm\n * Long legs for exceptional reach and stride\n * Enables precise high kicks to vital points\n * Excellent for maintaining distance\n */\n legLength: 102,\n\n /**\n * Arm Length: 82 cm\n * Extended reach for range advantage\n * Crucial for vital point precision strikes\n * Keeps opponents at safe distance\n */\n armLength: 82,\n\n /**\n * Muscle Mass: 30 kg (40% of body weight)\n * Lean, functional muscle for speed\n * Optimized for explosive movements\n * Sufficient for devastating precision strikes\n */\n muscleMass: 30,\n\n /**\n * Fat Mass: 10 kg (13% body fat)\n * Very low fat for maximum definition\n * Peak agility and flexibility\n * Athletic performance optimized\n */\n fatMass: 10,\n\n /**\n * Age: 28 years\n * Young and at peak physical agility\n * Optimal reflexes for split-second decisions\n * Experience balanced with peak conditioning\n */\n age: 28,\n\n /**\n * Total Height: 186 cm\n * Tall for exceptional reach advantage\n * Long limb ratios for vital point access\n * Intimidating presence while maintaining agility\n */\n totalHeight: 186,\n\n /**\n * Torso Length: 58 cm\n * Compact torso for lower center of gravity\n * Agile core for quick movement\n * Reduced vital point target area\n */\n torsoLength: 58,\n\n /**\n * Head Size: 22 cm\n * Normal head profile\n * Standard target area for head strikes\n * Balanced consciousness vulnerability\n */\n headSize: 22,\n\n /**\n * Neck Length: 11 cm\n * Longer neck for head movement evasion\n * Slightly increased choke vulnerability\n * Requires skilled guard positioning\n */\n neckLength: 11,\n\n /**\n * Shoulder Width: 44 cm\n * Lean but athletic shoulders\n * Good mobility with adequate coverage\n * Efficient for striking mechanics\n */\n shoulderWidth: 44,\n\n /**\n * Walk Speed: 6.5 m/s\n * FASTEST tactical movement\n * Optimized for silent, rapid repositioning\n * Assassin-level agility and speed\n */\n walkSpeed: 6.5,\n\n /**\n * Run Speed: 11.0 m/s\n * FASTEST sprint capability\n * Peak athletic conditioning for pursuit\n * Exceptional for closing distance quickly\n */\n runSpeed: 11.0,\n\n /**\n * Acceleration: 15.0 m/s²\n * HIGHEST explosiveness\n * Exceptional muscle-to-weight ratio\n * Lightning-fast direction changes\n */\n acceleration: 15.0,\n};\n\n/**\n * 해커 (Hacker) - Cyber Warrior Physical Profile\n *\n * **Philosophy**: Information as power through technology\n * **Training**: Digital native with supplemental physical training\n * **Build**: Average physique enhanced by technological augmentation\n *\n * Physical characteristics reflect a tech-focused lifestyle with functional\n * fitness rather than peak athletic conditioning. Attributes are average\n * but compensated by cybernetic enhancements and data-driven combat analysis.\n *\n * @korean 해커신체\n */\nexport const HACKER_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 72 kg\n * Average weight for height\n * Functional fitness from regular training\n * Tech worker who maintains fitness\n */\n weight: 72,\n\n /**\n * Leg Length: 92 cm\n * Standard leg proportions\n * Adequate for tech-assisted movement\n * Compensated by augmented targeting systems\n */\n legLength: 92,\n\n /**\n * Arm Length: 73 cm\n * Average arm reach\n * Sufficient when aided by cybernetic enhancements\n * Precision compensated by data analysis\n */\n armLength: 73,\n\n /**\n * Muscle Mass: 28 kg (39% of body weight)\n * Moderate muscle mass for tech worker\n * Maintained through efficient training\n * Relies more on tech than raw strength\n */\n muscleMass: 28,\n\n /**\n * Fat Mass: 15 kg (21% body fat)\n * Average body fat from desk work\n * Still functional for combat\n * Less emphasis on peak conditioning\n */\n fatMass: 15,\n\n /**\n * Age: 26 years\n * Young digital native\n * High neuroplasticity for tech integration\n * Peak learning and adaptation capabilities\n */\n age: 26,\n\n /**\n * Total Height: 175 cm\n * Average Korean male height\n * Standard proportions for tech integration\n * Balanced body type for augmentation\n */\n totalHeight: 175,\n\n /**\n * Torso Length: 57 cm\n * Average torso length\n * Standard core for cyber implants\n * Balanced Ki flow for tech-bio integration\n */\n torsoLength: 57,\n\n /**\n * Head Size: 22 cm\n * Average head size\n * Standard neural interface compatibility\n * Balanced for augmented reality overlays\n */\n headSize: 22,\n\n /**\n * Neck Length: 10 cm\n * Average neck length\n * Standard vulnerability to chokes\n * Adequate for neural interface cables\n */\n neckLength: 10,\n\n /**\n * Shoulder Width: 43 cm\n * Average shoulder span\n * Standard defense coverage\n * Balanced for wearable tech integration\n */\n shoulderWidth: 43,\n\n /**\n * Walk Speed: 5.5 m/s\n * Average tactical movement\n * Tech-focused rather than athletic\n * Compensated by cybernetic enhancements\n */\n walkSpeed: 5.5,\n\n /**\n * Run Speed: 8.5 m/s\n * Moderate sprint capability\n * Supplemental physical training\n * Relies on tech for combat advantage\n */\n runSpeed: 8.5,\n\n /**\n * Acceleration: 10.0 m/s²\n * Moderate explosiveness\n * Average physical conditioning\n * Compensated by tech-enhanced reactions\n */\n acceleration: 10.0,\n};\n\n/**\n * 정보요원 (Jeongbo Yowon) - Intelligence Operative Physical Profile\n *\n * **Philosophy**: Knowledge through observation and strategy\n * **Training**: Government intelligence agency with specialized combat\n * **Build**: Athletic operative with strategic fitness\n *\n * Physical characteristics reflect intelligence agency fitness standards\n * with emphasis on versatility, endurance, and adaptability. Balanced\n * attributes suitable for varied operational requirements.\n *\n * @korean 정보요원신체\n */\nexport const JEONGBO_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 78 kg\n * Fit intelligence operative build\n * Government agency fitness standard\n * Balance between capability and inconspicuousness\n */\n weight: 78,\n\n /**\n * Leg Length: 95 cm\n * Balanced leg length for varied terrain\n * Standard proportions for operational flexibility\n * Suitable for extended pursuit or evasion\n */\n legLength: 95,\n\n /**\n * Arm Length: 76 cm\n * Standard operative reach\n * Trained for weapon and hand-to-hand versatility\n * Balanced for multiple combat scenarios\n */\n armLength: 76,\n\n /**\n * Muscle Mass: 32 kg (41% of body weight)\n * Agency-required conditioning\n * Balanced strength for operational demands\n * Emphasis on functional fitness\n */\n muscleMass: 32,\n\n /**\n * Fat Mass: 12 kg (15% body fat)\n * Low but sustainable body fat\n * Maintains energy reserves for long operations\n * Within intelligence service standards\n */\n fatMass: 12,\n\n /**\n * Age: 34 years\n * Experienced operative\n * Peak of analytical and physical capability\n * Wisdom from field experience\n */\n age: 34,\n\n /**\n * Total Height: 179 cm\n * Standard government agency height\n * Balanced proportions for versatility\n * Neither imposing nor inconspicuous\n */\n totalHeight: 179,\n\n /**\n * Torso Length: 58 cm\n * Balanced torso for varied operations\n * Good breath control and stamina\n * Standard vital point distribution\n */\n torsoLength: 58,\n\n /**\n * Head Size: 22 cm\n * Average head size\n * Standard tactical gear compatibility\n * Balanced consciousness resilience\n */\n headSize: 22,\n\n /**\n * Neck Length: 10 cm\n * Average neck length\n * Trained resistance to chokes\n * Standard blood choke vulnerability\n */\n neckLength: 10,\n\n /**\n * Shoulder Width: 45 cm\n * Athletic shoulder width\n * Good defense coverage\n * Versatile grappling control\n */\n shoulderWidth: 45,\n\n /**\n * Walk Speed: 6.2 m/s\n * Fast tactical movement\n * Agency fitness standards\n * Excellent for varied operations\n */\n walkSpeed: 6.2,\n\n /**\n * Run Speed: 10.0 m/s\n * Strong sprint capability\n * Intelligence operative conditioning\n * Efficient pursuit and evasion\n */\n runSpeed: 10.0,\n\n /**\n * Acceleration: 14.0 m/s²\n * High explosiveness\n * Agency combat training\n * Quick response for tactical situations\n */\n acceleration: 14.0,\n};\n\n/**\n * 조직폭력배 (Jojik Pokryeokbae) - Organized Crime Physical Profile\n *\n * **Philosophy**: Survival through ruthlessness and brutality\n * **Training**: Street fighting and underground martial arts\n * **Build**: Heavy, powerful, intimidating presence\n *\n * Physical characteristics emphasize raw power and intimidation over\n * refined technique. Heavier build with high muscle mass for brutal\n * effectiveness and street-proven durability.\n *\n * @korean 조직폭력배신체\n */\nexport const JOJIK_PHYSICAL: PhysicalAttributes = {\n /**\n * Weight: 105 kg\n * MASSIVE build for power and intimidation\n * Like a heavyweight MMA fighter or large taekwondo practitioner\n * Dominant mass advantage in any confrontation\n */\n weight: 105,\n\n /**\n * Leg Length: 100 cm\n * Long, powerful legs despite heavy build\n * Devastating kicks with massive power\n * Surprising mobility for size\n */\n legLength: 100,\n\n /**\n * Arm Length: 84 cm\n * Long, thick arms for crushing power\n * Exceptional reach for grappling and strikes\n * Street-fighting dominance\n */\n armLength: 84,\n\n /**\n * Muscle Mass: 48 kg (46% of body weight)\n * Highest muscle mass of all archetypes\n * Built through intense street combat and heavy training\n * Raw, overwhelming power\n */\n muscleMass: 48,\n\n /**\n * Fat Mass: 20 kg (19% body fat)\n * Functional body fat for damage absorption\n * Provides padding against strikes\n * Still very fit despite bulk\n */\n fatMass: 20,\n\n /**\n * Age: 36 years\n * Veteran of street conflicts\n * Battle-scarred and experienced\n * Peak brutality and survival instincts\n */\n age: 36,\n\n /**\n * Total Height: 188 cm\n * Tall AND massive build\n * Physically imposing presence\n * Dominates any confrontation visually\n */\n totalHeight: 188,\n\n /**\n * Torso Length: 64 cm\n * Thick, powerful torso\n * Massive core strength\n * Enhanced durability and power generation\n */\n torsoLength: 64,\n\n /**\n * Head Size: 24 cm\n * Large, thick skull\n * Significant head strike resistance\n * High consciousness resilience\n */\n headSize: 24,\n\n /**\n * Neck Length: 11 cm\n * Thick, muscular neck\n * Very difficult to choke\n * Protected blood vessels\n */\n neckLength: 11,\n\n /**\n * Shoulder Width: 54 cm\n * WIDEST shoulders - intimidating presence\n * Maximum defense coverage\n * Overwhelming physical dominance\n */\n shoulderWidth: 54,\n\n /**\n * Walk Speed: 5.0 m/s\n * Slower tactical movement\n * Heavy build reduces mobility\n * Compensated by raw power and reach\n */\n walkSpeed: 5.0,\n\n /**\n * Run Speed: 8.0 m/s\n * Moderate sprint capability\n * Mass limits top speed\n * Still intimidating when charging\n */\n runSpeed: 8.0,\n\n /**\n * Acceleration: 9.0 m/s²\n * Lower explosiveness\n * Heavy mass requires more force to move\n * Compensated by devastating power on contact\n */\n acceleration: 9.0,\n};\n\n/**\n * Archetype physical attributes lookup map.\n *\n * **Korean**: 원형 신체 속성 맵 (Archetype Physical Attributes Map)\n *\n * Provides quick access to physical attribute profiles by archetype.\n * Used by combat system to retrieve realistic body dimensions and\n * composition for calculations.\n *\n * @example\n * ```typescript\n * const playerArchetype = PlayerArchetype.MUSA;\n * const physicalAttrs = ARCHETYPE_PHYSICAL_ATTRIBUTES[playerArchetype];\n * const kickRange = calculateKickRange(physicalAttrs.legLength);\n * ```\n *\n * @public\n * @korean 원형신체맵\n */\nexport const ARCHETYPE_PHYSICAL_ATTRIBUTES: Record<\n PlayerArchetype,\n PhysicalAttributes\n> = {\n [PlayerArchetype.MUSA]: MUSA_PHYSICAL,\n [PlayerArchetype.AMSALJA]: AMSALJA_PHYSICAL,\n [PlayerArchetype.HACKER]: HACKER_PHYSICAL,\n [PlayerArchetype.JEONGBO_YOWON]: JEONGBO_PHYSICAL,\n [PlayerArchetype.JOJIK_POKRYEOKBAE]: JOJIK_PHYSICAL,\n};\n\n/**\n * Get physical attributes for a specific archetype.\n *\n * **Korean**: 원형 신체 속성 가져오기 (Get Archetype Physical Attributes)\n *\n * Retrieves the physical attribute profile for the specified player archetype.\n * Returns a readonly copy to prevent accidental mutations.\n *\n * @param archetype - The player archetype to get attributes for\n * @returns Physical attributes for the specified archetype\n *\n * @example\n * ```typescript\n * const musaAttrs = getArchetypePhysicalAttributes(PlayerArchetype.MUSA);\n * console.log(`Musa weight: ${musaAttrs.weight}kg`);\n * console.log(`Musa arm reach: ${musaAttrs.armLength}cm`);\n * ```\n *\n * @public\n * @korean 원형신체가져오기\n */\nexport function getArchetypePhysicalAttributes(\n archetype: PlayerArchetype,\n): Readonly<PhysicalAttributes> {\n return ARCHETYPE_PHYSICAL_ATTRIBUTES[archetype];\n}\n\n/**\n * Calculate effective reach based on limb length and stance.\n *\n * **Korean**: 유효 거리 계산 (Calculate Effective Reach)\n *\n * Computes the effective combat reach considering limb length and\n * body positioning. Different techniques use different limbs and\n * leverage different amounts of body extension.\n *\n * @param limbLength - Length of the limb in centimeters\n * @param extension - Percentage of full extension (0.0 to 1.0)\n * @returns Effective reach in centimeters\n *\n * @example\n * ```typescript\n * // Full extension punch\n * const punchReach = calculateEffectiveReach(75, 1.0); // 75cm\n *\n * // 70% extension kick (stable stance)\n * const kickReach = calculateEffectiveReach(95, 0.7); // 66.5cm\n * ```\n *\n * @public\n * @korean 유효거리계산\n */\nexport function calculateEffectiveReach(\n limbLength: number,\n extension: number = 1.0,\n): number {\n return limbLength * Math.max(0, Math.min(1, extension));\n}\n\n/**\n * Calculate movement speed modifier based on weight and leg length.\n *\n * **Korean**: 이동 속도 계산 (Calculate Movement Speed)\n *\n * Computes movement speed modifier based on body weight (inversely)\n * and leg length (positively). Heavier fighters move slower, while\n * longer legs provide faster base movement.\n *\n * Formula: baseSpeed * (legLength / 95) * (75 / weight)\n * - Normalized around 95cm legs and 75kg weight\n *\n * @param physical - Physical attributes of the fighter\n * @param baseSpeed - Base movement speed (default: 100)\n * @returns Modified movement speed\n *\n * @example\n * ```typescript\n * const musaSpeed = calculateMovementSpeed(MUSA_PHYSICAL);\n * // Result: 100 * (95/95) * (75/75) = 100\n *\n * const jojikSpeed = calculateMovementSpeed(JOJIK_PHYSICAL);\n * // Result: 100 * (90/95) * (75/85) = ~88.2 (slower)\n * ```\n *\n * @public\n * @korean 이동속도계산\n */\nexport function calculateMovementSpeed(\n physical: PhysicalAttributes,\n baseSpeed: number = 100,\n): number {\n const legFactor = physical.legLength / 95; // Normalized to 95cm average\n const weightFactor = 75 / physical.weight; // Normalized to 75kg average\n return baseSpeed * legFactor * weightFactor;\n}\n\n/**\n * Calculate damage modifier based on muscle mass.\n *\n * **Korean**: 공격력 계산 (Calculate Damage Output)\n *\n * Computes damage output modifier based on muscle mass. More muscle\n * means more power in strikes, but with diminishing returns.\n *\n * Formula: 1.0 + ((muscleMass - 35) / 35) * 0.3\n * - Normalized around 35kg muscle mass\n * - Maximum 30% bonus from muscle\n *\n * @param physical - Physical attributes of the fighter\n * @returns Damage multiplier (typically 0.7 to 1.3)\n *\n * @example\n * ```typescript\n * const musaDamage = calculateDamageModifier(MUSA_PHYSICAL);\n * // Result: 1.0 + ((38-35)/35)*0.3 = ~1.026\n *\n * const jojikDamage = calculateDamageModifier(JOJIK_PHYSICAL);\n * // Result: 1.0 + ((42-35)/35)*0.3 = ~1.06 (stronger)\n * ```\n *\n * @public\n * @korean 공격력계산\n */\nexport function calculateDamageModifier(physical: PhysicalAttributes): number {\n const normalizedMuscle = (physical.muscleMass - 35) / 35;\n return 1.0 + normalizedMuscle * 0.3;\n}\n\n/**\n * Calculate defense modifier based on fat mass and muscle mass.\n *\n * **Korean**: 방어력 계산 (Calculate Defense)\n *\n * Computes defense modifier based on fat mass (padding) and muscle mass\n * (structural integrity). Fat absorbs blunt damage, muscle protects\n * against impact.\n *\n * Formula: 1.0 + (fatMass / 100) + (muscleMass / 200)\n *\n * @param physical - Physical attributes of the fighter\n * @returns Defense multiplier (typically 1.0 to 1.3)\n *\n * @example\n * ```typescript\n * const amsaljaDefense = calculateDefenseModifier(AMSALJA_PHYSICAL);\n * // Result: 1.0 + (9/100) + (32/200) = 1.25\n *\n * const jojikDefense = calculateDefenseModifier(JOJIK_PHYSICAL);\n * // Result: 1.0 + (18/100) + (42/200) = 1.39 (tankier)\n * ```\n *\n * @public\n * @korean 방어력계산\n */\nexport function calculateDefenseModifier(physical: PhysicalAttributes): number {\n const fatPadding = physical.fatMass / 100;\n const muscleStructure = physical.muscleMass / 200;\n return 1.0 + fatPadding + muscleStructure;\n}\n\n/**\n * Calculate stamina regeneration rate based on age and fat mass.\n *\n * **Korean**: 체력 회복 속도 (Stamina Recovery Rate)\n *\n * Computes stamina recovery speed based on age (optimal 25-35) and\n * fat mass (lower is better for recovery). Younger fighters and leaner\n * builds recover faster.\n *\n * Formula: baseRate * ageFactor * fatFactor\n * - Age factor peaks at 30 years (1.0), decreases before and after\n * - Fat factor = 1.0 - (fatMass - 10) / 50\n *\n * @param physical - Physical attributes of the fighter\n * @param baseRate - Base recovery rate (default: 10 per second)\n * @returns Modified stamina recovery rate\n *\n * @example\n * ```typescript\n * const amsaljaRecovery = calculateStaminaRecovery(AMSALJA_PHYSICAL);\n * // Age 28, fat 9kg: ~10.2 per second\n *\n * const jojikRecovery = calculateStaminaRecovery(JOJIK_PHYSICAL);\n * // Age 36, fat 18kg: ~8.4 per second (slower)\n * ```\n *\n * @public\n * @korean 체력회복계산\n */\nexport function calculateStaminaRecovery(\n physical: PhysicalAttributes,\n baseRate: number = 10,\n): number {\n // Age factor: peaks at 30, decreases before and after\n const ageOptimal = 30;\n const ageDiff = Math.abs(physical.age - ageOptimal);\n const ageFactor = Math.max(0.7, 1.0 - ageDiff / 30);\n\n // Fat factor: lower fat = faster recovery\n const fatFactor = Math.max(0.7, 1.0 - (physical.fatMass - 10) / 50);\n\n return baseRate * ageFactor * fatFactor;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"techniqueMappings.js","names":[],"sources":["../../src/data/techniqueMappings.ts"],"sourcesContent":["/**\n * Technique to Animation Type mappings\n *\n * **Korean**: 기술-애니메이션 매핑\n *\n * Maps each technique to its corresponding AnimationType for attack movement physics.\n * This provides a type-safe, comprehensive mapping that replaces string-based\n * substring matching.\n *\n * @module data/techniqueMappings\n * @category Combat System\n * @korean 기술매핑\n */\n\nimport { TechniqueId } from \"../types/techniqueId\";\nimport { AnimationType } from \"../systems/animation/builders/MartialArtsConstants\";\nimport { AttackAnimationType } from \"../types/skeletal\";\n\n/**\n * Maps AttackAnimationType (from technique definitions) to AnimationType (for movement physics)\n *\n * AttackAnimationType is the skeletal animation type (PUNCH_HIGH, KICK_FRONT, etc.)\n * AnimationType is the martial arts movement type for physics calculations\n *\n * @korean 공격애니메이션타입-애니메이션타입매핑\n */\nexport const ATTACK_ANIMATION_TO_MOVEMENT_TYPE: Record<\n AttackAnimationType,\n AnimationType\n> = {\n // Punches → Punch types\n [AttackAnimationType.PUNCH_HIGH]: AnimationType.CROSS,\n [AttackAnimationType.PUNCH_MID]: AnimationType.JAB,\n [AttackAnimationType.PUNCH_LOW]: AnimationType.JAB,\n\n // Kicks → Kick types\n [AttackAnimationType.KICK_FRONT]: AnimationType.FRONT_KICK,\n [AttackAnimationType.KICK_SIDE]: AnimationType.SIDE_KICK,\n [AttackAnimationType.KICK_ROUNDHOUSE]: AnimationType.ROUNDHOUSE_KICK,\n\n // Elbows → Elbow types\n [AttackAnimationType.ELBOW_STRIKE]: AnimationType.ELBOW_STRIKE,\n [AttackAnimationType.ELBOW_UPPERCUT]: AnimationType.ELBOW_UPPERCUT,\n\n // Knees → Knee types\n [AttackAnimationType.KNEE_STRIKE]: AnimationType.KNEE_STRIKE,\n [AttackAnimationType.KNEE_CLINCH]: AnimationType.CLINCH_KNEE,\n\n // Pressure points → Specialized strikes\n [AttackAnimationType.PRESSURE_POINT]: AnimationType.PRESSURE_POINT_STRIKE,\n [AttackAnimationType.PRESSURE_POINT_RAPID]: AnimationType.RAPID_BARRAGE,\n};\n\n/**\n * Maps TechniqueId to AnimationType for movement physics\n *\n * This is the primary lookup table used by CombatScreen3D to determine\n * the correct movement animation for each technique.\n *\n * Derived from technique definitions but cached here for performance.\n *\n * @korean 기술ID-애니메이션타입매핑\n */\nexport const TECHNIQUE_TO_ANIMATION_TYPE: Record<TechniqueId, AnimationType> = {\n // 무사 (Musa) - Traditional Warrior\n [TechniqueId.MUSA_THUNDER_STRIKE]: AnimationType.HEAVEN_STRIKE, // PUNCH_HIGH → powerful descending\n [TechniqueId.MUSA_IRON_DEFENSE]: AnimationType.JAB, // PUNCH_MID → defensive\n [TechniqueId.MUSA_DRAGON_FIST]: AnimationType.JAB, // PUNCH_MID → piercing\n [TechniqueId.MUSA_MOUNTAIN_BREAKER]: AnimationType.CROSS, // PUNCH_HIGH → crushing\n\n // 암살자 (Amsalja) - Shadow Assassin\n [TechniqueId.AMSALJA_SHADOW_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.AMSALJA_NERVE_STRIKE]: AnimationType.NERVE_STRIKE, // PRESSURE_POINT → precise\n [TechniqueId.AMSALJA_DEADLY_PRECISION]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.AMSALJA_SILENT_DEATH]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT → lethal\n\n // 해커 (Hacker) - Cyber Warrior\n [TechniqueId.HACKER_ELECTRIC_SHOCK]: AnimationType.LIGHTNING_STRIKE, // PUNCH_MID → electric\n [TechniqueId.HACKER_DATA_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.HACKER_CYBER_OVERDRIVE]: AnimationType.RAPID_BARRAGE, // PRESSURE_POINT_RAPID\n [TechniqueId.HACKER_SYSTEM_CRASH]: AnimationType.NERVE_STRIKE, // PRESSURE_POINT → system\n\n // 정보요원 (Jeongbo) - Intelligence Operative\n [TechniqueId.JEONGBO_TACTICAL_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.JEONGBO_COUNTER_INTELLIGENCE]: AnimationType.JAB, // PUNCH_MID → counter\n [TechniqueId.JEONGBO_PSYCHOLOGICAL_WARFARE]: AnimationType.NERVE_STRIKE, // PRESSURE_POINT\n [TechniqueId.JEONGBO_PRECISION_TAKEDOWN]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.JEONGBO_INTELLIGENCE_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n\n // 조직폭력배 (Jojik) - Organized Crime\n [TechniqueId.JOJIK_STREET_BRAWL]: AnimationType.HOOK, // PUNCH_MID → brawling\n [TechniqueId.JOJIK_IMPROVISED_WEAPON]: AnimationType.HAMMER_FIST, // ELBOW_STRIKE variant\n [TechniqueId.JOJIK_RUTHLESS_ASSAULT]: AnimationType.CROSS, // PUNCH_HIGH → brutal\n [TechniqueId.JOJIK_BRUTAL_TAKEDOWN]: AnimationType.ELBOW_STRIKE, // ELBOW_STRIKE → takedown\n};\n\n/**\n * Get AnimationType for a given technique ID\n *\n * Looks up the AnimationType from the TECHNIQUE_TO_ANIMATION_TYPE mapping.\n * Currently only supports archetype techniques (TechniqueId enum).\n * Returns undefined for unknown techniques or trigram techniques.\n *\n * @param techniqueId - The technique ID\n * @returns The AnimationType for movement physics, or undefined if not found\n * @korean 기술ID로애니메이션타입가져오기\n */\nexport function getAnimationTypeForTechnique(\n techniqueId: string | undefined\n): AnimationType | undefined {\n if (!techniqueId) {\n return undefined;\n }\n \n // Check if techniqueId is in our mapping\n // Note: Only archetype techniques (TechniqueId enum) are currently mapped\n return TECHNIQUE_TO_ANIMATION_TYPE[techniqueId as TechniqueId];\n}\n\n/**\n * Get AnimationType from AttackAnimationType\n *\n * @param attackAnimationType - The attack animation type from technique definition\n * @returns The AnimationType for movement physics\n * @korean 공격애니메이션타입에서애니메이션타입가져오기\n */\nexport function getAnimationTypeFromAttackAnimation(\n attackAnimationType: AttackAnimationType\n): AnimationType {\n return ATTACK_ANIMATION_TO_MOVEMENT_TYPE[attackAnimationType];\n}\n\nexport default {\n TECHNIQUE_TO_ANIMATION_TYPE,\n ATTACK_ANIMATION_TO_MOVEMENT_TYPE,\n getAnimationTypeForTechnique,\n getAnimationTypeFromAttackAnimation,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,oCAGT;EAED,oBAAoB,aAAa,cAAc;EAC/C,oBAAoB,YAAY,cAAc;EAC9C,oBAAoB,YAAY,cAAc;EAG9C,oBAAoB,aAAa,cAAc;EAC/C,oBAAoB,YAAY,cAAc;EAC9C,oBAAoB,kBAAkB,cAAc;EAGpD,oBAAoB,eAAe,cAAc;EACjD,oBAAoB,iBAAiB,cAAc;EAGnD,oBAAoB,cAAc,cAAc;EAChD,oBAAoB,cAAc,cAAc;EAGhD,oBAAoB,iBAAiB,cAAc;EACnD,oBAAoB,uBAAuB,cAAc;CAC3D;;;;;;;;;;;AAYD,IAAa,8BAAkE;EAE5E,YAAY,sBAAsB,cAAc;EAChD,YAAY,oBAAoB,cAAc;EAC9C,YAAY,mBAAmB,cAAc;EAC7C,YAAY,wBAAwB,cAAc;EAGlD,YAAY,wBAAwB,cAAc;EAClD,YAAY,uBAAuB,cAAc;EACjD,YAAY,2BAA2B,cAAc;EACrD,YAAY,uBAAuB,cAAc;EAGjD,YAAY,wBAAwB,cAAc;EAClD,YAAY,qBAAqB,cAAc;EAC/C,YAAY,yBAAyB,cAAc;EACnD,YAAY,sBAAsB,cAAc;EAGhD,YAAY,0BAA0B,cAAc;EACpD,YAAY,+BAA+B,cAAc;EACzD,YAAY,gCAAgC,cAAc;EAC1D,YAAY,6BAA6B,cAAc;EACvD,YAAY,8BAA8B,cAAc;EAGxD,YAAY,qBAAqB,cAAc;EAC/C,YAAY,0BAA0B,cAAc;EACpD,YAAY,yBAAyB,cAAc;EACnD,YAAY,wBAAwB,cAAc;CACpD;;;;;;;;;;;;AAaD,SAAgB,6BACd,aAC2B;
|
|
1
|
+
{"version":3,"file":"techniqueMappings.js","names":[],"sources":["../../src/data/techniqueMappings.ts"],"sourcesContent":["/**\n * Technique to Animation Type mappings\n *\n * **Korean**: 기술-애니메이션 매핑\n *\n * Maps each technique to its corresponding AnimationType for attack movement physics.\n * This provides a type-safe, comprehensive mapping that replaces string-based\n * substring matching.\n *\n * @module data/techniqueMappings\n * @category Combat System\n * @korean 기술매핑\n */\n\nimport { TechniqueId } from \"../types/techniqueId\";\nimport { AnimationType } from \"../systems/animation/builders/MartialArtsConstants\";\nimport { AttackAnimationType } from \"../types/skeletal\";\n\n/**\n * Maps AttackAnimationType (from technique definitions) to AnimationType (for movement physics)\n *\n * AttackAnimationType is the skeletal animation type (PUNCH_HIGH, KICK_FRONT, etc.)\n * AnimationType is the martial arts movement type for physics calculations\n *\n * @korean 공격애니메이션타입-애니메이션타입매핑\n */\nexport const ATTACK_ANIMATION_TO_MOVEMENT_TYPE: Record<\n AttackAnimationType,\n AnimationType\n> = {\n // Punches → Punch types\n [AttackAnimationType.PUNCH_HIGH]: AnimationType.CROSS,\n [AttackAnimationType.PUNCH_MID]: AnimationType.JAB,\n [AttackAnimationType.PUNCH_LOW]: AnimationType.JAB,\n\n // Kicks → Kick types\n [AttackAnimationType.KICK_FRONT]: AnimationType.FRONT_KICK,\n [AttackAnimationType.KICK_SIDE]: AnimationType.SIDE_KICK,\n [AttackAnimationType.KICK_ROUNDHOUSE]: AnimationType.ROUNDHOUSE_KICK,\n\n // Elbows → Elbow types\n [AttackAnimationType.ELBOW_STRIKE]: AnimationType.ELBOW_STRIKE,\n [AttackAnimationType.ELBOW_UPPERCUT]: AnimationType.ELBOW_UPPERCUT,\n\n // Knees → Knee types\n [AttackAnimationType.KNEE_STRIKE]: AnimationType.KNEE_STRIKE,\n [AttackAnimationType.KNEE_CLINCH]: AnimationType.CLINCH_KNEE,\n\n // Pressure points → Specialized strikes\n [AttackAnimationType.PRESSURE_POINT]: AnimationType.PRESSURE_POINT_STRIKE,\n [AttackAnimationType.PRESSURE_POINT_RAPID]: AnimationType.RAPID_BARRAGE,\n};\n\n/**\n * Maps TechniqueId to AnimationType for movement physics\n *\n * This is the primary lookup table used by CombatScreen3D to determine\n * the correct movement animation for each technique.\n *\n * Derived from technique definitions but cached here for performance.\n *\n * @korean 기술ID-애니메이션타입매핑\n */\nexport const TECHNIQUE_TO_ANIMATION_TYPE: Record<TechniqueId, AnimationType> = {\n // 무사 (Musa) - Traditional Warrior\n [TechniqueId.MUSA_THUNDER_STRIKE]: AnimationType.HEAVEN_STRIKE, // PUNCH_HIGH → powerful descending\n [TechniqueId.MUSA_IRON_DEFENSE]: AnimationType.JAB, // PUNCH_MID → defensive\n [TechniqueId.MUSA_DRAGON_FIST]: AnimationType.JAB, // PUNCH_MID → piercing\n [TechniqueId.MUSA_MOUNTAIN_BREAKER]: AnimationType.CROSS, // PUNCH_HIGH → crushing\n\n // 암살자 (Amsalja) - Shadow Assassin\n [TechniqueId.AMSALJA_SHADOW_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.AMSALJA_NERVE_STRIKE]: AnimationType.NERVE_STRIKE, // PRESSURE_POINT → precise\n [TechniqueId.AMSALJA_DEADLY_PRECISION]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.AMSALJA_SILENT_DEATH]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT → lethal\n\n // 해커 (Hacker) - Cyber Warrior\n [TechniqueId.HACKER_ELECTRIC_SHOCK]: AnimationType.LIGHTNING_STRIKE, // PUNCH_MID → electric\n [TechniqueId.HACKER_DATA_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.HACKER_CYBER_OVERDRIVE]: AnimationType.RAPID_BARRAGE, // PRESSURE_POINT_RAPID\n [TechniqueId.HACKER_SYSTEM_CRASH]: AnimationType.NERVE_STRIKE, // PRESSURE_POINT → system\n\n // 정보요원 (Jeongbo) - Intelligence Operative\n [TechniqueId.JEONGBO_TACTICAL_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.JEONGBO_COUNTER_INTELLIGENCE]: AnimationType.JAB, // PUNCH_MID → counter\n [TechniqueId.JEONGBO_PSYCHOLOGICAL_WARFARE]: AnimationType.NERVE_STRIKE, // PRESSURE_POINT\n [TechniqueId.JEONGBO_PRECISION_TAKEDOWN]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n [TechniqueId.JEONGBO_INTELLIGENCE_STRIKE]: AnimationType.PRESSURE_POINT_STRIKE, // PRESSURE_POINT\n\n // 조직폭력배 (Jojik) - Organized Crime\n [TechniqueId.JOJIK_STREET_BRAWL]: AnimationType.HOOK, // PUNCH_MID → brawling\n [TechniqueId.JOJIK_IMPROVISED_WEAPON]: AnimationType.HAMMER_FIST, // ELBOW_STRIKE variant\n [TechniqueId.JOJIK_RUTHLESS_ASSAULT]: AnimationType.CROSS, // PUNCH_HIGH → brutal\n [TechniqueId.JOJIK_BRUTAL_TAKEDOWN]: AnimationType.ELBOW_STRIKE, // ELBOW_STRIKE → takedown\n};\n\n/**\n * Get AnimationType for a given technique ID\n *\n * Looks up the AnimationType from the TECHNIQUE_TO_ANIMATION_TYPE mapping.\n * Currently only supports archetype techniques (TechniqueId enum).\n * Returns undefined for unknown techniques or trigram techniques.\n *\n * @param techniqueId - The technique ID\n * @returns The AnimationType for movement physics, or undefined if not found\n * @korean 기술ID로애니메이션타입가져오기\n */\nexport function getAnimationTypeForTechnique(\n techniqueId: string | undefined\n): AnimationType | undefined {\n if (!techniqueId) {\n return undefined;\n }\n \n // Check if techniqueId is in our mapping\n // Note: Only archetype techniques (TechniqueId enum) are currently mapped\n return TECHNIQUE_TO_ANIMATION_TYPE[techniqueId as TechniqueId];\n}\n\n/**\n * Get AnimationType from AttackAnimationType\n *\n * @param attackAnimationType - The attack animation type from technique definition\n * @returns The AnimationType for movement physics\n * @korean 공격애니메이션타입에서애니메이션타입가져오기\n */\nexport function getAnimationTypeFromAttackAnimation(\n attackAnimationType: AttackAnimationType\n): AnimationType {\n return ATTACK_ANIMATION_TO_MOVEMENT_TYPE[attackAnimationType];\n}\n\nexport default {\n TECHNIQUE_TO_ANIMATION_TYPE,\n ATTACK_ANIMATION_TO_MOVEMENT_TYPE,\n getAnimationTypeForTechnique,\n getAnimationTypeFromAttackAnimation,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,oCAGT;EAED,oBAAoB,aAAa,cAAc;EAC/C,oBAAoB,YAAY,cAAc;EAC9C,oBAAoB,YAAY,cAAc;EAG9C,oBAAoB,aAAa,cAAc;EAC/C,oBAAoB,YAAY,cAAc;EAC9C,oBAAoB,kBAAkB,cAAc;EAGpD,oBAAoB,eAAe,cAAc;EACjD,oBAAoB,iBAAiB,cAAc;EAGnD,oBAAoB,cAAc,cAAc;EAChD,oBAAoB,cAAc,cAAc;EAGhD,oBAAoB,iBAAiB,cAAc;EACnD,oBAAoB,uBAAuB,cAAc;CAC3D;;;;;;;;;;;AAYD,IAAa,8BAAkE;EAE5E,YAAY,sBAAsB,cAAc;EAChD,YAAY,oBAAoB,cAAc;EAC9C,YAAY,mBAAmB,cAAc;EAC7C,YAAY,wBAAwB,cAAc;EAGlD,YAAY,wBAAwB,cAAc;EAClD,YAAY,uBAAuB,cAAc;EACjD,YAAY,2BAA2B,cAAc;EACrD,YAAY,uBAAuB,cAAc;EAGjD,YAAY,wBAAwB,cAAc;EAClD,YAAY,qBAAqB,cAAc;EAC/C,YAAY,yBAAyB,cAAc;EACnD,YAAY,sBAAsB,cAAc;EAGhD,YAAY,0BAA0B,cAAc;EACpD,YAAY,+BAA+B,cAAc;EACzD,YAAY,gCAAgC,cAAc;EAC1D,YAAY,6BAA6B,cAAc;EACvD,YAAY,8BAA8B,cAAc;EAGxD,YAAY,qBAAqB,cAAc;EAC/C,YAAY,0BAA0B,cAAc;EACpD,YAAY,yBAAyB,cAAc;EACnD,YAAY,wBAAwB,cAAc;CACpD;;;;;;;;;;;;AAaD,SAAgB,6BACd,aAC2B;CAC3B,IAAI,CAAC,aACH;CAKF,OAAO,4BAA4B;;;;;;;;;AAUrC,SAAgB,oCACd,qBACe;CACf,OAAO,kCAAkC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"techniques.js","names":[],"sources":["../../src/data/techniques.ts"],"sourcesContent":["/**\n * Technique definitions for all player archetypes.\n *\n * **Korean**: 기술 정의 (Technique Definitions)\n *\n * Each archetype has 3-5 unique techniques that reflect their combat philosophy\n * and specialization. Techniques are mapped to keyboard shortcuts Q-E-R-T-Y-F-G-Z-X-C.\n *\n * @module data/techniques\n * @category Combat System\n * @korean 기술데이터\n */\n\nimport { KoreanTechniquesSystem } from \"../systems/trigram/KoreanTechniques\";\nimport { KoreanTechnique } from \"../systems/vitalpoint/types\";\nimport {\n DamageType,\n PlayerArchetype,\n Technique,\n TechniqueKey,\n TrigramStance,\n} from \"../types\";\nimport { AttackAnimationType } from \"../types/skeletal\";\n\n/**\n * Technique definitions for 무사 (Musa) - Traditional Warrior.\n *\n * Philosophy: Honor through disciplined strength and overwhelming force.\n * Favored Stance: ☰ 건 (Geon) - Heaven\n */\nexport const MUSA_TECHNIQUES: readonly Technique[] = [\n {\n id: \"musa_thunder_strike\",\n name: {\n korean: \"천둥벽력\",\n english: \"Thunder Strike\",\n },\n description: {\n korean: \"강력한 하늘의 힘으로 적을 강타합니다\",\n english: \"Strike with the power of heaven\",\n },\n staminaCost: 15,\n kiCost: 10,\n damage: { min: 25, max: 35 },\n damageType: DamageType.BLUNT,\n cooldown: 1300, // animationDuration (800) + recovery (500)\n requiredStance: TrigramStance.GEON,\n keyboardShortcut: \"Q\",\n criticalChance: 0.25,\n animationDuration: 800,\n animation: {\n type: AttackAnimationType.PUNCH_HIGH,\n speedModifier: 0.9, // Powerful strike, slightly slower\n },\n },\n {\n id: \"musa_iron_defense\",\n name: {\n korean: \"철벽방어\",\n english: \"Iron Defense\",\n },\n description: {\n korean: \"산처럼 굳건한 방어 자세를 취합니다\",\n english: \"Adopt an immovable defensive stance\",\n },\n staminaCost: 10,\n kiCost: 8,\n damage: { min: 0, max: 5 },\n damageType: DamageType.IMPACT,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n requiredStance: TrigramStance.GAN,\n keyboardShortcut: \"T\",\n specialEffect: \"defense_boost\",\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.0, // Normal defensive speed\n },\n },\n {\n id: \"musa_dragon_fist\",\n name: {\n korean: \"용권\",\n english: \"Dragon Fist\",\n },\n description: {\n korean: \"용의 기세로 적을 관통합니다\",\n english: \"Pierce through with dragon's might\",\n },\n staminaCost: 18,\n kiCost: 12,\n damage: { min: 30, max: 40 },\n damageType: DamageType.PIERCING,\n cooldown: 1500, // animationDuration (1000) + recovery (500)\n keyboardShortcut: \"E\",\n targetsVitalPoint: true,\n criticalChance: 0.3,\n animationDuration: 1000,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 0.8, // Heavy piercing strike\n },\n },\n {\n id: \"musa_mountain_breaker\",\n name: {\n korean: \"파산격\",\n english: \"Mountain Breaker\",\n },\n description: {\n korean: \"산을 깨뜨리는 강력한 일격\",\n english: \"A devastating blow that shatters mountains\",\n },\n staminaCost: 20,\n kiCost: 15,\n damage: { min: 35, max: 50 },\n damageType: DamageType.CRUSHING,\n cooldown: 1700, // animationDuration (1200) + recovery (500)\n requiredStance: TrigramStance.GEON,\n keyboardShortcut: \"R\",\n criticalChance: 0.2,\n specialEffect: \"armor_break\",\n animationDuration: 1200,\n animation: {\n type: AttackAnimationType.PUNCH_HIGH,\n speedModifier: 0.8, // Powerful, slower strike\n },\n },\n];\n\n/**\n * Technique definitions for 암살자 (Amsalja) - Shadow Assassin.\n *\n * Philosophy: Precision through stealth and vital point mastery.\n * Favored Stance: ☲ 리 (Li) - Fire\n */\nexport const AMSALJA_TECHNIQUES: readonly Technique[] = [\n {\n id: \"amsalja_shadow_strike\",\n name: {\n korean: \"암영격\",\n english: \"Shadow Strike\",\n },\n description: {\n korean: \"그림자처럼 빠르게 급소를 노립니다\",\n english: \"Strike vital points with shadow speed\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 20, max: 35 },\n damageType: DamageType.NERVE,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n requiredStance: TrigramStance.LI,\n keyboardShortcut: \"Q\",\n targetsVitalPoint: true,\n criticalChance: 0.4,\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.2, // Very fast, precise strike\n },\n },\n {\n id: \"amsalja_nerve_strike\",\n name: {\n korean: \"신경타\",\n english: \"Nerve Strike\",\n },\n description: {\n korean: \"정확한 신경 타격으로 적을 마비시킵니다\",\n english: \"Paralyze the enemy with precise nerve strikes\",\n },\n staminaCost: 15,\n kiCost: 12,\n damage: { min: 15, max: 25 },\n damageType: DamageType.NERVE,\n cooldown: 1200, // animationDuration (700) + recovery (500)\n keyboardShortcut: \"T\",\n targetsVitalPoint: true,\n specialEffect: \"paralysis\",\n animationDuration: 700,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.1, // Fast precision\n },\n },\n {\n id: \"amsalja_deadly_precision\",\n name: {\n korean: \"치명정밀\",\n english: \"Deadly Precision\",\n },\n description: {\n korean: \"완벽한 정밀도로 치명적인 급소를 공격합니다\",\n english: \"Attack critical vital points with perfect accuracy\",\n },\n staminaCost: 18,\n kiCost: 15,\n damage: { min: 25, max: 45 },\n damageType: DamageType.PRESSURE,\n cooldown: 1400, // animationDuration (900) + recovery (500)\n requiredStance: TrigramStance.LI,\n keyboardShortcut: \"E\",\n targetsVitalPoint: true,\n criticalChance: 0.5,\n animationDuration: 900,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.0, // Precise, deliberate\n },\n },\n {\n id: \"amsalja_silent_death\",\n name: {\n korean: \"무음살\",\n english: \"Silent Death\",\n },\n description: {\n korean: \"소리 없이 치명적인 일격을 가합니다\",\n english: \"Deliver a silent, lethal strike\",\n },\n staminaCost: 22,\n kiCost: 18,\n damage: { min: 40, max: 60 },\n damageType: DamageType.NERVE,\n cooldown: 1500, // animationDuration (1000) + recovery (500)\n keyboardShortcut: \"R\",\n targetsVitalPoint: true,\n criticalChance: 0.6,\n specialEffect: \"instant_kill_chance\",\n animationDuration: 1000,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 0.9, // Powerful lethal strike\n },\n },\n];\n\n/**\n * Technique definitions for 해커 (Hacker) - Cyber Warrior.\n *\n * Philosophy: Technology-enhanced combat with data-driven precision.\n * Favored Stance: ☳ 진 (Jin) - Thunder\n */\nexport const HACKER_TECHNIQUES: readonly Technique[] = [\n {\n id: \"hacker_electric_shock\",\n name: {\n korean: \"전격\",\n english: \"Electric Shock\",\n },\n description: {\n korean: \"사이버 임플란트로 전기 충격을 가합니다\",\n english: \"Deliver electric shock via cyber implants\",\n },\n staminaCost: 10,\n kiCost: 12,\n damage: { min: 18, max: 28 },\n damageType: DamageType.ELECTRIC,\n cooldown: 1000, // animationDuration (500) + recovery (500)\n requiredStance: TrigramStance.JIN,\n keyboardShortcut: \"Q\",\n specialEffect: \"stun\",\n animationDuration: 500,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.2, // Fast electric strike\n },\n },\n {\n id: \"hacker_data_strike\",\n name: {\n korean: \"데이터 타격\",\n english: \"Data Strike\",\n },\n description: {\n korean: \"전투 데이터를 분석하여 최적의 공격을 수행합니다\",\n english: \"Analyze combat data for optimal attack\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 22, max: 32 },\n damageType: DamageType.PIERCING,\n cooldown: 1200, // animationDuration (700) + recovery (500)\n keyboardShortcut: \"T\",\n targetsVitalPoint: true,\n criticalChance: 0.35,\n animationDuration: 700,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.1, // Data-enhanced precision\n },\n },\n {\n id: \"hacker_cyber_overdrive\",\n name: {\n korean: \"사이버 가속\",\n english: \"Cyber Overdrive\",\n },\n description: {\n korean: \"임플란트를 과부하시켜 초고속 공격을 수행합니다\",\n english: \"Overload implants for lightning-fast attacks\",\n },\n staminaCost: 18,\n kiCost: 15,\n damage: { min: 15, max: 25 },\n damageType: DamageType.ELECTRIC,\n cooldown: 1700, // animationDuration (1200) + recovery (500)\n requiredStance: TrigramStance.JIN,\n keyboardShortcut: \"E\",\n specialEffect: \"multi_hit\",\n animationDuration: 1200,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT_RAPID,\n speedModifier: 1.3, // Ultra-fast combo\n },\n },\n {\n id: \"hacker_system_crash\",\n name: {\n korean: \"시스템 크래시\",\n english: \"System Crash\",\n },\n description: {\n korean: \"적의 신경 시스템을 해킹하여 무력화합니다\",\n english: \"Hack the enemy's nervous system\",\n },\n staminaCost: 20,\n kiCost: 18,\n damage: { min: 30, max: 45 },\n damageType: DamageType.PSYCHIC,\n cooldown: 1600, // animationDuration (1100) + recovery (500)\n keyboardShortcut: \"R\",\n targetsVitalPoint: true,\n specialEffect: \"system_shutdown\",\n animationDuration: 1100,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.0, // Calculated precision\n },\n },\n];\n\n/**\n * Technique definitions for 정보요원 (Jeongbo Yowon) - Intelligence Operative.\n *\n * Philosophy: Strategic analysis and exploiting weaknesses.\n * Favored Stance: ☵ 감 (Gam) - Water\n */\nexport const JEONGBO_YOWON_TECHNIQUES: readonly Technique[] = [\n {\n id: \"jeongbo_tactical_strike\",\n name: {\n korean: \"전술타격\",\n english: \"Tactical Strike\",\n },\n description: {\n korean: \"적의 약점을 분석하여 전술적으로 공격합니다\",\n english: \"Analyze and strike enemy weaknesses tactically\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 20, max: 30 },\n damageType: DamageType.PIERCING,\n cooldown: 1150, // animationDuration (650) + recovery (500)\n requiredStance: TrigramStance.GAM,\n keyboardShortcut: \"Q\",\n targetsVitalPoint: true,\n criticalChance: 0.3,\n animationDuration: 650,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.1, // Strategic precision\n },\n },\n {\n id: \"jeongbo_counter_intelligence\",\n name: {\n korean: \"역정보공작\",\n english: \"Counter Intelligence\",\n },\n description: {\n korean: \"적의 움직임을 읽고 반격합니다\",\n english: \"Read and counter enemy movements\",\n },\n staminaCost: 10,\n kiCost: 12,\n damage: { min: 15, max: 30 },\n damageType: DamageType.IMPACT,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n keyboardShortcut: \"T\",\n specialEffect: \"counter_stance\",\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.2, // Fast counter\n },\n },\n {\n id: \"jeongbo_psychological_warfare\",\n name: {\n korean: \"심리전\",\n english: \"Psychological Warfare\",\n },\n description: {\n korean: \"적의 정신을 교란하여 약화시킵니다\",\n english: \"Disrupt enemy's mental state\",\n },\n staminaCost: 15,\n kiCost: 15,\n damage: { min: 10, max: 20 },\n damageType: DamageType.PSYCHIC,\n cooldown: 1300, // animationDuration (800) + recovery (500)\n keyboardShortcut: \"E\",\n specialEffect: \"confusion\",\n animationDuration: 800,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.0, // Deliberate mental attack\n },\n },\n {\n id: \"jeongbo_intelligence_strike\",\n name: {\n korean: \"정보타격\",\n english: \"Intelligence Strike\",\n },\n description: {\n korean: \"수집한 정보를 바탕으로 완벽한 공격을 수행합니다\",\n english: \"Execute perfect attack based on gathered intelligence\",\n },\n staminaCost: 20,\n kiCost: 18,\n damage: { min: 35, max: 50 },\n damageType: DamageType.PIERCING,\n cooldown: 1500, // animationDuration (1000) + recovery (500)\n requiredStance: TrigramStance.GAM,\n keyboardShortcut: \"R\",\n targetsVitalPoint: true,\n criticalChance: 0.45,\n animationDuration: 1000,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 0.9, // Powerful decisive strike\n },\n },\n {\n id: \"jeongbo_precision_takedown\",\n name: {\n korean: \"정밀제압\",\n english: \"Precision Takedown\",\n },\n description: {\n korean: \"무력한 적을 정밀하게 제압합니다 - 서명 기술\",\n english: \"Precisely takedown helpless opponent - Signature Move\",\n },\n staminaCost: 25,\n kiCost: 20,\n damage: { min: 45, max: 65 },\n damageType: DamageType.PIERCING,\n cooldown: 1700, // animationDuration (1200) + recovery (500)\n requiredStance: TrigramStance.GAM,\n keyboardShortcut: \"Y\",\n targetsVitalPoint: true,\n criticalChance: 0.6,\n specialEffect: \"signature_move\",\n animationDuration: 1200,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 0.8, // Deliberate, precise execution\n },\n },\n];\n\n/**\n * Technique definitions for 조직폭력배 (Jojik Pokryeokbae) - Organized Crime.\n *\n * Philosophy: Ruthless pragmatism and brutal efficiency.\n * Favored Stance: ☷ 곤 (Gon) - Earth\n */\nexport const JOJIK_POKRYEOKBAE_TECHNIQUES: readonly Technique[] = [\n {\n id: \"jojik_street_brawl\",\n name: {\n korean: \"거리싸움\",\n english: \"Street Brawl\",\n },\n description: {\n korean: \"더러운 싸움으로 적을 제압합니다\",\n english: \"Overwhelm with dirty fighting\",\n },\n staminaCost: 10,\n kiCost: 8,\n damage: { min: 18, max: 28 },\n damageType: DamageType.BLUNT,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n requiredStance: TrigramStance.GON,\n keyboardShortcut: \"Q\",\n criticalChance: 0.25,\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.1, // Fast brawl strike\n },\n },\n {\n id: \"jojik_brutal_takedown\",\n name: {\n korean: \"잔혹제압\",\n english: \"Brutal Takedown\",\n },\n description: {\n korean: \"무자비하게 적을 쓰러뜨립니다\",\n english: \"Mercilessly takedown the enemy\",\n },\n staminaCost: 15,\n kiCost: 10,\n damage: { min: 25, max: 35 },\n damageType: DamageType.CRUSHING,\n cooldown: 1300, // animationDuration (800) + recovery (500)\n keyboardShortcut: \"T\",\n specialEffect: \"knockdown\",\n animationDuration: 800,\n animation: {\n type: AttackAnimationType.ELBOW_STRIKE,\n speedModifier: 0.9, // Heavy takedown\n },\n },\n {\n id: \"jojik_improvised_weapon\",\n name: {\n korean: \"즉석무기\",\n english: \"Improvised Weapon\",\n },\n description: {\n korean: \"주변 물건을 이용하여 공격합니다\",\n english: \"Attack using improvised objects\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 22, max: 38 },\n damageType: DamageType.SHARP,\n cooldown: 1200, // animationDuration (700) + recovery (500)\n requiredStance: TrigramStance.GON,\n keyboardShortcut: \"E\",\n criticalChance: 0.3,\n specialEffect: \"bleed\",\n animationDuration: 700,\n animation: {\n type: AttackAnimationType.PUNCH_HIGH,\n speedModifier: 1.0, // Unpredictable weapon strike\n },\n },\n {\n id: \"jojik_ruthless_assault\",\n name: {\n korean: \"무자비공격\",\n english: \"Ruthless Assault\",\n },\n description: {\n korean: \"자비 없이 적을 집중 공격합니다\",\n english: \"Relentlessly assault without mercy\",\n },\n staminaCost: 22,\n kiCost: 12,\n damage: { min: 30, max: 55 },\n damageType: DamageType.CRUSHING,\n cooldown: 1800, // animationDuration (1300) + recovery (500)\n keyboardShortcut: \"R\",\n criticalChance: 0.35,\n specialEffect: \"rage\",\n animationDuration: 1300,\n animation: {\n type: AttackAnimationType.PUNCH_LOW,\n speedModifier: 0.8, // Heavy brutal assault\n },\n },\n];\n\n/**\n * Get techniques for a specific player archetype.\n *\n * @param archetype - Player archetype\n * @returns Array of techniques for the archetype\n *\n * @public\n */\nexport function getTechniquesForArchetype(\n archetype: PlayerArchetype,\n): readonly Technique[] {\n switch (archetype) {\n case PlayerArchetype.MUSA:\n return MUSA_TECHNIQUES;\n case PlayerArchetype.AMSALJA:\n return AMSALJA_TECHNIQUES;\n case PlayerArchetype.HACKER:\n return HACKER_TECHNIQUES;\n case PlayerArchetype.JEONGBO_YOWON:\n return JEONGBO_YOWON_TECHNIQUES;\n case PlayerArchetype.JOJIK_POKRYEOKBAE:\n return JOJIK_POKRYEOKBAE_TECHNIQUES;\n default:\n // Exhaustive check: if a new archetype is added, TypeScript will error here\n const _exhaustiveCheck: never = archetype;\n throw new Error(`Unknown archetype: ${_exhaustiveCheck}`);\n }\n}\n\n/**\n * Convert KoreanTechnique to Technique format for UI compatibility\n */\nfunction convertKoreanToTechnique(koreanTech: KoreanTechnique): Technique {\n // Convert string damageType to DamageType enum\n const getDamageType = (type: string): DamageType => {\n // Map common string values to DamageType enum\n const typeMap: Record<string, DamageType> = {\n blunt: DamageType.BLUNT,\n physical: DamageType.BLUNT,\n piercing: DamageType.PIERCING,\n slashing: DamageType.SLASHING,\n crushing: DamageType.CRUSHING,\n impact: DamageType.IMPACT,\n joint: DamageType.JOINT,\n electric: DamageType.ELECTRIC,\n psychic: DamageType.PSYCHIC,\n };\n return typeMap[type.toLowerCase()] ?? DamageType.BLUNT;\n };\n\n return {\n id: koreanTech.id,\n name: {\n korean: koreanTech.koreanName || koreanTech.name.korean,\n english: koreanTech.englishName || koreanTech.name.english,\n romanized: koreanTech.romanized || koreanTech.name.romanized,\n },\n description: koreanTech.description,\n staminaCost: koreanTech.staminaCost,\n kiCost: koreanTech.kiCost,\n damage: {\n min: Math.floor(koreanTech.damage * 0.8),\n max: Math.ceil(koreanTech.damage * 1.2),\n },\n damageType: getDamageType(koreanTech.damageType),\n cooldown: koreanTech.recoveryTime + koreanTech.executionTime,\n requiredStance: koreanTech.stance,\n keyboardShortcut: \"Q\", // Placeholder; immediately overridden by getTechniquesForStanceAndArchetype()\n criticalChance: koreanTech.critChance,\n animationDuration: koreanTech.executionTime,\n };\n}\n\n/**\n * Get techniques for a player based on their current stance and archetype.\n * Combines trigram stance techniques with archetype-specific bonuses.\n *\n * @param stance - Current player stance\n * @param archetype - Player archetype\n * @returns Array of available techniques with proper keyboard shortcuts assigned\n *\n * @public\n */\nexport function getTechniquesForStanceAndArchetype(\n stance: TrigramStance,\n archetype: PlayerArchetype,\n): readonly Technique[] {\n // Get stance-based techniques from Korean martial arts system\n const koreanTechniques = KoreanTechniquesSystem.getAllAvailableTechniques(\n stance,\n archetype,\n );\n\n // Convert to Technique format\n const convertedTechniques = koreanTechniques.map(convertKoreanToTechnique);\n\n // Also include archetype-specific special techniques\n const archetypeTechniques = getTechniquesForArchetype(archetype);\n\n // Filter archetype techniques to only include those matching current stance or no stance requirement\n const filteredArchetypeTechniques = archetypeTechniques.filter(\n (tech) => !tech.requiredStance || tech.requiredStance === stance,\n );\n\n // Combine both sets, prioritizing stance techniques\n const allTechniques = [\n ...convertedTechniques,\n ...filteredArchetypeTechniques,\n ];\n\n // Limit to maximum 10 techniques (keyboard shortcuts Q-E-R-T-Y-F-G-Z-X-C)\n const limitedTechniques = allTechniques.slice(0, 10);\n\n // Assign keyboard shortcuts using conflict-free keys around WASD\n const keyboardShortcuts = [\n \"Q\",\n \"E\",\n \"R\",\n \"T\",\n \"Y\",\n \"F\",\n \"G\",\n \"Z\",\n \"X\",\n \"C\",\n ] as const;\n return limitedTechniques.map((tech, index) => ({\n ...tech,\n keyboardShortcut: keyboardShortcuts[index] as TechniqueKey,\n }));\n}\n\n/**\n * Get a specific technique by ID.\n *\n * @param techniqueId - Unique technique identifier\n * @returns Technique if found, undefined otherwise\n *\n * @public\n */\nexport function getTechniqueById(techniqueId: string): Technique | undefined {\n const allTechniques = [\n ...MUSA_TECHNIQUES,\n ...AMSALJA_TECHNIQUES,\n ...HACKER_TECHNIQUES,\n ...JEONGBO_YOWON_TECHNIQUES,\n ...JOJIK_POKRYEOKBAE_TECHNIQUES,\n ];\n\n return allTechniques.find((tech) => tech.id === techniqueId);\n}\n\nexport default {\n getTechniquesForArchetype,\n getTechniquesForStanceAndArchetype,\n getTechniqueById,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"techniques.js","names":[],"sources":["../../src/data/techniques.ts"],"sourcesContent":["/**\n * Technique definitions for all player archetypes.\n *\n * **Korean**: 기술 정의 (Technique Definitions)\n *\n * Each archetype has 3-5 unique techniques that reflect their combat philosophy\n * and specialization. Techniques are mapped to keyboard shortcuts Q-E-R-T-Y-F-G-Z-X-C.\n *\n * @module data/techniques\n * @category Combat System\n * @korean 기술데이터\n */\n\nimport { KoreanTechniquesSystem } from \"../systems/trigram/KoreanTechniques\";\nimport { KoreanTechnique } from \"../systems/vitalpoint/types\";\nimport {\n DamageType,\n PlayerArchetype,\n Technique,\n TechniqueKey,\n TrigramStance,\n} from \"../types\";\nimport { AttackAnimationType } from \"../types/skeletal\";\n\n/**\n * Technique definitions for 무사 (Musa) - Traditional Warrior.\n *\n * Philosophy: Honor through disciplined strength and overwhelming force.\n * Favored Stance: ☰ 건 (Geon) - Heaven\n */\nexport const MUSA_TECHNIQUES: readonly Technique[] = [\n {\n id: \"musa_thunder_strike\",\n name: {\n korean: \"천둥벽력\",\n english: \"Thunder Strike\",\n },\n description: {\n korean: \"강력한 하늘의 힘으로 적을 강타합니다\",\n english: \"Strike with the power of heaven\",\n },\n staminaCost: 15,\n kiCost: 10,\n damage: { min: 25, max: 35 },\n damageType: DamageType.BLUNT,\n cooldown: 1300, // animationDuration (800) + recovery (500)\n requiredStance: TrigramStance.GEON,\n keyboardShortcut: \"Q\",\n criticalChance: 0.25,\n animationDuration: 800,\n animation: {\n type: AttackAnimationType.PUNCH_HIGH,\n speedModifier: 0.9, // Powerful strike, slightly slower\n },\n },\n {\n id: \"musa_iron_defense\",\n name: {\n korean: \"철벽방어\",\n english: \"Iron Defense\",\n },\n description: {\n korean: \"산처럼 굳건한 방어 자세를 취합니다\",\n english: \"Adopt an immovable defensive stance\",\n },\n staminaCost: 10,\n kiCost: 8,\n damage: { min: 0, max: 5 },\n damageType: DamageType.IMPACT,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n requiredStance: TrigramStance.GAN,\n keyboardShortcut: \"T\",\n specialEffect: \"defense_boost\",\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.0, // Normal defensive speed\n },\n },\n {\n id: \"musa_dragon_fist\",\n name: {\n korean: \"용권\",\n english: \"Dragon Fist\",\n },\n description: {\n korean: \"용의 기세로 적을 관통합니다\",\n english: \"Pierce through with dragon's might\",\n },\n staminaCost: 18,\n kiCost: 12,\n damage: { min: 30, max: 40 },\n damageType: DamageType.PIERCING,\n cooldown: 1500, // animationDuration (1000) + recovery (500)\n keyboardShortcut: \"E\",\n targetsVitalPoint: true,\n criticalChance: 0.3,\n animationDuration: 1000,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 0.8, // Heavy piercing strike\n },\n },\n {\n id: \"musa_mountain_breaker\",\n name: {\n korean: \"파산격\",\n english: \"Mountain Breaker\",\n },\n description: {\n korean: \"산을 깨뜨리는 강력한 일격\",\n english: \"A devastating blow that shatters mountains\",\n },\n staminaCost: 20,\n kiCost: 15,\n damage: { min: 35, max: 50 },\n damageType: DamageType.CRUSHING,\n cooldown: 1700, // animationDuration (1200) + recovery (500)\n requiredStance: TrigramStance.GEON,\n keyboardShortcut: \"R\",\n criticalChance: 0.2,\n specialEffect: \"armor_break\",\n animationDuration: 1200,\n animation: {\n type: AttackAnimationType.PUNCH_HIGH,\n speedModifier: 0.8, // Powerful, slower strike\n },\n },\n];\n\n/**\n * Technique definitions for 암살자 (Amsalja) - Shadow Assassin.\n *\n * Philosophy: Precision through stealth and vital point mastery.\n * Favored Stance: ☲ 리 (Li) - Fire\n */\nexport const AMSALJA_TECHNIQUES: readonly Technique[] = [\n {\n id: \"amsalja_shadow_strike\",\n name: {\n korean: \"암영격\",\n english: \"Shadow Strike\",\n },\n description: {\n korean: \"그림자처럼 빠르게 급소를 노립니다\",\n english: \"Strike vital points with shadow speed\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 20, max: 35 },\n damageType: DamageType.NERVE,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n requiredStance: TrigramStance.LI,\n keyboardShortcut: \"Q\",\n targetsVitalPoint: true,\n criticalChance: 0.4,\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.2, // Very fast, precise strike\n },\n },\n {\n id: \"amsalja_nerve_strike\",\n name: {\n korean: \"신경타\",\n english: \"Nerve Strike\",\n },\n description: {\n korean: \"정확한 신경 타격으로 적을 마비시킵니다\",\n english: \"Paralyze the enemy with precise nerve strikes\",\n },\n staminaCost: 15,\n kiCost: 12,\n damage: { min: 15, max: 25 },\n damageType: DamageType.NERVE,\n cooldown: 1200, // animationDuration (700) + recovery (500)\n keyboardShortcut: \"T\",\n targetsVitalPoint: true,\n specialEffect: \"paralysis\",\n animationDuration: 700,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.1, // Fast precision\n },\n },\n {\n id: \"amsalja_deadly_precision\",\n name: {\n korean: \"치명정밀\",\n english: \"Deadly Precision\",\n },\n description: {\n korean: \"완벽한 정밀도로 치명적인 급소를 공격합니다\",\n english: \"Attack critical vital points with perfect accuracy\",\n },\n staminaCost: 18,\n kiCost: 15,\n damage: { min: 25, max: 45 },\n damageType: DamageType.PRESSURE,\n cooldown: 1400, // animationDuration (900) + recovery (500)\n requiredStance: TrigramStance.LI,\n keyboardShortcut: \"E\",\n targetsVitalPoint: true,\n criticalChance: 0.5,\n animationDuration: 900,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.0, // Precise, deliberate\n },\n },\n {\n id: \"amsalja_silent_death\",\n name: {\n korean: \"무음살\",\n english: \"Silent Death\",\n },\n description: {\n korean: \"소리 없이 치명적인 일격을 가합니다\",\n english: \"Deliver a silent, lethal strike\",\n },\n staminaCost: 22,\n kiCost: 18,\n damage: { min: 40, max: 60 },\n damageType: DamageType.NERVE,\n cooldown: 1500, // animationDuration (1000) + recovery (500)\n keyboardShortcut: \"R\",\n targetsVitalPoint: true,\n criticalChance: 0.6,\n specialEffect: \"instant_kill_chance\",\n animationDuration: 1000,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 0.9, // Powerful lethal strike\n },\n },\n];\n\n/**\n * Technique definitions for 해커 (Hacker) - Cyber Warrior.\n *\n * Philosophy: Technology-enhanced combat with data-driven precision.\n * Favored Stance: ☳ 진 (Jin) - Thunder\n */\nexport const HACKER_TECHNIQUES: readonly Technique[] = [\n {\n id: \"hacker_electric_shock\",\n name: {\n korean: \"전격\",\n english: \"Electric Shock\",\n },\n description: {\n korean: \"사이버 임플란트로 전기 충격을 가합니다\",\n english: \"Deliver electric shock via cyber implants\",\n },\n staminaCost: 10,\n kiCost: 12,\n damage: { min: 18, max: 28 },\n damageType: DamageType.ELECTRIC,\n cooldown: 1000, // animationDuration (500) + recovery (500)\n requiredStance: TrigramStance.JIN,\n keyboardShortcut: \"Q\",\n specialEffect: \"stun\",\n animationDuration: 500,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.2, // Fast electric strike\n },\n },\n {\n id: \"hacker_data_strike\",\n name: {\n korean: \"데이터 타격\",\n english: \"Data Strike\",\n },\n description: {\n korean: \"전투 데이터를 분석하여 최적의 공격을 수행합니다\",\n english: \"Analyze combat data for optimal attack\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 22, max: 32 },\n damageType: DamageType.PIERCING,\n cooldown: 1200, // animationDuration (700) + recovery (500)\n keyboardShortcut: \"T\",\n targetsVitalPoint: true,\n criticalChance: 0.35,\n animationDuration: 700,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.1, // Data-enhanced precision\n },\n },\n {\n id: \"hacker_cyber_overdrive\",\n name: {\n korean: \"사이버 가속\",\n english: \"Cyber Overdrive\",\n },\n description: {\n korean: \"임플란트를 과부하시켜 초고속 공격을 수행합니다\",\n english: \"Overload implants for lightning-fast attacks\",\n },\n staminaCost: 18,\n kiCost: 15,\n damage: { min: 15, max: 25 },\n damageType: DamageType.ELECTRIC,\n cooldown: 1700, // animationDuration (1200) + recovery (500)\n requiredStance: TrigramStance.JIN,\n keyboardShortcut: \"E\",\n specialEffect: \"multi_hit\",\n animationDuration: 1200,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT_RAPID,\n speedModifier: 1.3, // Ultra-fast combo\n },\n },\n {\n id: \"hacker_system_crash\",\n name: {\n korean: \"시스템 크래시\",\n english: \"System Crash\",\n },\n description: {\n korean: \"적의 신경 시스템을 해킹하여 무력화합니다\",\n english: \"Hack the enemy's nervous system\",\n },\n staminaCost: 20,\n kiCost: 18,\n damage: { min: 30, max: 45 },\n damageType: DamageType.PSYCHIC,\n cooldown: 1600, // animationDuration (1100) + recovery (500)\n keyboardShortcut: \"R\",\n targetsVitalPoint: true,\n specialEffect: \"system_shutdown\",\n animationDuration: 1100,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.0, // Calculated precision\n },\n },\n];\n\n/**\n * Technique definitions for 정보요원 (Jeongbo Yowon) - Intelligence Operative.\n *\n * Philosophy: Strategic analysis and exploiting weaknesses.\n * Favored Stance: ☵ 감 (Gam) - Water\n */\nexport const JEONGBO_YOWON_TECHNIQUES: readonly Technique[] = [\n {\n id: \"jeongbo_tactical_strike\",\n name: {\n korean: \"전술타격\",\n english: \"Tactical Strike\",\n },\n description: {\n korean: \"적의 약점을 분석하여 전술적으로 공격합니다\",\n english: \"Analyze and strike enemy weaknesses tactically\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 20, max: 30 },\n damageType: DamageType.PIERCING,\n cooldown: 1150, // animationDuration (650) + recovery (500)\n requiredStance: TrigramStance.GAM,\n keyboardShortcut: \"Q\",\n targetsVitalPoint: true,\n criticalChance: 0.3,\n animationDuration: 650,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.1, // Strategic precision\n },\n },\n {\n id: \"jeongbo_counter_intelligence\",\n name: {\n korean: \"역정보공작\",\n english: \"Counter Intelligence\",\n },\n description: {\n korean: \"적의 움직임을 읽고 반격합니다\",\n english: \"Read and counter enemy movements\",\n },\n staminaCost: 10,\n kiCost: 12,\n damage: { min: 15, max: 30 },\n damageType: DamageType.IMPACT,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n keyboardShortcut: \"T\",\n specialEffect: \"counter_stance\",\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.2, // Fast counter\n },\n },\n {\n id: \"jeongbo_psychological_warfare\",\n name: {\n korean: \"심리전\",\n english: \"Psychological Warfare\",\n },\n description: {\n korean: \"적의 정신을 교란하여 약화시킵니다\",\n english: \"Disrupt enemy's mental state\",\n },\n staminaCost: 15,\n kiCost: 15,\n damage: { min: 10, max: 20 },\n damageType: DamageType.PSYCHIC,\n cooldown: 1300, // animationDuration (800) + recovery (500)\n keyboardShortcut: \"E\",\n specialEffect: \"confusion\",\n animationDuration: 800,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 1.0, // Deliberate mental attack\n },\n },\n {\n id: \"jeongbo_intelligence_strike\",\n name: {\n korean: \"정보타격\",\n english: \"Intelligence Strike\",\n },\n description: {\n korean: \"수집한 정보를 바탕으로 완벽한 공격을 수행합니다\",\n english: \"Execute perfect attack based on gathered intelligence\",\n },\n staminaCost: 20,\n kiCost: 18,\n damage: { min: 35, max: 50 },\n damageType: DamageType.PIERCING,\n cooldown: 1500, // animationDuration (1000) + recovery (500)\n requiredStance: TrigramStance.GAM,\n keyboardShortcut: \"R\",\n targetsVitalPoint: true,\n criticalChance: 0.45,\n animationDuration: 1000,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 0.9, // Powerful decisive strike\n },\n },\n {\n id: \"jeongbo_precision_takedown\",\n name: {\n korean: \"정밀제압\",\n english: \"Precision Takedown\",\n },\n description: {\n korean: \"무력한 적을 정밀하게 제압합니다 - 서명 기술\",\n english: \"Precisely takedown helpless opponent - Signature Move\",\n },\n staminaCost: 25,\n kiCost: 20,\n damage: { min: 45, max: 65 },\n damageType: DamageType.PIERCING,\n cooldown: 1700, // animationDuration (1200) + recovery (500)\n requiredStance: TrigramStance.GAM,\n keyboardShortcut: \"Y\",\n targetsVitalPoint: true,\n criticalChance: 0.6,\n specialEffect: \"signature_move\",\n animationDuration: 1200,\n animation: {\n type: AttackAnimationType.PRESSURE_POINT,\n speedModifier: 0.8, // Deliberate, precise execution\n },\n },\n];\n\n/**\n * Technique definitions for 조직폭력배 (Jojik Pokryeokbae) - Organized Crime.\n *\n * Philosophy: Ruthless pragmatism and brutal efficiency.\n * Favored Stance: ☷ 곤 (Gon) - Earth\n */\nexport const JOJIK_POKRYEOKBAE_TECHNIQUES: readonly Technique[] = [\n {\n id: \"jojik_street_brawl\",\n name: {\n korean: \"거리싸움\",\n english: \"Street Brawl\",\n },\n description: {\n korean: \"더러운 싸움으로 적을 제압합니다\",\n english: \"Overwhelm with dirty fighting\",\n },\n staminaCost: 10,\n kiCost: 8,\n damage: { min: 18, max: 28 },\n damageType: DamageType.BLUNT,\n cooldown: 1100, // animationDuration (600) + recovery (500)\n requiredStance: TrigramStance.GON,\n keyboardShortcut: \"Q\",\n criticalChance: 0.25,\n animationDuration: 600,\n animation: {\n type: AttackAnimationType.PUNCH_MID,\n speedModifier: 1.1, // Fast brawl strike\n },\n },\n {\n id: \"jojik_brutal_takedown\",\n name: {\n korean: \"잔혹제압\",\n english: \"Brutal Takedown\",\n },\n description: {\n korean: \"무자비하게 적을 쓰러뜨립니다\",\n english: \"Mercilessly takedown the enemy\",\n },\n staminaCost: 15,\n kiCost: 10,\n damage: { min: 25, max: 35 },\n damageType: DamageType.CRUSHING,\n cooldown: 1300, // animationDuration (800) + recovery (500)\n keyboardShortcut: \"T\",\n specialEffect: \"knockdown\",\n animationDuration: 800,\n animation: {\n type: AttackAnimationType.ELBOW_STRIKE,\n speedModifier: 0.9, // Heavy takedown\n },\n },\n {\n id: \"jojik_improvised_weapon\",\n name: {\n korean: \"즉석무기\",\n english: \"Improvised Weapon\",\n },\n description: {\n korean: \"주변 물건을 이용하여 공격합니다\",\n english: \"Attack using improvised objects\",\n },\n staminaCost: 12,\n kiCost: 10,\n damage: { min: 22, max: 38 },\n damageType: DamageType.SHARP,\n cooldown: 1200, // animationDuration (700) + recovery (500)\n requiredStance: TrigramStance.GON,\n keyboardShortcut: \"E\",\n criticalChance: 0.3,\n specialEffect: \"bleed\",\n animationDuration: 700,\n animation: {\n type: AttackAnimationType.PUNCH_HIGH,\n speedModifier: 1.0, // Unpredictable weapon strike\n },\n },\n {\n id: \"jojik_ruthless_assault\",\n name: {\n korean: \"무자비공격\",\n english: \"Ruthless Assault\",\n },\n description: {\n korean: \"자비 없이 적을 집중 공격합니다\",\n english: \"Relentlessly assault without mercy\",\n },\n staminaCost: 22,\n kiCost: 12,\n damage: { min: 30, max: 55 },\n damageType: DamageType.CRUSHING,\n cooldown: 1800, // animationDuration (1300) + recovery (500)\n keyboardShortcut: \"R\",\n criticalChance: 0.35,\n specialEffect: \"rage\",\n animationDuration: 1300,\n animation: {\n type: AttackAnimationType.PUNCH_LOW,\n speedModifier: 0.8, // Heavy brutal assault\n },\n },\n];\n\n/**\n * Get techniques for a specific player archetype.\n *\n * @param archetype - Player archetype\n * @returns Array of techniques for the archetype\n *\n * @public\n */\nexport function getTechniquesForArchetype(\n archetype: PlayerArchetype,\n): readonly Technique[] {\n switch (archetype) {\n case PlayerArchetype.MUSA:\n return MUSA_TECHNIQUES;\n case PlayerArchetype.AMSALJA:\n return AMSALJA_TECHNIQUES;\n case PlayerArchetype.HACKER:\n return HACKER_TECHNIQUES;\n case PlayerArchetype.JEONGBO_YOWON:\n return JEONGBO_YOWON_TECHNIQUES;\n case PlayerArchetype.JOJIK_POKRYEOKBAE:\n return JOJIK_POKRYEOKBAE_TECHNIQUES;\n default:\n // Exhaustive check: if a new archetype is added, TypeScript will error here\n const _exhaustiveCheck: never = archetype;\n throw new Error(`Unknown archetype: ${_exhaustiveCheck}`);\n }\n}\n\n/**\n * Convert KoreanTechnique to Technique format for UI compatibility\n */\nfunction convertKoreanToTechnique(koreanTech: KoreanTechnique): Technique {\n // Convert string damageType to DamageType enum\n const getDamageType = (type: string): DamageType => {\n // Map common string values to DamageType enum\n const typeMap: Record<string, DamageType> = {\n blunt: DamageType.BLUNT,\n physical: DamageType.BLUNT,\n piercing: DamageType.PIERCING,\n slashing: DamageType.SLASHING,\n crushing: DamageType.CRUSHING,\n impact: DamageType.IMPACT,\n joint: DamageType.JOINT,\n electric: DamageType.ELECTRIC,\n psychic: DamageType.PSYCHIC,\n };\n return typeMap[type.toLowerCase()] ?? DamageType.BLUNT;\n };\n\n return {\n id: koreanTech.id,\n name: {\n korean: koreanTech.koreanName || koreanTech.name.korean,\n english: koreanTech.englishName || koreanTech.name.english,\n romanized: koreanTech.romanized || koreanTech.name.romanized,\n },\n description: koreanTech.description,\n staminaCost: koreanTech.staminaCost,\n kiCost: koreanTech.kiCost,\n damage: {\n min: Math.floor(koreanTech.damage * 0.8),\n max: Math.ceil(koreanTech.damage * 1.2),\n },\n damageType: getDamageType(koreanTech.damageType),\n cooldown: koreanTech.recoveryTime + koreanTech.executionTime,\n requiredStance: koreanTech.stance,\n keyboardShortcut: \"Q\", // Placeholder; immediately overridden by getTechniquesForStanceAndArchetype()\n criticalChance: koreanTech.critChance,\n animationDuration: koreanTech.executionTime,\n };\n}\n\n/**\n * Get techniques for a player based on their current stance and archetype.\n * Combines trigram stance techniques with archetype-specific bonuses.\n *\n * @param stance - Current player stance\n * @param archetype - Player archetype\n * @returns Array of available techniques with proper keyboard shortcuts assigned\n *\n * @public\n */\nexport function getTechniquesForStanceAndArchetype(\n stance: TrigramStance,\n archetype: PlayerArchetype,\n): readonly Technique[] {\n // Get stance-based techniques from Korean martial arts system\n const koreanTechniques = KoreanTechniquesSystem.getAllAvailableTechniques(\n stance,\n archetype,\n );\n\n // Convert to Technique format\n const convertedTechniques = koreanTechniques.map(convertKoreanToTechnique);\n\n // Also include archetype-specific special techniques\n const archetypeTechniques = getTechniquesForArchetype(archetype);\n\n // Filter archetype techniques to only include those matching current stance or no stance requirement\n const filteredArchetypeTechniques = archetypeTechniques.filter(\n (tech) => !tech.requiredStance || tech.requiredStance === stance,\n );\n\n // Combine both sets, prioritizing stance techniques\n const allTechniques = [\n ...convertedTechniques,\n ...filteredArchetypeTechniques,\n ];\n\n // Limit to maximum 10 techniques (keyboard shortcuts Q-E-R-T-Y-F-G-Z-X-C)\n const limitedTechniques = allTechniques.slice(0, 10);\n\n // Assign keyboard shortcuts using conflict-free keys around WASD\n const keyboardShortcuts = [\n \"Q\",\n \"E\",\n \"R\",\n \"T\",\n \"Y\",\n \"F\",\n \"G\",\n \"Z\",\n \"X\",\n \"C\",\n ] as const;\n return limitedTechniques.map((tech, index) => ({\n ...tech,\n keyboardShortcut: keyboardShortcuts[index] as TechniqueKey,\n }));\n}\n\n/**\n * Get a specific technique by ID.\n *\n * @param techniqueId - Unique technique identifier\n * @returns Technique if found, undefined otherwise\n *\n * @public\n */\nexport function getTechniqueById(techniqueId: string): Technique | undefined {\n const allTechniques = [\n ...MUSA_TECHNIQUES,\n ...AMSALJA_TECHNIQUES,\n ...HACKER_TECHNIQUES,\n ...JEONGBO_YOWON_TECHNIQUES,\n ...JOJIK_POKRYEOKBAE_TECHNIQUES,\n ];\n\n return allTechniques.find((tech) => tech.id === techniqueId);\n}\n\nexport default {\n getTechniquesForArchetype,\n getTechniquesForStanceAndArchetype,\n getTechniqueById,\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useActionFeedback.js","names":[],"sources":["../../src/hooks/useActionFeedback.ts"],"sourcesContent":["/**\n * useActionFeedback Hook - Player Action Feedback State Management\n * \n * Manages state for floating damage numbers, combo counter, technique names,\n * and action indicators (Perfect, Critical, Blocked, Dodged).\n *\n * @module hooks/useActionFeedback\n * @category Combat UI\n * @korean 액션피드백\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Position } from \"../types\";\n\n/**\n * Types of action feedback indicators\n */\nexport type ActionFeedbackType = \n | \"perfect\"\n | \"critical\"\n | \"blocked\"\n | \"dodged\"\n | \"technique\"\n | \"combo_milestone\";\n\n/**\n * Damage number type for color coding\n */\nexport type DamageType = \"normal\" | \"critical\" | \"vital\";\n\n/**\n * Represents a floating damage number\n */\nexport interface DamageNumber {\n readonly id: string;\n readonly damage: number;\n readonly position: Position;\n readonly type: DamageType;\n readonly timestamp: number;\n}\n\n/**\n * Represents an action feedback indicator\n */\nexport interface ActionFeedback {\n readonly id: string;\n readonly type: ActionFeedbackType;\n readonly text: string;\n readonly textKorean: string;\n readonly position: Position;\n readonly timestamp: number;\n}\n\n/**\n * Action feedback state\n */\nexport interface ActionFeedbackState {\n readonly damageNumbers: DamageNumber[];\n readonly actionFeedbacks: ActionFeedback[];\n readonly comboCount: number;\n readonly lastHitTime: number;\n readonly currentTechnique: { korean: string; english: string } | null;\n readonly techniqueShowTime: number;\n}\n\n/**\n * Action feedback actions interface\n */\nexport interface ActionFeedbackActions {\n readonly addDamageNumber: (damage: number, position: Position, type?: DamageType) => void;\n readonly addActionFeedback: (type: ActionFeedbackType, text: string, textKorean: string, position: Position) => void;\n readonly incrementCombo: () => void;\n readonly resetCombo: () => void;\n readonly showTechnique: (korean: string, english: string) => void;\n readonly hideTechnique: () => void;\n readonly clearExpired: () => void;\n}\n\n/**\n * Configuration for useActionFeedback hook\n */\nexport interface UseActionFeedbackConfig {\n /** Duration in ms for damage numbers to display (default: 1500) */\n readonly damageNumberDuration?: number;\n /** Duration in ms for action feedback to display (default: 1200) */\n readonly actionFeedbackDuration?: number;\n /** Duration in ms for technique name to display (default: 2000) */\n readonly techniqueDuration?: number;\n /** Duration in ms before combo resets after no hits (default: 2000) */\n readonly comboResetTime?: number;\n}\n\n/** Default configuration */\nconst DEFAULT_CONFIG: Required<UseActionFeedbackConfig> = {\n damageNumberDuration: 1500,\n actionFeedbackDuration: 1200,\n techniqueDuration: 2000,\n comboResetTime: 2000,\n};\n\n/**\n * useActionFeedback Hook\n * \n * Manages combat action feedback including:\n * - Floating damage numbers with color coding (normal, critical, vital)\n * - Combo counter with automatic reset\n * - Technique name display (Korean | English)\n * - Action indicators (Perfect, Critical, Blocked, Dodged)\n *\n * @param config - Optional configuration for durations and timing\n * @returns Action feedback state and actions\n *\n * @example\n * ```typescript\n * const { state, actions } = useActionFeedback({\n * damageNumberDuration: 1500,\n * comboResetTime: 2000,\n * });\n *\n * // Add damage number\n * actions.addDamageNumber(25, { x: 100, y: 200 }, 'critical');\n *\n * // Show technique name\n * actions.showTechnique('천둥벽력', 'Thunder Strike');\n *\n * // Increment combo\n * actions.incrementCombo();\n * ```\n */\nexport function useActionFeedback(config: UseActionFeedbackConfig = {}): {\n state: ActionFeedbackState;\n actions: ActionFeedbackActions;\n} {\n const {\n damageNumberDuration,\n actionFeedbackDuration,\n techniqueDuration,\n comboResetTime,\n } = { ...DEFAULT_CONFIG, ...config };\n\n // State\n const [damageNumbers, setDamageNumbers] = useState<DamageNumber[]>([]);\n const [actionFeedbacks, setActionFeedbacks] = useState<ActionFeedback[]>([]);\n const [comboCount, setComboCount] = useState(0);\n const [lastHitTime, setLastHitTime] = useState(0);\n const [currentTechnique, setCurrentTechnique] = useState<{ korean: string; english: string } | null>(null);\n const [techniqueShowTime, setTechniqueShowTime] = useState(0);\n\n // Refs for timers\n const comboResetTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const techniqueTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const cleanupIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const idCounterRef = useRef(0);\n\n // Generate unique ID using counter and timestamp for guaranteed uniqueness\n const generateId = useCallback(() => {\n idCounterRef.current += 1;\n return `feedback_${Date.now()}_${idCounterRef.current}`;\n }, []);\n\n // Add damage number\n const addDamageNumber = useCallback((\n damage: number,\n position: Position,\n type: DamageType = \"normal\"\n ) => {\n const damageNumber: DamageNumber = {\n id: generateId(),\n damage,\n position,\n type,\n timestamp: Date.now(),\n };\n setDamageNumbers(prev => [...prev, damageNumber]);\n }, [generateId]);\n\n // Add action feedback\n const addActionFeedback = useCallback((\n type: ActionFeedbackType,\n text: string,\n textKorean: string,\n position: Position\n ) => {\n const feedback: ActionFeedback = {\n id: generateId(),\n type,\n text,\n textKorean,\n position,\n timestamp: Date.now(),\n };\n setActionFeedbacks(prev => [...prev, feedback]);\n }, [generateId]);\n\n // Increment combo counter\n const incrementCombo = useCallback(() => {\n setComboCount(prev => prev + 1);\n setLastHitTime(Date.now());\n\n // Clear existing reset timer\n if (comboResetTimerRef.current) {\n clearTimeout(comboResetTimerRef.current);\n }\n\n // Set new reset timer\n comboResetTimerRef.current = setTimeout(() => {\n setComboCount(0);\n }, comboResetTime);\n }, [comboResetTime]);\n\n // Reset combo counter\n const resetCombo = useCallback(() => {\n setComboCount(0);\n if (comboResetTimerRef.current) {\n clearTimeout(comboResetTimerRef.current);\n comboResetTimerRef.current = null;\n }\n }, []);\n\n // Show technique name\n const showTechnique = useCallback((korean: string, english: string) => {\n setCurrentTechnique({ korean, english });\n setTechniqueShowTime(Date.now());\n\n // Clear existing timer\n if (techniqueTimerRef.current) {\n clearTimeout(techniqueTimerRef.current);\n }\n\n // Set hide timer\n techniqueTimerRef.current = setTimeout(() => {\n setCurrentTechnique(null);\n }, techniqueDuration);\n }, [techniqueDuration]);\n\n // Hide technique name\n const hideTechnique = useCallback(() => {\n setCurrentTechnique(null);\n if (techniqueTimerRef.current) {\n clearTimeout(techniqueTimerRef.current);\n techniqueTimerRef.current = null;\n }\n }, []);\n\n // Clear expired items\n const clearExpired = useCallback(() => {\n const now = Date.now();\n\n setDamageNumbers(prev =>\n prev.filter(d => now - d.timestamp < damageNumberDuration)\n );\n\n setActionFeedbacks(prev =>\n prev.filter(f => now - f.timestamp < actionFeedbackDuration)\n );\n }, [damageNumberDuration, actionFeedbackDuration]);\n\n // Setup cleanup interval\n useEffect(() => {\n cleanupIntervalRef.current = setInterval(clearExpired, 100);\n\n return () => {\n if (cleanupIntervalRef.current) {\n clearInterval(cleanupIntervalRef.current);\n }\n if (comboResetTimerRef.current) {\n clearTimeout(comboResetTimerRef.current);\n }\n if (techniqueTimerRef.current) {\n clearTimeout(techniqueTimerRef.current);\n }\n };\n }, [clearExpired]);\n\n return {\n state: {\n damageNumbers,\n actionFeedbacks,\n comboCount,\n lastHitTime,\n currentTechnique,\n techniqueShowTime,\n },\n actions: {\n addDamageNumber,\n addActionFeedback,\n incrementCombo,\n resetCombo,\n showTechnique,\n hideTechnique,\n clearExpired,\n },\n };\n}\n\nexport default useActionFeedback;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useActionFeedback.js","names":[],"sources":["../../src/hooks/useActionFeedback.ts"],"sourcesContent":["/**\n * useActionFeedback Hook - Player Action Feedback State Management\n * \n * Manages state for floating damage numbers, combo counter, technique names,\n * and action indicators (Perfect, Critical, Blocked, Dodged).\n *\n * @module hooks/useActionFeedback\n * @category Combat UI\n * @korean 액션피드백\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Position } from \"../types\";\n\n/**\n * Types of action feedback indicators\n */\nexport type ActionFeedbackType = \n | \"perfect\"\n | \"critical\"\n | \"blocked\"\n | \"dodged\"\n | \"technique\"\n | \"combo_milestone\";\n\n/**\n * Damage number type for color coding\n */\nexport type DamageType = \"normal\" | \"critical\" | \"vital\";\n\n/**\n * Represents a floating damage number\n */\nexport interface DamageNumber {\n readonly id: string;\n readonly damage: number;\n readonly position: Position;\n readonly type: DamageType;\n readonly timestamp: number;\n}\n\n/**\n * Represents an action feedback indicator\n */\nexport interface ActionFeedback {\n readonly id: string;\n readonly type: ActionFeedbackType;\n readonly text: string;\n readonly textKorean: string;\n readonly position: Position;\n readonly timestamp: number;\n}\n\n/**\n * Action feedback state\n */\nexport interface ActionFeedbackState {\n readonly damageNumbers: DamageNumber[];\n readonly actionFeedbacks: ActionFeedback[];\n readonly comboCount: number;\n readonly lastHitTime: number;\n readonly currentTechnique: { korean: string; english: string } | null;\n readonly techniqueShowTime: number;\n}\n\n/**\n * Action feedback actions interface\n */\nexport interface ActionFeedbackActions {\n readonly addDamageNumber: (damage: number, position: Position, type?: DamageType) => void;\n readonly addActionFeedback: (type: ActionFeedbackType, text: string, textKorean: string, position: Position) => void;\n readonly incrementCombo: () => void;\n readonly resetCombo: () => void;\n readonly showTechnique: (korean: string, english: string) => void;\n readonly hideTechnique: () => void;\n readonly clearExpired: () => void;\n}\n\n/**\n * Configuration for useActionFeedback hook\n */\nexport interface UseActionFeedbackConfig {\n /** Duration in ms for damage numbers to display (default: 1500) */\n readonly damageNumberDuration?: number;\n /** Duration in ms for action feedback to display (default: 1200) */\n readonly actionFeedbackDuration?: number;\n /** Duration in ms for technique name to display (default: 2000) */\n readonly techniqueDuration?: number;\n /** Duration in ms before combo resets after no hits (default: 2000) */\n readonly comboResetTime?: number;\n}\n\n/** Default configuration */\nconst DEFAULT_CONFIG: Required<UseActionFeedbackConfig> = {\n damageNumberDuration: 1500,\n actionFeedbackDuration: 1200,\n techniqueDuration: 2000,\n comboResetTime: 2000,\n};\n\n/**\n * useActionFeedback Hook\n * \n * Manages combat action feedback including:\n * - Floating damage numbers with color coding (normal, critical, vital)\n * - Combo counter with automatic reset\n * - Technique name display (Korean | English)\n * - Action indicators (Perfect, Critical, Blocked, Dodged)\n *\n * @param config - Optional configuration for durations and timing\n * @returns Action feedback state and actions\n *\n * @example\n * ```typescript\n * const { state, actions } = useActionFeedback({\n * damageNumberDuration: 1500,\n * comboResetTime: 2000,\n * });\n *\n * // Add damage number\n * actions.addDamageNumber(25, { x: 100, y: 200 }, 'critical');\n *\n * // Show technique name\n * actions.showTechnique('천둥벽력', 'Thunder Strike');\n *\n * // Increment combo\n * actions.incrementCombo();\n * ```\n */\nexport function useActionFeedback(config: UseActionFeedbackConfig = {}): {\n state: ActionFeedbackState;\n actions: ActionFeedbackActions;\n} {\n const {\n damageNumberDuration,\n actionFeedbackDuration,\n techniqueDuration,\n comboResetTime,\n } = { ...DEFAULT_CONFIG, ...config };\n\n // State\n const [damageNumbers, setDamageNumbers] = useState<DamageNumber[]>([]);\n const [actionFeedbacks, setActionFeedbacks] = useState<ActionFeedback[]>([]);\n const [comboCount, setComboCount] = useState(0);\n const [lastHitTime, setLastHitTime] = useState(0);\n const [currentTechnique, setCurrentTechnique] = useState<{ korean: string; english: string } | null>(null);\n const [techniqueShowTime, setTechniqueShowTime] = useState(0);\n\n // Refs for timers\n const comboResetTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const techniqueTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const cleanupIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const idCounterRef = useRef(0);\n\n // Generate unique ID using counter and timestamp for guaranteed uniqueness\n const generateId = useCallback(() => {\n idCounterRef.current += 1;\n return `feedback_${Date.now()}_${idCounterRef.current}`;\n }, []);\n\n // Add damage number\n const addDamageNumber = useCallback((\n damage: number,\n position: Position,\n type: DamageType = \"normal\"\n ) => {\n const damageNumber: DamageNumber = {\n id: generateId(),\n damage,\n position,\n type,\n timestamp: Date.now(),\n };\n setDamageNumbers(prev => [...prev, damageNumber]);\n }, [generateId]);\n\n // Add action feedback\n const addActionFeedback = useCallback((\n type: ActionFeedbackType,\n text: string,\n textKorean: string,\n position: Position\n ) => {\n const feedback: ActionFeedback = {\n id: generateId(),\n type,\n text,\n textKorean,\n position,\n timestamp: Date.now(),\n };\n setActionFeedbacks(prev => [...prev, feedback]);\n }, [generateId]);\n\n // Increment combo counter\n const incrementCombo = useCallback(() => {\n setComboCount(prev => prev + 1);\n setLastHitTime(Date.now());\n\n // Clear existing reset timer\n if (comboResetTimerRef.current) {\n clearTimeout(comboResetTimerRef.current);\n }\n\n // Set new reset timer\n comboResetTimerRef.current = setTimeout(() => {\n setComboCount(0);\n }, comboResetTime);\n }, [comboResetTime]);\n\n // Reset combo counter\n const resetCombo = useCallback(() => {\n setComboCount(0);\n if (comboResetTimerRef.current) {\n clearTimeout(comboResetTimerRef.current);\n comboResetTimerRef.current = null;\n }\n }, []);\n\n // Show technique name\n const showTechnique = useCallback((korean: string, english: string) => {\n setCurrentTechnique({ korean, english });\n setTechniqueShowTime(Date.now());\n\n // Clear existing timer\n if (techniqueTimerRef.current) {\n clearTimeout(techniqueTimerRef.current);\n }\n\n // Set hide timer\n techniqueTimerRef.current = setTimeout(() => {\n setCurrentTechnique(null);\n }, techniqueDuration);\n }, [techniqueDuration]);\n\n // Hide technique name\n const hideTechnique = useCallback(() => {\n setCurrentTechnique(null);\n if (techniqueTimerRef.current) {\n clearTimeout(techniqueTimerRef.current);\n techniqueTimerRef.current = null;\n }\n }, []);\n\n // Clear expired items\n const clearExpired = useCallback(() => {\n const now = Date.now();\n\n setDamageNumbers(prev =>\n prev.filter(d => now - d.timestamp < damageNumberDuration)\n );\n\n setActionFeedbacks(prev =>\n prev.filter(f => now - f.timestamp < actionFeedbackDuration)\n );\n }, [damageNumberDuration, actionFeedbackDuration]);\n\n // Setup cleanup interval\n useEffect(() => {\n cleanupIntervalRef.current = setInterval(clearExpired, 100);\n\n return () => {\n if (cleanupIntervalRef.current) {\n clearInterval(cleanupIntervalRef.current);\n }\n if (comboResetTimerRef.current) {\n clearTimeout(comboResetTimerRef.current);\n }\n if (techniqueTimerRef.current) {\n clearTimeout(techniqueTimerRef.current);\n }\n };\n }, [clearExpired]);\n\n return {\n state: {\n damageNumbers,\n actionFeedbacks,\n comboCount,\n lastHitTime,\n currentTechnique,\n techniqueShowTime,\n },\n actions: {\n addDamageNumber,\n addActionFeedback,\n incrementCombo,\n resetCombo,\n showTechnique,\n hideTechnique,\n clearExpired,\n },\n };\n}\n\nexport default useActionFeedback;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBalanceAnimations.js","names":[],"sources":["../../src/hooks/useBalanceAnimations.ts"],"sourcesContent":["/**\n * useBalanceAnimations - Shared hook for balance state visual effects\n *\n * Manages sway, stumble, and lean animations based on player balance state.\n * Reduces code duplication in skeletal animation components.\n *\n * @module hooks/useBalanceAnimations\n * @category Hooks\n * @korean 균형애니메이션훅\n */\n\nimport { useRef, useState } from \"react\";\nimport type { BalanceState } from \"../types/player-visual\";\n\n/**\n * Animation constants for balance state sway effects.\n * Defines intensity, speed, and lean parameters for visual feedback.\n * @korean 균형상태애니메이션상수\n */\nconst BALANCE_STATE_ANIMATION_CONSTANTS = {\n SHAKEN: {\n swayIntensity: 0.02, // 2% subtle sway\n swaySpeed: 2, // Hz frequency\n },\n VULNERABLE: {\n swayIntensity: 0.04, // 4% moderate sway\n swaySpeed: 3, // Hz frequency\n },\n HELPLESS: {\n stumbleIntensity: 0.08, // 8% pronounced stumble\n stumbleSpeed: 1.5, // Hz frequency (slower, more dramatic)\n leanIntensity: 0.15, // 15° forward lean angle\n lowerStance: -0.15, // Lower Y position for stumbling effect\n },\n SWAY_THRESHOLD: 0.001, // Minimum sway to consider significant\n} as const;\n\n/**\n * Checks if there is significant sway that requires animation updates.\n *\n * @param swayPosition - Current sway position [x, y, z]\n * @param helplessRotation - Current helpless rotation angle\n * @returns True if sway is above threshold\n * @korean 의미있는흔들림확인\n */\nconst hasSignificantSway = (\n swayPosition: [number, number, number],\n helplessRotation: number\n): boolean => {\n return (\n Math.abs(swayPosition[0]) >\n BALANCE_STATE_ANIMATION_CONSTANTS.SWAY_THRESHOLD ||\n Math.abs(swayPosition[1]) >\n BALANCE_STATE_ANIMATION_CONSTANTS.SWAY_THRESHOLD ||\n Math.abs(helplessRotation) >\n BALANCE_STATE_ANIMATION_CONSTANTS.SWAY_THRESHOLD\n );\n};\n\n/**\n * Options for useBalanceAnimations hook\n * @korean 균형애니메이션훅옵션\n */\nexport interface UseBalanceAnimationsOptions {\n /** Current balance state */\n readonly balance?: BalanceState;\n}\n\n/**\n * Return type for useBalanceAnimations hook\n * @korean 균형애니메이션훅반환타입\n */\nexport interface UseBalanceAnimationsReturn {\n /** Current sway position offset [x, y, z] */\n readonly swayPosition: [number, number, number];\n /** Current helpless rotation (forward lean) */\n readonly helplessRotation: number;\n /** Update balance animations (call in useFrame) */\n readonly updateBalanceAnimations: (delta: number, frameCounter: number) => void;\n}\n\n/**\n * useBalanceAnimations hook\n *\n * Manages balance state visual effects including sway, stumble, and lean\n * animations. Updates at 60fps with periodic state syncs to reduce re-renders.\n *\n * @param options - Balance animation options\n * @returns Balance animation state and update function\n *\n * @example\n * ```tsx\n * const { swayPosition, helplessRotation, updateBalanceAnimations } =\n * useBalanceAnimations({\n * balance: \"VULNERABLE\",\n * });\n *\n * // In useFrame callback\n * let frameCounter = 0;\n * useFrame((_, delta) => {\n * frameCounter = (frameCounter + 1) % 10;\n * updateBalanceAnimations(delta, frameCounter);\n * });\n *\n * // Apply to character group in render:\n * // position={swayPosition} rotation={[helplessRotation, 0, 0]}\n * ```\n *\n * @korean 균형애니메이션훅\n */\nexport function useBalanceAnimations(\n options: UseBalanceAnimationsOptions\n): UseBalanceAnimationsReturn {\n const { balance = \"READY\" } = options;\n\n // Sway time ref for animation\n const swayTimeRef = useRef(0);\n\n // Sway position and rotation states\n const [swayPosition, setSwayPosition] = useState<[number, number, number]>([\n 0, 0, 0,\n ]);\n const [helplessRotation, setHelplessRotation] = useState<number>(0);\n\n // Update balance animations (called at 60fps in useFrame)\n const updateBalanceAnimations = (\n delta: number,\n frameCounter: number\n ): void => {\n if (balance === \"HELPLESS\") {\n // Helpless state: pronounced stumbling motion\n swayTimeRef.current += delta;\n\n const { stumbleIntensity, stumbleSpeed, leanIntensity, lowerStance } =\n BALANCE_STATE_ANIMATION_CONSTANTS.HELPLESS;\n\n const swayX =\n Math.sin(swayTimeRef.current * stumbleSpeed) * stumbleIntensity;\n const swayY =\n Math.cos(swayTimeRef.current * stumbleSpeed * 0.5) *\n stumbleIntensity *\n 0.3 +\n lowerStance;\n const leanAngle =\n Math.sin(swayTimeRef.current * stumbleSpeed * 0.7) * leanIntensity;\n\n // Update periodically to reduce React re-renders\n if (frameCounter % 2 === 0) {\n setSwayPosition([swayX, swayY, 0]);\n setHelplessRotation(leanAngle);\n }\n } else if (balance === \"SHAKEN\" || balance === \"VULNERABLE\") {\n // Shaken/Vulnerable state: subtle sway\n swayTimeRef.current += delta;\n\n const animConfig =\n balance === \"SHAKEN\"\n ? BALANCE_STATE_ANIMATION_CONSTANTS.SHAKEN\n : BALANCE_STATE_ANIMATION_CONSTANTS.VULNERABLE;\n\n const swayX =\n Math.sin(swayTimeRef.current * animConfig.swaySpeed) *\n animConfig.swayIntensity;\n const swayY =\n Math.cos(swayTimeRef.current * animConfig.swaySpeed * 0.8) *\n animConfig.swayIntensity *\n 0.5;\n\n // Update sway position periodically\n if (frameCounter % 2 === 0) {\n setSwayPosition([swayX, swayY, 0]);\n setHelplessRotation(0);\n }\n } else {\n // Smoothly return to neutral position\n if (\n frameCounter % 2 === 0 &&\n hasSignificantSway(swayPosition, helplessRotation)\n ) {\n setSwayPosition([swayPosition[0] * 0.95, swayPosition[1] * 0.95, 0]);\n setHelplessRotation(helplessRotation * 0.95);\n }\n\n // Reset sway time when not swaying\n if (!hasSignificantSway(swayPosition, helplessRotation)) {\n swayTimeRef.current = 0;\n }\n }\n };\n\n return {\n swayPosition,\n helplessRotation,\n updateBalanceAnimations,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAmBA,IAAM,oCAAoC;CACxC,QAAQ;EACN,eAAe;EACf,WAAW;EACZ;CACD,YAAY;EACV,eAAe;EACf,WAAW;EACZ;CACD,UAAU;EACR,kBAAkB;EAClB,cAAc;EACd,eAAe;EACf,aAAa;EACd;CACD,gBAAgB;CACjB;;;;;;;;;AAUD,IAAM,sBACJ,cACA,qBACY;
|
|
1
|
+
{"version":3,"file":"useBalanceAnimations.js","names":[],"sources":["../../src/hooks/useBalanceAnimations.ts"],"sourcesContent":["/**\n * useBalanceAnimations - Shared hook for balance state visual effects\n *\n * Manages sway, stumble, and lean animations based on player balance state.\n * Reduces code duplication in skeletal animation components.\n *\n * @module hooks/useBalanceAnimations\n * @category Hooks\n * @korean 균형애니메이션훅\n */\n\nimport { useRef, useState } from \"react\";\nimport type { BalanceState } from \"../types/player-visual\";\n\n/**\n * Animation constants for balance state sway effects.\n * Defines intensity, speed, and lean parameters for visual feedback.\n * @korean 균형상태애니메이션상수\n */\nconst BALANCE_STATE_ANIMATION_CONSTANTS = {\n SHAKEN: {\n swayIntensity: 0.02, // 2% subtle sway\n swaySpeed: 2, // Hz frequency\n },\n VULNERABLE: {\n swayIntensity: 0.04, // 4% moderate sway\n swaySpeed: 3, // Hz frequency\n },\n HELPLESS: {\n stumbleIntensity: 0.08, // 8% pronounced stumble\n stumbleSpeed: 1.5, // Hz frequency (slower, more dramatic)\n leanIntensity: 0.15, // 15° forward lean angle\n lowerStance: -0.15, // Lower Y position for stumbling effect\n },\n SWAY_THRESHOLD: 0.001, // Minimum sway to consider significant\n} as const;\n\n/**\n * Checks if there is significant sway that requires animation updates.\n *\n * @param swayPosition - Current sway position [x, y, z]\n * @param helplessRotation - Current helpless rotation angle\n * @returns True if sway is above threshold\n * @korean 의미있는흔들림확인\n */\nconst hasSignificantSway = (\n swayPosition: [number, number, number],\n helplessRotation: number\n): boolean => {\n return (\n Math.abs(swayPosition[0]) >\n BALANCE_STATE_ANIMATION_CONSTANTS.SWAY_THRESHOLD ||\n Math.abs(swayPosition[1]) >\n BALANCE_STATE_ANIMATION_CONSTANTS.SWAY_THRESHOLD ||\n Math.abs(helplessRotation) >\n BALANCE_STATE_ANIMATION_CONSTANTS.SWAY_THRESHOLD\n );\n};\n\n/**\n * Options for useBalanceAnimations hook\n * @korean 균형애니메이션훅옵션\n */\nexport interface UseBalanceAnimationsOptions {\n /** Current balance state */\n readonly balance?: BalanceState;\n}\n\n/**\n * Return type for useBalanceAnimations hook\n * @korean 균형애니메이션훅반환타입\n */\nexport interface UseBalanceAnimationsReturn {\n /** Current sway position offset [x, y, z] */\n readonly swayPosition: [number, number, number];\n /** Current helpless rotation (forward lean) */\n readonly helplessRotation: number;\n /** Update balance animations (call in useFrame) */\n readonly updateBalanceAnimations: (delta: number, frameCounter: number) => void;\n}\n\n/**\n * useBalanceAnimations hook\n *\n * Manages balance state visual effects including sway, stumble, and lean\n * animations. Updates at 60fps with periodic state syncs to reduce re-renders.\n *\n * @param options - Balance animation options\n * @returns Balance animation state and update function\n *\n * @example\n * ```tsx\n * const { swayPosition, helplessRotation, updateBalanceAnimations } =\n * useBalanceAnimations({\n * balance: \"VULNERABLE\",\n * });\n *\n * // In useFrame callback\n * let frameCounter = 0;\n * useFrame((_, delta) => {\n * frameCounter = (frameCounter + 1) % 10;\n * updateBalanceAnimations(delta, frameCounter);\n * });\n *\n * // Apply to character group in render:\n * // position={swayPosition} rotation={[helplessRotation, 0, 0]}\n * ```\n *\n * @korean 균형애니메이션훅\n */\nexport function useBalanceAnimations(\n options: UseBalanceAnimationsOptions\n): UseBalanceAnimationsReturn {\n const { balance = \"READY\" } = options;\n\n // Sway time ref for animation\n const swayTimeRef = useRef(0);\n\n // Sway position and rotation states\n const [swayPosition, setSwayPosition] = useState<[number, number, number]>([\n 0, 0, 0,\n ]);\n const [helplessRotation, setHelplessRotation] = useState<number>(0);\n\n // Update balance animations (called at 60fps in useFrame)\n const updateBalanceAnimations = (\n delta: number,\n frameCounter: number\n ): void => {\n if (balance === \"HELPLESS\") {\n // Helpless state: pronounced stumbling motion\n swayTimeRef.current += delta;\n\n const { stumbleIntensity, stumbleSpeed, leanIntensity, lowerStance } =\n BALANCE_STATE_ANIMATION_CONSTANTS.HELPLESS;\n\n const swayX =\n Math.sin(swayTimeRef.current * stumbleSpeed) * stumbleIntensity;\n const swayY =\n Math.cos(swayTimeRef.current * stumbleSpeed * 0.5) *\n stumbleIntensity *\n 0.3 +\n lowerStance;\n const leanAngle =\n Math.sin(swayTimeRef.current * stumbleSpeed * 0.7) * leanIntensity;\n\n // Update periodically to reduce React re-renders\n if (frameCounter % 2 === 0) {\n setSwayPosition([swayX, swayY, 0]);\n setHelplessRotation(leanAngle);\n }\n } else if (balance === \"SHAKEN\" || balance === \"VULNERABLE\") {\n // Shaken/Vulnerable state: subtle sway\n swayTimeRef.current += delta;\n\n const animConfig =\n balance === \"SHAKEN\"\n ? BALANCE_STATE_ANIMATION_CONSTANTS.SHAKEN\n : BALANCE_STATE_ANIMATION_CONSTANTS.VULNERABLE;\n\n const swayX =\n Math.sin(swayTimeRef.current * animConfig.swaySpeed) *\n animConfig.swayIntensity;\n const swayY =\n Math.cos(swayTimeRef.current * animConfig.swaySpeed * 0.8) *\n animConfig.swayIntensity *\n 0.5;\n\n // Update sway position periodically\n if (frameCounter % 2 === 0) {\n setSwayPosition([swayX, swayY, 0]);\n setHelplessRotation(0);\n }\n } else {\n // Smoothly return to neutral position\n if (\n frameCounter % 2 === 0 &&\n hasSignificantSway(swayPosition, helplessRotation)\n ) {\n setSwayPosition([swayPosition[0] * 0.95, swayPosition[1] * 0.95, 0]);\n setHelplessRotation(helplessRotation * 0.95);\n }\n\n // Reset sway time when not swaying\n if (!hasSignificantSway(swayPosition, helplessRotation)) {\n swayTimeRef.current = 0;\n }\n }\n };\n\n return {\n swayPosition,\n helplessRotation,\n updateBalanceAnimations,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAmBA,IAAM,oCAAoC;CACxC,QAAQ;EACN,eAAe;EACf,WAAW;EACZ;CACD,YAAY;EACV,eAAe;EACf,WAAW;EACZ;CACD,UAAU;EACR,kBAAkB;EAClB,cAAc;EACd,eAAe;EACf,aAAa;EACd;CACD,gBAAgB;CACjB;;;;;;;;;AAUD,IAAM,sBACJ,cACA,qBACY;CACZ,OACE,KAAK,IAAI,aAAa,GAAG,GACvB,kCAAkC,kBACpC,KAAK,IAAI,aAAa,GAAG,GACvB,kCAAkC,kBACpC,KAAK,IAAI,iBAAiB,GACxB,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDxC,SAAgB,qBACd,SAC4B;CAC5B,MAAM,EAAE,UAAU,YAAY;CAG9B,MAAM,cAAc,OAAO,EAAE;CAG7B,MAAM,CAAC,cAAc,mBAAmB,SAAmC;EACzE;EAAG;EAAG;EACP,CAAC;CACF,MAAM,CAAC,kBAAkB,uBAAuB,SAAiB,EAAE;CAGnE,MAAM,2BACJ,OACA,iBACS;EACT,IAAI,YAAY,YAAY;GAE1B,YAAY,WAAW;GAEvB,MAAM,EAAE,kBAAkB,cAAc,eAAe,gBACrD,kCAAkC;GAEpC,MAAM,QACJ,KAAK,IAAI,YAAY,UAAU,aAAa,GAAG;GACjD,MAAM,QACJ,KAAK,IAAI,YAAY,UAAU,eAAe,GAAI,GAChD,mBACA,KACF;GACF,MAAM,YACJ,KAAK,IAAI,YAAY,UAAU,eAAe,GAAI,GAAG;GAGvD,IAAI,eAAe,MAAM,GAAG;IAC1B,gBAAgB;KAAC;KAAO;KAAO;KAAE,CAAC;IAClC,oBAAoB,UAAU;;SAE3B,IAAI,YAAY,YAAY,YAAY,cAAc;GAE3D,YAAY,WAAW;GAEvB,MAAM,aACJ,YAAY,WACR,kCAAkC,SAClC,kCAAkC;GAExC,MAAM,QACJ,KAAK,IAAI,YAAY,UAAU,WAAW,UAAU,GACpD,WAAW;GACb,MAAM,QACJ,KAAK,IAAI,YAAY,UAAU,WAAW,YAAY,GAAI,GAC1D,WAAW,gBACX;GAGF,IAAI,eAAe,MAAM,GAAG;IAC1B,gBAAgB;KAAC;KAAO;KAAO;KAAE,CAAC;IAClC,oBAAoB,EAAE;;SAEnB;GAEL,IACE,eAAe,MAAM,KACrB,mBAAmB,cAAc,iBAAiB,EAClD;IACA,gBAAgB;KAAC,aAAa,KAAK;KAAM,aAAa,KAAK;KAAM;KAAE,CAAC;IACpE,oBAAoB,mBAAmB,IAAK;;GAI9C,IAAI,CAAC,mBAAmB,cAAc,iBAAiB,EACrD,YAAY,UAAU;;;CAK5B,OAAO;EACL;EACA;EACA;EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCombatTimer.js","names":[],"sources":["../../src/hooks/useCombatTimer.ts"],"sourcesContent":["/**\n * useCombatTimer - Hook for managing combat round timer\n *\n * Korean: 전투 라운드 타이머 훅 (Combat Round Timer Hook)\n *\n * Manages countdown timer for combat rounds with:\n * - Pause/resume support\n * - Warning thresholds at 10s and 5s\n * - Audio alerts for warnings\n * - Time's up callback\n *\n * @module hooks/useCombatTimer\n * @category Combat Hooks\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { useAudio } from \"../audio/AudioProvider\";\n\n/**\n * Timer warning level indicating urgency\n */\nexport type TimerWarningLevel = \"none\" | \"warning\" | \"urgent\";\n\n/**\n * Configuration for the combat timer hook\n */\nexport interface UseCombatTimerConfig {\n /** Initial time in seconds */\n readonly initialTime: number;\n /** Whether the timer is paused */\n readonly isPaused: boolean;\n /** Callback when timer reaches 0 */\n readonly onTimeUp: () => void;\n /** Warning threshold in seconds (default: 10) */\n readonly warningThreshold?: number;\n /** Urgent warning threshold in seconds (default: 5) */\n readonly urgentThreshold?: number;\n /** Optional key to force timer reset (e.g., round number) */\n readonly resetKey?: string;\n}\n\n/**\n * Return value from useCombatTimer hook\n */\nexport interface UseCombatTimerReturn {\n /** Current time remaining in seconds */\n readonly timeRemaining: number;\n /** Current warning level */\n readonly warningLevel: TimerWarningLevel;\n /** Whether timer has reached 0 */\n readonly isTimeUp: boolean;\n /** Formatted time string (MM:SS) */\n readonly formattedTime: string;\n}\n\n/**\n * Format seconds into MM:SS format\n * @param seconds - Time in seconds\n * @returns Formatted string (e.g., \"03:45\", \"00:05\")\n */\nfunction formatTime(seconds: number): string {\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = Math.floor(seconds % 60);\n return `${minutes.toString().padStart(2, \"0\")}:${remainingSeconds\n .toString()\n .padStart(2, \"0\")}`;\n}\n\n/**\n * Get warning level based on time remaining\n */\nfunction getWarningLevel(\n timeRemaining: number,\n warningThreshold: number,\n urgentThreshold: number,\n): TimerWarningLevel {\n if (timeRemaining <= urgentThreshold) {\n return \"urgent\";\n }\n if (timeRemaining <= warningThreshold) {\n return \"warning\";\n }\n return \"none\";\n}\n\n/**\n * useCombatTimer Hook\n *\n * Manages combat round countdown timer with pause support and audio warnings.\n *\n * Features:\n * - Counts down from initial time to 0\n * - Pauses/resumes based on isPaused prop\n * - Plays audio warning at warning threshold (default 10s)\n * - Plays urgent audio warning at urgent threshold (default 5s)\n * - Calls onTimeUp when timer reaches 0\n * - Provides formatted time string (MM:SS)\n * - Returns current warning level for UI styling\n *\n * Korean: 전투 라운드 타이머 관리 훅\n *\n * @example\n * ```tsx\n * const { timeRemaining, warningLevel, formattedTime } = useCombatTimer({\n * initialTime: 180, // 3 minutes\n * isPaused: false,\n * onTimeUp: () => handleRoundEnd(),\n * warningThreshold: 10,\n * urgentThreshold: 5,\n * });\n * ```\n */\nexport function useCombatTimer(\n config: UseCombatTimerConfig,\n): UseCombatTimerReturn {\n const {\n initialTime,\n isPaused,\n onTimeUp,\n warningThreshold = 10,\n urgentThreshold = 5,\n resetKey,\n } = config;\n\n const audio = useAudio();\n const [timeRemaining, setTimeRemaining] = useState(initialTime);\n const [isTimeUp, setIsTimeUp] = useState(false);\n const lastWarningRef = useRef<TimerWarningLevel>(\"none\");\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Reset timer when initialTime or resetKey changes (new round)\n useEffect(() => {\n setTimeRemaining(initialTime);\n setIsTimeUp(false);\n lastWarningRef.current = \"none\";\n }, [initialTime, resetKey]);\n\n // Timer countdown logic\n useEffect(() => {\n // Don't run if paused or time is up\n if (isPaused || isTimeUp) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n return;\n }\n\n // Track start time for precise elapsed time calculation\n const startTimeRef = Date.now();\n const startingTimeRemaining = timeRemaining;\n\n // Start interval\n intervalRef.current = setInterval(() => {\n const elapsed = (Date.now() - startTimeRef) / 1000;\n const next = Math.max(0, startingTimeRemaining - elapsed);\n\n setTimeRemaining(next);\n\n // Check if time just reached 0\n if (next <= 0 && !isTimeUp) {\n setIsTimeUp(true);\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n onTimeUp();\n }\n }, 100);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n };\n // timeRemaining is intentionally excluded - we capture the starting value once\n // and count down from there, not restart the interval on every tick\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPaused, isTimeUp, onTimeUp]);\n\n // Warning level calculation\n const warningLevel = getWarningLevel(\n timeRemaining,\n warningThreshold,\n urgentThreshold,\n );\n\n // Audio warnings - timeRemaining checked via warningLevel which captures threshold transitions\n useEffect(() => {\n if (!audio.isAudioReady) return;\n if (isPaused) return;\n\n // Play warning sound at threshold\n if (\n warningLevel === \"warning\" &&\n lastWarningRef.current === \"none\" &&\n timeRemaining <= warningThreshold &&\n timeRemaining > urgentThreshold\n ) {\n audio.playSFX(\"attack_light\"); // Placeholder - will be timer_warning_10s\n lastWarningRef.current = \"warning\";\n }\n\n // Play urgent warning sound at urgent threshold\n if (\n warningLevel === \"urgent\" &&\n lastWarningRef.current !== \"urgent\" &&\n timeRemaining <= urgentThreshold &&\n timeRemaining > 0\n ) {\n audio.playSFX(\"attack_heavy\"); // Placeholder - will be timer_warning_5s\n lastWarningRef.current = \"urgent\";\n }\n }, [\n warningLevel,\n timeRemaining,\n audio,\n isPaused,\n warningThreshold,\n urgentThreshold,\n ]);\n\n // Format time for display\n const formattedTime = formatTime(timeRemaining);\n\n return {\n timeRemaining,\n warningLevel,\n isTimeUp,\n formattedTime,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA4DA,SAAS,WAAW,SAAyB;CAC3C,MAAM,UAAU,KAAK,MAAM,UAAU,GAAG;CACxC,MAAM,mBAAmB,KAAK,MAAM,UAAU,GAAG;
|
|
1
|
+
{"version":3,"file":"useCombatTimer.js","names":[],"sources":["../../src/hooks/useCombatTimer.ts"],"sourcesContent":["/**\n * useCombatTimer - Hook for managing combat round timer\n *\n * Korean: 전투 라운드 타이머 훅 (Combat Round Timer Hook)\n *\n * Manages countdown timer for combat rounds with:\n * - Pause/resume support\n * - Warning thresholds at 10s and 5s\n * - Audio alerts for warnings\n * - Time's up callback\n *\n * @module hooks/useCombatTimer\n * @category Combat Hooks\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { useAudio } from \"../audio/AudioProvider\";\n\n/**\n * Timer warning level indicating urgency\n */\nexport type TimerWarningLevel = \"none\" | \"warning\" | \"urgent\";\n\n/**\n * Configuration for the combat timer hook\n */\nexport interface UseCombatTimerConfig {\n /** Initial time in seconds */\n readonly initialTime: number;\n /** Whether the timer is paused */\n readonly isPaused: boolean;\n /** Callback when timer reaches 0 */\n readonly onTimeUp: () => void;\n /** Warning threshold in seconds (default: 10) */\n readonly warningThreshold?: number;\n /** Urgent warning threshold in seconds (default: 5) */\n readonly urgentThreshold?: number;\n /** Optional key to force timer reset (e.g., round number) */\n readonly resetKey?: string;\n}\n\n/**\n * Return value from useCombatTimer hook\n */\nexport interface UseCombatTimerReturn {\n /** Current time remaining in seconds */\n readonly timeRemaining: number;\n /** Current warning level */\n readonly warningLevel: TimerWarningLevel;\n /** Whether timer has reached 0 */\n readonly isTimeUp: boolean;\n /** Formatted time string (MM:SS) */\n readonly formattedTime: string;\n}\n\n/**\n * Format seconds into MM:SS format\n * @param seconds - Time in seconds\n * @returns Formatted string (e.g., \"03:45\", \"00:05\")\n */\nfunction formatTime(seconds: number): string {\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = Math.floor(seconds % 60);\n return `${minutes.toString().padStart(2, \"0\")}:${remainingSeconds\n .toString()\n .padStart(2, \"0\")}`;\n}\n\n/**\n * Get warning level based on time remaining\n */\nfunction getWarningLevel(\n timeRemaining: number,\n warningThreshold: number,\n urgentThreshold: number,\n): TimerWarningLevel {\n if (timeRemaining <= urgentThreshold) {\n return \"urgent\";\n }\n if (timeRemaining <= warningThreshold) {\n return \"warning\";\n }\n return \"none\";\n}\n\n/**\n * useCombatTimer Hook\n *\n * Manages combat round countdown timer with pause support and audio warnings.\n *\n * Features:\n * - Counts down from initial time to 0\n * - Pauses/resumes based on isPaused prop\n * - Plays audio warning at warning threshold (default 10s)\n * - Plays urgent audio warning at urgent threshold (default 5s)\n * - Calls onTimeUp when timer reaches 0\n * - Provides formatted time string (MM:SS)\n * - Returns current warning level for UI styling\n *\n * Korean: 전투 라운드 타이머 관리 훅\n *\n * @example\n * ```tsx\n * const { timeRemaining, warningLevel, formattedTime } = useCombatTimer({\n * initialTime: 180, // 3 minutes\n * isPaused: false,\n * onTimeUp: () => handleRoundEnd(),\n * warningThreshold: 10,\n * urgentThreshold: 5,\n * });\n * ```\n */\nexport function useCombatTimer(\n config: UseCombatTimerConfig,\n): UseCombatTimerReturn {\n const {\n initialTime,\n isPaused,\n onTimeUp,\n warningThreshold = 10,\n urgentThreshold = 5,\n resetKey,\n } = config;\n\n const audio = useAudio();\n const [timeRemaining, setTimeRemaining] = useState(initialTime);\n const [isTimeUp, setIsTimeUp] = useState(false);\n const lastWarningRef = useRef<TimerWarningLevel>(\"none\");\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Reset timer when initialTime or resetKey changes (new round)\n useEffect(() => {\n setTimeRemaining(initialTime);\n setIsTimeUp(false);\n lastWarningRef.current = \"none\";\n }, [initialTime, resetKey]);\n\n // Timer countdown logic\n useEffect(() => {\n // Don't run if paused or time is up\n if (isPaused || isTimeUp) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n return;\n }\n\n // Track start time for precise elapsed time calculation\n const startTimeRef = Date.now();\n const startingTimeRemaining = timeRemaining;\n\n // Start interval\n intervalRef.current = setInterval(() => {\n const elapsed = (Date.now() - startTimeRef) / 1000;\n const next = Math.max(0, startingTimeRemaining - elapsed);\n\n setTimeRemaining(next);\n\n // Check if time just reached 0\n if (next <= 0 && !isTimeUp) {\n setIsTimeUp(true);\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n onTimeUp();\n }\n }, 100);\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n };\n // timeRemaining is intentionally excluded - we capture the starting value once\n // and count down from there, not restart the interval on every tick\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isPaused, isTimeUp, onTimeUp]);\n\n // Warning level calculation\n const warningLevel = getWarningLevel(\n timeRemaining,\n warningThreshold,\n urgentThreshold,\n );\n\n // Audio warnings - timeRemaining checked via warningLevel which captures threshold transitions\n useEffect(() => {\n if (!audio.isAudioReady) return;\n if (isPaused) return;\n\n // Play warning sound at threshold\n if (\n warningLevel === \"warning\" &&\n lastWarningRef.current === \"none\" &&\n timeRemaining <= warningThreshold &&\n timeRemaining > urgentThreshold\n ) {\n audio.playSFX(\"attack_light\"); // Placeholder - will be timer_warning_10s\n lastWarningRef.current = \"warning\";\n }\n\n // Play urgent warning sound at urgent threshold\n if (\n warningLevel === \"urgent\" &&\n lastWarningRef.current !== \"urgent\" &&\n timeRemaining <= urgentThreshold &&\n timeRemaining > 0\n ) {\n audio.playSFX(\"attack_heavy\"); // Placeholder - will be timer_warning_5s\n lastWarningRef.current = \"urgent\";\n }\n }, [\n warningLevel,\n timeRemaining,\n audio,\n isPaused,\n warningThreshold,\n urgentThreshold,\n ]);\n\n // Format time for display\n const formattedTime = formatTime(timeRemaining);\n\n return {\n timeRemaining,\n warningLevel,\n isTimeUp,\n formattedTime,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA4DA,SAAS,WAAW,SAAyB;CAC3C,MAAM,UAAU,KAAK,MAAM,UAAU,GAAG;CACxC,MAAM,mBAAmB,KAAK,MAAM,UAAU,GAAG;CACjD,OAAO,GAAG,QAAQ,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,iBAC9C,UAAU,CACV,SAAS,GAAG,IAAI;;;;;AAMrB,SAAS,gBACP,eACA,kBACA,iBACmB;CACnB,IAAI,iBAAiB,iBACnB,OAAO;CAET,IAAI,iBAAiB,kBACnB,OAAO;CAET,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BT,SAAgB,eACd,QACsB;CACtB,MAAM,EACJ,aACA,UACA,UACA,mBAAmB,IACnB,kBAAkB,GAClB,aACE;CAEJ,MAAM,QAAQ,UAAU;CACxB,MAAM,CAAC,eAAe,oBAAoB,SAAS,YAAY;CAC/D,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;CAC/C,MAAM,iBAAiB,OAA0B,OAAO;CACxD,MAAM,cAAc,OAA8C,KAAK;CAGvE,gBAAgB;EACd,iBAAiB,YAAY;EAC7B,YAAY,MAAM;EAClB,eAAe,UAAU;IACxB,CAAC,aAAa,SAAS,CAAC;CAG3B,gBAAgB;EAEd,IAAI,YAAY,UAAU;GACxB,IAAI,YAAY,SAAS;IACvB,cAAc,YAAY,QAAQ;IAClC,YAAY,UAAU;;GAExB;;EAIF,MAAM,eAAe,KAAK,KAAK;EAC/B,MAAM,wBAAwB;EAG9B,YAAY,UAAU,kBAAkB;GACtC,MAAM,WAAW,KAAK,KAAK,GAAG,gBAAgB;GAC9C,MAAM,OAAO,KAAK,IAAI,GAAG,wBAAwB,QAAQ;GAEzD,iBAAiB,KAAK;GAGtB,IAAI,QAAQ,KAAK,CAAC,UAAU;IAC1B,YAAY,KAAK;IACjB,IAAI,YAAY,SAAS;KACvB,cAAc,YAAY,QAAQ;KAClC,YAAY,UAAU;;IAExB,UAAU;;KAEX,IAAI;EAEP,aAAa;GACX,IAAI,YAAY,SAAS;IACvB,cAAc,YAAY,QAAQ;IAClC,YAAY,UAAU;;;IAMzB;EAAC;EAAU;EAAU;EAAS,CAAC;CAGlC,MAAM,eAAe,gBACnB,eACA,kBACA,gBACD;CAGD,gBAAgB;EACd,IAAI,CAAC,MAAM,cAAc;EACzB,IAAI,UAAU;EAGd,IACE,iBAAiB,aACjB,eAAe,YAAY,UAC3B,iBAAiB,oBACjB,gBAAgB,iBAChB;GACA,MAAM,QAAQ,eAAe;GAC7B,eAAe,UAAU;;EAI3B,IACE,iBAAiB,YACjB,eAAe,YAAY,YAC3B,iBAAiB,mBACjB,gBAAgB,GAChB;GACA,MAAM,QAAQ,eAAe;GAC7B,eAAe,UAAU;;IAE1B;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CAKF,OAAO;EACL;EACA;EACA;EACA,eANoB,WAAW,cAM/B;EACD"}
|