Silent Hill
Konami's 1999 PlayStation survival horror game, read through shdecompilations' silent-hill-decomp, a matching decompilation of the US release.
On this page
Silent Hill is Konami’s 1999 PlayStation survival horror game. The code read here is shdecompilations’ silent-hill-decomp, a matching decompilation that builds the US release; its game logic is in the overlay BODYPROG.BIN, and each enemy’s code is compiled into the map overlays that use it.
The pocket radio is a proximity-warning: it picks enemies by distance on the ground plane, with no line-of-sight test, and in dark interiors only those in Harry’s own 40-unit chunk count1.
The flashlight makes Harry easier to notice. Once it is half lit, the game reads the map’s flashlight-on preset instead of its dark one2, and enemies use those flags for how far they notice him: a larval stalker in a dark map targets him from 17 units with the light on and from 2.5 with it off3, and a walking creeper’s range also depends on its facing4.
Of the healing items, a Health Drink restores 40 of Harry’s 100 health, a First Aid Kit 80, and an Ampoule 100; the Ampoule then keeps healing him from a store of 3005. An ammunition pickup gives 15 handgun bullets or 6 shells. Easy at least doubles that, Normal and Hard leave it alone, and an Extra Options setting multiplies it up to six times6.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Proximity warning | Audio cue | the pocket radio plays static for the two nearest enemies within 32 units, by distance alone, louder as they close in |
| Light detection | Own light | in dark maps the flashlight lengthens the range at which enemies notice Harry, from 2.5 to 17 units for a larval stalker |
| Healing item | Instant | a Health Drink adds 40 health, a First Aid Kit 80, and an Ampoule 100, out of 100 |
| Healing item | Over time | an Ampoule also fills a store of 300 that restores health as it drains |
| Ammunition | Separate counts | separate counts for handgun bullets, shotgun shells, and rifle shells; pickups give 15, 6, and 6, doubled at least on Easy |
Every claim about this game, by concept (6)
References
- ^In 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.
- ^In the US build, the flashlight swaps which environment preset's flags are live, and enemy code reads those flags.
Gfx_EffectsUpdatemovesflashlightIntensitytoward 1 while the flashlight is on and toward 0 while it's off, by 4 ×g_DeltaTimeper update, andfunc_8003F838copies the live flags (field_154) from the flashlight-off preset (field_1C[0]) while the intensity is under 0.5 and from the flashlight-on preset (field_1C[1]) from 0.5 up.WorldEnv_MapPresetSetgives a map whose header's unnamedfield_16is 2 the preset pair 6 and 3, or 7 and 4 in low-visibility interiors (off, then on). Presets 6 and 7 setSpecialEnvEventFlags_DarkEnvironmentandSpecialEnvEventFlags_FlashlightAllowed; presets 3 and 4 setFlashlightAllowedwithoutDarkEnvironment. A map whosefield_16is 1 gets preset 1 or 2 for both, which set neither flag, andGfx_MapEnvStepUpdatemarks the flashlight unavailable whenever the two presets are the same. So in those dark maps, the flags read as dark with the flashlight off and as lit with it on; map events can load other pairs.Codeshdecompilations/silent-hill-decompHow we know
393 if (g_SysWork.field_2388.isFlashlightOn) ⋮ 395 g_SysWork.field_2388.flashlightIntensity += Q12_MULT_FLOAT_PRECISE(g_DeltaTime, 4.0f); ⋮ 397 else ⋮ 399 g_SysWork.field_2388.flashlightIntensity -= Q12_MULT_FLOAT_PRECISE(g_DeltaTime, 4.0f); ⋮ 402 g_SysWork.field_2388.flashlightIntensity = CLAMP(g_SysWork.field_2388.flashlightIntensity, Q12(0.0f), Q12(1.0f));
src/bodyprog/world/world_effects.c lines 393–403 at 405a621 · upstream ↗ 412 if (ptr->primitiveType == PrimitiveType_None) ⋮ 414 ptr->field_1C[0] = ptr->field_84[0]; 415 ptr->field_1C[1] = ptr->field_84[1];
src/bodyprog/world/world_effects.c lines 412–415 at 405a621 · upstream ↗ 430 func_8003F838(&ptr->field_154, &ptr->field_1C[0], &ptr->field_1C[1], ptr->flashlightIntensity);src/bodyprog/world/world_effects.c line 430 at 405a621 · upstream ↗ 636static void func_8003F838(s_StructUnk3* target, s_StructUnk3* envSettings0, s_StructUnk3* envSettings1, q19_12 weight) // 0x8003F838 ⋮ 649 // Copy enviroment flags. 650 if (weight < Q12(0.5f)) ⋮ 652 target->effectsInfo.flags.field_00[0] = envSettings0->effectsInfo.flags.field_00[0]; ⋮ 654 else ⋮ 656 target->effectsInfo.flags.field_00[0] = envSettings1->effectsInfo.flags.field_00[0];
src/bodyprog/world/world_effects.c lines 636–657 at 405a621 · upstream ↗ 319 if (preset0 == preset1) ⋮ 321 g_SysWork.field_2388.isFlashlightUnavailable = true; ⋮ 336 Gfx_FogParametersSet(&g_SysWork.field_2388.field_84[0], preset0); 337 Gfx_FogParametersSet(&g_SysWork.field_2388.field_84[1], preset1);
src/bodyprog/world/world_effects.c lines 316–337 at 405a621 · upstream ↗ 22static s_MapEnvPresetIdxs D_800A9F80 = { 1, 1 }; 23static s_MapEnvPresetIdxs D_800A9F84 = { 2, 2 }; 24static s_MapEnvPresetIdxs D_800A9F88 = { 6, 3 }; 25static s_MapEnvPresetIdxs D_800A9F8C = { 7, 4 };
src/bodyprog/world/world_effects.c lines 22–25 at 405a621 · upstream ↗ 210 switch (mapHdr->field_16) ⋮ 212 case 1: 213 if (hasActiveChunk) ⋮ 215 presetIdxPtr = &D_800A9F84; ⋮ 217 else ⋮ 219 presetIdxPtr = &D_800A9F80; ⋮ 221 break; ⋮ 223 case 2: 224 if (hasActiveChunk) ⋮ 226 presetIdxPtr = &D_800A9F8C; ⋮ 228 else ⋮ 230 presetIdxPtr = &D_800A9F88; ⋮
src/bodyprog/world/world_effects.c lines 210–232 at 405a621 · upstream ↗ 5s_MapEffectsInfo MAP_EFFECTS_INFOS[21] = { ⋮ 7 .flags = { .field_00 = { SpecialEnvEventFlags_None, 0xFF, UnkGfxEnum_0, 0 }}, ⋮ 23 .flags = { .field_00 = { SpecialEnvEventFlags_None, 0xFF, UnkGfxEnum_0, 0 }}, ⋮ 39 .flags = { .field_00 = { SpecialEnvEventFlags_None, 0xFF, UnkGfxEnum_2, 0 }}, ⋮ 55 .flags = { .field_00 = { (SpecialEnvEventFlags_FlashlightAllowed | SpecialEnvEventFlags_EnableBrightness | SpecialEnvEventFlags_EnableLensflare), 0xFF, UnkGfxEnum_1, 0 }}, ⋮ 71 .flags = { .field_00 = { (SpecialEnvEventFlags_FlashlightAllowed | SpecialEnvEventFlags_EnableBrightness | SpecialEnvEventFlags_EnableLensflare), 0xFF, UnkGfxEnum_1, 0 }}, ⋮ 87 .flags = { .field_00 = { (SpecialEnvEventFlags_FlashlightAllowed | SpecialEnvEventFlags_EnableBrightness | SpecialEnvEventFlags_EnableLensflare), 0xFF, UnkGfxEnum_1, 0 }}, ⋮ 103 .flags = { .field_00 = { (SpecialEnvEventFlags_DarkEnvironment | SpecialEnvEventFlags_FlashlightAllowed | SpecialEnvEventFlags_EnableBrightness), 0xFF, UnkGfxEnum_0, 0 }}, ⋮ 119 .flags = { .field_00 = { (SpecialEnvEventFlags_DarkEnvironment | SpecialEnvEventFlags_FlashlightAllowed | SpecialEnvEventFlags_EnableBrightness), 0xFF, UnkGfxEnum_0, 0 }},
src/bodyprog/sys/map_info.c lines 5–119 at 405a621 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^In the US build,
LarvalStalker_ControlUpdatesets the larval stalker's target position to Harry's whenever his distance on the ground plane is under 2 × base + step, with base and step picked by the live light flags (silent-hill/flashlight-presets): 2.5 and 8 when neitherDarkEnvironmentnorFlashlightAllowedis set, 3.5 and 10 when onlyFlashlightAllowedis, and 0.5 and 1.5 otherwise. Computed, that's 13 world units in fog presets; in the dark map presets, 17 units with the flashlight on and 2.5 with it off. This check reads no facing and no line of sight.Codeshdecompilations/silent-hill-decompHow we know
84void LarvalStalker_ControlUpdate(s_SubCharacter* larvalStalker)src/maps/characters/larval_stalker.c line 84 at 405a621 · upstream ↗ 111 idxInfo = g_SysWork.field_2388.field_154.effectsInfo.flags.field_0 & (SpecialEnvEventFlags_DarkEnvironment | SpecialEnvEventFlags_FlashlightAllowed); 112 if (idxInfo == 0) ⋮ 114 baseDistMax = Q12(2.5f); 115 distStep = Q12(8.0f); ⋮ 117 else if (idxInfo == 2) ⋮ 119 baseDistMax = Q12(3.5f); 120 distStep = Q12(10.0f); ⋮ 122 else ⋮ 124 baseDistMax = Q12(0.5f); 125 distStep = Q12(1.5f); ⋮ 128 if (Math_Vector2MagCalcSafeQ6(g_SysWork.playerWork.player.position.vx - larvalStalker->position.vx, 129 g_SysWork.playerWork.player.position.vz - larvalStalker->position.vz) < ((baseDistMax * 2) + distStep)) ⋮
src/maps/characters/larval_stalker.c lines 111–133 at 405a621 · upstream ↗ 298 SpecialEnvEventFlags_DarkEnvironment = 1 << 0, // Double check. 299 SpecialEnvEventFlags_FlashlightAllowed = 1 << 1,
include/game.h lines 298–299 at 405a621 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^In the US build, a walking creeper (
Creeper_ControlWalkForward) retargets Harry's position whenfunc_8006FD90passes, with arguments picked by the live light flags (silent-hill/flashlight-presets).func_8006FD90scales a range by how directly the creeper faces Harry, f = 1 − |angle off its heading|/180° (1 straight ahead, 0 behind), raised to the power count + 1; it fails beyond base + step × that, and otherwise a ray test toward Harry (Ray_CharaTraceQuery) decides. With onlyFlashlightAllowedset, the creeper calls it with count 0, base 12, and step 8: 12 units behind to 20 ahead. WithFlashlightAllowedandDarkEnvironment, count 2, base 0.8, step 0.4: 0.8 to 1.2 units. With neither flag, count 1, base 4, step 12: 4 to 16 units (all computed). A separate check (func_80070360with 0.5) or an alert flag also retargets it.Codeshdecompilations/silent-hill-decompHow we know
372void Creeper_ControlWalkForward(s_SubCharacter* creeper) ⋮ 384 if (((g_SysWork.field_2388.field_154.effectsInfo.flags.field_0 & (SpecialEnvEventFlags_DarkEnvironment | SpecialEnvEventFlags_FlashlightAllowed)) == SpecialEnvEventFlags_FlashlightAllowed && func_8006FD90(creeper, 0, Q12(12.0f), Q12(8.0f))) || 385 ((g_SysWork.field_2388.field_154.effectsInfo.flags.field_00[0] & SpecialEnvEventFlags_FlashlightAllowed) && 386 (g_SysWork.field_2388.field_154.effectsInfo.flags.field_00[0] & SpecialEnvEventFlags_DarkEnvironment) && func_8006FD90(creeper, 2, Q12(0.8f), Q12(0.4f))) || 387 (!(g_SysWork.field_2388.field_154.effectsInfo.flags.field_0 & (SpecialEnvEventFlags_DarkEnvironment | SpecialEnvEventFlags_FlashlightAllowed)) && func_8006FD90(creeper, 1, Q12(4.0f), Q12(12.0f))) || 388 (func_80070360(creeper, 0, Q12(0.5f)) || creeperProps.flags & CreeperFlag_Alerted)) ⋮ 390 creeperProps.targetPositionX = playerChara.position.vx; 391 creeperProps.targetPositionZ = playerChara.position.vz;
src/maps/characters/creeper.c lines 372–392 at 405a621 · upstream ↗ 137bool func_8006FD90(s_SubCharacter* chara, s32 count, q19_12 baseDistMax, q19_12 distStep) // 0x8006FD90 ⋮ 149 g_SysWork.playerWork.player.position.vz - chara->position.vz) - ⋮ 152 distMult = (Math_AngleNormalizeSigned(ratan2(g_SysWork.playerWork.player.position.vx - chara->position.vx, 153 g_SysWork.playerWork.player.position.vz - chara->position.vz) - 154 chara->rotation.vy) * 2) + Q12_ANGLE(360.0f); ⋮ 158 distMult = (Q12_ANGLE(180.0f) - Math_AngleNormalizeSigned((ratan2(g_SysWork.playerWork.player.position.vx - chara->position.vx, 159 g_SysWork.playerWork.player.position.vz - chara->position.vz) - 160 chara->rotation.vy))) * 2; ⋮ 163 for (i = distMult; count > 0; count--) ⋮ 165 distMult = Q12_MULT_PRECISE(distMult, i); ⋮ 168 dist = Math_Vector2MagCalcSafeQ6(g_SysWork.playerWork.player.position.vx - chara->position.vx, 169 g_SysWork.playerWork.player.position.vz - chara->position.vz); ⋮
src/bodyprog/collision/los.c lines 137–171 at 405a621 · upstream ↗ 173 return false; ⋮ 195 return !Ray_CharaTraceQuery(&sp10, &pos, &offset, chara) || sp20.vx != Q12(0.0f);
src/bodyprog/collision/los.c lines 172–195 at 405a621 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^In the US build, using a healing item from the inventory (
Inventory_PlayerItemScroll) adds 40 health for a Health Drink, 80 for a First Aid Kit, and 100 for an Ampoule, then clamps Harry's health to 0–100 and spends one item. An Ampoule also setshealthSaturationto 300 (a set, not an add).Player_LogicUpdatelowershealthSaturationbyg_DeltaTimeon each update and, while any remains, raises Harry's health by the same amount, capped at 100. So an Ampoule fills health and then keeps restoring it, up to 300 more in all (computed), with the store draining even while health is full.Codeshdecompilations/silent-hill-decompHow we know
1995void Inventory_PlayerItemScroll(u32* selectedItemId) // 0x800523D8src/bodyprog/items/item_screens_3.c line 1995 at 405a621 · upstream ↗ 2516 switch (g_SavegamePtr->items[g_SysWork.invItemSelectedIdx].id) ⋮ 2518 case InvItemId_HealthDrink: 2519 case InvItemId_FirstAidKit: 2520 case InvItemId_Ampoule: 2521 switch (g_SavegamePtr->items[g_SysWork.invItemSelectedIdx].id) ⋮ 2523 case InvItemId_FirstAidKit: 2524 g_SysWork.playerWork.player.health += Q12(80.0f); 2525 break; ⋮ 2527 case InvItemId_HealthDrink: 2528 g_SysWork.playerWork.player.health += Q12(40.0f); 2529 break; ⋮ 2531 case InvItemId_Ampoule: ⋮
src/bodyprog/items/item_screens_3.c lines 2516–2539 at 405a621 · upstream ↗ 1230void Player_LogicUpdate(s_SubCharacter* player, s_PlayerExtra* extra, GsCOORDINATE2* coords) // 0x80071CE8src/bodyprog/player_control.c line 1230 at 405a621 · upstream ↗ 1289 g_SavegamePtr->healthSaturation -= g_DeltaTime; 1290 g_SavegamePtr->healthSaturation = CLAMP(g_SavegamePtr->healthSaturation, Q12(0.0f), Q12(300.0f)); ⋮ 1292 if (g_SavegamePtr->healthSaturation != Q12(0.0f)) ⋮ 1294 playerChara.health += g_DeltaTime; 1295 playerChara.health = CLAMP(playerChara.health, Q12(0.0f), Q12(100.0f));
src/bodyprog/player_control.c lines 1289–1296 at 405a621 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^In the US build,
Event_CommonItemTakegives 15 handgun bullets, 6 shotgun shells, or 6 rifle shells per ammunition pickup, times a multiplier ofextraBulletAdjust+ 1, which is at least 2 on Easy; healing pickups always give one item. Normal and Hard don't change the count.extraBulletAdjustis an Extra Options setting: the options screen allows 1 plus one step for each of the five low bits set inextraOptionsEnabled, so ×1 to ×6.Codeshdecompilations/silent-hill-decompHow we know
7#define DEFAULT_PICKUP_ITEM_COUNT 1 8#define HANDGUN_AMMO_PICKUP_ITEM_COUNT 15 9#define SHOTGUN_AMMO_PICKUP_ITEM_COUNT 6 10#define RIFLE_AMMO_PICKUP_ITEM_COUNT 6
include/bodyprog/items.h lines 7–10 at 405a621 · upstream ↗ 1104void Event_CommonItemTake(u32 pickupType, e_EventFlag eventFlagIdx) // 0x800879FC ⋮ 1106 #define EASY_DIFFICULTY_AMMO_COUNT_MULT_MIN 2 ⋮ 1111 ammoCountMult = g_GameWork.config.extraBulletAdjust + 1; 1112 if (g_SavegamePtr->gameDifficulty == GameDifficulty_Easy) ⋮ 1114 ammoCountMult = CLAMP(ammoCountMult, EASY_DIFFICULTY_AMMO_COUNT_MULT_MIN, ammoCountMult); ⋮ 1121 Event_ItemTake(InvItemId_FirstAidKit, DEFAULT_PICKUP_ITEM_COUNT, eventFlagIdx, MapMsgIdx_FirstAidSelect); ⋮ 1133 Event_ItemTake(InvItemId_HandgunBullets, ammoCountMult * HANDGUN_AMMO_PICKUP_ITEM_COUNT, eventFlagIdx, MapMsgIdx_HandgunAmmoSelect); ⋮ 1137 Event_ItemTake(InvItemId_ShotgunShells, ammoCountMult * SHOTGUN_AMMO_PICKUP_ITEM_COUNT, eventFlagIdx, MapMsgIdx_ShotgunAmmoSelect); ⋮ 1141 Event_ItemTake(InvItemId_RifleShells, ammoCountMult * RIFLE_AMMO_PICKUP_ITEM_COUNT, eventFlagIdx, MapMsgIdx_RifleAmmoSelect);
src/bodyprog/events/events_util.c lines 1104–1142 at 405a621 · upstream ↗ 136 g_ExtraOptionsMenu_BulletMultMax = 1; 137 unlockedOptFlags = g_GameWork.config.extraOptionsEnabled; ⋮ 139 // Set available bullet multiplier. 140 for (i = 0; i < 5; i++) ⋮ 142 if (unlockedOptFlags & (1 << i)) ⋮ 144 g_ExtraOptionsMenu_BulletMultMax++;
src/screens/options/options.c lines 136–146 at 405a621 · upstream ↗ 460 g_GameWork.config.extraBulletAdjust = g_GameWork.config.extraBulletAdjust + (g_ExtraOptionsMenu_BulletMultMax - 1); ⋮ 462 g_GameWork.config.extraBulletAdjust = g_GameWork.config.extraBulletAdjust % g_ExtraOptionsMenu_BulletMultMax;
src/screens/options/options.c lines 460–462 at 405a621 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked 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