blacktrigram 0.7.23 → 0.7.24

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ConsciousnessSystem.js","names":[],"sources":["../../../src/systems/combat/ConsciousnessSystem.ts"],"sourcesContent":["/**\n * Consciousness System for managing awareness and cognitive function levels.\n *\n * **Korean**: 의식 시스템 (Consciousness System)\n *\n * Implements consciousness levels based on head trauma, blood flow restriction,\n * and neural damage. Consciousness affects reaction time, targeting precision,\n * and overall combat effectiveness.\n *\n * ## Consciousness Levels\n *\n * - **전투각성 (Combat Alert)**: 100% - Full awareness, optimal combat ability\n * - **혼란상태 (Disoriented)**: 70% - Reduced reaction, vulnerability window\n * - **기절직전 (Stunned)**: 40% - Severe impairment, incapacitation opportunity\n * - **무의식 (Unconscious)**: 0% - Complete incapacitation\n *\n * ## Fall System Integration\n *\n * When consciousness drops below 10%, the system triggers fall animations (낙법).\n * The character loses the ability to stand and collapses to the ground.\n * Fall direction is based on last impact location.\n *\n * @module systems/combat/ConsciousnessSystem\n * @category Combat System\n * @korean 의식시스템\n */\n\nimport { VitalPointCategory } from \"@/types\";\nimport type { TrigramStance } from \"@/types/common\";\nimport { determineFallFromStance } from \"../animation\";\nimport type { FallType } from \"../animation/core/types\";\nimport { PlayerState } from \"../player\";\n\n/**\n * Consciousness levels representing cognitive function and awareness.\n *\n * **Korean**: 의식 수준\n */\nexport enum ConsciousnessLevel {\n /** Full combat awareness (90-100%) */\n COMBAT_ALERT = \"combat_alert\",\n /** Disoriented and vulnerable (50-89%) */\n DISORIENTED = \"disoriented\",\n /** Severely stunned (10-49%) */\n STUNNED = \"stunned\",\n /** Completely unconscious (0-9%) */\n UNCONSCIOUS = \"unconscious\",\n}\n\n/**\n * Effects of consciousness levels on combat performance.\n */\ninterface ConsciousnessEffects {\n /** Consciousness value range */\n readonly range: readonly [number, number];\n /** Reaction time multiplier */\n readonly reactionTimeMultiplier: number;\n /** Accuracy penalty */\n readonly accuracyPenalty: number;\n /** Defense penalty */\n readonly defensePenalty: number;\n /** Can perform actions */\n readonly canAct: boolean;\n /** Vision clarity multiplier */\n readonly visionClarity: number;\n}\n\n/**\n * Consciousness System managing awareness and cognitive function.\n *\n * Tracks consciousness damage from:\n * - Head trauma (strikes to head region)\n * - Neurological vital point hits\n * - Blood flow restriction (vascular hits)\n * - Respiratory disruption\n *\n * Consciousness naturally recovers over time when not taking damage.\n *\n * @example\n * ```typescript\n * const consciousnessSystem = new ConsciousnessSystem();\n *\n * // Apply damage from head strike\n * const newPlayer = consciousnessSystem.applyDamage(\n * player,\n * 15,\n * VitalPointCategory.NEUROLOGICAL\n * );\n *\n * // Check consciousness level\n * const level = consciousnessSystem.getLevel(newPlayer.consciousness);\n * console.log(`Consciousness: ${level}`);\n *\n * // Apply recovery over time\n * const recovered = consciousnessSystem.applyRecovery(newPlayer, 1000);\n * ```\n *\n * @public\n * @korean 의식시스템\n */\nexport class ConsciousnessSystem {\n /**\n * Consciousness level effects and thresholds.\n */\n private readonly levelEffects: Record<\n ConsciousnessLevel,\n ConsciousnessEffects\n > = {\n [ConsciousnessLevel.COMBAT_ALERT]: {\n range: [90, 100],\n reactionTimeMultiplier: 1.0,\n accuracyPenalty: 0.0,\n defensePenalty: 0.0,\n canAct: true,\n visionClarity: 1.0,\n },\n [ConsciousnessLevel.DISORIENTED]: {\n range: [50, 89],\n reactionTimeMultiplier: 1.3, // 30% slower reactions\n accuracyPenalty: 0.2, // -20% accuracy\n defensePenalty: 0.15, // -15% defense\n canAct: true,\n visionClarity: 0.7,\n },\n [ConsciousnessLevel.STUNNED]: {\n range: [20, 49], // Updated: Changed from [10, 49] to [20, 49]\n reactionTimeMultiplier: 2.0, // 2x slower reactions\n accuracyPenalty: 0.5, // -50% accuracy\n defensePenalty: 0.4, // -40% defense\n canAct: true,\n visionClarity: 0.4,\n },\n [ConsciousnessLevel.UNCONSCIOUS]: {\n range: [0, 19], // Updated: Changed from [0, 9] to [0, 19] - incapacitation threshold <20%\n reactionTimeMultiplier: Infinity,\n accuracyPenalty: 1.0, // Complete inability\n defensePenalty: 1.0, // No defense\n canAct: false,\n visionClarity: 0.0,\n },\n };\n\n /**\n * Damage multipliers by vital point category affecting consciousness.\n */\n private readonly categoryMultipliers: Record<string, number> = {\n [VitalPointCategory.NEUROLOGICAL]: 3.0, // Nerve strikes heavily affect consciousness\n [VitalPointCategory.VASCULAR]: 2.0, // Blood flow restriction\n [VitalPointCategory.RESPIRATORY]: 1.5, // Breathing difficulty\n default: 0.5, // Other damage has minor effect\n };\n\n /**\n * Base recovery rate per second.\n */\n private readonly baseRecoveryRate = 5.0; // 5 points per second\n\n /**\n * Incapacitation threshold - consciousness <20% renders player helpless.\n *\n * **Korean**: 무력화한계 (Incapacitation Threshold)\n */\n private readonly incapacitationThreshold = 20;\n\n /**\n * Duration of helplessness when consciousness drops below threshold (3-5 seconds).\n */\n private readonly helplessDuration = {\n min: 3000, // 3 seconds\n max: 5000, // 5 seconds\n };\n\n /**\n * Time without head trauma required for consciousness recovery (5 seconds).\n */\n private readonly noTraumaRecoveryTime = 5000; // 5 seconds\n\n /**\n * Applies consciousness damage from combat.\n *\n * Calculates consciousness reduction based on damage amount and\n * vital point category. Neurological and vascular damage have\n * the highest impact on consciousness.\n *\n * @param player - Current player state\n * @param damage - Base damage amount\n * @param category - Vital point category hit\n * @returns Updated player state with reduced consciousness\n *\n * @example\n * ```typescript\n * // Head strike causes significant consciousness damage\n * const newPlayer = system.applyDamage(\n * player,\n * 20,\n * VitalPointCategory.NEUROLOGICAL\n * );\n * console.log(`Consciousness: ${newPlayer.consciousness}`);\n * ```\n *\n * @public\n * @korean 의식피해적용\n */\n applyDamage(\n player: PlayerState,\n damage: number,\n category?: VitalPointCategory\n ): PlayerState {\n // Get multiplier based on category\n const multiplier = category\n ? this.categoryMultipliers[category] ?? this.categoryMultipliers.default\n : this.categoryMultipliers.default;\n\n // Calculate consciousness damage\n const consciousnessDamage = damage * multiplier;\n\n // Apply damage, clamped to 0-100 range\n const newConsciousness = Math.max(\n 0,\n Math.min(100, player.consciousness - consciousnessDamage)\n );\n\n return {\n ...player,\n consciousness: newConsciousness,\n };\n }\n\n /**\n * Applies consciousness recovery over time.\n *\n * Consciousness naturally recovers when not taking damage.\n * Recovery rate depends on current level - severely stunned\n * players recover more slowly.\n *\n * **Note**: Full recovery only occurs after 5 seconds without head trauma.\n *\n * @param player - Current player state\n * @param deltaTime - Time elapsed in milliseconds\n * @param lastHeadTraumaTime - Timestamp of last head trauma (optional)\n * @returns Updated player state with recovered consciousness\n *\n * @example\n * ```typescript\n * // In game loop (60fps, ~16ms per frame)\n * player = system.applyRecovery(player, 16, player.lastActionTime);\n * ```\n *\n * @public\n * @korean 의식회복\n */\n applyRecovery(\n player: PlayerState,\n deltaTime: number,\n lastHeadTraumaTime?: number\n ): PlayerState {\n // Already at full consciousness\n if (player.consciousness >= 100) {\n return player;\n }\n\n // Check if enough time has passed since last head trauma\n const timeSinceTrauma = lastHeadTraumaTime\n ? Date.now() - lastHeadTraumaTime\n : Infinity;\n\n // Don't recover if head trauma is recent (within 5 seconds)\n if (timeSinceTrauma < this.noTraumaRecoveryTime) {\n return player;\n }\n\n // Calculate recovery based on time\n const deltaSeconds = deltaTime / 1000;\n const level = this.getLevel(player.consciousness);\n\n // Recovery rate modifier based on level\n let recoveryModifier = 1.0;\n if (level === ConsciousnessLevel.STUNNED) {\n recoveryModifier = 0.5; // Slower recovery when stunned\n } else if (level === ConsciousnessLevel.UNCONSCIOUS) {\n recoveryModifier = 0.2; // Very slow recovery when unconscious\n }\n\n const recovery = this.baseRecoveryRate * deltaSeconds * recoveryModifier;\n const newConsciousness = Math.min(100, player.consciousness + recovery);\n\n return {\n ...player,\n consciousness: newConsciousness,\n };\n }\n\n /**\n * Determines consciousness level from consciousness value.\n *\n * Updated thresholds:\n * - 90-100: Combat Alert\n * - 50-89: Disoriented\n * - 20-49: Stunned\n * - 0-19: Unconscious (incapacitation threshold <20%)\n *\n * @param consciousness - Consciousness value (0-100)\n * @returns Current consciousness level\n *\n * @example\n * ```typescript\n * const level = system.getLevel(75);\n * console.log(level); // DISORIENTED\n *\n * const level2 = system.getLevel(15);\n * console.log(level2); // UNCONSCIOUS (below incapacitation threshold)\n * ```\n *\n * @public\n * @korean 의식수준확인\n */\n getLevel(consciousness: number): ConsciousnessLevel {\n if (consciousness >= 90) return ConsciousnessLevel.COMBAT_ALERT;\n if (consciousness >= 50) return ConsciousnessLevel.DISORIENTED;\n if (consciousness >= 20) return ConsciousnessLevel.STUNNED;\n return ConsciousnessLevel.UNCONSCIOUS;\n }\n\n /**\n * Gets effects for a specific consciousness level.\n *\n * @param level - Consciousness level\n * @returns Effects applied at that level\n *\n * @public\n * @korean 의식효과\n */\n getEffects(level: ConsciousnessLevel): ConsciousnessEffects {\n return this.levelEffects[level];\n }\n\n /**\n * Applies consciousness effects to player state.\n *\n * Modifies player stats based on current consciousness level.\n *\n * @param player - Current player state\n * @returns Modified player state with consciousness effects\n *\n * @public\n * @korean 의식효과적용\n */\n applyEffects(player: PlayerState): PlayerState {\n const level = this.getLevel(player.consciousness);\n const effects = this.getEffects(level);\n\n return {\n ...player,\n attackPower: Math.floor(\n player.attackPower * (1 - effects.accuracyPenalty)\n ),\n defense: Math.floor(player.defense * (1 - effects.defensePenalty)),\n technique: Math.floor(player.technique * (1 - effects.accuracyPenalty)),\n isStunned:\n player.isStunned ||\n level === ConsciousnessLevel.UNCONSCIOUS ||\n level === ConsciousnessLevel.STUNNED,\n };\n }\n\n /**\n * Checks if player is at incapacitation threshold.\n *\n * **Korean**: 무력화한계 (Incapacitation Threshold)\n *\n * When consciousness drops below 20%, player becomes helpless for 3-5 seconds.\n *\n * @param player - Current player state\n * @returns True if consciousness is below incapacitation threshold (<20%)\n *\n * @example\n * ```typescript\n * if (system.isAtIncapacitationThreshold(player)) {\n * // Player is helpless, trigger helpless state\n * const helplessDuration = system.getHelplessDuration();\n * console.log(`Player helpless for ${helplessDuration}ms`);\n * }\n * ```\n *\n * @public\n * @korean 무력화한계확인\n */\n isAtIncapacitationThreshold(player: PlayerState): boolean {\n return player.consciousness < this.incapacitationThreshold;\n }\n\n /**\n * Gets random helpless duration when consciousness drops below threshold.\n *\n * Returns a random duration between 3-5 seconds (3000-5000ms).\n *\n * @returns Helpless duration in milliseconds\n *\n * @public\n * @korean 무력화지속시간\n */\n getHelplessDuration(): number {\n return (\n this.helplessDuration.min +\n Math.random() * (this.helplessDuration.max - this.helplessDuration.min)\n );\n }\n\n /**\n * Checks if enough time has passed for consciousness recovery.\n *\n * Consciousness only recovers after 5 seconds without head trauma.\n *\n * @param lastHeadTraumaTime - Timestamp of last head trauma\n * @returns True if recovery is allowed\n *\n * @public\n * @korean 회복가능확인\n */\n canRecover(lastHeadTraumaTime: number): boolean {\n const timeSinceTrauma = Date.now() - lastHeadTraumaTime;\n return timeSinceTrauma >= this.noTraumaRecoveryTime;\n }\n\n /**\n * Checks if player is incapacitated due to consciousness.\n *\n * @param player - Current player state\n * @returns True if player is unconscious\n *\n * @public\n * @korean 무의식확인\n */\n isIncapacitated(player: PlayerState): boolean {\n return (\n this.getLevel(player.consciousness) === ConsciousnessLevel.UNCONSCIOUS\n );\n }\n\n /**\n * Gets bilingual name for consciousness level.\n *\n * @param level - Consciousness level\n * @returns Korean and English level names\n *\n * @public\n * @korean 의식이름\n */\n getLevelName(level: ConsciousnessLevel): { korean: string; english: string } {\n const names: Record<\n ConsciousnessLevel,\n { korean: string; english: string }\n > = {\n [ConsciousnessLevel.COMBAT_ALERT]: {\n korean: \"전투각성\",\n english: \"Combat Alert\",\n },\n [ConsciousnessLevel.DISORIENTED]: {\n korean: \"혼란상태\",\n english: \"Disoriented\",\n },\n [ConsciousnessLevel.STUNNED]: {\n korean: \"기절직전\",\n english: \"Stunned\",\n },\n [ConsciousnessLevel.UNCONSCIOUS]: {\n korean: \"무의식\",\n english: \"Unconscious\",\n },\n };\n\n return names[level];\n }\n\n /**\n * Gets description of consciousness level effects.\n *\n * @param level - Consciousness level\n * @returns Bilingual description\n *\n * @public\n * @korean 의식설명\n */\n getLevelDescription(level: ConsciousnessLevel): {\n korean: string;\n english: string;\n } {\n const descriptions: Record<\n ConsciousnessLevel,\n { korean: string; english: string }\n > = {\n [ConsciousnessLevel.COMBAT_ALERT]: {\n korean: \"완전한 의식과 전투 능력\",\n english: \"Full awareness and combat ability\",\n },\n [ConsciousnessLevel.DISORIENTED]: {\n korean: \"반응 시간 저하 및 혼란\",\n english: \"Reduced reaction time and confusion\",\n },\n [ConsciousnessLevel.STUNNED]: {\n korean: \"심각한 손상, 무력화 위험\",\n english: \"Severe impairment, incapacitation risk\",\n },\n [ConsciousnessLevel.UNCONSCIOUS]: {\n korean: \"완전한 무의식 상태\",\n english: \"Complete unconsciousness\",\n },\n };\n\n return descriptions[level];\n }\n\n /**\n * Gets color indicator for consciousness level (for UI).\n *\n * @param level - Consciousness level\n * @returns Hex color code\n *\n * @public\n * @korean 의식색상\n */\n getLevelColor(level: ConsciousnessLevel): number {\n const colors: Record<ConsciousnessLevel, number> = {\n [ConsciousnessLevel.COMBAT_ALERT]: 0x00ff00, // Green\n [ConsciousnessLevel.DISORIENTED]: 0xffaa00, // Orange\n [ConsciousnessLevel.STUNNED]: 0xff4400, // Red-orange\n [ConsciousnessLevel.UNCONSCIOUS]: 0xff0000, // Red\n };\n\n return colors[level];\n }\n\n /**\n * Checks if consciousness is low enough to trigger fall animation.\n *\n * Falls occur when consciousness drops below 10% (UNCONSCIOUS threshold).\n * This represents complete loss of ability to maintain standing position.\n *\n * Korean terminology:\n * - 의식상실낙법 (Uisik Sangsil Nakbeop): Consciousness loss fall\n * - 기절낙하 (Gijeol Nakha): Knockout collapse\n *\n * @param player - Current player state\n * @returns True if fall animation should trigger\n *\n * @example\n * ```typescript\n * if (consciousnessSystem.shouldTriggerFall(player)) {\n * const fallType = consciousnessSystem.determineFallType(\n * player,\n * lastImpactAngle\n * );\n * animationMachine.transitionTo(FALL_TYPE_TO_ANIMATION[fallType]);\n * }\n * ```\n *\n * @public\n * @korean 의식상실낙법확인\n */\n shouldTriggerFall(player: PlayerState): boolean {\n return player.consciousness < 10; // UNCONSCIOUS threshold\n }\n\n /**\n * Determines fall direction based on last impact and stance.\n *\n * When consciousness is lost, fall direction is determined by:\n * - Last attack angle (if available)\n * - Current stance bias (if no attack data)\n * - Default to backward fall (natural collapse)\n *\n * Korean falling from consciousness loss:\n * - 후방의식상실 (Hubang Uisik Sangsil): Backward consciousness loss fall\n * - 전방기절 (Jeonbang Gijeol): Forward knockout\n *\n * @param player - Current player state\n * @param lastImpactAngle - Angle of last hit (optional)\n * @returns Fall type to use for animation\n *\n * @example\n * ```typescript\n * // Player loses consciousness from frontal head strike\n * const fallType = consciousnessSystem.determineFallType(\n * player,\n * 0 // Front angle\n * );\n * // Returns: 'backward' (knocked back by frontal strike)\n *\n * // Player loses consciousness without specific impact\n * const fallType = consciousnessSystem.determineFallType(player);\n * // Returns: Stance-based fall or 'backward' default\n * ```\n *\n * @public\n * @korean 의식상실낙법결정\n */\n determineFallType(_player: PlayerState, lastImpactAngle?: number): FallType {\n // If we have impact angle, use simple direction logic\n if (lastImpactAngle !== undefined) {\n const normalizedAngle = Math.abs(lastImpactAngle);\n\n // Front impact (0° ±45°) causes backward fall\n if (normalizedAngle < Math.PI / 4) {\n return \"backward\";\n }\n\n // Rear impact (180° ±45°) causes forward fall\n // Since normalizedAngle is in [0, π], any angle > 3π/4 is a rear impact\n if (normalizedAngle > (3 * Math.PI) / 4) {\n return \"forward\";\n }\n\n // Side impacts: at this point normalizedAngle is in (π/4, 3π/4),\n // so lastImpactAngle cannot be 0 or ±π.\n if (lastImpactAngle < 0) {\n return \"side_left\";\n }\n if (lastImpactAngle > 0) {\n return \"side_right\";\n }\n\n // Fallback for exact 0 (or extremely small) angles in case future\n // changes alter the front/rear checks above. We treat this as a\n // natural backward collapse rather than a side fall.\n return \"backward\";\n }\n\n // Default to backward fall (natural collapse from consciousness loss)\n return \"backward\";\n }\n\n /**\n * Determines fall type based on stance when consciousness is lost.\n *\n * Uses stance bias to determine fall direction when consciousness\n * is lost without specific impact data.\n *\n * Korean terminology:\n * - 자세의식상실 (Jase Uisik Sangsil): Stance-based consciousness loss\n *\n * @param stance - Current trigram stance\n * @returns Fall type based on stance characteristics\n *\n * @example\n * ```typescript\n * // Player in Mountain stance (defensive back)\n * const fallType = consciousnessSystem.determineFallTypeFromStance(\n * TrigramStance.GAN\n * );\n * // Returns: 'backward' (Mountain has defensive backward bias)\n * ```\n *\n * @public\n * @korean 자세의식상실낙법\n */\n determineFallTypeFromStance(stance: TrigramStance): FallType {\n return determineFallFromStance(stance, \"backward\");\n }\n}\n\nexport default ConsciousnessSystem;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ConsciousnessSystem.js","names":[],"sources":["../../../src/systems/combat/ConsciousnessSystem.ts"],"sourcesContent":["/**\n * Consciousness System for managing awareness and cognitive function levels.\n *\n * **Korean**: 의식 시스템 (Consciousness System)\n *\n * Implements consciousness levels based on head trauma, blood flow restriction,\n * and neural damage. Consciousness affects reaction time, targeting precision,\n * and overall combat effectiveness.\n *\n * ## Consciousness Levels\n *\n * - **전투각성 (Combat Alert)**: 100% - Full awareness, optimal combat ability\n * - **혼란상태 (Disoriented)**: 70% - Reduced reaction, vulnerability window\n * - **기절직전 (Stunned)**: 40% - Severe impairment, incapacitation opportunity\n * - **무의식 (Unconscious)**: 0% - Complete incapacitation\n *\n * ## Fall System Integration\n *\n * When consciousness drops below 10%, the system triggers fall animations (낙법).\n * The character loses the ability to stand and collapses to the ground.\n * Fall direction is based on last impact location.\n *\n * @module systems/combat/ConsciousnessSystem\n * @category Combat System\n * @korean 의식시스템\n */\n\nimport { VitalPointCategory } from \"@/types\";\nimport type { TrigramStance } from \"@/types/common\";\nimport { determineFallFromStance } from \"../animation\";\nimport type { FallType } from \"../animation/core/types\";\nimport { PlayerState } from \"../player\";\n\n/**\n * Consciousness levels representing cognitive function and awareness.\n *\n * **Korean**: 의식 수준\n */\nexport enum ConsciousnessLevel {\n /** Full combat awareness (90-100%) */\n COMBAT_ALERT = \"combat_alert\",\n /** Disoriented and vulnerable (50-89%) */\n DISORIENTED = \"disoriented\",\n /** Severely stunned (10-49%) */\n STUNNED = \"stunned\",\n /** Completely unconscious (0-9%) */\n UNCONSCIOUS = \"unconscious\",\n}\n\n/**\n * Effects of consciousness levels on combat performance.\n */\ninterface ConsciousnessEffects {\n /** Consciousness value range */\n readonly range: readonly [number, number];\n /** Reaction time multiplier */\n readonly reactionTimeMultiplier: number;\n /** Accuracy penalty */\n readonly accuracyPenalty: number;\n /** Defense penalty */\n readonly defensePenalty: number;\n /** Can perform actions */\n readonly canAct: boolean;\n /** Vision clarity multiplier */\n readonly visionClarity: number;\n}\n\n/**\n * Consciousness System managing awareness and cognitive function.\n *\n * Tracks consciousness damage from:\n * - Head trauma (strikes to head region)\n * - Neurological vital point hits\n * - Blood flow restriction (vascular hits)\n * - Respiratory disruption\n *\n * Consciousness naturally recovers over time when not taking damage.\n *\n * @example\n * ```typescript\n * const consciousnessSystem = new ConsciousnessSystem();\n *\n * // Apply damage from head strike\n * const newPlayer = consciousnessSystem.applyDamage(\n * player,\n * 15,\n * VitalPointCategory.NEUROLOGICAL\n * );\n *\n * // Check consciousness level\n * const level = consciousnessSystem.getLevel(newPlayer.consciousness);\n * console.log(`Consciousness: ${level}`);\n *\n * // Apply recovery over time\n * const recovered = consciousnessSystem.applyRecovery(newPlayer, 1000);\n * ```\n *\n * @public\n * @korean 의식시스템\n */\nexport class ConsciousnessSystem {\n /**\n * Consciousness level effects and thresholds.\n */\n private readonly levelEffects: Record<\n ConsciousnessLevel,\n ConsciousnessEffects\n > = {\n [ConsciousnessLevel.COMBAT_ALERT]: {\n range: [90, 100],\n reactionTimeMultiplier: 1.0,\n accuracyPenalty: 0.0,\n defensePenalty: 0.0,\n canAct: true,\n visionClarity: 1.0,\n },\n [ConsciousnessLevel.DISORIENTED]: {\n range: [50, 89],\n reactionTimeMultiplier: 1.3, // 30% slower reactions\n accuracyPenalty: 0.2, // -20% accuracy\n defensePenalty: 0.15, // -15% defense\n canAct: true,\n visionClarity: 0.7,\n },\n [ConsciousnessLevel.STUNNED]: {\n range: [20, 49], // Updated: Changed from [10, 49] to [20, 49]\n reactionTimeMultiplier: 2.0, // 2x slower reactions\n accuracyPenalty: 0.5, // -50% accuracy\n defensePenalty: 0.4, // -40% defense\n canAct: true,\n visionClarity: 0.4,\n },\n [ConsciousnessLevel.UNCONSCIOUS]: {\n range: [0, 19], // Updated: Changed from [0, 9] to [0, 19] - incapacitation threshold <20%\n reactionTimeMultiplier: Infinity,\n accuracyPenalty: 1.0, // Complete inability\n defensePenalty: 1.0, // No defense\n canAct: false,\n visionClarity: 0.0,\n },\n };\n\n /**\n * Damage multipliers by vital point category affecting consciousness.\n */\n private readonly categoryMultipliers: Record<string, number> = {\n [VitalPointCategory.NEUROLOGICAL]: 3.0, // Nerve strikes heavily affect consciousness\n [VitalPointCategory.VASCULAR]: 2.0, // Blood flow restriction\n [VitalPointCategory.RESPIRATORY]: 1.5, // Breathing difficulty\n default: 0.5, // Other damage has minor effect\n };\n\n /**\n * Base recovery rate per second.\n */\n private readonly baseRecoveryRate = 5.0; // 5 points per second\n\n /**\n * Incapacitation threshold - consciousness <20% renders player helpless.\n *\n * **Korean**: 무력화한계 (Incapacitation Threshold)\n */\n private readonly incapacitationThreshold = 20;\n\n /**\n * Duration of helplessness when consciousness drops below threshold (3-5 seconds).\n */\n private readonly helplessDuration = {\n min: 3000, // 3 seconds\n max: 5000, // 5 seconds\n };\n\n /**\n * Time without head trauma required for consciousness recovery (5 seconds).\n */\n private readonly noTraumaRecoveryTime = 5000; // 5 seconds\n\n /**\n * Applies consciousness damage from combat.\n *\n * Calculates consciousness reduction based on damage amount and\n * vital point category. Neurological and vascular damage have\n * the highest impact on consciousness.\n *\n * @param player - Current player state\n * @param damage - Base damage amount\n * @param category - Vital point category hit\n * @returns Updated player state with reduced consciousness\n *\n * @example\n * ```typescript\n * // Head strike causes significant consciousness damage\n * const newPlayer = system.applyDamage(\n * player,\n * 20,\n * VitalPointCategory.NEUROLOGICAL\n * );\n * console.log(`Consciousness: ${newPlayer.consciousness}`);\n * ```\n *\n * @public\n * @korean 의식피해적용\n */\n applyDamage(\n player: PlayerState,\n damage: number,\n category?: VitalPointCategory\n ): PlayerState {\n // Get multiplier based on category\n const multiplier = category\n ? this.categoryMultipliers[category] ?? this.categoryMultipliers.default\n : this.categoryMultipliers.default;\n\n // Calculate consciousness damage\n const consciousnessDamage = damage * multiplier;\n\n // Apply damage, clamped to 0-100 range\n const newConsciousness = Math.max(\n 0,\n Math.min(100, player.consciousness - consciousnessDamage)\n );\n\n return {\n ...player,\n consciousness: newConsciousness,\n };\n }\n\n /**\n * Applies consciousness recovery over time.\n *\n * Consciousness naturally recovers when not taking damage.\n * Recovery rate depends on current level - severely stunned\n * players recover more slowly.\n *\n * **Note**: Full recovery only occurs after 5 seconds without head trauma.\n *\n * @param player - Current player state\n * @param deltaTime - Time elapsed in milliseconds\n * @param lastHeadTraumaTime - Timestamp of last head trauma (optional)\n * @returns Updated player state with recovered consciousness\n *\n * @example\n * ```typescript\n * // In game loop (60fps, ~16ms per frame)\n * player = system.applyRecovery(player, 16, player.lastActionTime);\n * ```\n *\n * @public\n * @korean 의식회복\n */\n applyRecovery(\n player: PlayerState,\n deltaTime: number,\n lastHeadTraumaTime?: number\n ): PlayerState {\n // Already at full consciousness\n if (player.consciousness >= 100) {\n return player;\n }\n\n // Check if enough time has passed since last head trauma\n const timeSinceTrauma = lastHeadTraumaTime\n ? Date.now() - lastHeadTraumaTime\n : Infinity;\n\n // Don't recover if head trauma is recent (within 5 seconds)\n if (timeSinceTrauma < this.noTraumaRecoveryTime) {\n return player;\n }\n\n // Calculate recovery based on time\n const deltaSeconds = deltaTime / 1000;\n const level = this.getLevel(player.consciousness);\n\n // Recovery rate modifier based on level\n let recoveryModifier = 1.0;\n if (level === ConsciousnessLevel.STUNNED) {\n recoveryModifier = 0.5; // Slower recovery when stunned\n } else if (level === ConsciousnessLevel.UNCONSCIOUS) {\n recoveryModifier = 0.2; // Very slow recovery when unconscious\n }\n\n const recovery = this.baseRecoveryRate * deltaSeconds * recoveryModifier;\n const newConsciousness = Math.min(100, player.consciousness + recovery);\n\n return {\n ...player,\n consciousness: newConsciousness,\n };\n }\n\n /**\n * Determines consciousness level from consciousness value.\n *\n * Updated thresholds:\n * - 90-100: Combat Alert\n * - 50-89: Disoriented\n * - 20-49: Stunned\n * - 0-19: Unconscious (incapacitation threshold <20%)\n *\n * @param consciousness - Consciousness value (0-100)\n * @returns Current consciousness level\n *\n * @example\n * ```typescript\n * const level = system.getLevel(75);\n * console.log(level); // DISORIENTED\n *\n * const level2 = system.getLevel(15);\n * console.log(level2); // UNCONSCIOUS (below incapacitation threshold)\n * ```\n *\n * @public\n * @korean 의식수준확인\n */\n getLevel(consciousness: number): ConsciousnessLevel {\n if (consciousness >= 90) return ConsciousnessLevel.COMBAT_ALERT;\n if (consciousness >= 50) return ConsciousnessLevel.DISORIENTED;\n if (consciousness >= 20) return ConsciousnessLevel.STUNNED;\n return ConsciousnessLevel.UNCONSCIOUS;\n }\n\n /**\n * Gets effects for a specific consciousness level.\n *\n * @param level - Consciousness level\n * @returns Effects applied at that level\n *\n * @public\n * @korean 의식효과\n */\n getEffects(level: ConsciousnessLevel): ConsciousnessEffects {\n return this.levelEffects[level];\n }\n\n /**\n * Applies consciousness effects to player state.\n *\n * Modifies player stats based on current consciousness level.\n *\n * @param player - Current player state\n * @returns Modified player state with consciousness effects\n *\n * @public\n * @korean 의식효과적용\n */\n applyEffects(player: PlayerState): PlayerState {\n const level = this.getLevel(player.consciousness);\n const effects = this.getEffects(level);\n\n return {\n ...player,\n attackPower: Math.floor(\n player.attackPower * (1 - effects.accuracyPenalty)\n ),\n defense: Math.floor(player.defense * (1 - effects.defensePenalty)),\n technique: Math.floor(player.technique * (1 - effects.accuracyPenalty)),\n isStunned:\n player.isStunned ||\n level === ConsciousnessLevel.UNCONSCIOUS ||\n level === ConsciousnessLevel.STUNNED,\n };\n }\n\n /**\n * Checks if player is at incapacitation threshold.\n *\n * **Korean**: 무력화한계 (Incapacitation Threshold)\n *\n * When consciousness drops below 20%, player becomes helpless for 3-5 seconds.\n *\n * @param player - Current player state\n * @returns True if consciousness is below incapacitation threshold (<20%)\n *\n * @example\n * ```typescript\n * if (system.isAtIncapacitationThreshold(player)) {\n * // Player is helpless, trigger helpless state\n * const helplessDuration = system.getHelplessDuration();\n * console.log(`Player helpless for ${helplessDuration}ms`);\n * }\n * ```\n *\n * @public\n * @korean 무력화한계확인\n */\n isAtIncapacitationThreshold(player: PlayerState): boolean {\n return player.consciousness < this.incapacitationThreshold;\n }\n\n /**\n * Gets random helpless duration when consciousness drops below threshold.\n *\n * Returns a random duration between 3-5 seconds (3000-5000ms).\n *\n * @returns Helpless duration in milliseconds\n *\n * @public\n * @korean 무력화지속시간\n */\n getHelplessDuration(): number {\n return (\n this.helplessDuration.min +\n Math.random() * (this.helplessDuration.max - this.helplessDuration.min)\n );\n }\n\n /**\n * Checks if enough time has passed for consciousness recovery.\n *\n * Consciousness only recovers after 5 seconds without head trauma.\n *\n * @param lastHeadTraumaTime - Timestamp of last head trauma\n * @returns True if recovery is allowed\n *\n * @public\n * @korean 회복가능확인\n */\n canRecover(lastHeadTraumaTime: number): boolean {\n const timeSinceTrauma = Date.now() - lastHeadTraumaTime;\n return timeSinceTrauma >= this.noTraumaRecoveryTime;\n }\n\n /**\n * Checks if player is incapacitated due to consciousness.\n *\n * @param player - Current player state\n * @returns True if player is unconscious\n *\n * @public\n * @korean 무의식확인\n */\n isIncapacitated(player: PlayerState): boolean {\n return (\n this.getLevel(player.consciousness) === ConsciousnessLevel.UNCONSCIOUS\n );\n }\n\n /**\n * Gets bilingual name for consciousness level.\n *\n * @param level - Consciousness level\n * @returns Korean and English level names\n *\n * @public\n * @korean 의식이름\n */\n getLevelName(level: ConsciousnessLevel): { korean: string; english: string } {\n const names: Record<\n ConsciousnessLevel,\n { korean: string; english: string }\n > = {\n [ConsciousnessLevel.COMBAT_ALERT]: {\n korean: \"전투각성\",\n english: \"Combat Alert\",\n },\n [ConsciousnessLevel.DISORIENTED]: {\n korean: \"혼란상태\",\n english: \"Disoriented\",\n },\n [ConsciousnessLevel.STUNNED]: {\n korean: \"기절직전\",\n english: \"Stunned\",\n },\n [ConsciousnessLevel.UNCONSCIOUS]: {\n korean: \"무의식\",\n english: \"Unconscious\",\n },\n };\n\n return names[level];\n }\n\n /**\n * Gets description of consciousness level effects.\n *\n * @param level - Consciousness level\n * @returns Bilingual description\n *\n * @public\n * @korean 의식설명\n */\n getLevelDescription(level: ConsciousnessLevel): {\n korean: string;\n english: string;\n } {\n const descriptions: Record<\n ConsciousnessLevel,\n { korean: string; english: string }\n > = {\n [ConsciousnessLevel.COMBAT_ALERT]: {\n korean: \"완전한 의식과 전투 능력\",\n english: \"Full awareness and combat ability\",\n },\n [ConsciousnessLevel.DISORIENTED]: {\n korean: \"반응 시간 저하 및 혼란\",\n english: \"Reduced reaction time and confusion\",\n },\n [ConsciousnessLevel.STUNNED]: {\n korean: \"심각한 손상, 무력화 위험\",\n english: \"Severe impairment, incapacitation risk\",\n },\n [ConsciousnessLevel.UNCONSCIOUS]: {\n korean: \"완전한 무의식 상태\",\n english: \"Complete unconsciousness\",\n },\n };\n\n return descriptions[level];\n }\n\n /**\n * Gets color indicator for consciousness level (for UI).\n *\n * @param level - Consciousness level\n * @returns Hex color code\n *\n * @public\n * @korean 의식색상\n */\n getLevelColor(level: ConsciousnessLevel): number {\n const colors: Record<ConsciousnessLevel, number> = {\n [ConsciousnessLevel.COMBAT_ALERT]: 0x00ff00, // Green\n [ConsciousnessLevel.DISORIENTED]: 0xffaa00, // Orange\n [ConsciousnessLevel.STUNNED]: 0xff4400, // Red-orange\n [ConsciousnessLevel.UNCONSCIOUS]: 0xff0000, // Red\n };\n\n return colors[level];\n }\n\n /**\n * Checks if consciousness is low enough to trigger fall animation.\n *\n * Falls occur when consciousness drops below 10% (UNCONSCIOUS threshold).\n * This represents complete loss of ability to maintain standing position.\n *\n * Korean terminology:\n * - 의식상실낙법 (Uisik Sangsil Nakbeop): Consciousness loss fall\n * - 기절낙하 (Gijeol Nakha): Knockout collapse\n *\n * @param player - Current player state\n * @returns True if fall animation should trigger\n *\n * @example\n * ```typescript\n * if (consciousnessSystem.shouldTriggerFall(player)) {\n * const fallType = consciousnessSystem.determineFallType(\n * player,\n * lastImpactAngle\n * );\n * animationMachine.transitionTo(FALL_TYPE_TO_ANIMATION[fallType]);\n * }\n * ```\n *\n * @public\n * @korean 의식상실낙법확인\n */\n shouldTriggerFall(player: PlayerState): boolean {\n return player.consciousness < 10; // UNCONSCIOUS threshold\n }\n\n /**\n * Determines fall direction based on last impact and stance.\n *\n * When consciousness is lost, fall direction is determined by:\n * - Last attack angle (if available)\n * - Current stance bias (if no attack data)\n * - Default to backward fall (natural collapse)\n *\n * Korean falling from consciousness loss:\n * - 후방의식상실 (Hubang Uisik Sangsil): Backward consciousness loss fall\n * - 전방기절 (Jeonbang Gijeol): Forward knockout\n *\n * @param player - Current player state\n * @param lastImpactAngle - Angle of last hit (optional)\n * @returns Fall type to use for animation\n *\n * @example\n * ```typescript\n * // Player loses consciousness from frontal head strike\n * const fallType = consciousnessSystem.determineFallType(\n * player,\n * 0 // Front angle\n * );\n * // Returns: 'backward' (knocked back by frontal strike)\n *\n * // Player loses consciousness without specific impact\n * const fallType = consciousnessSystem.determineFallType(player);\n * // Returns: Stance-based fall or 'backward' default\n * ```\n *\n * @public\n * @korean 의식상실낙법결정\n */\n determineFallType(_player: PlayerState, lastImpactAngle?: number): FallType {\n // If we have impact angle, use simple direction logic\n if (lastImpactAngle !== undefined) {\n const normalizedAngle = Math.abs(lastImpactAngle);\n\n // Front impact (0° ±45°) causes backward fall\n if (normalizedAngle < Math.PI / 4) {\n return \"backward\";\n }\n\n // Rear impact (180° ±45°) causes forward fall\n // Since normalizedAngle is in [0, π], any angle > 3π/4 is a rear impact\n if (normalizedAngle > (3 * Math.PI) / 4) {\n return \"forward\";\n }\n\n // Side impacts: at this point normalizedAngle is in (π/4, 3π/4),\n // so lastImpactAngle cannot be 0 or ±π.\n if (lastImpactAngle < 0) {\n return \"side_left\";\n }\n if (lastImpactAngle > 0) {\n return \"side_right\";\n }\n\n // Fallback for exact 0 (or extremely small) angles in case future\n // changes alter the front/rear checks above. We treat this as a\n // natural backward collapse rather than a side fall.\n return \"backward\";\n }\n\n // Default to backward fall (natural collapse from consciousness loss)\n return \"backward\";\n }\n\n /**\n * Determines fall type based on stance when consciousness is lost.\n *\n * Uses stance bias to determine fall direction when consciousness\n * is lost without specific impact data.\n *\n * Korean terminology:\n * - 자세의식상실 (Jase Uisik Sangsil): Stance-based consciousness loss\n *\n * @param stance - Current trigram stance\n * @returns Fall type based on stance characteristics\n *\n * @example\n * ```typescript\n * // Player in Mountain stance (defensive back)\n * const fallType = consciousnessSystem.determineFallTypeFromStance(\n * TrigramStance.GAN\n * );\n * // Returns: 'backward' (Mountain has defensive backward bias)\n * ```\n *\n * @public\n * @korean 자세의식상실낙법\n */\n determineFallTypeFromStance(stance: TrigramStance): FallType {\n return determineFallFromStance(stance, \"backward\");\n }\n}\n\nexport default ConsciousnessSystem;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PainResponseSystem.js","names":[],"sources":["../../../src/systems/combat/PainResponseSystem.ts"],"sourcesContent":["/**\n * Pain Response System for managing cumulative pain effects in combat.\n * \n * **Korean**: 고통 반응 시스템 (Pain Response System)\n * \n * Implements realistic pain accumulation that progressively reduces combat\n * effectiveness. Unlike health, pain represents the body's protective response\n * to damage, reducing capabilities before critical injury occurs.\n * \n * ## Pain Mechanics\n * \n * - **충격통 (Shock Pain)**: Instant reaction affecting all abilities (10-30% reduction for 2-3 seconds)\n * - **누적외상 (Cumulative Trauma)**: Progressive damage impairment\n * - **통증과부하 (Pain Overload)**: Complete incapacitation from overwhelming pain (>80 pain)\n * - **무력화한계 (Incapacitation Threshold)**: Point of complete combat inability\n * \n * ## Pain Levels\n * \n * - **0-20**: Minimal pain - no significant effects\n * - **20-40**: Moderate pain - slight performance reduction (-10%)\n * - **40-60**: Significant pain - noticeable impairment (-20%)\n * - **60-80**: Severe pain - major limitations (-35%)\n * - **80-100**: Pain overload - chance of stun/unconsciousness, extreme impairment (-50%)\n * \n * @module systems/combat/PainResponseSystem\n * @category Combat System\n * @korean 고통반응시스템\n */\n\nimport { PlayerState } from \"../player\";\nimport { VitalPointSeverity, VitalPointCategory } from \"@/types\";\n\n/**\n * Pain level categories for status indication.\n */\nexport enum PainLevel {\n /** Minimal pain (0-20) - no significant effects */\n MINIMAL = \"minimal\",\n /** Moderate pain (20-40) - slight performance reduction (-10%) */\n MODERATE = \"moderate\",\n /** Significant pain (40-60) - noticeable impairment (-20%) */\n SIGNIFICANT = \"significant\",\n /** Severe pain (60-80) - major limitations (-35%) */\n SEVERE = \"severe\",\n /** Pain overload (80-100) - chance of stun/unconsciousness, extreme impairment (-50%) */\n OVERLOAD = \"overload\",\n}\n\n/**\n * Shock pain effect from sudden trauma.\n * \n * **Korean**: 충격통 효과 (Shock Pain Effect)\n * \n * Represents instant reaction to damage affecting all abilities for 2-3 seconds.\n */\nexport interface ShockPainEffect {\n /** Intensity of shock pain (0.1-0.3 for 10-30% reduction) */\n readonly intensity: number;\n /** Duration remaining in milliseconds (2000-3000ms) */\n readonly duration: number;\n /** Timestamp when shock pain was applied */\n readonly startTime: number;\n /** Damage value that caused the shock */\n readonly causedByDamage: number;\n}\n\n/**\n * Effects of pain on combat performance.\n */\ninterface PainEffects {\n /** Pain value range */\n readonly range: readonly [number, number];\n /** Overall performance penalty multiplier */\n readonly performancePenalty: number;\n /** Accuracy reduction */\n readonly accuracyReduction: number;\n /** Damage output reduction */\n readonly damageReduction: number;\n /** Movement speed reduction */\n readonly speedReduction: number;\n /** Chance of involuntary stun (0-1) */\n readonly stunChance: number;\n}\n\n/**\n * Pain Response System managing cumulative pain effects.\n * \n * Pain accumulates from all damage sources and reduces combat effectiveness\n * progressively. High pain can incapacitate even if health remains adequate.\n * Pain dissipates slowly over time.\n * \n * @example\n * ```typescript\n * const painSystem = new PainResponseSystem();\n * \n * // Apply pain from damage\n * const newPlayer = painSystem.applyPain(player, 15, VitalPointSeverity.MAJOR);\n * \n * // Check pain level\n * const level = painSystem.getPainLevel(newPlayer.pain);\n * \n * // Apply dissipation over time\n * const recovered = painSystem.applyDissipation(newPlayer, 1000);\n * ```\n * \n * @public\n * @korean 고통반응시스템\n */\nexport class PainResponseSystem {\n /**\n * Pain level effects and thresholds matching requirements.\n */\n private readonly painEffects: Record<PainLevel, PainEffects> = {\n [PainLevel.MINIMAL]: {\n range: [0, 20],\n performancePenalty: 0.0,\n accuracyReduction: 0.0,\n damageReduction: 0.0,\n speedReduction: 0.0,\n stunChance: 0.0,\n },\n [PainLevel.MODERATE]: {\n range: [20, 40],\n performancePenalty: 0.1, // -10% overall\n accuracyReduction: 0.1,\n damageReduction: 0.1,\n speedReduction: 0.05,\n stunChance: 0.0,\n },\n [PainLevel.SIGNIFICANT]: {\n range: [40, 60],\n performancePenalty: 0.2, // -20% overall\n accuracyReduction: 0.2,\n damageReduction: 0.2,\n speedReduction: 0.15,\n stunChance: 0.05, // 5% chance\n },\n [PainLevel.SEVERE]: {\n range: [60, 80],\n performancePenalty: 0.35, // -35% overall\n accuracyReduction: 0.35,\n damageReduction: 0.35,\n speedReduction: 0.25,\n stunChance: 0.15, // 15% chance\n },\n [PainLevel.OVERLOAD]: {\n range: [80, 100],\n performancePenalty: 0.5, // -50% overall\n accuracyReduction: 0.5,\n damageReduction: 0.5,\n speedReduction: 0.4,\n stunChance: 0.3, // 30% chance per hit at pain >80\n },\n };\n\n /**\n * Pain multipliers by vital point severity.\n */\n private readonly severityMultipliers: Record<VitalPointSeverity, number> = {\n [VitalPointSeverity.MINOR]: 0.5,\n [VitalPointSeverity.MODERATE]: 1.0,\n [VitalPointSeverity.MAJOR]: 1.5,\n [VitalPointSeverity.CRITICAL]: 2.0,\n [VitalPointSeverity.LETHAL]: 3.0,\n };\n\n /**\n * Pain multipliers by vital point category.\n */\n private readonly categoryMultipliers: Record<string, number> = {\n [VitalPointCategory.NEUROLOGICAL]: 2.5, // Nerve strikes cause intense pain\n [VitalPointCategory.VASCULAR]: 1.5, // Blood flow restriction\n [VitalPointCategory.RESPIRATORY]: 2.0, // Breathing difficulty causes panic\n [VitalPointCategory.SKELETAL]: 1.8, // Bone/structural damage\n [VitalPointCategory.MUSCULAR]: 1.4, // Muscle trauma\n [VitalPointCategory.ORGAN]: 2.2, // Internal organ trauma\n [VitalPointCategory.JOINT]: 1.9, // Joint damage\n [VitalPointCategory.CIRCULATORY]: 1.6, // Circulatory disruption\n default: 1.0, // Standard damage\n };\n\n /**\n * Base pain dissipation rate per second (requirement: -5 pain/second).\n */\n private readonly BASE_DISSIPATION_RATE = 5.0; // -5 pain per second\n\n /**\n * Shock pain duration range in milliseconds (requirement: 2-3 seconds).\n */\n private readonly SHOCK_PAIN_DURATION = {\n min: 2000, // 2 seconds\n max: 3000, // 3 seconds\n };\n\n /**\n * Minimum damage to trigger shock pain.\n */\n private readonly SHOCK_PAIN_THRESHOLD = 10;\n\n /**\n * Pain overload threshold for stun chance (requirement: >80).\n */\n private readonly PAIN_OVERLOAD_THRESHOLD = 80;\n\n /**\n * Shock pain intensity constants.\n */\n private readonly MAX_SHOCK_INTENSITY = 0.3; // 30% max reduction\n private readonly MIN_SHOCK_INTENSITY = 0.1; // 10% min reduction\n private readonly DAMAGE_SCALE_FACTOR = 100; // for normalizing damage to 0-1 range\n private readonly INTENSITY_RANGE = 0.2; // 20% variable range\n\n /**\n * Pain to damage ratio for cumulative trauma calculation.\n */\n private readonly PAIN_TO_DAMAGE_RATIO = 0.5;\n\n /**\n * Applies pain from combat damage with shock pain effects.\n * \n * Calculates pain increase based on damage amount, vital point severity,\n * and vital point category. Also determines if shock pain effect should be triggered.\n * \n * **Shock Pain**: Instant 10-30% reduction for 2-3 seconds on significant hits (>=10 damage)\n * **Cumulative Trauma**: Progressive pain accumulation that reduces performance\n * **Pain Overload**: At >80 pain, chance of stun/unconsciousness\n * \n * @param player - Current player state\n * @param damage - Base damage amount\n * @param severity - Optional vital point severity\n * @param category - Optional vital point category for more accurate pain calculation\n * @returns Updated player state with increased pain and optional shock effect\n * \n * @example\n * ```typescript\n * // Normal hit\n * const result = system.applyPain(player, 10);\n * \n * // Vital point neurological hit with shock pain\n * const result = system.applyPain(\n * player, \n * 20, \n * VitalPointSeverity.MAJOR,\n * VitalPointCategory.NEUROLOGICAL\n * );\n * if (result.shockEffect) {\n * console.log(`Shock pain active for ${result.shockEffect.duration}ms`);\n * }\n * ```\n * \n * @public\n * @korean 고통적용\n */\n applyPain(\n player: PlayerState,\n damage: number,\n severity?: VitalPointSeverity,\n category?: VitalPointCategory\n ): { player: PlayerState; shockEffect?: ShockPainEffect } {\n // Get multipliers based on severity and category\n const severityMultiplier = severity\n ? this.severityMultipliers[severity]\n : 1.0;\n \n const categoryMultiplier = category\n ? this.categoryMultipliers[category] ?? this.categoryMultipliers.default\n : this.categoryMultipliers.default;\n\n // Calculate pain increase (cumulative trauma)\n const painIncrease = damage * severityMultiplier * categoryMultiplier * this.PAIN_TO_DAMAGE_RATIO;\n\n // Apply pain, clamped to 0-100\n const newPain = Math.max(0, Math.min(100, player.pain + painIncrease));\n\n let shockEffect: ShockPainEffect | undefined;\n\n // Trigger shock pain for significant hits (>=10 damage)\n if (damage >= this.SHOCK_PAIN_THRESHOLD) {\n // Calculate shock intensity: 10-30% reduction based on damage\n const shockIntensity = Math.min(\n this.MAX_SHOCK_INTENSITY,\n this.MIN_SHOCK_INTENSITY + (damage / this.DAMAGE_SCALE_FACTOR) * this.INTENSITY_RANGE\n );\n \n // Random duration between 2-3 seconds\n const shockDuration =\n this.SHOCK_PAIN_DURATION.min +\n Math.random() *\n (this.SHOCK_PAIN_DURATION.max - this.SHOCK_PAIN_DURATION.min);\n\n shockEffect = {\n intensity: shockIntensity,\n duration: shockDuration,\n startTime: Date.now(),\n causedByDamage: damage,\n };\n }\n\n const updatedPlayer: PlayerState = {\n ...player,\n pain: newPain,\n };\n\n return { player: updatedPlayer, shockEffect };\n }\n\n /**\n * Applies pain dissipation over time (requirement: -5 pain/second).\n * \n * Pain naturally dissipates when not taking damage at a constant rate\n * of -5 pain per second.\n * \n * @param player - Current player state\n * @param deltaTime - Time elapsed in milliseconds\n * @returns Updated player state with reduced pain\n * \n * @example\n * ```typescript\n * // In game loop (~60fps, 16ms per frame)\n * player = system.applyDissipation(player, 16);\n * ```\n * \n * @public\n * @korean 고통감소\n */\n applyDissipation(player: PlayerState, deltaTime: number): PlayerState {\n // Already at zero pain\n if (player.pain <= 0) {\n return player;\n }\n\n const deltaSeconds = deltaTime / 1000;\n \n // Constant dissipation rate of -5 pain/second\n const dissipation = this.BASE_DISSIPATION_RATE * deltaSeconds;\n const newPain = Math.max(0, player.pain - dissipation);\n\n return {\n ...player,\n pain: newPain,\n };\n }\n\n /**\n * Determines pain level from pain value.\n * \n * @param pain - Pain value (0-100)\n * @returns Current pain level\n * \n * @public\n * @korean 고통수준확인\n */\n getPainLevel(pain: number): PainLevel {\n if (pain >= 80) return PainLevel.OVERLOAD;\n if (pain >= 60) return PainLevel.SEVERE;\n if (pain >= 40) return PainLevel.SIGNIFICANT;\n if (pain >= 20) return PainLevel.MODERATE;\n return PainLevel.MINIMAL;\n }\n\n /**\n * Gets effects for a specific pain level.\n * \n * @param level - Pain level\n * @returns Effects applied at that level\n * \n * @public\n * @korean 고통효과\n */\n getEffects(level: PainLevel): PainEffects {\n return this.painEffects[level];\n }\n\n /**\n * Applies pain effects to player state, including shock pain.\n * \n * Modifies player stats based on current pain level. When shock pain\n * is active, additional penalties are applied temporarily.\n * \n * @param player - Current player state\n * @param shockEffect - Optional active shock pain effect\n * @returns Modified player state with pain effects\n * \n * @public\n * @korean 고통효과적용\n */\n applyEffects(\n player: PlayerState,\n shockEffect?: ShockPainEffect\n ): PlayerState {\n const level = this.getPainLevel(player.pain);\n const effects = this.getEffects(level);\n\n // Calculate total penalties (base pain + shock pain if active)\n let totalAccuracyPenalty = effects.accuracyReduction;\n let totalDamagePenalty = effects.damageReduction;\n\n // Apply shock pain if still active\n if (shockEffect) {\n const elapsed = Date.now() - shockEffect.startTime;\n if (elapsed < shockEffect.duration) {\n // Add shock pain intensity to penalties\n totalAccuracyPenalty = Math.min(\n 1.0,\n totalAccuracyPenalty + shockEffect.intensity\n );\n totalDamagePenalty = Math.min(\n 1.0,\n totalDamagePenalty + shockEffect.intensity\n );\n }\n }\n\n return {\n ...player,\n attackPower: Math.floor(\n player.attackPower * (1 - totalDamagePenalty)\n ),\n defense: Math.floor(\n player.defense * (1 - effects.performancePenalty)\n ),\n speed: Math.floor(\n player.speed * (1 - effects.speedReduction)\n ),\n technique: Math.floor(\n player.technique * (1 - totalAccuracyPenalty)\n ),\n };\n }\n\n /**\n * Checks if pain overload should trigger stun.\n * \n * At pain >80, there's a chance per hit to trigger stun based on pain level.\n * Pain Overload level has 30% chance to trigger stun.\n * \n * @param player - Current player state\n * @returns True if player should be stunned from pain\n * \n * @public\n * @korean 고통기절확인\n */\n shouldTriggerStun(player: PlayerState): boolean {\n if (player.pain < this.PAIN_OVERLOAD_THRESHOLD) {\n return false;\n }\n\n const level = this.getPainLevel(player.pain);\n const effects = this.getEffects(level);\n\n // Roll for stun chance\n return Math.random() < effects.stunChance;\n }\n\n /**\n * Checks if player is in pain overload state (>80 pain).\n * \n * @param player - Current player state\n * @returns True if pain is above overload threshold\n * \n * @public\n * @korean 고통과부하확인\n */\n isInPainOverload(player: PlayerState): boolean {\n return player.pain >= this.PAIN_OVERLOAD_THRESHOLD;\n }\n\n /**\n * Checks if player is incapacitated by pain.\n * \n * @param player - Current player state\n * @returns True if pain is at overload level\n * \n * @public\n * @korean 고통무력화확인\n */\n isIncapacitated(player: PlayerState): boolean {\n return this.getPainLevel(player.pain) === PainLevel.OVERLOAD;\n }\n\n /**\n * Gets bilingual name for pain level.\n * \n * @param level - Pain level\n * @returns Korean and English level names\n * \n * @public\n * @korean 고통이름\n */\n getLevelName(level: PainLevel): { korean: string; english: string } {\n const names: Record<PainLevel, { korean: string; english: string }> = {\n [PainLevel.MINIMAL]: {\n korean: \"최소\",\n english: \"Minimal\",\n },\n [PainLevel.MODERATE]: {\n korean: \"보통\",\n english: \"Moderate\",\n },\n [PainLevel.SIGNIFICANT]: {\n korean: \"상당\",\n english: \"Significant\",\n },\n [PainLevel.SEVERE]: {\n korean: \"심각\",\n english: \"Severe\",\n },\n [PainLevel.OVERLOAD]: {\n korean: \"과부하\",\n english: \"Overload\",\n },\n };\n\n return names[level];\n }\n\n /**\n * Gets description of pain level effects.\n * \n * @param level - Pain level\n * @returns Bilingual description\n * \n * @public\n * @korean 고통설명\n */\n getLevelDescription(level: PainLevel): {\n korean: string;\n english: string;\n } {\n const descriptions: Record<\n PainLevel,\n { korean: string; english: string }\n > = {\n [PainLevel.MINIMAL]: {\n korean: \"최소한의 고통, 전투 능력에 영향 없음\",\n english: \"Minimal pain, no significant effects on combat\",\n },\n [PainLevel.MODERATE]: {\n korean: \"보통 고통, 약간의 능력 저하 (-10%)\",\n english: \"Moderate pain, slight performance reduction (-10%)\",\n },\n [PainLevel.SIGNIFICANT]: {\n korean: \"상당한 고통, 명확한 손상 (-20%)\",\n english: \"Significant pain, noticeable impairment (-20%)\",\n },\n [PainLevel.SEVERE]: {\n korean: \"심각한 고통, 주요 제한 (-35%)\",\n english: \"Severe pain, major limitations (-35%)\",\n },\n [PainLevel.OVERLOAD]: {\n korean: \"고통 과부하, 기절 위험 (-50%, 30% 기절 확률)\",\n english: \"Pain overload, stun risk (-50%, 30% stun chance)\",\n },\n };\n\n return descriptions[level];\n }\n}\n\nexport default PainResponseSystem;\n"],"mappings":"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"}
1
+ {"version":3,"file":"PainResponseSystem.js","names":[],"sources":["../../../src/systems/combat/PainResponseSystem.ts"],"sourcesContent":["/**\n * Pain Response System for managing cumulative pain effects in combat.\n * \n * **Korean**: 고통 반응 시스템 (Pain Response System)\n * \n * Implements realistic pain accumulation that progressively reduces combat\n * effectiveness. Unlike health, pain represents the body's protective response\n * to damage, reducing capabilities before critical injury occurs.\n * \n * ## Pain Mechanics\n * \n * - **충격통 (Shock Pain)**: Instant reaction affecting all abilities (10-30% reduction for 2-3 seconds)\n * - **누적외상 (Cumulative Trauma)**: Progressive damage impairment\n * - **통증과부하 (Pain Overload)**: Complete incapacitation from overwhelming pain (>80 pain)\n * - **무력화한계 (Incapacitation Threshold)**: Point of complete combat inability\n * \n * ## Pain Levels\n * \n * - **0-20**: Minimal pain - no significant effects\n * - **20-40**: Moderate pain - slight performance reduction (-10%)\n * - **40-60**: Significant pain - noticeable impairment (-20%)\n * - **60-80**: Severe pain - major limitations (-35%)\n * - **80-100**: Pain overload - chance of stun/unconsciousness, extreme impairment (-50%)\n * \n * @module systems/combat/PainResponseSystem\n * @category Combat System\n * @korean 고통반응시스템\n */\n\nimport { PlayerState } from \"../player\";\nimport { VitalPointSeverity, VitalPointCategory } from \"@/types\";\n\n/**\n * Pain level categories for status indication.\n */\nexport enum PainLevel {\n /** Minimal pain (0-20) - no significant effects */\n MINIMAL = \"minimal\",\n /** Moderate pain (20-40) - slight performance reduction (-10%) */\n MODERATE = \"moderate\",\n /** Significant pain (40-60) - noticeable impairment (-20%) */\n SIGNIFICANT = \"significant\",\n /** Severe pain (60-80) - major limitations (-35%) */\n SEVERE = \"severe\",\n /** Pain overload (80-100) - chance of stun/unconsciousness, extreme impairment (-50%) */\n OVERLOAD = \"overload\",\n}\n\n/**\n * Shock pain effect from sudden trauma.\n * \n * **Korean**: 충격통 효과 (Shock Pain Effect)\n * \n * Represents instant reaction to damage affecting all abilities for 2-3 seconds.\n */\nexport interface ShockPainEffect {\n /** Intensity of shock pain (0.1-0.3 for 10-30% reduction) */\n readonly intensity: number;\n /** Duration remaining in milliseconds (2000-3000ms) */\n readonly duration: number;\n /** Timestamp when shock pain was applied */\n readonly startTime: number;\n /** Damage value that caused the shock */\n readonly causedByDamage: number;\n}\n\n/**\n * Effects of pain on combat performance.\n */\ninterface PainEffects {\n /** Pain value range */\n readonly range: readonly [number, number];\n /** Overall performance penalty multiplier */\n readonly performancePenalty: number;\n /** Accuracy reduction */\n readonly accuracyReduction: number;\n /** Damage output reduction */\n readonly damageReduction: number;\n /** Movement speed reduction */\n readonly speedReduction: number;\n /** Chance of involuntary stun (0-1) */\n readonly stunChance: number;\n}\n\n/**\n * Pain Response System managing cumulative pain effects.\n * \n * Pain accumulates from all damage sources and reduces combat effectiveness\n * progressively. High pain can incapacitate even if health remains adequate.\n * Pain dissipates slowly over time.\n * \n * @example\n * ```typescript\n * const painSystem = new PainResponseSystem();\n * \n * // Apply pain from damage\n * const newPlayer = painSystem.applyPain(player, 15, VitalPointSeverity.MAJOR);\n * \n * // Check pain level\n * const level = painSystem.getPainLevel(newPlayer.pain);\n * \n * // Apply dissipation over time\n * const recovered = painSystem.applyDissipation(newPlayer, 1000);\n * ```\n * \n * @public\n * @korean 고통반응시스템\n */\nexport class PainResponseSystem {\n /**\n * Pain level effects and thresholds matching requirements.\n */\n private readonly painEffects: Record<PainLevel, PainEffects> = {\n [PainLevel.MINIMAL]: {\n range: [0, 20],\n performancePenalty: 0.0,\n accuracyReduction: 0.0,\n damageReduction: 0.0,\n speedReduction: 0.0,\n stunChance: 0.0,\n },\n [PainLevel.MODERATE]: {\n range: [20, 40],\n performancePenalty: 0.1, // -10% overall\n accuracyReduction: 0.1,\n damageReduction: 0.1,\n speedReduction: 0.05,\n stunChance: 0.0,\n },\n [PainLevel.SIGNIFICANT]: {\n range: [40, 60],\n performancePenalty: 0.2, // -20% overall\n accuracyReduction: 0.2,\n damageReduction: 0.2,\n speedReduction: 0.15,\n stunChance: 0.05, // 5% chance\n },\n [PainLevel.SEVERE]: {\n range: [60, 80],\n performancePenalty: 0.35, // -35% overall\n accuracyReduction: 0.35,\n damageReduction: 0.35,\n speedReduction: 0.25,\n stunChance: 0.15, // 15% chance\n },\n [PainLevel.OVERLOAD]: {\n range: [80, 100],\n performancePenalty: 0.5, // -50% overall\n accuracyReduction: 0.5,\n damageReduction: 0.5,\n speedReduction: 0.4,\n stunChance: 0.3, // 30% chance per hit at pain >80\n },\n };\n\n /**\n * Pain multipliers by vital point severity.\n */\n private readonly severityMultipliers: Record<VitalPointSeverity, number> = {\n [VitalPointSeverity.MINOR]: 0.5,\n [VitalPointSeverity.MODERATE]: 1.0,\n [VitalPointSeverity.MAJOR]: 1.5,\n [VitalPointSeverity.CRITICAL]: 2.0,\n [VitalPointSeverity.LETHAL]: 3.0,\n };\n\n /**\n * Pain multipliers by vital point category.\n */\n private readonly categoryMultipliers: Record<string, number> = {\n [VitalPointCategory.NEUROLOGICAL]: 2.5, // Nerve strikes cause intense pain\n [VitalPointCategory.VASCULAR]: 1.5, // Blood flow restriction\n [VitalPointCategory.RESPIRATORY]: 2.0, // Breathing difficulty causes panic\n [VitalPointCategory.SKELETAL]: 1.8, // Bone/structural damage\n [VitalPointCategory.MUSCULAR]: 1.4, // Muscle trauma\n [VitalPointCategory.ORGAN]: 2.2, // Internal organ trauma\n [VitalPointCategory.JOINT]: 1.9, // Joint damage\n [VitalPointCategory.CIRCULATORY]: 1.6, // Circulatory disruption\n default: 1.0, // Standard damage\n };\n\n /**\n * Base pain dissipation rate per second (requirement: -5 pain/second).\n */\n private readonly BASE_DISSIPATION_RATE = 5.0; // -5 pain per second\n\n /**\n * Shock pain duration range in milliseconds (requirement: 2-3 seconds).\n */\n private readonly SHOCK_PAIN_DURATION = {\n min: 2000, // 2 seconds\n max: 3000, // 3 seconds\n };\n\n /**\n * Minimum damage to trigger shock pain.\n */\n private readonly SHOCK_PAIN_THRESHOLD = 10;\n\n /**\n * Pain overload threshold for stun chance (requirement: >80).\n */\n private readonly PAIN_OVERLOAD_THRESHOLD = 80;\n\n /**\n * Shock pain intensity constants.\n */\n private readonly MAX_SHOCK_INTENSITY = 0.3; // 30% max reduction\n private readonly MIN_SHOCK_INTENSITY = 0.1; // 10% min reduction\n private readonly DAMAGE_SCALE_FACTOR = 100; // for normalizing damage to 0-1 range\n private readonly INTENSITY_RANGE = 0.2; // 20% variable range\n\n /**\n * Pain to damage ratio for cumulative trauma calculation.\n */\n private readonly PAIN_TO_DAMAGE_RATIO = 0.5;\n\n /**\n * Applies pain from combat damage with shock pain effects.\n * \n * Calculates pain increase based on damage amount, vital point severity,\n * and vital point category. Also determines if shock pain effect should be triggered.\n * \n * **Shock Pain**: Instant 10-30% reduction for 2-3 seconds on significant hits (>=10 damage)\n * **Cumulative Trauma**: Progressive pain accumulation that reduces performance\n * **Pain Overload**: At >80 pain, chance of stun/unconsciousness\n * \n * @param player - Current player state\n * @param damage - Base damage amount\n * @param severity - Optional vital point severity\n * @param category - Optional vital point category for more accurate pain calculation\n * @returns Updated player state with increased pain and optional shock effect\n * \n * @example\n * ```typescript\n * // Normal hit\n * const result = system.applyPain(player, 10);\n * \n * // Vital point neurological hit with shock pain\n * const result = system.applyPain(\n * player, \n * 20, \n * VitalPointSeverity.MAJOR,\n * VitalPointCategory.NEUROLOGICAL\n * );\n * if (result.shockEffect) {\n * console.log(`Shock pain active for ${result.shockEffect.duration}ms`);\n * }\n * ```\n * \n * @public\n * @korean 고통적용\n */\n applyPain(\n player: PlayerState,\n damage: number,\n severity?: VitalPointSeverity,\n category?: VitalPointCategory\n ): { player: PlayerState; shockEffect?: ShockPainEffect } {\n // Get multipliers based on severity and category\n const severityMultiplier = severity\n ? this.severityMultipliers[severity]\n : 1.0;\n \n const categoryMultiplier = category\n ? this.categoryMultipliers[category] ?? this.categoryMultipliers.default\n : this.categoryMultipliers.default;\n\n // Calculate pain increase (cumulative trauma)\n const painIncrease = damage * severityMultiplier * categoryMultiplier * this.PAIN_TO_DAMAGE_RATIO;\n\n // Apply pain, clamped to 0-100\n const newPain = Math.max(0, Math.min(100, player.pain + painIncrease));\n\n let shockEffect: ShockPainEffect | undefined;\n\n // Trigger shock pain for significant hits (>=10 damage)\n if (damage >= this.SHOCK_PAIN_THRESHOLD) {\n // Calculate shock intensity: 10-30% reduction based on damage\n const shockIntensity = Math.min(\n this.MAX_SHOCK_INTENSITY,\n this.MIN_SHOCK_INTENSITY + (damage / this.DAMAGE_SCALE_FACTOR) * this.INTENSITY_RANGE\n );\n \n // Random duration between 2-3 seconds\n const shockDuration =\n this.SHOCK_PAIN_DURATION.min +\n Math.random() *\n (this.SHOCK_PAIN_DURATION.max - this.SHOCK_PAIN_DURATION.min);\n\n shockEffect = {\n intensity: shockIntensity,\n duration: shockDuration,\n startTime: Date.now(),\n causedByDamage: damage,\n };\n }\n\n const updatedPlayer: PlayerState = {\n ...player,\n pain: newPain,\n };\n\n return { player: updatedPlayer, shockEffect };\n }\n\n /**\n * Applies pain dissipation over time (requirement: -5 pain/second).\n * \n * Pain naturally dissipates when not taking damage at a constant rate\n * of -5 pain per second.\n * \n * @param player - Current player state\n * @param deltaTime - Time elapsed in milliseconds\n * @returns Updated player state with reduced pain\n * \n * @example\n * ```typescript\n * // In game loop (~60fps, 16ms per frame)\n * player = system.applyDissipation(player, 16);\n * ```\n * \n * @public\n * @korean 고통감소\n */\n applyDissipation(player: PlayerState, deltaTime: number): PlayerState {\n // Already at zero pain\n if (player.pain <= 0) {\n return player;\n }\n\n const deltaSeconds = deltaTime / 1000;\n \n // Constant dissipation rate of -5 pain/second\n const dissipation = this.BASE_DISSIPATION_RATE * deltaSeconds;\n const newPain = Math.max(0, player.pain - dissipation);\n\n return {\n ...player,\n pain: newPain,\n };\n }\n\n /**\n * Determines pain level from pain value.\n * \n * @param pain - Pain value (0-100)\n * @returns Current pain level\n * \n * @public\n * @korean 고통수준확인\n */\n getPainLevel(pain: number): PainLevel {\n if (pain >= 80) return PainLevel.OVERLOAD;\n if (pain >= 60) return PainLevel.SEVERE;\n if (pain >= 40) return PainLevel.SIGNIFICANT;\n if (pain >= 20) return PainLevel.MODERATE;\n return PainLevel.MINIMAL;\n }\n\n /**\n * Gets effects for a specific pain level.\n * \n * @param level - Pain level\n * @returns Effects applied at that level\n * \n * @public\n * @korean 고통효과\n */\n getEffects(level: PainLevel): PainEffects {\n return this.painEffects[level];\n }\n\n /**\n * Applies pain effects to player state, including shock pain.\n * \n * Modifies player stats based on current pain level. When shock pain\n * is active, additional penalties are applied temporarily.\n * \n * @param player - Current player state\n * @param shockEffect - Optional active shock pain effect\n * @returns Modified player state with pain effects\n * \n * @public\n * @korean 고통효과적용\n */\n applyEffects(\n player: PlayerState,\n shockEffect?: ShockPainEffect\n ): PlayerState {\n const level = this.getPainLevel(player.pain);\n const effects = this.getEffects(level);\n\n // Calculate total penalties (base pain + shock pain if active)\n let totalAccuracyPenalty = effects.accuracyReduction;\n let totalDamagePenalty = effects.damageReduction;\n\n // Apply shock pain if still active\n if (shockEffect) {\n const elapsed = Date.now() - shockEffect.startTime;\n if (elapsed < shockEffect.duration) {\n // Add shock pain intensity to penalties\n totalAccuracyPenalty = Math.min(\n 1.0,\n totalAccuracyPenalty + shockEffect.intensity\n );\n totalDamagePenalty = Math.min(\n 1.0,\n totalDamagePenalty + shockEffect.intensity\n );\n }\n }\n\n return {\n ...player,\n attackPower: Math.floor(\n player.attackPower * (1 - totalDamagePenalty)\n ),\n defense: Math.floor(\n player.defense * (1 - effects.performancePenalty)\n ),\n speed: Math.floor(\n player.speed * (1 - effects.speedReduction)\n ),\n technique: Math.floor(\n player.technique * (1 - totalAccuracyPenalty)\n ),\n };\n }\n\n /**\n * Checks if pain overload should trigger stun.\n * \n * At pain >80, there's a chance per hit to trigger stun based on pain level.\n * Pain Overload level has 30% chance to trigger stun.\n * \n * @param player - Current player state\n * @returns True if player should be stunned from pain\n * \n * @public\n * @korean 고통기절확인\n */\n shouldTriggerStun(player: PlayerState): boolean {\n if (player.pain < this.PAIN_OVERLOAD_THRESHOLD) {\n return false;\n }\n\n const level = this.getPainLevel(player.pain);\n const effects = this.getEffects(level);\n\n // Roll for stun chance\n return Math.random() < effects.stunChance;\n }\n\n /**\n * Checks if player is in pain overload state (>80 pain).\n * \n * @param player - Current player state\n * @returns True if pain is above overload threshold\n * \n * @public\n * @korean 고통과부하확인\n */\n isInPainOverload(player: PlayerState): boolean {\n return player.pain >= this.PAIN_OVERLOAD_THRESHOLD;\n }\n\n /**\n * Checks if player is incapacitated by pain.\n * \n * @param player - Current player state\n * @returns True if pain is at overload level\n * \n * @public\n * @korean 고통무력화확인\n */\n isIncapacitated(player: PlayerState): boolean {\n return this.getPainLevel(player.pain) === PainLevel.OVERLOAD;\n }\n\n /**\n * Gets bilingual name for pain level.\n * \n * @param level - Pain level\n * @returns Korean and English level names\n * \n * @public\n * @korean 고통이름\n */\n getLevelName(level: PainLevel): { korean: string; english: string } {\n const names: Record<PainLevel, { korean: string; english: string }> = {\n [PainLevel.MINIMAL]: {\n korean: \"최소\",\n english: \"Minimal\",\n },\n [PainLevel.MODERATE]: {\n korean: \"보통\",\n english: \"Moderate\",\n },\n [PainLevel.SIGNIFICANT]: {\n korean: \"상당\",\n english: \"Significant\",\n },\n [PainLevel.SEVERE]: {\n korean: \"심각\",\n english: \"Severe\",\n },\n [PainLevel.OVERLOAD]: {\n korean: \"과부하\",\n english: \"Overload\",\n },\n };\n\n return names[level];\n }\n\n /**\n * Gets description of pain level effects.\n * \n * @param level - Pain level\n * @returns Bilingual description\n * \n * @public\n * @korean 고통설명\n */\n getLevelDescription(level: PainLevel): {\n korean: string;\n english: string;\n } {\n const descriptions: Record<\n PainLevel,\n { korean: string; english: string }\n > = {\n [PainLevel.MINIMAL]: {\n korean: \"최소한의 고통, 전투 능력에 영향 없음\",\n english: \"Minimal pain, no significant effects on combat\",\n },\n [PainLevel.MODERATE]: {\n korean: \"보통 고통, 약간의 능력 저하 (-10%)\",\n english: \"Moderate pain, slight performance reduction (-10%)\",\n },\n [PainLevel.SIGNIFICANT]: {\n korean: \"상당한 고통, 명확한 손상 (-20%)\",\n english: \"Significant pain, noticeable impairment (-20%)\",\n },\n [PainLevel.SEVERE]: {\n korean: \"심각한 고통, 주요 제한 (-35%)\",\n english: \"Severe pain, major limitations (-35%)\",\n },\n [PainLevel.OVERLOAD]: {\n korean: \"고통 과부하, 기절 위험 (-50%, 30% 기절 확률)\",\n english: \"Pain overload, stun risk (-50%, 30% stun chance)\",\n },\n };\n\n return descriptions[level];\n }\n}\n\nexport default PainResponseSystem;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"effects.js","names":[],"sources":["../../src/systems/effects.ts"],"sourcesContent":["// Import enums from enums.ts\n\n// Combat effects and status system for Korean martial arts\n\n// Hit effect for visual feedback\n// Hit effect types\n\nexport enum HitEffectType {\n GENERAL_DAMAGE = \"general_damage\",\n CRITICAL_HIT = \"critical_hit\",\n VITAL_POINT_STRIKE = \"vital_point_strike\",\n STATUS_EFFECT = \"status_effect\",\n MISS = \"miss\",\n BLOCK = \"block\",\n PARRY = \"parry\",\n COUNTER = \"counter\",\n HIT = \"hit\",\n}\n\n// Effect types for status effects\nexport enum HitEffectEnum {\n STUN = \"stun\",\n WEAKNESS = \"weakness\",\n STAMINA_DRAIN = \"stamina_drain\",\n VULNERABILITY = \"vulnerability\",\n BLEEDING = \"bleeding\",\n BUFF = \"buff\",\n DEBUFF = \"debuff\",\n PARALYSIS = \"paralysis\",\n POISON = \"poison\",\n BURN = \"burn\",\n FREEZE = \"freeze\",\n CONFUSION = \"confusion\",\n}\n\n// Effect intensity levels\nexport enum EffectIntensity {\n WEAK = \"weak\",\n MINOR = \"minor\",\n LOW = \"low\",\n MEDIUM = \"medium\",\n MODERATE = \"moderate\",\n HIGH = \"high\",\n SEVERE = \"severe\",\n CRITICAL = \"critical\",\n EXTREME = \"extreme\",\n}\n\n// Status effects that can be applied to players\n// Effect types\nexport type EffectType =\n | \"stun\"\n | \"poison\"\n | \"burn\"\n | \"bleed\"\n | \"exhausted\"\n | \"focused\"\n | \"rage\"\n | \"defensive\"\n | \"weakened\"\n | \"strengthened\"\n | \"paralysis\" // Add missing paralysis\n | \"confusion\" // Add missing confusion\n | \"vulnerability\" // Add missing vulnerability\n | \"stamina_drain\"; // Add missing stamina_drain\n\n// Particle effect for visual feedback\n// Particle effect types\nexport type ParticleType =\n | \"spark\"\n | \"blood\"\n | \"energy\"\n | \"dust\"\n | \"flash\"\n | \"smoke\"\n | \"lightning\"\n | \"wind\";\n\n// Environmental effect\n// Environmental effect types\nexport type EnvironmentalEffectType =\n | \"smoke\"\n | \"fire\"\n | \"ice\"\n | \"wind\"\n | \"lightning\"\n | \"darkness\"\n | \"light\"\n | \"pressure\";\n"],"mappings":";AAOA,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,oBAAA;AACA,eAAA,kBAAA;AACA,eAAA,wBAAA;AACA,eAAA,mBAAA;AACA,eAAA,UAAA;AACA,eAAA,WAAA;AACA,eAAA,WAAA;AACA,eAAA,aAAA;AACA,eAAA,SAAA;;KACD;AAGD,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,UAAA;AACA,eAAA,cAAA;AACA,eAAA,mBAAA;AACA,eAAA,mBAAA;AACA,eAAA,cAAA;AACA,eAAA,UAAA;AACA,eAAA,YAAA;AACA,eAAA,eAAA;AACA,eAAA,YAAA;AACA,eAAA,UAAA;AACA,eAAA,YAAA;AACA,eAAA,eAAA;;KACD;AAGD,IAAY,kBAAL,yBAAA,iBAAA;AACL,iBAAA,UAAA;AACA,iBAAA,WAAA;AACA,iBAAA,SAAA;AACA,iBAAA,YAAA;AACA,iBAAA,cAAA;AACA,iBAAA,UAAA;AACA,iBAAA,YAAA;AACA,iBAAA,cAAA;AACA,iBAAA,aAAA;;KACD"}
1
+ {"version":3,"file":"effects.js","names":[],"sources":["../../src/systems/effects.ts"],"sourcesContent":["// Import enums from enums.ts\n\n// Combat effects and status system for Korean martial arts\n\n// Hit effect for visual feedback\n// Hit effect types\n\nexport enum HitEffectType {\n GENERAL_DAMAGE = \"general_damage\",\n CRITICAL_HIT = \"critical_hit\",\n VITAL_POINT_STRIKE = \"vital_point_strike\",\n STATUS_EFFECT = \"status_effect\",\n MISS = \"miss\",\n BLOCK = \"block\",\n PARRY = \"parry\",\n COUNTER = \"counter\",\n HIT = \"hit\",\n}\n\n// Effect types for status effects\nexport enum HitEffectEnum {\n STUN = \"stun\",\n WEAKNESS = \"weakness\",\n STAMINA_DRAIN = \"stamina_drain\",\n VULNERABILITY = \"vulnerability\",\n BLEEDING = \"bleeding\",\n BUFF = \"buff\",\n DEBUFF = \"debuff\",\n PARALYSIS = \"paralysis\",\n POISON = \"poison\",\n BURN = \"burn\",\n FREEZE = \"freeze\",\n CONFUSION = \"confusion\",\n}\n\n// Effect intensity levels\nexport enum EffectIntensity {\n WEAK = \"weak\",\n MINOR = \"minor\",\n LOW = \"low\",\n MEDIUM = \"medium\",\n MODERATE = \"moderate\",\n HIGH = \"high\",\n SEVERE = \"severe\",\n CRITICAL = \"critical\",\n EXTREME = \"extreme\",\n}\n\n// Status effects that can be applied to players\n// Effect types\nexport type EffectType =\n | \"stun\"\n | \"poison\"\n | \"burn\"\n | \"bleed\"\n | \"exhausted\"\n | \"focused\"\n | \"rage\"\n | \"defensive\"\n | \"weakened\"\n | \"strengthened\"\n | \"paralysis\" // Add missing paralysis\n | \"confusion\" // Add missing confusion\n | \"vulnerability\" // Add missing vulnerability\n | \"stamina_drain\"; // Add missing stamina_drain\n\n// Particle effect for visual feedback\n// Particle effect types\nexport type ParticleType =\n | \"spark\"\n | \"blood\"\n | \"energy\"\n | \"dust\"\n | \"flash\"\n | \"smoke\"\n | \"lightning\"\n | \"wind\";\n\n// Environmental effect\n// Environmental effect types\nexport type EnvironmentalEffectType =\n | \"smoke\"\n | \"fire\"\n | \"ice\"\n | \"wind\"\n | \"lightning\"\n | \"darkness\"\n | \"light\"\n | \"pressure\";\n"],"mappings":";AAOA,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,oBAAiB;AACjB,eAAA,kBAAe;AACf,eAAA,wBAAqB;AACrB,eAAA,mBAAgB;AAChB,eAAA,UAAO;AACP,eAAA,WAAQ;AACR,eAAA,WAAQ;AACR,eAAA,aAAU;AACV,eAAA,SAAM;;KACP;AAGD,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,UAAO;AACP,eAAA,cAAW;AACX,eAAA,mBAAgB;AAChB,eAAA,mBAAgB;AAChB,eAAA,cAAW;AACX,eAAA,UAAO;AACP,eAAA,YAAS;AACT,eAAA,eAAY;AACZ,eAAA,YAAS;AACT,eAAA,UAAO;AACP,eAAA,YAAS;AACT,eAAA,eAAY;;KACb;AAGD,IAAY,kBAAL,yBAAA,iBAAA;AACL,iBAAA,UAAO;AACP,iBAAA,WAAQ;AACR,iBAAA,SAAM;AACN,iBAAA,YAAS;AACT,iBAAA,cAAW;AACX,iBAAA,UAAO;AACP,iBAAA,YAAS;AACT,iBAAA,cAAW;AACX,iBAAA,aAAU;;KACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"game.js","names":[],"sources":["../../src/systems/game.ts"],"sourcesContent":["// Core game state and flow management\n\nimport { GameMode, KoreanText } from \"@/types\";\nimport type { PlayerState } from \"./player\";\n\n// Match configuration\nexport interface MatchConfig {\n readonly mode: GameMode;\n readonly rounds: number;\n readonly roundDuration: number; // seconds\n readonly player1Archetype: string;\n readonly player2Archetype: string;\n readonly stage: string;\n readonly difficulty?: \"easy\" | \"medium\" | \"hard\" | \"expert\";\n}\n\n// Game event system\nexport interface GameEvent {\n readonly id: string;\n readonly type: GameEventType;\n readonly timestamp: number;\n readonly playerId?: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Event data can contain various types depending on event type\n readonly data: Record<string, any>;\n readonly message?: KoreanText;\n}\n\n// Game event types\nexport enum GameEventType {\n GAME_START = \"game_start\",\n ROUND_START = \"round_start\",\n ROUND_END = \"round_end\",\n MATCH_END = \"match_end\",\n PLAYER_ATTACK = \"player_attack\",\n PLAYER_HIT = \"player_hit\",\n STANCE_CHANGE = \"stance_change\",\n TECHNIQUE_EXECUTE = \"technique_execute\",\n VITAL_POINT_HIT = \"vital_point_hit\",\n STATUS_EFFECT = \"status_effect\",\n PAUSE_TOGGLE = \"pause_toggle\",\n ERROR = \"error\",\n}\n\n// Game session interface\nexport interface GameSession {\n readonly id: string;\n readonly gameMode: GameMode;\n readonly players: readonly [PlayerState, PlayerState];\n readonly currentRound: number;\n readonly maxRounds: number;\n readonly roundTimeLimit: number;\n readonly timeRemaining: number;\n readonly isPaused: boolean;\n readonly isGameOver: boolean;\n readonly winner: PlayerState | null;\n}\n\n// Game configuration\nexport interface GameConfig {\n readonly maxHealth: number;\n readonly maxKi: number;\n readonly maxStamina: number;\n readonly roundDuration: number;\n readonly maxRounds: number;\n readonly difficulty: \"beginner\" | \"intermediate\" | \"expert\" | \"master\";\n readonly enableVitalPoints: boolean;\n readonly enableStatusEffects: boolean;\n readonly allowArchetypeSwitching: boolean;\n}\n\n// Game save data\nexport interface GameSaveData {\n readonly version: string;\n readonly playerId: string;\n readonly playerProgress: {\n readonly archetypeExperience: Record<string, number>;\n readonly unlockedTechniques: readonly string[];\n readonly achievements: readonly string[];\n };\n readonly settings: {\n readonly volume: number;\n readonly difficulty: string;\n readonly controls: Record<string, string>;\n };\n readonly statistics: {\n readonly totalMatches: number;\n readonly wins: number;\n readonly losses: number;\n readonly favoriteArchetype: string;\n };\n}\n"],"mappings":";AA4BA,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,gBAAA;AACA,eAAA,iBAAA;AACA,eAAA,eAAA;AACA,eAAA,eAAA;AACA,eAAA,mBAAA;AACA,eAAA,gBAAA;AACA,eAAA,mBAAA;AACA,eAAA,uBAAA;AACA,eAAA,qBAAA;AACA,eAAA,mBAAA;AACA,eAAA,kBAAA;AACA,eAAA,WAAA;;KACD"}
1
+ {"version":3,"file":"game.js","names":[],"sources":["../../src/systems/game.ts"],"sourcesContent":["// Core game state and flow management\n\nimport { GameMode, KoreanText } from \"@/types\";\nimport type { PlayerState } from \"./player\";\n\n// Match configuration\nexport interface MatchConfig {\n readonly mode: GameMode;\n readonly rounds: number;\n readonly roundDuration: number; // seconds\n readonly player1Archetype: string;\n readonly player2Archetype: string;\n readonly stage: string;\n readonly difficulty?: \"easy\" | \"medium\" | \"hard\" | \"expert\";\n}\n\n// Game event system\nexport interface GameEvent {\n readonly id: string;\n readonly type: GameEventType;\n readonly timestamp: number;\n readonly playerId?: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Event data can contain various types depending on event type\n readonly data: Record<string, any>;\n readonly message?: KoreanText;\n}\n\n// Game event types\nexport enum GameEventType {\n GAME_START = \"game_start\",\n ROUND_START = \"round_start\",\n ROUND_END = \"round_end\",\n MATCH_END = \"match_end\",\n PLAYER_ATTACK = \"player_attack\",\n PLAYER_HIT = \"player_hit\",\n STANCE_CHANGE = \"stance_change\",\n TECHNIQUE_EXECUTE = \"technique_execute\",\n VITAL_POINT_HIT = \"vital_point_hit\",\n STATUS_EFFECT = \"status_effect\",\n PAUSE_TOGGLE = \"pause_toggle\",\n ERROR = \"error\",\n}\n\n// Game session interface\nexport interface GameSession {\n readonly id: string;\n readonly gameMode: GameMode;\n readonly players: readonly [PlayerState, PlayerState];\n readonly currentRound: number;\n readonly maxRounds: number;\n readonly roundTimeLimit: number;\n readonly timeRemaining: number;\n readonly isPaused: boolean;\n readonly isGameOver: boolean;\n readonly winner: PlayerState | null;\n}\n\n// Game configuration\nexport interface GameConfig {\n readonly maxHealth: number;\n readonly maxKi: number;\n readonly maxStamina: number;\n readonly roundDuration: number;\n readonly maxRounds: number;\n readonly difficulty: \"beginner\" | \"intermediate\" | \"expert\" | \"master\";\n readonly enableVitalPoints: boolean;\n readonly enableStatusEffects: boolean;\n readonly allowArchetypeSwitching: boolean;\n}\n\n// Game save data\nexport interface GameSaveData {\n readonly version: string;\n readonly playerId: string;\n readonly playerProgress: {\n readonly archetypeExperience: Record<string, number>;\n readonly unlockedTechniques: readonly string[];\n readonly achievements: readonly string[];\n };\n readonly settings: {\n readonly volume: number;\n readonly difficulty: string;\n readonly controls: Record<string, string>;\n };\n readonly statistics: {\n readonly totalMatches: number;\n readonly wins: number;\n readonly losses: number;\n readonly favoriteArchetype: string;\n };\n}\n"],"mappings":";AA4BA,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,gBAAa;AACb,eAAA,iBAAc;AACd,eAAA,eAAY;AACZ,eAAA,eAAY;AACZ,eAAA,mBAAgB;AAChB,eAAA,gBAAa;AACb,eAAA,mBAAgB;AAChB,eAAA,uBAAoB;AACpB,eAAA,qBAAkB;AAClB,eAAA,mBAAgB;AAChB,eAAA,kBAAe;AACf,eAAA,WAAQ;;KACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"SpeedModifierSystem.js","names":[],"sources":["../../../src/systems/physics/SpeedModifierSystem.ts"],"sourcesContent":["/**\n * Speed Modifier System\n *\n * **Korean**: 속도 변경 시스템 (Speed Modifier System)\n *\n * Implements comprehensive movement speed modifier system that dynamically adjusts\n * player movement speed based on multiple factors: combat stance, leg injuries,\n * stamina depletion, and combat state. Integrates with physics-based movement\n * system for authentic Korean martial arts combat feel.\n *\n * ## System Features\n *\n * - Base movement speeds for walking, running, backward, lateral, and crouching\n * - Eight Trigram stance-based speed modifiers (80% to 125%)\n * - Injury-based speed reduction from leg damage (0% to 100% penalty)\n * - Stamina-based acceleration penalty (0% to 75% penalty)\n * - Combat state speed adjustments (0% to 100% penalty)\n * - Multiplicative and additive modifier stacking\n *\n * ## Speed Calculation Formula\n *\n * ```\n * Final Speed = Base Speed\n * × Stance Modifier\n * × (1 - Injury Penalty from Legs, Torso & Pain)\n * × (1 - Combat State Penalty)\n *\n * Final Acceleration = Base Acceleration\n * × (1 - Stamina Penalty)\n * ```\n *\n * @module systems/physics/SpeedModifierSystem\n * @category Physics System\n * @korean 속도변경시스템\n */\n\nimport type {\n BodyPartHealth,\n BodyPartMaxHealth,\n} from \"@/systems/bodypart/types\";\nimport type { PlayerState } from \"@/systems/player\";\nimport { CombatState, TrigramStance } from \"@/types/common\";\nimport { BASE_MOVEMENT_ACCELERATION } from \"@/types/physicsConstants\";\nimport { STANCE_SPEED_MODIFIERS } from \"./MovementPhysics\";\nimport { injuryMovementModifier } from \"@/systems/movement/InjuryMovementModifier\";\n\n/**\n * Complete speed modifier state for physics calculations.\n *\n * **Korean**: 속도 변경 상태 (Speed Modifier State)\n *\n * Contains all calculated speed modifiers and final values for application\n * to the physics-based movement system.\n *\n * @public\n * @category Physics System\n * @korean 속도변경상태\n */\nexport interface SpeedModifierState {\n /** Base movement speed before modifiers (m/s) */\n readonly baseSpeed: number;\n /** Stance-based speed multiplier (0.80 to 1.25) */\n readonly stanceModifier: number;\n /** Injury-based speed reduction (0.0 to 0.75, percentage reduction) - Korean: 부상감소 */\n readonly injuryPenalty: number;\n /** Combat state speed reduction (0.0 to 1.0, percentage reduction) */\n readonly combatStatePenalty: number;\n /** Stamina-based acceleration reduction (0.0 to 0.75, percentage reduction) - Korean: 스태미나효과 */\n readonly staminaPenalty: number;\n /** Final calculated movement speed (m/s) */\n readonly finalSpeed: number;\n /** Final calculated acceleration (m/s²) */\n readonly finalAcceleration: number;\n /** Whether running is allowed (false when stamina < 10%) */\n readonly canRun: boolean;\n}\n\n/**\n * Movement type enumeration.\n *\n * **Korean**: 이동 유형 (Movement Type)\n *\n * @public\n * @category Physics System\n */\nexport enum MovementType {\n /** Walking forward - Korean: 걷기 */\n WALKING = \"walking\",\n /** Running/sprinting forward - Korean: 달리기 */\n RUNNING = \"running\",\n /** Moving backward - Korean: 후퇴 */\n BACKWARD = \"backward\",\n /** Side-stepping left/right - Korean: 측면이동 */\n LATERAL = \"lateral\",\n /** Crouching movement - Korean: 웅크리기 */\n CROUCHING = \"crouching\",\n}\n\n/**\n * Speed Modifier System class.\n *\n * **Korean**: 속도 변경 시스템 클래스\n *\n * Calculates comprehensive speed modifiers from multiple factors including\n * stance, injuries, stamina, and combat state. Integrates with existing\n * body part and movement systems.\n *\n * @example\n * ```typescript\n * const system = new SpeedModifierSystem();\n *\n * const modifiers = system.calculateSpeedModifiers(\n * playerState,\n * MovementType.RUNNING,\n * true // isCrouching\n * );\n *\n * // Apply to movement physics\n * movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n * movementPhysics.setAcceleration(modifiers.finalAcceleration);\n * ```\n *\n * @public\n * @category Physics System\n */\nexport class SpeedModifierSystem {\n /**\n * Base walking speed (m/s)\n * Standard walking pace for combat movement - crosses 14m arena in ~2.3s\n *\n * **Korean**: 기본 걷기 속도 (Base Walking Speed)\n */\n private readonly BASE_WALKING_SPEED = 6.0;\n\n /**\n * Base running speed (m/s)\n * Sprint speed for rapid repositioning - crosses 14m arena in ~1.4s\n *\n * **Korean**: 기본 달리기 속도 (Base Running Speed)\n */\n private readonly BASE_RUNNING_SPEED = 10.0;\n\n /**\n * Lateral movement speed (m/s)\n * Fast side-stepping for combat positioning\n *\n * **Korean**: 측면 이동 속도 (Lateral Movement Speed)\n */\n private readonly LATERAL_SPEED = 5.0;\n\n /**\n * Crouching movement speed (m/s)\n * Defensive low movement for cautious approach\n *\n * **Korean**: 웅크림 이동 속도 (Crouching Movement Speed)\n */\n private readonly CROUCHING_SPEED = 3.0;\n\n /**\n * Backward speed multiplier (75% of forward speed)\n *\n * **Korean**: 후퇴 속도 배수 (Backward Speed Multiplier)\n */\n private readonly BACKWARD_SPEED_MULTIPLIER = 0.75;\n\n /**\n * Base acceleration rate (m/s²)\n * Instant-response acceleration for combat movement\n * (e.g., reaches 6 m/s walking speed in 0.2s; 10 m/s sprint speed in 0.33s)\n * Increased from 12.0 to 30.0 for responsive, arcade-style combat feel\n *\n * Imported from physicsConstants.ts to maintain consistency across systems.\n *\n * **Korean**: 기본 가속도 (Base Acceleration)\n */\n private readonly BASE_ACCELERATION = BASE_MOVEMENT_ACCELERATION;\n\n /**\n * Combat state speed penalty multipliers\n *\n * **Korean**: 전투 상태 속도 패널티 (Combat State Speed Penalties)\n */\n private readonly COMBAT_STATE_PENALTIES: Record<CombatState, number> = {\n [CombatState.IDLE]: 0.0, // No penalty when idle\n [CombatState.ATTACKING]: 0.3, // -30% during attack commitment\n [CombatState.DEFENDING]: 0.2, // -20% while guarding\n [CombatState.STUNNED]: 1.0, // Cannot move when stunned\n [CombatState.RECOVERING]: 0.4, // -40% during recovery frames\n [CombatState.COUNTERING]: 0.25, // -25% during counter execution\n [CombatState.TRANSITIONING]: 0.15, // -15% during stance transitions\n [CombatState.GRAPPLING]: 0.8, // -80% while controlling opponent\n [CombatState.GRAPPLED]: 1.0, // Cannot move while being controlled\n };\n\n // Constructor removed - no longer need MovementPenaltySystem instance\n // Using injuryMovementModifier singleton instead\n\n /**\n * Calculate comprehensive speed modifiers for player movement.\n *\n * **Korean**: 속도 변경 계산 (Calculate Speed Modifiers)\n *\n * Analyzes player state and returns complete speed modifier information\n * including all individual factors and final calculated values.\n *\n * @param playerState - Current player state with stance, health, stamina\n * @param movementType - Type of movement being performed\n * @param isCrouching - Whether player is in crouching stance\n * @returns Complete speed modifier state with all factors\n *\n * @public\n */\n public calculateSpeedModifiers(\n playerState: PlayerState,\n movementType: MovementType = MovementType.WALKING,\n isCrouching: boolean = false,\n ): SpeedModifierState {\n // Get base speed based on movement type and archetype-specific speeds\n const baseSpeed = this.getBaseSpeed(\n movementType,\n isCrouching,\n playerState.physicalAttributes,\n );\n\n // Calculate injury penalty from leg damage using NEW InjuryMovementModifier system\n // This replaces the old MovementPenaltySystem with comprehensive injury calculations\n const injuryPenalty = this.calculateInjuryPenalty(\n playerState.bodyPartHealth,\n playerState.bodyPartMaxHealth,\n playerState.pain,\n );\n\n // Calculate stance modifier separately.\n // NOTE: InjuryMovementModifier is called with neutral GEON stance inside\n // calculateInjuryPenalty() so that injury effects are isolated from stance.\n // The actual current stance effect must be applied here via stanceModifier.\n const stanceModifier = this.getStanceSpeedModifier(\n playerState.currentStance,\n );\n\n // Calculate combat state penalty\n const combatStatePenalty = this.getCombatStatePenalty(\n playerState.combatState,\n );\n\n // Calculate stamina penalty (affects acceleration only)\n const staminaPenalty = this.calculateStaminaPenalty(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Check if running is allowed\n const canRun = this.canPlayerRun(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Calculate final speed with all modifiers applied multiplicatively\n // Formula: Base × Stance × (1 - Injury) × (1 - CombatState)\n // Note: Injury penalty now excludes stance (calculated with GEON), so we apply stance here\n const finalSpeed =\n baseSpeed *\n stanceModifier *\n (1.0 - injuryPenalty) *\n (1.0 - combatStatePenalty);\n\n // Calculate final acceleration using archetype-specific base and stamina penalty\n // Formula: ArchetypeAcceleration × (1 - StaminaPenalty)\n const archetypeAcceleration =\n playerState.physicalAttributes?.acceleration ?? this.BASE_ACCELERATION;\n const finalAcceleration = archetypeAcceleration * (1.0 - staminaPenalty);\n\n return {\n baseSpeed,\n stanceModifier,\n injuryPenalty,\n combatStatePenalty,\n staminaPenalty,\n finalSpeed,\n finalAcceleration,\n canRun,\n };\n }\n\n /**\n * Get base speed for movement type.\n *\n * **Korean**: 기본 속도 계산 (Get Base Speed)\n *\n * Uses archetype-specific walk/run speeds when available,\n * falls back to default values for backwards compatibility.\n *\n * @param movementType - Type of movement\n * @param isCrouching - Whether player is crouching\n * @param physicalAttributes - Player's physical attributes (optional)\n * @returns Base speed in m/s\n *\n * @private\n */\n private getBaseSpeed(\n movementType: MovementType,\n isCrouching: boolean,\n physicalAttributes?: import(\"@/types\").PhysicalAttributes,\n ): number {\n if (isCrouching) {\n return this.CROUCHING_SPEED;\n }\n\n // Use archetype-specific speeds if available\n const archetypeWalkSpeed =\n physicalAttributes?.walkSpeed ?? this.BASE_WALKING_SPEED;\n const archetypeRunSpeed =\n physicalAttributes?.runSpeed ?? this.BASE_RUNNING_SPEED;\n\n switch (movementType) {\n case MovementType.WALKING:\n return archetypeWalkSpeed;\n case MovementType.RUNNING:\n return archetypeRunSpeed;\n case MovementType.BACKWARD:\n return archetypeWalkSpeed * this.BACKWARD_SPEED_MULTIPLIER;\n case MovementType.LATERAL:\n // Lateral speed scales proportionally to archetype walk speed\n return (\n archetypeWalkSpeed * (this.LATERAL_SPEED / this.BASE_WALKING_SPEED)\n );\n case MovementType.CROUCHING:\n return this.CROUCHING_SPEED;\n default:\n return archetypeWalkSpeed;\n }\n }\n\n /**\n * Get stance-based speed modifier.\n *\n * **Korean**: 자세 속도 배수 계산 (Get Stance Speed Modifier)\n *\n * @param stance - Current Eight Trigram stance\n * @returns Speed multiplier (0.80 to 1.25)\n *\n * @private\n */\n private getStanceSpeedModifier(stance: TrigramStance): number {\n return STANCE_SPEED_MODIFIERS[stance] ?? 1.0;\n }\n\n /**\n * Calculate injury-based speed penalty from leg damage.\n *\n * **Korean**: 부상 속도 패널티 계산 (Calculate Injury Penalty)\n *\n * Uses NEW InjuryMovementModifier to determine speed reduction based on\n * leg damage severity, torso damage, and pain levels.\n * NOTE: Stance modifier is calculated separately to maintain compatibility\n * with existing SpeedModifierState interface.\n * \n * Penalties are progressive and realistic:\n * - Leg injuries: 0-100% penalty based on health\n * - Torso injuries: 0-30% minor penalty\n * - Both legs injured: Additional 20% cumulative penalty\n * - Pain overload: -15% when pain ≥ 80\n *\n * @param bodyPartHealth - Current body part health\n * @param bodyPartMaxHealth - Maximum body part health\n * @param painLevel - Current pain level (0-100)\n * @returns Speed penalty as percentage (0.0 to 0.9 max)\n *\n * @private\n */\n private calculateInjuryPenalty(\n bodyPartHealth: BodyPartHealth | undefined,\n bodyPartMaxHealth: BodyPartMaxHealth | undefined,\n painLevel: number,\n ): number {\n if (!bodyPartHealth || !bodyPartMaxHealth) {\n return 0.0; // No penalty if body part health not tracked\n }\n\n // Use NEW InjuryMovementModifier system for comprehensive injury calculation\n // Use NEUTRAL stance (GEON = 1.0x) to get pure injury penalty without stance influence\n // Stance is applied separately in calculateSpeedModifiers for compatibility\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0, // Base speed of 1.0 to get pure multiplier\n bodyPartHealth,\n TrigramStance.GEON, // Neutral stance to isolate injury penalty\n painLevel,\n );\n\n // Convert speedMultiplier to penalty percentage\n // speedMultiplier of 1.0 = no penalty (0.0)\n // speedMultiplier of 0.5 = 50% penalty (0.5)\n // speedMultiplier of 0.1 = 90% penalty (0.9)\n const penalty = 1.0 - result.speedMultiplier;\n\n // Return penalty (already clamped by InjuryMovementModifier to min 0.1 speed)\n return Math.min(penalty, 0.9);\n }\n\n /**\n * Calculate combat state speed penalty.\n *\n * **Korean**: 전투 상태 속도 패널티 계산 (Get Combat State Penalty)\n *\n * Different combat states restrict movement:\n * - IDLE: 0% penalty (full movement)\n * - ATTACKING: -30% penalty (committed to technique)\n * - DEFENDING: -20% penalty (guard up, limited mobility)\n * - STUNNED: -100% penalty (cannot move)\n * - RECOVERING: -40% penalty (vulnerable, slow movement)\n * - COUNTERING: -25% penalty (counter execution)\n * - TRANSITIONING: -15% penalty (stance change)\n *\n * @param combatState - Current combat state\n * @returns Speed penalty as percentage (0.0 to 1.0)\n *\n * @private\n */\n private getCombatStatePenalty(combatState: CombatState): number {\n return this.COMBAT_STATE_PENALTIES[combatState] ?? 0.0;\n }\n\n /**\n * Calculate stamina-based acceleration penalty.\n *\n * **Korean**: 스태미나 가속 패널티 계산 (Calculate Stamina Penalty)\n *\n * Stamina affects acceleration rate, making it harder to change direction\n * or speed up when fatigued:\n * - High stamina (70-100%): 0% penalty (normal acceleration)\n * - Medium stamina (40-70%): -20% penalty\n * - Low stamina (10-40%): -50% penalty\n * - Depleted stamina (<10%): -75% penalty, cannot run\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns Acceleration penalty as percentage (0.0 to 0.75)\n *\n * @private\n */\n private calculateStaminaPenalty(\n currentStamina: number,\n maxStamina: number,\n ): number {\n if (maxStamina <= 0) {\n return 0.0; // No penalty if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n\n if (staminaPercent >= 70) {\n return 0.0; // High stamina: no penalty\n } else if (staminaPercent >= 40) {\n return 0.2; // Medium stamina: -20% acceleration\n } else if (staminaPercent >= 10) {\n return 0.5; // Low stamina: -50% acceleration\n } else {\n return 0.75; // Depleted stamina: -75% acceleration\n }\n }\n\n /**\n * Check if player can run based on stamina level.\n *\n * **Korean**: 달리기 가능 확인 (Can Player Run)\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns True if player has enough stamina to run\n *\n * @private\n */\n private canPlayerRun(currentStamina: number, maxStamina: number): boolean {\n if (maxStamina <= 0) {\n return true; // Allow running if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n return staminaPercent >= 10; // Cannot run when stamina < 10%\n }\n\n /**\n * Apply speed modifiers to movement physics system.\n *\n * **Korean**: 속도 변경 적용 (Apply Speed Modifiers)\n *\n * Convenience method to directly apply calculated modifiers to a\n * movement physics instance.\n *\n * @param movementPhysics - Movement physics system to update\n * @param modifiers - Calculated speed modifier state\n *\n * @public\n */\n public applySpeedModifiers(\n movementPhysics: {\n setMaxSpeed: (speed: number) => void;\n setAcceleration: (accel: number) => void;\n },\n modifiers: SpeedModifierState,\n ): void {\n movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n movementPhysics.setAcceleration(modifiers.finalAcceleration);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAqFA,IAAY,eAAL,yBAAA,cAAA;;AAEL,cAAA,aAAA;;AAEA,cAAA,aAAA;;AAEA,cAAA,cAAA;;AAEA,cAAA,aAAA;;AAEA,cAAA,eAAA;;KACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BD,IAAa,sBAAb,MAAiC;;;;;;;CAO/B,qBAAsC;;;;;;;CAQtC,qBAAsC;;;;;;;CAQtC,gBAAiC;;;;;;;CAQjC,kBAAmC;;;;;;CAOnC,4BAA6C;;;;;;;;;;;CAY7C,oBAAA;;;;;;CAOA,yBAAuE;GACpE,YAAY,OAAO;GACnB,YAAY,YAAY;GACxB,YAAY,YAAY;GACxB,YAAY,UAAU;GACtB,YAAY,aAAa;GACzB,YAAY,aAAa;GACzB,YAAY,gBAAgB;GAC5B,YAAY,YAAY;GACxB,YAAY,WAAW;EACzB;;;;;;;;;;;;;;;;CAoBD,wBACE,aACA,eAA6B,aAAa,SAC1C,cAAuB,OACH;EAEpB,MAAM,YAAY,KAAK,aACrB,cACA,aACA,YAAY,mBACb;EAID,MAAM,gBAAgB,KAAK,uBACzB,YAAY,gBACZ,YAAY,mBACZ,YAAY,KACb;EAMD,MAAM,iBAAiB,KAAK,uBAC1B,YAAY,cACb;EAGD,MAAM,qBAAqB,KAAK,sBAC9B,YAAY,YACb;EAGD,MAAM,iBAAiB,KAAK,wBAC1B,YAAY,SACZ,YAAY,WACb;EAGD,MAAM,SAAS,KAAK,aAClB,YAAY,SACZ,YAAY,WACb;AAiBD,SAAO;GACL;GACA;GACA;GACA;GACA;GACA,YAjBA,YACA,kBACC,IAAM,kBACN,IAAM;GAeP,oBAVA,YAAY,oBAAoB,gBAAgB,KAAK,sBACJ,IAAM;GAUvD;GACD;;;;;;;;;;;;;;;;;CAkBH,aACE,cACA,aACA,oBACQ;AACR,MAAI,YACF,QAAO,KAAK;EAId,MAAM,qBACJ,oBAAoB,aAAa,KAAK;EACxC,MAAM,oBACJ,oBAAoB,YAAY,KAAK;AAEvC,UAAQ,cAAR;GACE,KAAK,aAAa,QAChB,QAAO;GACT,KAAK,aAAa,QAChB,QAAO;GACT,KAAK,aAAa,SAChB,QAAO,qBAAqB,KAAK;GACnC,KAAK,aAAa,QAEhB,QACE,sBAAsB,KAAK,gBAAgB,KAAK;GAEpD,KAAK,aAAa,UAChB,QAAO,KAAK;GACd,QACE,QAAO;;;;;;;;;;;;;CAcb,uBAA+B,QAA+B;AAC5D,SAAO,uBAAuB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3C,uBACE,gBACA,mBACA,WACQ;AACR,MAAI,CAAC,kBAAkB,CAAC,kBACtB,QAAO;EAiBT,MAAM,UAAU,IAXD,uBAAuB,uBACpC,GACA,gBACA,cAAc,MACd,UACD,CAM4B;AAG7B,SAAO,KAAK,IAAI,SAAS,GAAI;;;;;;;;;;;;;;;;;;;;;CAsB/B,sBAA8B,aAAkC;AAC9D,SAAO,KAAK,uBAAuB,gBAAgB;;;;;;;;;;;;;;;;;;;;CAqBrD,wBACE,gBACA,YACQ;AACR,MAAI,cAAc,EAChB,QAAO;EAGT,MAAM,iBAAkB,iBAAiB,aAAc;AAEvD,MAAI,kBAAkB,GACpB,QAAO;WACE,kBAAkB,GAC3B,QAAO;WACE,kBAAkB,GAC3B,QAAO;MAEP,QAAO;;;;;;;;;;;;;CAeX,aAAqB,gBAAwB,YAA6B;AACxE,MAAI,cAAc,EAChB,QAAO;AAIT,SADwB,iBAAiB,aAAc,OAC9B;;;;;;;;;;;;;;;CAgB3B,oBACE,iBAIA,WACM;AACN,kBAAgB,YAAY,UAAU,WAAW;AACjD,kBAAgB,gBAAgB,UAAU,kBAAkB"}
1
+ {"version":3,"file":"SpeedModifierSystem.js","names":[],"sources":["../../../src/systems/physics/SpeedModifierSystem.ts"],"sourcesContent":["/**\n * Speed Modifier System\n *\n * **Korean**: 속도 변경 시스템 (Speed Modifier System)\n *\n * Implements comprehensive movement speed modifier system that dynamically adjusts\n * player movement speed based on multiple factors: combat stance, leg injuries,\n * stamina depletion, and combat state. Integrates with physics-based movement\n * system for authentic Korean martial arts combat feel.\n *\n * ## System Features\n *\n * - Base movement speeds for walking, running, backward, lateral, and crouching\n * - Eight Trigram stance-based speed modifiers (80% to 125%)\n * - Injury-based speed reduction from leg damage (0% to 100% penalty)\n * - Stamina-based acceleration penalty (0% to 75% penalty)\n * - Combat state speed adjustments (0% to 100% penalty)\n * - Multiplicative and additive modifier stacking\n *\n * ## Speed Calculation Formula\n *\n * ```\n * Final Speed = Base Speed\n * × Stance Modifier\n * × (1 - Injury Penalty from Legs, Torso & Pain)\n * × (1 - Combat State Penalty)\n *\n * Final Acceleration = Base Acceleration\n * × (1 - Stamina Penalty)\n * ```\n *\n * @module systems/physics/SpeedModifierSystem\n * @category Physics System\n * @korean 속도변경시스템\n */\n\nimport type {\n BodyPartHealth,\n BodyPartMaxHealth,\n} from \"@/systems/bodypart/types\";\nimport type { PlayerState } from \"@/systems/player\";\nimport { CombatState, TrigramStance } from \"@/types/common\";\nimport { BASE_MOVEMENT_ACCELERATION } from \"@/types/physicsConstants\";\nimport { STANCE_SPEED_MODIFIERS } from \"./MovementPhysics\";\nimport { injuryMovementModifier } from \"@/systems/movement/InjuryMovementModifier\";\n\n/**\n * Complete speed modifier state for physics calculations.\n *\n * **Korean**: 속도 변경 상태 (Speed Modifier State)\n *\n * Contains all calculated speed modifiers and final values for application\n * to the physics-based movement system.\n *\n * @public\n * @category Physics System\n * @korean 속도변경상태\n */\nexport interface SpeedModifierState {\n /** Base movement speed before modifiers (m/s) */\n readonly baseSpeed: number;\n /** Stance-based speed multiplier (0.80 to 1.25) */\n readonly stanceModifier: number;\n /** Injury-based speed reduction (0.0 to 0.75, percentage reduction) - Korean: 부상감소 */\n readonly injuryPenalty: number;\n /** Combat state speed reduction (0.0 to 1.0, percentage reduction) */\n readonly combatStatePenalty: number;\n /** Stamina-based acceleration reduction (0.0 to 0.75, percentage reduction) - Korean: 스태미나효과 */\n readonly staminaPenalty: number;\n /** Final calculated movement speed (m/s) */\n readonly finalSpeed: number;\n /** Final calculated acceleration (m/s²) */\n readonly finalAcceleration: number;\n /** Whether running is allowed (false when stamina < 10%) */\n readonly canRun: boolean;\n}\n\n/**\n * Movement type enumeration.\n *\n * **Korean**: 이동 유형 (Movement Type)\n *\n * @public\n * @category Physics System\n */\nexport enum MovementType {\n /** Walking forward - Korean: 걷기 */\n WALKING = \"walking\",\n /** Running/sprinting forward - Korean: 달리기 */\n RUNNING = \"running\",\n /** Moving backward - Korean: 후퇴 */\n BACKWARD = \"backward\",\n /** Side-stepping left/right - Korean: 측면이동 */\n LATERAL = \"lateral\",\n /** Crouching movement - Korean: 웅크리기 */\n CROUCHING = \"crouching\",\n}\n\n/**\n * Speed Modifier System class.\n *\n * **Korean**: 속도 변경 시스템 클래스\n *\n * Calculates comprehensive speed modifiers from multiple factors including\n * stance, injuries, stamina, and combat state. Integrates with existing\n * body part and movement systems.\n *\n * @example\n * ```typescript\n * const system = new SpeedModifierSystem();\n *\n * const modifiers = system.calculateSpeedModifiers(\n * playerState,\n * MovementType.RUNNING,\n * true // isCrouching\n * );\n *\n * // Apply to movement physics\n * movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n * movementPhysics.setAcceleration(modifiers.finalAcceleration);\n * ```\n *\n * @public\n * @category Physics System\n */\nexport class SpeedModifierSystem {\n /**\n * Base walking speed (m/s)\n * Standard walking pace for combat movement - crosses 14m arena in ~2.3s\n *\n * **Korean**: 기본 걷기 속도 (Base Walking Speed)\n */\n private readonly BASE_WALKING_SPEED = 6.0;\n\n /**\n * Base running speed (m/s)\n * Sprint speed for rapid repositioning - crosses 14m arena in ~1.4s\n *\n * **Korean**: 기본 달리기 속도 (Base Running Speed)\n */\n private readonly BASE_RUNNING_SPEED = 10.0;\n\n /**\n * Lateral movement speed (m/s)\n * Fast side-stepping for combat positioning\n *\n * **Korean**: 측면 이동 속도 (Lateral Movement Speed)\n */\n private readonly LATERAL_SPEED = 5.0;\n\n /**\n * Crouching movement speed (m/s)\n * Defensive low movement for cautious approach\n *\n * **Korean**: 웅크림 이동 속도 (Crouching Movement Speed)\n */\n private readonly CROUCHING_SPEED = 3.0;\n\n /**\n * Backward speed multiplier (75% of forward speed)\n *\n * **Korean**: 후퇴 속도 배수 (Backward Speed Multiplier)\n */\n private readonly BACKWARD_SPEED_MULTIPLIER = 0.75;\n\n /**\n * Base acceleration rate (m/s²)\n * Instant-response acceleration for combat movement\n * (e.g., reaches 6 m/s walking speed in 0.2s; 10 m/s sprint speed in 0.33s)\n * Increased from 12.0 to 30.0 for responsive, arcade-style combat feel\n *\n * Imported from physicsConstants.ts to maintain consistency across systems.\n *\n * **Korean**: 기본 가속도 (Base Acceleration)\n */\n private readonly BASE_ACCELERATION = BASE_MOVEMENT_ACCELERATION;\n\n /**\n * Combat state speed penalty multipliers\n *\n * **Korean**: 전투 상태 속도 패널티 (Combat State Speed Penalties)\n */\n private readonly COMBAT_STATE_PENALTIES: Record<CombatState, number> = {\n [CombatState.IDLE]: 0.0, // No penalty when idle\n [CombatState.ATTACKING]: 0.3, // -30% during attack commitment\n [CombatState.DEFENDING]: 0.2, // -20% while guarding\n [CombatState.STUNNED]: 1.0, // Cannot move when stunned\n [CombatState.RECOVERING]: 0.4, // -40% during recovery frames\n [CombatState.COUNTERING]: 0.25, // -25% during counter execution\n [CombatState.TRANSITIONING]: 0.15, // -15% during stance transitions\n [CombatState.GRAPPLING]: 0.8, // -80% while controlling opponent\n [CombatState.GRAPPLED]: 1.0, // Cannot move while being controlled\n };\n\n // Constructor removed - no longer need MovementPenaltySystem instance\n // Using injuryMovementModifier singleton instead\n\n /**\n * Calculate comprehensive speed modifiers for player movement.\n *\n * **Korean**: 속도 변경 계산 (Calculate Speed Modifiers)\n *\n * Analyzes player state and returns complete speed modifier information\n * including all individual factors and final calculated values.\n *\n * @param playerState - Current player state with stance, health, stamina\n * @param movementType - Type of movement being performed\n * @param isCrouching - Whether player is in crouching stance\n * @returns Complete speed modifier state with all factors\n *\n * @public\n */\n public calculateSpeedModifiers(\n playerState: PlayerState,\n movementType: MovementType = MovementType.WALKING,\n isCrouching: boolean = false,\n ): SpeedModifierState {\n // Get base speed based on movement type and archetype-specific speeds\n const baseSpeed = this.getBaseSpeed(\n movementType,\n isCrouching,\n playerState.physicalAttributes,\n );\n\n // Calculate injury penalty from leg damage using NEW InjuryMovementModifier system\n // This replaces the old MovementPenaltySystem with comprehensive injury calculations\n const injuryPenalty = this.calculateInjuryPenalty(\n playerState.bodyPartHealth,\n playerState.bodyPartMaxHealth,\n playerState.pain,\n );\n\n // Calculate stance modifier separately.\n // NOTE: InjuryMovementModifier is called with neutral GEON stance inside\n // calculateInjuryPenalty() so that injury effects are isolated from stance.\n // The actual current stance effect must be applied here via stanceModifier.\n const stanceModifier = this.getStanceSpeedModifier(\n playerState.currentStance,\n );\n\n // Calculate combat state penalty\n const combatStatePenalty = this.getCombatStatePenalty(\n playerState.combatState,\n );\n\n // Calculate stamina penalty (affects acceleration only)\n const staminaPenalty = this.calculateStaminaPenalty(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Check if running is allowed\n const canRun = this.canPlayerRun(\n playerState.stamina,\n playerState.maxStamina,\n );\n\n // Calculate final speed with all modifiers applied multiplicatively\n // Formula: Base × Stance × (1 - Injury) × (1 - CombatState)\n // Note: Injury penalty now excludes stance (calculated with GEON), so we apply stance here\n const finalSpeed =\n baseSpeed *\n stanceModifier *\n (1.0 - injuryPenalty) *\n (1.0 - combatStatePenalty);\n\n // Calculate final acceleration using archetype-specific base and stamina penalty\n // Formula: ArchetypeAcceleration × (1 - StaminaPenalty)\n const archetypeAcceleration =\n playerState.physicalAttributes?.acceleration ?? this.BASE_ACCELERATION;\n const finalAcceleration = archetypeAcceleration * (1.0 - staminaPenalty);\n\n return {\n baseSpeed,\n stanceModifier,\n injuryPenalty,\n combatStatePenalty,\n staminaPenalty,\n finalSpeed,\n finalAcceleration,\n canRun,\n };\n }\n\n /**\n * Get base speed for movement type.\n *\n * **Korean**: 기본 속도 계산 (Get Base Speed)\n *\n * Uses archetype-specific walk/run speeds when available,\n * falls back to default values for backwards compatibility.\n *\n * @param movementType - Type of movement\n * @param isCrouching - Whether player is crouching\n * @param physicalAttributes - Player's physical attributes (optional)\n * @returns Base speed in m/s\n *\n * @private\n */\n private getBaseSpeed(\n movementType: MovementType,\n isCrouching: boolean,\n physicalAttributes?: import(\"@/types\").PhysicalAttributes,\n ): number {\n if (isCrouching) {\n return this.CROUCHING_SPEED;\n }\n\n // Use archetype-specific speeds if available\n const archetypeWalkSpeed =\n physicalAttributes?.walkSpeed ?? this.BASE_WALKING_SPEED;\n const archetypeRunSpeed =\n physicalAttributes?.runSpeed ?? this.BASE_RUNNING_SPEED;\n\n switch (movementType) {\n case MovementType.WALKING:\n return archetypeWalkSpeed;\n case MovementType.RUNNING:\n return archetypeRunSpeed;\n case MovementType.BACKWARD:\n return archetypeWalkSpeed * this.BACKWARD_SPEED_MULTIPLIER;\n case MovementType.LATERAL:\n // Lateral speed scales proportionally to archetype walk speed\n return (\n archetypeWalkSpeed * (this.LATERAL_SPEED / this.BASE_WALKING_SPEED)\n );\n case MovementType.CROUCHING:\n return this.CROUCHING_SPEED;\n default:\n return archetypeWalkSpeed;\n }\n }\n\n /**\n * Get stance-based speed modifier.\n *\n * **Korean**: 자세 속도 배수 계산 (Get Stance Speed Modifier)\n *\n * @param stance - Current Eight Trigram stance\n * @returns Speed multiplier (0.80 to 1.25)\n *\n * @private\n */\n private getStanceSpeedModifier(stance: TrigramStance): number {\n return STANCE_SPEED_MODIFIERS[stance] ?? 1.0;\n }\n\n /**\n * Calculate injury-based speed penalty from leg damage.\n *\n * **Korean**: 부상 속도 패널티 계산 (Calculate Injury Penalty)\n *\n * Uses NEW InjuryMovementModifier to determine speed reduction based on\n * leg damage severity, torso damage, and pain levels.\n * NOTE: Stance modifier is calculated separately to maintain compatibility\n * with existing SpeedModifierState interface.\n * \n * Penalties are progressive and realistic:\n * - Leg injuries: 0-100% penalty based on health\n * - Torso injuries: 0-30% minor penalty\n * - Both legs injured: Additional 20% cumulative penalty\n * - Pain overload: -15% when pain ≥ 80\n *\n * @param bodyPartHealth - Current body part health\n * @param bodyPartMaxHealth - Maximum body part health\n * @param painLevel - Current pain level (0-100)\n * @returns Speed penalty as percentage (0.0 to 0.9 max)\n *\n * @private\n */\n private calculateInjuryPenalty(\n bodyPartHealth: BodyPartHealth | undefined,\n bodyPartMaxHealth: BodyPartMaxHealth | undefined,\n painLevel: number,\n ): number {\n if (!bodyPartHealth || !bodyPartMaxHealth) {\n return 0.0; // No penalty if body part health not tracked\n }\n\n // Use NEW InjuryMovementModifier system for comprehensive injury calculation\n // Use NEUTRAL stance (GEON = 1.0x) to get pure injury penalty without stance influence\n // Stance is applied separately in calculateSpeedModifiers for compatibility\n const result = injuryMovementModifier.calculateMovementSpeed(\n 1.0, // Base speed of 1.0 to get pure multiplier\n bodyPartHealth,\n TrigramStance.GEON, // Neutral stance to isolate injury penalty\n painLevel,\n );\n\n // Convert speedMultiplier to penalty percentage\n // speedMultiplier of 1.0 = no penalty (0.0)\n // speedMultiplier of 0.5 = 50% penalty (0.5)\n // speedMultiplier of 0.1 = 90% penalty (0.9)\n const penalty = 1.0 - result.speedMultiplier;\n\n // Return penalty (already clamped by InjuryMovementModifier to min 0.1 speed)\n return Math.min(penalty, 0.9);\n }\n\n /**\n * Calculate combat state speed penalty.\n *\n * **Korean**: 전투 상태 속도 패널티 계산 (Get Combat State Penalty)\n *\n * Different combat states restrict movement:\n * - IDLE: 0% penalty (full movement)\n * - ATTACKING: -30% penalty (committed to technique)\n * - DEFENDING: -20% penalty (guard up, limited mobility)\n * - STUNNED: -100% penalty (cannot move)\n * - RECOVERING: -40% penalty (vulnerable, slow movement)\n * - COUNTERING: -25% penalty (counter execution)\n * - TRANSITIONING: -15% penalty (stance change)\n *\n * @param combatState - Current combat state\n * @returns Speed penalty as percentage (0.0 to 1.0)\n *\n * @private\n */\n private getCombatStatePenalty(combatState: CombatState): number {\n return this.COMBAT_STATE_PENALTIES[combatState] ?? 0.0;\n }\n\n /**\n * Calculate stamina-based acceleration penalty.\n *\n * **Korean**: 스태미나 가속 패널티 계산 (Calculate Stamina Penalty)\n *\n * Stamina affects acceleration rate, making it harder to change direction\n * or speed up when fatigued:\n * - High stamina (70-100%): 0% penalty (normal acceleration)\n * - Medium stamina (40-70%): -20% penalty\n * - Low stamina (10-40%): -50% penalty\n * - Depleted stamina (<10%): -75% penalty, cannot run\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns Acceleration penalty as percentage (0.0 to 0.75)\n *\n * @private\n */\n private calculateStaminaPenalty(\n currentStamina: number,\n maxStamina: number,\n ): number {\n if (maxStamina <= 0) {\n return 0.0; // No penalty if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n\n if (staminaPercent >= 70) {\n return 0.0; // High stamina: no penalty\n } else if (staminaPercent >= 40) {\n return 0.2; // Medium stamina: -20% acceleration\n } else if (staminaPercent >= 10) {\n return 0.5; // Low stamina: -50% acceleration\n } else {\n return 0.75; // Depleted stamina: -75% acceleration\n }\n }\n\n /**\n * Check if player can run based on stamina level.\n *\n * **Korean**: 달리기 가능 확인 (Can Player Run)\n *\n * @param currentStamina - Current stamina points\n * @param maxStamina - Maximum stamina capacity\n * @returns True if player has enough stamina to run\n *\n * @private\n */\n private canPlayerRun(currentStamina: number, maxStamina: number): boolean {\n if (maxStamina <= 0) {\n return true; // Allow running if stamina not tracked\n }\n\n const staminaPercent = (currentStamina / maxStamina) * 100;\n return staminaPercent >= 10; // Cannot run when stamina < 10%\n }\n\n /**\n * Apply speed modifiers to movement physics system.\n *\n * **Korean**: 속도 변경 적용 (Apply Speed Modifiers)\n *\n * Convenience method to directly apply calculated modifiers to a\n * movement physics instance.\n *\n * @param movementPhysics - Movement physics system to update\n * @param modifiers - Calculated speed modifier state\n *\n * @public\n */\n public applySpeedModifiers(\n movementPhysics: {\n setMaxSpeed: (speed: number) => void;\n setAcceleration: (accel: number) => void;\n },\n modifiers: SpeedModifierState,\n ): void {\n movementPhysics.setMaxSpeed(modifiers.finalSpeed);\n movementPhysics.setAcceleration(modifiers.finalAcceleration);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAqFA,IAAY,eAAL,yBAAA,cAAA;;AAEL,cAAA,aAAU;;AAEV,cAAA,aAAU;;AAEV,cAAA,cAAW;;AAEX,cAAA,aAAU;;AAEV,cAAA,eAAY;;KACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BD,IAAa,sBAAb,MAAiC;;;;;;;CAO/B,qBAAsC;;;;;;;CAQtC,qBAAsC;;;;;;;CAQtC,gBAAiC;;;;;;;CAQjC,kBAAmC;;;;;;CAOnC,4BAA6C;;;;;;;;;;;CAY7C,oBAAA;;;;;;CAOA,yBAAuE;GACpE,YAAY,OAAO;GACnB,YAAY,YAAY;GACxB,YAAY,YAAY;GACxB,YAAY,UAAU;GACtB,YAAY,aAAa;GACzB,YAAY,aAAa;GACzB,YAAY,gBAAgB;GAC5B,YAAY,YAAY;GACxB,YAAY,WAAW;EACzB;;;;;;;;;;;;;;;;CAoBD,wBACE,aACA,eAA6B,aAAa,SAC1C,cAAuB,OACH;EAEpB,MAAM,YAAY,KAAK,aACrB,cACA,aACA,YAAY,mBACb;EAID,MAAM,gBAAgB,KAAK,uBACzB,YAAY,gBACZ,YAAY,mBACZ,YAAY,KACb;EAMD,MAAM,iBAAiB,KAAK,uBAC1B,YAAY,cACb;EAGD,MAAM,qBAAqB,KAAK,sBAC9B,YAAY,YACb;EAGD,MAAM,iBAAiB,KAAK,wBAC1B,YAAY,SACZ,YAAY,WACb;EAGD,MAAM,SAAS,KAAK,aAClB,YAAY,SACZ,YAAY,WACb;AAiBD,SAAO;GACL;GACA;GACA;GACA;GACA;GACA,YAjBA,YACA,kBACC,IAAM,kBACN,IAAM;GAeP,oBAVA,YAAY,oBAAoB,gBAAgB,KAAK,sBACJ,IAAM;GAUvD;GACD;;;;;;;;;;;;;;;;;CAkBH,aACE,cACA,aACA,oBACQ;AACR,MAAI,YACF,QAAO,KAAK;EAId,MAAM,qBACJ,oBAAoB,aAAa,KAAK;EACxC,MAAM,oBACJ,oBAAoB,YAAY,KAAK;AAEvC,UAAQ,cAAR;GACE,KAAK,aAAa,QAChB,QAAO;GACT,KAAK,aAAa,QAChB,QAAO;GACT,KAAK,aAAa,SAChB,QAAO,qBAAqB,KAAK;GACnC,KAAK,aAAa,QAEhB,QACE,sBAAsB,KAAK,gBAAgB,KAAK;GAEpD,KAAK,aAAa,UAChB,QAAO,KAAK;GACd,QACE,QAAO;;;;;;;;;;;;;CAcb,uBAA+B,QAA+B;AAC5D,SAAO,uBAAuB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3C,uBACE,gBACA,mBACA,WACQ;AACR,MAAI,CAAC,kBAAkB,CAAC,kBACtB,QAAO;EAiBT,MAAM,UAAU,IAXD,uBAAuB,uBACpC,GACA,gBACA,cAAc,MACd,UACD,CAM4B;AAG7B,SAAO,KAAK,IAAI,SAAS,GAAI;;;;;;;;;;;;;;;;;;;;;CAsB/B,sBAA8B,aAAkC;AAC9D,SAAO,KAAK,uBAAuB,gBAAgB;;;;;;;;;;;;;;;;;;;;CAqBrD,wBACE,gBACA,YACQ;AACR,MAAI,cAAc,EAChB,QAAO;EAGT,MAAM,iBAAkB,iBAAiB,aAAc;AAEvD,MAAI,kBAAkB,GACpB,QAAO;WACE,kBAAkB,GAC3B,QAAO;WACE,kBAAkB,GAC3B,QAAO;MAEP,QAAO;;;;;;;;;;;;;CAeX,aAAqB,gBAAwB,YAA6B;AACxE,MAAI,cAAc,EAChB,QAAO;AAIT,SADwB,iBAAiB,aAAc,OAC9B;;;;;;;;;;;;;;;CAgB3B,oBACE,iBAIA,WACM;AACN,kBAAgB,YAAY,UAAU,WAAW;AACjD,kBAAgB,gBAAgB,UAAU,kBAAkB"}
@@ -1 +1 @@
1
- {"version":3,"file":"AccessibilityTypes.js","names":[],"sources":["../../src/types/AccessibilityTypes.ts"],"sourcesContent":["/**\n * Accessibility type definitions for WCAG 2.1 Level AA compliance\n * Provides type-safe ARIA attributes and keyboard navigation interfaces\n * \n * @module types/AccessibilityTypes\n * @category Accessibility\n * @korean 접근성 타입\n */\n\n/**\n * ARIA role types for semantic HTML elements\n */\nexport type AriaRole =\n | 'button'\n | 'navigation'\n | 'main'\n | 'complementary'\n | 'contentinfo'\n | 'banner'\n | 'form'\n | 'search'\n | 'region'\n | 'article'\n | 'alert'\n | 'alertdialog'\n | 'dialog'\n | 'menu'\n | 'menubar'\n | 'menuitem'\n | 'menuitemcheckbox'\n | 'menuitemradio'\n | 'progressbar'\n | 'slider'\n | 'spinbutton'\n | 'tab'\n | 'tablist'\n | 'tabpanel'\n | 'toolbar'\n | 'tooltip'\n | 'group'\n | 'listbox'\n | 'option'\n | 'radio'\n | 'radiogroup'\n | 'switch'\n | 'link'\n | 'img'\n | 'presentation'\n | 'none';\n\n/**\n * ARIA live region politeness levels\n */\nexport type AriaLive = 'off' | 'polite' | 'assertive';\n\n/**\n * ARIA current state values\n */\nexport type AriaCurrent =\n | 'page'\n | 'step'\n | 'location'\n | 'date'\n | 'time'\n | 'true'\n | 'false';\n\n/**\n * Keyboard key codes for navigation\n */\nexport enum KeyCode {\n ENTER = 'Enter',\n SPACE = ' ',\n ESCAPE = 'Escape',\n TAB = 'Tab',\n ARROW_UP = 'ArrowUp',\n ARROW_DOWN = 'ArrowDown',\n ARROW_LEFT = 'ArrowLeft',\n ARROW_RIGHT = 'ArrowRight',\n HOME = 'Home',\n END = 'End',\n PAGE_UP = 'PageUp',\n PAGE_DOWN = 'PageDown',\n}\n\n/**\n * Keyboard navigation actions\n */\nexport interface KeyboardActions {\n /** Action triggered on Enter or Space */\n readonly onActivate?: () => void;\n /** Action triggered on Escape */\n readonly onCancel?: () => void;\n /** Action triggered on arrow keys */\n readonly onNavigate?: (direction: 'up' | 'down' | 'left' | 'right') => void;\n /** Action triggered on Tab key */\n readonly onTab?: (shiftKey: boolean) => void;\n /** Action triggered on Home/End keys */\n readonly onJump?: (to: 'start' | 'end') => void;\n}\n\n/**\n * ARIA attributes for components\n */\nexport interface AriaAttributes {\n /** ARIA role */\n readonly role?: AriaRole;\n /** ARIA label (Korean | English bilingual format) */\n readonly 'aria-label'?: string;\n /** ARIA labelled by element ID */\n readonly 'aria-labelledby'?: string;\n /** ARIA described by element ID */\n readonly 'aria-describedby'?: string;\n /** ARIA live region politeness */\n readonly 'aria-live'?: AriaLive;\n /** ARIA expanded state */\n readonly 'aria-expanded'?: boolean;\n /** ARIA pressed state */\n readonly 'aria-pressed'?: boolean;\n /** ARIA selected state */\n readonly 'aria-selected'?: boolean;\n /** ARIA checked state */\n readonly 'aria-checked'?: boolean | 'mixed';\n /** ARIA disabled state */\n readonly 'aria-disabled'?: boolean;\n /** ARIA hidden state */\n readonly 'aria-hidden'?: boolean;\n /** ARIA current state */\n readonly 'aria-current'?: AriaCurrent;\n /** ARIA modal state */\n readonly 'aria-modal'?: boolean;\n /** ARIA controls element ID */\n readonly 'aria-controls'?: string;\n /** ARIA owns element IDs */\n readonly 'aria-owns'?: string;\n /** ARIA has popup type */\n readonly 'aria-haspopup'?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';\n /** ARIA value now (for progress indicators) */\n readonly 'aria-valuenow'?: number;\n /** ARIA value min */\n readonly 'aria-valuemin'?: number;\n /** ARIA value max */\n readonly 'aria-valuemax'?: number;\n /** ARIA value text */\n readonly 'aria-valuetext'?: string;\n /** ARIA orientation */\n readonly 'aria-orientation'?: 'horizontal' | 'vertical';\n /** ARIA atomic (for live regions) */\n readonly 'aria-atomic'?: boolean;\n /** ARIA relevant (for live regions) */\n readonly 'aria-relevant'?: 'additions' | 'removals' | 'text' | 'all';\n /** ARIA busy state */\n readonly 'aria-busy'?: boolean;\n /** ARIA invalid state */\n readonly 'aria-invalid'?: boolean | 'grammar' | 'spelling';\n /** ARIA required state */\n readonly 'aria-required'?: boolean;\n /** ARIA readonly state */\n readonly 'aria-readonly'?: boolean;\n}\n\n/**\n * Focus management configuration\n */\nexport interface FocusConfig {\n /** Whether element should receive focus on mount */\n readonly autoFocus?: boolean;\n /** Whether focus should be trapped within element */\n readonly trapFocus?: boolean;\n /** Whether focus should be restored on unmount */\n readonly restoreFocus?: boolean;\n /** Initial focus target selector */\n readonly initialFocus?: string;\n /** Return focus target selector */\n readonly returnFocus?: string;\n}\n\n/**\n * Focus indicator style configuration\n */\nexport interface FocusIndicatorStyle {\n /** Outline width in pixels */\n readonly outlineWidth?: number;\n /** Outline color (hex) */\n readonly outlineColor?: number;\n /** Outline offset in pixels */\n readonly outlineOffset?: number;\n /** Outline style */\n readonly outlineStyle?: 'solid' | 'dashed' | 'dotted';\n /** Box shadow for glow effect */\n readonly boxShadow?: string;\n /** Transition duration in seconds */\n readonly transitionDuration?: number;\n}\n\n/**\n * Keyboard event handler type\n */\nexport type KeyboardEventHandler = (event: KeyboardEvent) => void;\n\n/**\n * Focus event handler type\n */\nexport type FocusEventHandler = (event: FocusEvent) => void;\n\n/**\n * Screen reader announcement configuration\n */\nexport interface ScreenReaderAnnouncement {\n /** Message to announce (Korean | English bilingual) */\n readonly message: string;\n /** Politeness level */\n readonly politeness?: AriaLive;\n /** Delay before announcement in milliseconds */\n readonly delay?: number;\n}\n\n/**\n * Color contrast configuration for WCAG compliance\n */\nexport interface ColorContrastConfig {\n /** Foreground color (hex) */\n readonly foreground: number;\n /** Background color (hex) */\n readonly background: number;\n /** Target contrast ratio (4.5:1 for normal text, 3:1 for large text or UI) */\n readonly targetRatio: 4.5 | 3;\n /** Whether this is for large text (18pt+ or 14pt+ bold) */\n readonly isLargeText?: boolean;\n}\n\n/**\n * Accessibility validation result\n */\nexport interface AccessibilityValidation {\n /** Whether validation passed */\n readonly passed: boolean;\n /** Validation errors */\n readonly errors: readonly string[];\n /** Validation warnings */\n readonly warnings: readonly string[];\n /** Validation recommendations */\n readonly recommendations: readonly string[];\n}\n\n/**\n * WCAG compliance level\n */\nexport enum WCAGLevel {\n A = 'A',\n AA = 'AA',\n AAA = 'AAA',\n}\n\n/**\n * WCAG compliance check result\n */\nexport interface WCAGComplianceResult {\n /** Compliance level achieved */\n readonly level: WCAGLevel;\n /** Whether component meets target level */\n readonly compliant: boolean;\n /** Specific criteria results */\n readonly criteria: {\n readonly keyboardAccessible: boolean;\n readonly colorContrast: boolean;\n readonly focusVisible: boolean;\n readonly ariaLabels: boolean;\n readonly semanticHTML: boolean;\n readonly errorIdentification: boolean;\n };\n /** Issues found */\n readonly issues: readonly string[];\n}\n\n/**\n * Bilingual label format (Korean | English)\n */\nexport interface BilingualLabel {\n /** Korean text */\n readonly korean: string;\n /** English text */\n readonly english: string;\n /** Formatted label string (Korean | English) */\n readonly label: string;\n}\n\n/**\n * Helper function to create bilingual labels\n */\nexport const createBilingualLabel = (\n korean: string,\n english: string\n): BilingualLabel => ({\n korean,\n english,\n label: `${korean} | ${english}`,\n});\n"],"mappings":";;;;AAsEA,IAAY,UAAL,yBAAA,SAAA;AACL,SAAA,WAAA;AACA,SAAA,WAAA;AACA,SAAA,YAAA;AACA,SAAA,SAAA;AACA,SAAA,cAAA;AACA,SAAA,gBAAA;AACA,SAAA,gBAAA;AACA,SAAA,iBAAA;AACA,SAAA,UAAA;AACA,SAAA,SAAA;AACA,SAAA,aAAA;AACA,SAAA,eAAA;;KACD;;;;AAqKD,IAAY,YAAL,yBAAA,WAAA;AACL,WAAA,OAAA;AACA,WAAA,QAAA;AACA,WAAA,SAAA;;KACD;;;;AAsCD,IAAa,wBACX,QACA,aACoB;CACpB;CACA;CACA,OAAO,GAAG,OAAO,KAAK;CACvB"}
1
+ {"version":3,"file":"AccessibilityTypes.js","names":[],"sources":["../../src/types/AccessibilityTypes.ts"],"sourcesContent":["/**\n * Accessibility type definitions for WCAG 2.1 Level AA compliance\n * Provides type-safe ARIA attributes and keyboard navigation interfaces\n * \n * @module types/AccessibilityTypes\n * @category Accessibility\n * @korean 접근성 타입\n */\n\n/**\n * ARIA role types for semantic HTML elements\n */\nexport type AriaRole =\n | 'button'\n | 'navigation'\n | 'main'\n | 'complementary'\n | 'contentinfo'\n | 'banner'\n | 'form'\n | 'search'\n | 'region'\n | 'article'\n | 'alert'\n | 'alertdialog'\n | 'dialog'\n | 'menu'\n | 'menubar'\n | 'menuitem'\n | 'menuitemcheckbox'\n | 'menuitemradio'\n | 'progressbar'\n | 'slider'\n | 'spinbutton'\n | 'tab'\n | 'tablist'\n | 'tabpanel'\n | 'toolbar'\n | 'tooltip'\n | 'group'\n | 'listbox'\n | 'option'\n | 'radio'\n | 'radiogroup'\n | 'switch'\n | 'link'\n | 'img'\n | 'presentation'\n | 'none';\n\n/**\n * ARIA live region politeness levels\n */\nexport type AriaLive = 'off' | 'polite' | 'assertive';\n\n/**\n * ARIA current state values\n */\nexport type AriaCurrent =\n | 'page'\n | 'step'\n | 'location'\n | 'date'\n | 'time'\n | 'true'\n | 'false';\n\n/**\n * Keyboard key codes for navigation\n */\nexport enum KeyCode {\n ENTER = 'Enter',\n SPACE = ' ',\n ESCAPE = 'Escape',\n TAB = 'Tab',\n ARROW_UP = 'ArrowUp',\n ARROW_DOWN = 'ArrowDown',\n ARROW_LEFT = 'ArrowLeft',\n ARROW_RIGHT = 'ArrowRight',\n HOME = 'Home',\n END = 'End',\n PAGE_UP = 'PageUp',\n PAGE_DOWN = 'PageDown',\n}\n\n/**\n * Keyboard navigation actions\n */\nexport interface KeyboardActions {\n /** Action triggered on Enter or Space */\n readonly onActivate?: () => void;\n /** Action triggered on Escape */\n readonly onCancel?: () => void;\n /** Action triggered on arrow keys */\n readonly onNavigate?: (direction: 'up' | 'down' | 'left' | 'right') => void;\n /** Action triggered on Tab key */\n readonly onTab?: (shiftKey: boolean) => void;\n /** Action triggered on Home/End keys */\n readonly onJump?: (to: 'start' | 'end') => void;\n}\n\n/**\n * ARIA attributes for components\n */\nexport interface AriaAttributes {\n /** ARIA role */\n readonly role?: AriaRole;\n /** ARIA label (Korean | English bilingual format) */\n readonly 'aria-label'?: string;\n /** ARIA labelled by element ID */\n readonly 'aria-labelledby'?: string;\n /** ARIA described by element ID */\n readonly 'aria-describedby'?: string;\n /** ARIA live region politeness */\n readonly 'aria-live'?: AriaLive;\n /** ARIA expanded state */\n readonly 'aria-expanded'?: boolean;\n /** ARIA pressed state */\n readonly 'aria-pressed'?: boolean;\n /** ARIA selected state */\n readonly 'aria-selected'?: boolean;\n /** ARIA checked state */\n readonly 'aria-checked'?: boolean | 'mixed';\n /** ARIA disabled state */\n readonly 'aria-disabled'?: boolean;\n /** ARIA hidden state */\n readonly 'aria-hidden'?: boolean;\n /** ARIA current state */\n readonly 'aria-current'?: AriaCurrent;\n /** ARIA modal state */\n readonly 'aria-modal'?: boolean;\n /** ARIA controls element ID */\n readonly 'aria-controls'?: string;\n /** ARIA owns element IDs */\n readonly 'aria-owns'?: string;\n /** ARIA has popup type */\n readonly 'aria-haspopup'?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';\n /** ARIA value now (for progress indicators) */\n readonly 'aria-valuenow'?: number;\n /** ARIA value min */\n readonly 'aria-valuemin'?: number;\n /** ARIA value max */\n readonly 'aria-valuemax'?: number;\n /** ARIA value text */\n readonly 'aria-valuetext'?: string;\n /** ARIA orientation */\n readonly 'aria-orientation'?: 'horizontal' | 'vertical';\n /** ARIA atomic (for live regions) */\n readonly 'aria-atomic'?: boolean;\n /** ARIA relevant (for live regions) */\n readonly 'aria-relevant'?: 'additions' | 'removals' | 'text' | 'all';\n /** ARIA busy state */\n readonly 'aria-busy'?: boolean;\n /** ARIA invalid state */\n readonly 'aria-invalid'?: boolean | 'grammar' | 'spelling';\n /** ARIA required state */\n readonly 'aria-required'?: boolean;\n /** ARIA readonly state */\n readonly 'aria-readonly'?: boolean;\n}\n\n/**\n * Focus management configuration\n */\nexport interface FocusConfig {\n /** Whether element should receive focus on mount */\n readonly autoFocus?: boolean;\n /** Whether focus should be trapped within element */\n readonly trapFocus?: boolean;\n /** Whether focus should be restored on unmount */\n readonly restoreFocus?: boolean;\n /** Initial focus target selector */\n readonly initialFocus?: string;\n /** Return focus target selector */\n readonly returnFocus?: string;\n}\n\n/**\n * Focus indicator style configuration\n */\nexport interface FocusIndicatorStyle {\n /** Outline width in pixels */\n readonly outlineWidth?: number;\n /** Outline color (hex) */\n readonly outlineColor?: number;\n /** Outline offset in pixels */\n readonly outlineOffset?: number;\n /** Outline style */\n readonly outlineStyle?: 'solid' | 'dashed' | 'dotted';\n /** Box shadow for glow effect */\n readonly boxShadow?: string;\n /** Transition duration in seconds */\n readonly transitionDuration?: number;\n}\n\n/**\n * Keyboard event handler type\n */\nexport type KeyboardEventHandler = (event: KeyboardEvent) => void;\n\n/**\n * Focus event handler type\n */\nexport type FocusEventHandler = (event: FocusEvent) => void;\n\n/**\n * Screen reader announcement configuration\n */\nexport interface ScreenReaderAnnouncement {\n /** Message to announce (Korean | English bilingual) */\n readonly message: string;\n /** Politeness level */\n readonly politeness?: AriaLive;\n /** Delay before announcement in milliseconds */\n readonly delay?: number;\n}\n\n/**\n * Color contrast configuration for WCAG compliance\n */\nexport interface ColorContrastConfig {\n /** Foreground color (hex) */\n readonly foreground: number;\n /** Background color (hex) */\n readonly background: number;\n /** Target contrast ratio (4.5:1 for normal text, 3:1 for large text or UI) */\n readonly targetRatio: 4.5 | 3;\n /** Whether this is for large text (18pt+ or 14pt+ bold) */\n readonly isLargeText?: boolean;\n}\n\n/**\n * Accessibility validation result\n */\nexport interface AccessibilityValidation {\n /** Whether validation passed */\n readonly passed: boolean;\n /** Validation errors */\n readonly errors: readonly string[];\n /** Validation warnings */\n readonly warnings: readonly string[];\n /** Validation recommendations */\n readonly recommendations: readonly string[];\n}\n\n/**\n * WCAG compliance level\n */\nexport enum WCAGLevel {\n A = 'A',\n AA = 'AA',\n AAA = 'AAA',\n}\n\n/**\n * WCAG compliance check result\n */\nexport interface WCAGComplianceResult {\n /** Compliance level achieved */\n readonly level: WCAGLevel;\n /** Whether component meets target level */\n readonly compliant: boolean;\n /** Specific criteria results */\n readonly criteria: {\n readonly keyboardAccessible: boolean;\n readonly colorContrast: boolean;\n readonly focusVisible: boolean;\n readonly ariaLabels: boolean;\n readonly semanticHTML: boolean;\n readonly errorIdentification: boolean;\n };\n /** Issues found */\n readonly issues: readonly string[];\n}\n\n/**\n * Bilingual label format (Korean | English)\n */\nexport interface BilingualLabel {\n /** Korean text */\n readonly korean: string;\n /** English text */\n readonly english: string;\n /** Formatted label string (Korean | English) */\n readonly label: string;\n}\n\n/**\n * Helper function to create bilingual labels\n */\nexport const createBilingualLabel = (\n korean: string,\n english: string\n): BilingualLabel => ({\n korean,\n english,\n label: `${korean} | ${english}`,\n});\n"],"mappings":";;;;AAsEA,IAAY,UAAL,yBAAA,SAAA;AACL,SAAA,WAAQ;AACR,SAAA,WAAQ;AACR,SAAA,YAAS;AACT,SAAA,SAAM;AACN,SAAA,cAAW;AACX,SAAA,gBAAa;AACb,SAAA,gBAAa;AACb,SAAA,iBAAc;AACd,SAAA,UAAO;AACP,SAAA,SAAM;AACN,SAAA,aAAU;AACV,SAAA,eAAY;;KACb;;;;AAqKD,IAAY,YAAL,yBAAA,WAAA;AACL,WAAA,OAAI;AACJ,WAAA,QAAK;AACL,WAAA,SAAM;;KACP;;;;AAsCD,IAAa,wBACX,QACA,aACoB;CACpB;CACA;CACA,OAAO,GAAG,OAAO,KAAK;CACvB"}