Mechanic · enemies & ai · survival horror
Proximity warning
A device or display that tells the player an enemy is near before it can be seen.
On this page
A proximity warning tells the player an enemy is close before it comes into view. Silent Hill’s pocket radio plays static for the two nearest enemies within 32 world units, chosen by distance alone with no line-of-sight test, and the static grows louder as each comes closer1.
- Audio cueSilent Hill (1999). The pocket radio plays static for the two nearest enemies within 32 units, by distance alone, louder as they close in.1
Games
| Game | Year | How | Note |
|---|---|---|---|
| Silent Hill | 1999 | Audio cue | the pocket radio plays static for the two nearest enemies within 32 units, by distance alone, louder as they close in |
Every claim about this mechanic, by game (1)
References
- ^ abIn the US build (SLUS-00707),
Game_NpcUpdatepicks the enemies the pocket radio reacts to by distance alone, with no line-of-sight test. An enemy (a character id up toChara_MonsterCybil, the code's last common enemy) counts while its health is above 0, itsCharaFlag_NoRadioStaticflag is clear (Split Head's init sets it; other setters weren't read), and its squared distance from Harry on the ground plane, x and z with height ignored, is under 32² world units (a unit is Q12 1.0). In maps flaggedMapFlag_Interiorwith one or two active chunks, which the code calls low-visibility interiors, the enemy must also share Harry's 40-unit chunk cell on both axes. The code keeps the three nearest, and the radio's two static channels (g_RadioNoise[2]) each follow one of the nearest two, only whileItemToggleFlag_RadioOnis set. Each channel is panned toward its enemy, and its volume falls with distance: the attenuation is the distance converted byQ12_TO_Q4(sixteenths of a unit, by the decompilers' reading, which their comment "TODO: Is it Q4 here?" doubts), halved outside low-visibility interiors, capped at 255, andSd_SfxAttributesUpdatetakes that share out of 255 from the volume. Computed under that reading, the static falls silent at about 16 units in a low-visibility interior and about 32 units elsewhere.Codeshdecompilations/silent-hill-decomprevisedHow we know
218 posXShift6 = Q12_TO_Q6(g_SysWork.playerWork.player.position.vx); 219 posZShift6 = Q12_TO_Q6(g_SysWork.playerWork.player.position.vz); ⋮ 227 closestNpcInfos[j].distanceToNpc = SQUARE(32);
src/bodyprog/events/npc_main.c lines 218–229 at 405a621 · upstream ↗ 243 // Only process enemy NPC for radio interference. 244 if (curNpc->model.charaId <= CHARA_LAST_ENEMY_ID) ⋮ 246 // Compute square integer distance from player to NPC. 247 curDistToNpc = Q12_SQUARE_PRECISE(Q12_TO_Q6(curNpc->position.vx) - posXShift6) + 248 Q12_SQUARE_PRECISE(Q12_TO_Q6(curNpc->position.vz) - posZShift6); ⋮ 250 // Check if map is low-visibility interior. 251 isLowVisInterior = false; 252 if (g_MapOverlayHdr.mapInfo->flags & MapFlag_Interior) ⋮ 254 isLowVisInterior = (g_MapOverlayHdr.mapInfo->flags & (MapFlag_OneActiveChunk | 255 MapFlag_TwoActiveChunks)) > 0; ⋮ 262 if (curNpc->health <= Q12(0.0f) || 263 curNpc->flags & CharaFlag_NoRadioStatic || ⋮
src/bodyprog/events/npc_main.c lines 243–287 at 405a621 · upstream ↗ 7#define CHUNK_SIZE 40.0finclude/bodyprog/map/terrain.h line 7 at 405a621 · upstream ↗ #define CHARA_LAST_ENEMY_ID Chara_MonsterCybil
include/bodyprog/chara/chara.h#L15 · upstream ↗ 62 splitHead->flags |= CharaFlag_NoRadioStatic | CharaFlag_Hit;src/maps/characters/split_head.c line 62 at 405a621 · upstream ↗ 155 s_CloseNpcInfo closestNpcInfos[3];src/bodyprog/events/npc_main.c line 155 at 405a621 · upstream ↗ 181 s32 func_800382B0(s32 bitIdx) ⋮ 185 for (i = 0; i < (ARRAY_SIZE(closestNpcInfos) - 1); i++) ⋮ 197 static s32 func_800382EC() ⋮ 201 for (i = 0; i < (ARRAY_SIZE(closestNpcInfos) - 1); i++)
src/bodyprog/events/npc_main.c lines 181–201 at 405a621 · upstream ↗ 68s_RadioNoise g_RadioNoise[2];src/bodyprog/events/game_sys_states.c line 68 at 405a621 · upstream ↗ 362 if (!(g_SavegamePtr->itemToggleFlags & ItemToggleFlag_RadioOn)) ⋮ 364 return;
src/bodyprog/events/npc_main.c lines 362–365 at 405a621 · upstream ↗ 423 isExterior = false; 424 if (!(g_MapOverlayHdr.mapInfo->flags & MapFlag_Interior) || 425 !(g_MapOverlayHdr.mapInfo->flags & (MapFlag_OneActiveChunk | MapFlag_TwoActiveChunks))) ⋮ 427 isExterior = true; ⋮ 433 balance = Vc_StereoBalanceGet(&closeNpcInfo->position); ⋮ 435 // Compute volume from distance. 436 distToNpc = Q12_TO_Q4(SquareRoot12(Q12(closeNpcInfo->distanceToNpc))); 437 if (isExterior) ⋮ 439 distToNpc = DIV_FAST(distToNpc, 2); ⋮ 442 // Compute clamped volume from Q4 distance. TODO: Is it Q4 here? 443 vol = CLAMP(distToNpc, Q8(0.0f), Q8_CLAMPED(1.0f)); ⋮ 445 Sd_SfxAttributesUpdate(Sfx_RadioInterferenceLoop + l, balance, vol, 0);
src/bodyprog/events/npc_main.c lines 423–445 at 405a621 · upstream ↗ 560 convertedVol = vol; 561 convertedVol = g_Sd_VabPlayingInfo.volumeLeft - ((g_Sd_VabPlayingInfo.volumeLeft * (convertedVol)) / 255);
src/bodyprog/sound/sd_call.c lines 560–561 at 405a621 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
Sources
Code
- shdecompilations contributors. 2026. “silent-hill-decomp: a matching decompilation of Silent Hill for the PlayStation (shdecompilations/silent-hill-decomp).” Commit 405a621. shdecompilations/silent-hill-decomp @ 405a621 · licence, all uses