Mechanic · enemies & ai · stealth
Noise detection
How enemies hear the player's noises, and which noises reach which enemies.
On this page
Noise detection decides which enemies hear a sound the player makes. In Metal Gear Solid each noise has a power. A quiet noise reaches guards within 1,500 units, a loud one within 8,000, and an explosion is heard at any distance. A knock on a wall or a footstep on a noisy floor reaches only the one guard nearest by route1.
- By powerMetal Gear Solid (1998). A noise's power sets who hears it: a radius, every guard, or the one nearest guard, which is how a knock on a wall draws a single guard.1
Games
| Game | Year | How | Note |
|---|---|---|---|
| Metal Gear Solid | 1998 | By power | a noise's power sets who hears it: a radius, every guard, or the one nearest guard, which is how a knock on a wall draws a single guard |
Every claim about this mechanic, by game (1)
References
- ^ abIn Metal Gear Solid Integral (SLPM-86247), a noise is a power, a length, and a position (GM_SetNoise), and a noise replaces the current one only if its power is higher, or equal with a length at least as long. A guard whose
field_BA3bit 1 is set (its setup sets it) hears the current noise by its power (s00a_command_800C9930): 5 within 1,500 units, 200 within COM_NOISEMODE_DIS (8,000 by default; a stage script'syoption sets it), 255 at any distance, and 100 only if it is the guard the commander picked; for every power but 255 the guard must be on Snake's map, and 255 has its own test on GM_ClaymoreMap. Other powers aren't heard, such as the 4 of Snake's kick. For a 100, the commander (s00a_command_800CF9A0), outside mode 1, picks the guard within COM_NOISEMODE_DIS of the noise whose HZD_ZoneDistance to it is under 300 and least; that guard hears it and clears it, so one guard answers. Knocking on a wall makes a 100:sna_knock_80054D68probes the wall beside Snake and, when the surface's attribute code is under 4, startsNewAfterSe, which 6 frames later plays the knock and calls GM_SetNoise(100, 16) at Snake's position. A footstep makes a 100 when Snake isn't in a duct (PLAYER_INTRUDE) and the stage script'snlist gives the floor under him a nonzero noise flag. Explosions (blast.c) and stun grenades (stngrnd.c) make a 255. A patrolling guard (think2 0,s00a_command_800CD210) answers a heard noise (field_BA1bit 1) after bits 4 and 2 and before footprints (bit 16) and sight; for a 255 it goes to the same reaction state as a sighting (think2 7), which after 21 updates (computed) sets itsalert_levelto 255.CodeFoxdieTeam/mgs_reversingrevisedHow we know
74static inline void GM_SetNoise( int power, int length, SVECTOR *pos ) ⋮ 76 int old ; ⋮ 78 old = GM_NoisePower ; 79 if ( power < old ) return ; 80 if ( power == old && length < GM_NoiseLength ) return ; 81 GM_NoisePower = power ; 82 GM_NoiseLength = length ; 83 GM_NoisePosition = *pos ;
source/game/g_macro.h lines 74–84 at bf9189e · upstream ↗ 62void s00a_command_800C9930( WatcherWork* work ) ⋮ 64 CONTROL *ctrl; 65 if ( !( work->field_BA3 & 1 ) ) ⋮ 67 return; ⋮ 72 return; ⋮ 78 return; ⋮ 83 if ( GM_NoisePower == 0xFF ) ⋮ 86 if ( !( ctrl->map->index & GM_ClaymoreMap ) && ⋮ 90 return; ⋮ 93 else ⋮ 95 if ( !( ctrl->map->index & GM_PlayerMap ) ) ⋮ 97 return; ⋮
source/enemy/enemy.c lines 62–130 at bf9189e · upstream ↗ 677 work->field_BA3 = 7;source/enemy/watcher.c line 677 at bf9189e · upstream ↗ 1190 COM_NOISEMODE_DIS = 0x1F40; ⋮ 1192 ops = GCL_GetOption( 'y' ); 1193 if ( ops ) ⋮ 1195 COM_NOISEMODE_DIS = GCL_StrToInt( ops );
source/enemy/command.c lines 1190–1196 at bf9189e · upstream ↗ 714int s00a_command_800CF9A0( WatcherWork *work, int dis, int idx ) ⋮ 721 if ( TOPCOMMAND.mode == 1 ) ⋮ 723 goto exit; ⋮ 726 if ( GM_NoisePower != 0x64 ) ⋮ 728 goto exit; ⋮ 733 goto exit; ⋮ 736 if ( GV_DiffVec3( &GM_NoisePosition, &ctrl->mov ) >= COM_NOISEMODE_DIS ) ⋮ 738 goto exit; ⋮ 741 x = s00a_command_800CF940( ctrl->map->hzd, &ctrl->mov, &GM_NoisePosition ); ⋮ 743 if ( x < 300 && x < dis ) ⋮ 745 COM_NoiseMinDisID = idx; 746 dis = x;
source/enemy/command.c lines 714–750 at bf9189e · upstream ↗ 697int s00a_command_800CF940( HZD_HDL *hzd, SVECTOR *pos, SVECTOR *pos2 ) ⋮ 702 from = HZD_GetAddress( hzd, pos, -1 ); ⋮ 707 to = HZD_GetAddress( hzd, pos2, -1 ); 708 do { 709 return HZD_ZoneDistance( hzd, from & 0xFF, to & 0xFF );
source/enemy/command.c lines 697–711 at bf9189e · upstream ↗ 4128 if (sna_8004F628(work, &vec, -250, HZD_CHK_D_SEGMENT | HZD_CHK_F_SEGMENT, SEGMENT_ATR, var_t0)) ⋮ 4130 temp_v0 = HZD_GetOnlineHazardAtr(); 4131 code = (temp_v0 >> 8) & 7; ⋮ 4133 if (code < 4) ⋮ 4135 temp_v0 = GM_GetNoiseSound(temp_v0, 0); 4136 noise = temp_v0; 4137 NewAfterSe(noise, 6);
source/chara/snake/sna_init.c lines 4128–4137 at bf9189e · upstream ↗ 14static void Act(Work *work) ⋮ 16 if ( --work->time == 0 ) ⋮ 18 // Play the sound 19 GM_SeSetMode(&GM_PlayerPosition, work->sound, GM_SEMODE_BOMB); ⋮ 21 // Allow soliders/chavs/whatever to hear it 22 GM_SetNoise(100, 16, &GM_PlayerPosition);
source/chara/snake/afterse.c lines 14–22 at bf9189e · upstream ↗ 104 else ⋮ 106 index = asioto_800C396C(work); ⋮ 112 bank2 = asioto_800C392C(work); 113 if (bank2 >= 0) ⋮ 115 GM_SeSet(&GM_PlayerPosition, work->se[bank2][index]); ⋮ 117 if (work->noise[bank2] != 0) ⋮ 119 GM_SetNoise(100, 4, &GM_PlayerPosition);
source/enemy/asioto.c lines 104–120 at bf9189e · upstream ↗ 90 if (GM_PlayerStatus & PLAYER_INTRUDE) ⋮ 92 if (GM_PlayerStatus & PLAYER_MOVE)
source/enemy/asioto.c lines 90–92 at bf9189e · upstream ↗ 193 if (GCL_GetOption('n')) ⋮ 202 work->noise[i] = GCL_StrToInt(GCL_NextStr());
source/enemy/asioto.c lines 193–202 at bf9189e · upstream ↗ 6847 sound = SE_KICK_SWING; ⋮ 6854 GM_SetNoise(4, 2, &work->control.mov);
source/chara/snake/sna_init.c lines 6847–6854 at bf9189e · upstream ↗ 170 GM_SetNoise(255, 32, &work->pos);source/bullet/blast.c line 170 at bf9189e · upstream ↗ 224 GM_SetNoise(255, 32, &work->field_E0);source/okajima/stngrnd.c line 224 at bf9189e · upstream ↗ 1939 if ( work->field_BA1 & 4 ) ⋮ 1941 s00a_command_800CB3F0( work ); ⋮ 1943 else if ( work->field_BA1 & 2) ⋮ 1945 s00a_command_800CB610( work ); ⋮ 1947 else if ( work->field_BA1 & 1) ⋮ 1949 s00a_command_800CB504( work ); ⋮ 1951 else if ( work->field_BA1 & 16 ) ⋮ 1953 s00a_command_800CB628( work );
source/enemy/think.c lines 1939–1954 at bf9189e · upstream ↗ 558 case 255: 559 s00a_command_800CAB74( work ); 560 s00a_command_800CEB54(); 561 work->think2 = 7; 562 work->think3 = 16;
source/enemy/think.c lines 558–562 at bf9189e · upstream ↗ 2344 case 16: 2345 if ( s00a_command_800CBE90( work ) ) ⋮ 2356 work->alert_level = 255;
source/enemy/think.c lines 2344–2356 at bf9189e · upstream ↗ 953int s00a_command_800CBE90( WatcherWork* work ) ⋮ 962 if ( work->count3 > 20 ) ⋮ 964 return 1; ⋮ 967 work->count3++;
source/enemy/think.c lines 953–969 at bf9189e · 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
- FoxdieTeam and mgs_reversing contributors. 2026. “mgs_reversing: a matching decompilation of Metal Gear Solid Integral for the PlayStation (FoxdieTeam/mgs_reversing).” Commit bf9189e. FoxdieTeam/mgs_reversing @ bf9189e · licence, all uses