Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | 4x 4x 4x 80x 80x 30x 50x 80x 1x 49x 49x 37x 4x 33x 4x 29x 26x 15x 4x 4x 24x 24x 24x 7x 17x 12x 12x 5x 7x 5x 42x | /**
* Body Region Sound Mapping for Black Trigram
* Maps body regions and impact intensities to existing audio assets
*
* Uses only existing sound files - no new audio creation needed:
* - hit_flesh_* for soft tissue impacts
* - hit_light_* for minor bone contact
* - hit_medium_* for solid bone impacts
* - hit_heavy_* for devastating bone damage
* - hit_critical_* for fracture-level and vital point strikes
* - body_realistic_sound_* as ambient bone/flesh mixing
*/
import { AudioBodyRegion, ImpactIntensity } from "./types";
/**
* Body region to sound ID mapping
* Returns base sound ID without variant number
*/
export const BODY_REGION_SOUND_MAP: Record<
AudioBodyRegion,
Record<ImpactIntensity, string>
> = {
head: {
// Head strikes: skull thud, skull crack sounds
light: "hit_light", // Glancing temple/jaw hits
medium: "hit_medium", // Solid jaw/temple strikes
heavy: "hit_heavy", // Devastating skull impacts
critical: "hit_critical", // Vital point (temple, back of neck)
fracture: "hit_critical", // Skull fracture sounds (severe)
},
torso: {
// Torso strikes: rib impact, rib crack, internal organ thuds
light: "hit_light", // Light rib contact
medium: "hit_medium", // Solid rib/sternum impact
heavy: "hit_heavy", // Rib-breaking force, liver strikes
critical: "hit_critical", // Solar plexus, heart vital points
fracture: "hit_critical", // Multiple rib fractures, internal damage
},
arms: {
// Arm/limb strikes: limb bone thud, joint crack
light: "hit_flesh", // Muscle strikes, glancing blows
medium: "hit_medium", // Solid elbow/forearm bone contact
heavy: "hit_heavy", // Joint destruction (shoulder, elbow, wrist)
critical: "hit_critical", // Nerve strikes, joint breaks
fracture: "hit_critical", // Complete arm bone fracture
},
legs: {
// Leg strikes: knee cap, shin bone, ankle impacts
light: "hit_flesh", // Thigh muscle strikes
medium: "hit_medium", // Shin/knee bone impacts
heavy: "hit_heavy", // Knee destruction, ankle breaks
critical: "hit_critical", // Vital leg nerve strikes
fracture: "hit_critical", // Femur/tibia fractures
},
soft_tissue: {
// Soft tissue: muscle thud, flesh impact (no bone contact)
light: "hit_flesh", // Light muscle contact
medium: "hit_flesh", // Solid muscle compression
heavy: "body_realistic_sound", // Deep muscle trauma
critical: "hit_critical", // Soft vital points (throat, groin)
fracture: "hit_critical", // Severe soft tissue damage
},
};
/**
* Number of audio variants per sound type
* Used for random selection in combat
*/
export const SOUND_VARIANT_COUNTS: Record<string, number> = {
hit_flesh: 4,
hit_light: 4,
hit_medium: 4,
hit_heavy: 4,
hit_critical: 4,
body_realistic_sound: 1, // Only 1 variant available
};
/**
* Volume multipliers based on impact intensity
* Higher damage = louder sounds (as per requirements)
*/
export const IMPACT_VOLUME_MULTIPLIERS: Record<ImpactIntensity, number> = {
light: 0.7, // -30% volume
medium: 0.85, // -15% volume
heavy: 1.0, // Normal volume
critical: 1.15, // +15% volume
fracture: 1.3, // +30% volume (bone-breaking audio)
};
/**
* Get sound ID for a bone impact event
* @param region - Body region struck
* @param intensity - Impact intensity level
* @param randomize - Whether to add random variant (default: true)
* @returns Sound ID to play (e.g., "hit_critical_3")
*/
export function getBoneImpactSoundId(
region: AudioBodyRegion,
intensity: ImpactIntensity,
randomize: boolean = true
): string {
const baseSoundId = BODY_REGION_SOUND_MAP[region][intensity];
if (!randomize) {
return baseSoundId;
}
// Get variant count for this sound type
const variantCount = SOUND_VARIANT_COUNTS[baseSoundId] ?? 1;
if (variantCount === 1) {
return baseSoundId;
}
// Random variant selection (1 to variantCount)
const variant = Math.floor(Math.random() * variantCount) + 1;
return `${baseSoundId}_${variant}`;
}
/**
* Calculate impact intensity from damage amount
* @param damage - Damage dealt in attack
* @param remainingHealth - Target's remaining health (for fracture detection)
* @param isVitalPoint - Whether strike hit a vital point
* @returns Impact intensity level
*/
export function calculateImpactIntensity(
damage: number,
remainingHealth?: number,
isVitalPoint?: boolean
): ImpactIntensity {
// Vital point strikes are always critical (highest priority)
if (isVitalPoint) {
return "critical";
}
// Fracture detection: health below 30% + high damage
// Note: Assumes maxHealth = 100 (standard across codebase)
if (
remainingHealth !== undefined &&
remainingHealth < 30 &&
damage >= 20
) {
return "fracture";
}
// Intensity based on damage amount
if (damage >= 40) return "critical";
if (damage >= 25) return "heavy";
if (damage >= 10) return "medium";
return "light";
}
/**
* Body region detection thresholds
* Y-axis thresholds for vertical body regions
*/
const REGION_DETECTION_THRESHOLDS = {
HEAD_MIN: 0.75, // Top 25% of body is head
TORSO_MIN: 0.25, // Middle 50% is torso (or arms)
ARMS_X_MIN: 0.3, // Side hits (X > 0.3) in torso range are arms
} as const;
/**
* Detect body region from 3D hit coordinates
* Uses Y-axis (vertical) and X-axis (horizontal) to determine region
*
* @param hitPosition - 3D position where strike landed
* @param characterHeight - Total height of character model (default: 2.0)
* @returns Body region struck
*/
export function detectAudioBodyRegion(
hitPosition: { x: number; y: number; z?: number },
characterHeight: number = 2.0
): AudioBodyRegion {
const { x, y } = hitPosition;
const normalizedY = y / characterHeight; // Normalize to 0-1 range
// Head region: top 25% of body (HEAD_MIN - 1.0)
if (normalizedY >= REGION_DETECTION_THRESHOLDS.HEAD_MIN) {
return "head";
}
// Torso region: middle 50% of body (TORSO_MIN - HEAD_MIN)
if (normalizedY >= REGION_DETECTION_THRESHOLDS.TORSO_MIN) {
// Check horizontal position for arms
const absX = Math.abs(x);
if (absX > REGION_DETECTION_THRESHOLDS.ARMS_X_MIN) {
// Hits on the sides are likely arms
return "arms";
}
return "torso";
}
// Legs region: bottom 25% of body (0 - TORSO_MIN)
return "legs";
}
/**
* Get volume multiplier for impact intensity
* @param intensity - Impact intensity level
* @returns Volume multiplier (0.7 to 1.3)
*/
export function getImpactVolumeMultiplier(intensity: ImpactIntensity): number {
return IMPACT_VOLUME_MULTIPLIERS[intensity];
}
|