elishacloud / Silent-Hill-2-Enhancements

A project designed to enhance Silent Hill 2 (SH2) graphics and audio for the PC. It also includes scripts to build or modify SH2 audio files (SFX, BGM and Dialog).
http://www.enhanced.townofsilenthill.com/SH2/
zlib License
574 stars 41 forks source link

Disable (and in one spot: enable) the ability to save in certain rooms #118

Closed Polymega closed 2 years ago

Polymega commented 5 years ago

@Bigmanjapan found another interesting issue with the ability to save/load almost anywhere:

If you go on the Hospital's roof the ability to save will be disabled, as the game is waiting on you to go near the diary then trigger the RPT ambush attack.

However, if you don't go near this journal you're able to go back down the staircase from which you came, but upon doing so the ability to save will still be grayed out everywhere you go until you either 1) load another save or 2) trigger that rooftop cutscene.

To resolve this (enable/disable saving address found by Bigmanjapan):


This re-enables the ability to save if a person enters the roof but decides to go back down without triggering the cutscene.


We disable this for the Flashlight & Mannequin apartment room because, if you load back into this room a blood pool will form prematurely around the dormant Mannequin (before it comes to life) and the Mannequin will spin around erratically as it comes to life.

We disable this for the Pyramid Head apartment room because, if someone saves within the closet, the camera will be completely blacked out upon game load here.

We disable this for the Hotel stairs on fire because, if you load back into this area, the fire and smoke effects won't render.


For this one we need to prevent saving in a specific room WHILE James' X coordinate is less than a certain float value. This is to prevent getting trapped in the Labyrinth elevator as reported here.

As soon as the elevator stops moving there's an instruction to re-enable saving. The problem is, saving the instant you regain this feature is what causes the bug linked above. So we need to modify this instruction to prevent the game from allowing us to save again the moment the elevator stops, and instead reactivate saving once we fully exit the elevator (via James' coordinates).

sh2pc.exe+1831BA (005831BA)
Change mov [0079B830],00000001 to mov [0079B830],00000000

Once we change that, we do the following:

In regards to James' position: Being a negative value, less than -18600 would be something like -18750 and greater than would be something like -18425.

To maybe help save some time, you've used the James coordinate address before in the HospitalChaseFix mod found here: https://github.com/elishacloud/Silent-Hill-2-Enhancements/blob/master/Patches/HospitalChase.cpp#L35


To anyone else reading this: Remember: The ability to save/load almost anywhere is an awesome feature uniquely built-in to the PC version, and once you start using it you'll become spoiled by just how nice it is. However, there are bound to be hiccups from this feature, as it is a bonus feature not built-in to any other version.

Polymega commented 5 years ago

Possible fix name:

GameLoadFix = 1 // Disables free-saving in a few rooms that would cause game issues upon file loading back into the rooms.

elishacloud commented 5 years ago

Done! This fix should be in the next update. Here is a testing module: d3d8.zip

Polymega commented 5 years ago

Thanks Elisha! I did a playtest on all binaries for this fix and have some notes.


Please change Room ID 00000042 to 00000029

This is in regards to the first part of the fix (where we re-enable saving for the room). Sorry about that; not sure how I came up with 0x42!


I've now realized that the save byte we're overriding will get over-overrode by the game if James' acquires an item. Is there a way to keep the byte change persistent while in any of these rooms?


We'll also need to do that instruction change after the elevator ride down, which I can ask Aero_ about soon:

sh2pc.exe+1831BA (005831BA)
Change mov [0079B830],00000001 to mov [0079B830],00000000

elishacloud commented 5 years ago

Please change Room ID 00000042 to 00000029

Done!

I've now realized that the save byte we're overriding will get over-overrode by the game if James' acquires an item. Is there a way to keep the byte change persistent while in any of these rooms?

I think the best way to fix this would be to re-write this for each iteration. That is an easy fix.

We'll also need to do that instruction change after the elevator ride down, which I can ask Aero_ about soon:

sh2pc.exe+1831BA (005831BA)
Change mov [0079B830],00000001 to mov [0079B830],00000000

No problem, I can change this. Just give me the details of this. Should I just do this once when the game starts?

Polymega commented 5 years ago

No problem, I can change this. Just give me the details of this. Should I just do this once when the game starts?

Yes sir! I'm 99% sure this save instruction is specific only to the elevator room we're making better.

elishacloud commented 5 years ago

Ok, try this one. It should fix all of these issues: d3d8.zip

Polymega commented 5 years ago

This one fixes everything for 1.0 and 1.1! The game immediately crashes upon trying to launch the DC binary. In the log file, the last entry shown is enabling the Xinput Vibration fix.

Problem signature:
  Problem Event Name:   BEX
  Application Name: sh2pc.exe
  Application Version:  0.0.0.0
  Application Timestamp:    68373737
  Fault Module Name:    d3d8.dll
  Fault Module Version: 1.3.1386.0
  Fault Module Timestamp:   5d3e7e8c
  Exception Offset: 0003feb6
  Exception Code:   c0000417
  Exception Data:   00000000
  OS Version:   6.1.7601.2.1.0.768.3
  Locale ID:    1033
  Additional Information 1: 6d89
  Additional Information 2: 6d89e5a34f8164462efc592184fe582d
  Additional Information 3: aab0
  Additional Information 4: aab0205361cc3dd171ae6b25e4b02705

Thanks again. I'll test the blood pool fix tomorrow.

elishacloud commented 5 years ago

Can you try the blood pool testing module for this? The blood pool testing module should have all the fixes in it.

Polymega commented 5 years ago

Using the blood pool testing module, the game still crashes upon launch for DC.

Polymega commented 5 years ago

The DC binary is crashing for me on the public release now. How weird. Running the DC binary as admin lets me launch it. Wanted to post this now to say everything is likely good on your end with these test modules. What on Earth happened on my end? I'll report back.

Polymega commented 5 years ago

Huh. It's ReShade all of a sudden? Removing d3d9.dll makes the DC binary launch again without having to run it in admin mode.

d3d9.log report on DC crash:

16:19:29:436 [06708] | INFO  | Initializing crosire's ReShade version '4.2.1.542' (32-bit) built on '2019-03-04 22:32:13' loaded from "C:\Program Files (x86)\KONAMI\Silent Hill 2\d3d9.dll" to "C:\Program Files (x86)\KONAMI\Silent Hill 2\sh2pc.exe" ...
16:19:29:482 [06708] | INFO  | Registering hooks for "user32.dll" ...
16:19:29:482 [06708] | INFO  | > Libraries loaded.
16:19:29:482 [06708] | INFO  | > Found 13 match(es). Installing ...
16:19:29:498 [06708] | INFO  | Registering hooks for "ws2_32.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed.
16:19:29:498 [06708] | INFO  | Registering hooks for "C:\windows\system32\d3d9.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed until first call to an exported function.
16:19:29:498 [06708] | INFO  | Registering hooks for "C:\windows\system32\d3d10.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed.
16:19:29:498 [06708] | INFO  | Registering hooks for "C:\windows\system32\d3d10_1.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed.
16:19:29:498 [06708] | INFO  | Registering hooks for "C:\windows\system32\d3d11.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed.
16:19:29:498 [06708] | INFO  | Registering hooks for "C:\windows\system32\dxgi.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed.
16:19:29:498 [06708] | INFO  | Registering hooks for "C:\windows\system32\opengl32.dll" ...
16:19:29:498 [06708] | INFO  | > Delayed.
16:19:29:498 [06708] | INFO  | Initialized.

I'll try updating ReShade in the near future to see if that fixes it.

elishacloud commented 5 years ago

Weird. Glad my fix was good, though not sure why ReShade would be crashing now. Seems to work fine on my computer.

Polymega commented 5 years ago

Just updated to 4.3.0 of ReShade and DC seems to be fine now. So strange... But back to testing. Stay tuned for some notes soon!

Polymega commented 5 years ago

Okay, I was able to finish testing the enable/disable saving fix here for the DC binary (already did so for 1.0 and 1.1 the other night) and it's working great there, too. So this is working great across all executables with all fix parts accounted for now!

Polymega commented 4 years ago

A few areas need to be added to GameLoadFix, where saving should be disabled.


If Room ID 0xC7 (BFaW Mansion attic) disable saving.


We need to disable saving underneath the tunnel (where you fight the first Lying Figure). If you save and load back into this tunnel, the radio will still go off, as if you've never acquired the radio yet, even if you've already killed the enemy here.

To achieve this, we need to add an additional check, along with the room ID check:

The "James' Z position" address is new for use in the project.

Previously, we have been using James' X position for fixes such as here, here, and here. It may not be important to do, but you might want to rename those previous variables to something like JamesXPosAddr and SH2_JamesXPos, since we'd be now using addresses for both James' X and Z position.


This request will prevent the player from saving in the Alternate Hotel elevator, which, upon file load, would completely black out the screen.

After learning about this, I decided to check all other elevator areas in the game and, sure enough, we ought to prevent saving in all of the remaining elevators as well.

(I hope this pseudo code makes sense)

For these particular rooms:

{ If Room ID 0x2A (Hospital elevator) || Room ID 0x46 (Alternate Hospital elevator) || (Room ID 0x9D (Hotel employee elevator room) && James' X position is < 60650.0f) || (Room ID 0xB8 (Alternate Hotel elevator hallway) && James' X position is > -15800.0f)

}

The "Elevator running" and "in-game voice event" addresses are new for use in the project.

For the second part of the pseudo-code (where we NOP the Quick Save instruction entirely), it needs to meet the previous condition of being in one of those particular elevator rooms (and James is at a certain position, if applicable). We only want to completely disable (NOP) the Quick Save function while in these particular rooms, no where else.

We need to NOP the Quick Save function entirely to prevent issues such as this. Simply put: The save anywhere feature and elevators don't play nice with each other. Thanks to Bigmanjapan for finding the Quick Save/Load instructions.

Bigmanjapan commented 4 years ago

We need to disable saving underneath the tunnel (where you fight the first Lying Figure). If you save and load back into this tunnel, the radio will still go off, as if you've never acquired the radio yet, even if you've already killed the enemy here.

How about using the cutscene indexes? The tunnel location is strictly limited by 0x06 cutscene at the entrance and 0x08 cutscene at the exit. Disable saving upon the triggering first, enable saving upon triggering the second.

Polymega commented 4 years ago

How about using the cutscene indexes? The tunnel location is strictly limited by 0x06 cutscene at the entrance and 0x08 cutscene at the exit. Disable saving upon the triggering first, enable saving upon triggering the second.

If a player initiates cutscene 0x06 then decides to exit/load a new save file mid-fight (before initiating cutscene 0x08) wouldn't the save feature be perpetually disabled, as the script would still be waiting on 0x08?

For what it's worth, there's no other point/area in Town East (room ID 0x04) where James' Z position can go above 49000.

Bigmanjapan commented 4 years ago

If a player initiates cutscene 0x06 then decides to exit/load a new save file mid-fight (before initiating cutscene 0x08) wouldn't the save feature be perpetually disabled, as the script would still be waiting on 0x08?

Good point. You method fits better then.

elishacloud commented 4 years ago

Implemented the update to GameLoadFix. This fix was a bit more involved. It is generally considered a bad idea to NOP an instruction in the middle of the program running, so I created an ASM function to handle the switching here. Also finding the address for the in-game voice event created some difficulties. Anyways, I think this works correctly.

Test build: d3d8.zip

Polymega commented 4 years ago

Thanks Elisha.

I immediately noticed that if you try to quick save anywhere (F5 key, by default), even in places where you still can quick save, it'll crash the game. This is likely a result of the ASM function to NOP-but-not-actually-NOP the quick save instruction.

I haven't been able to test anywhere else due to this for the time being.

elishacloud commented 4 years ago

Yes, it was the ASM function. Try this new one.

Testing build: d3d8.zip

Polymega commented 4 years ago

Thanks!

For this build, while I haven't tested every target room, I am able to save in old rooms we originally disabled saving in, and I'm still able to save in new rooms we're trying to disable saving in.

elishacloud commented 4 years ago

Are you sure this is a problem with the latest build? I tried an older build (before I made any changes to this part of the code) and it seems to have the same issue. Is it possible that this fix was broken a while ago?

Polymega commented 4 years ago

It's working on the latest public release and on the build you linked.

I know a while back you had to put in code to have it constantly check and ensure the game didn't overwrite our override to disable saving while in these rooms. Maybe it has something to do with that?

Try loading the save file labeled Apartments 2F Room (near the top), pull up the map, and head to Room 205. This is one of the rooms you shouldn't be able to save in with GameLoadFix.

Edit: You'll have to cross through a hole in the wall inside Room 209 (where you load from the save) to get out to the main hallway.

Edit 2: You can make a Quick Save right in front of Room 205's door for future quick tests.

elishacloud commented 4 years ago

Ok, one more try. I forgot to statically define two variables! This one should work now. :-)

Testing build: d3d8.zip

Polymega commented 4 years ago

Beautiful! Tested and working great across all binaries.

I know this addendum to GameLoadFix was rather involved, but we just fixed some nasty save and gameplay bugs with this.

I'm 99% confident we have now addressed all trouble areas for the game in regards to save spots. Thanks again Elisha and Bigmanjapan!

Polymega commented 4 years ago

(NOT to be added for this upcoming update.)

Bigmanjapan has been doing a very thorough playtest and found some other areas that could benefit from GameLoadFix.

Please wait until we release the next update before implementing this addition, as it'll require a lot of playtesting after-the-fact:


This will disable to the ability to quick save while Eddie is speaking in-game after the first bowling cutscene, or while Mary is speaking during the final hallway trek to the final boss.

I do not think it can be added to this portion of code, as we only want to kill the quick save instruction while In-Game Voice Event is active while in these rooms. Otherwise, we want to be able to save like normal while in these rooms.


This will be an all-new generic/global addition to GameLoadFix.


01FB7F4D byte (full screen image event) is a new address to the project. When set to 0, that means a full screen event is currently active/triggered.

Note: We might now have different pieces of code that'll completely kill the quick save feature. You might want to have some sort of check to ensure that so long as one piece of code is currently killing the quick save feature to keep it disabled until all flags are cleared.

Thanks to Bigmanjapan for their work/research on this.

elishacloud commented 4 years ago

Ok, I'm going to reopen this. We can fix it after this update.

elishacloud commented 4 years ago

If 01FB7F4D byte (full screen image event) == 0

@Polymega, are you sure this is correct? This seems to completely disable quick saves. Maybe this should be if full screen image does not equal 0?

Example:

Here is a test build with these changes: d3d8.zip

Polymega commented 4 years ago

Thanks Elisha.

are you sure this is correct? This seems to completely disable quick saves. Maybe this should be if full screen image does not equal 0?

Yes, the byte is a little misleading for this one. Whenever it gets set to 0 is when a full screen image event occurs, such as transcribing notes on the map, text/subtitles popping up, riddle/memo images on screen, etc. It changes to 1 whenever you're in-game playing normally, otherwise.

So we want to disable the Quick Save function entirely when the byte is 0, and have it restored/working when it's 1.

On that note, you may want to change this description to say // Disable game saves for specific rooms and disable quick save if the Elevator is running or there is in-game voice event happening.

Edit: Here, too.

When that elevator address is set to 0, it actually means the elevator is moving. It's the same as this byte, in that 0 means active for how we're describing the address.


I did a quick test and there's an error.

Whenever 01FB7F4D byte (full screen image event) == 0 I am still able to Quick Save. Once the fullscreen image event goes away (so the byte changes back to 1) I can no longer Quick Save at all, at any time or any where.

This might simply be confusion on how 0 should be the trigger, and not 1?

elishacloud commented 4 years ago

On that note, you may want to change this description to say

Done. Will be in the next update.

Whenever 01FB7F4D byte (full screen image event) == 0 I am still able to Quick Save.

I made this change and put the test build below. This will block quick saves whenever the value at that address is 0. However, it seems to block a lot of quick saves for me. For example when you start a new game and are in the bathroom you cannot do a quick save. It seems like the value is set to 0 by default so by default it will block the quick save.

Anyways, in this update I also logged the address I am using to get the quick save value, so you can verify it is the right address.

Testing build: d3d8.zip

Polymega commented 4 years ago

This looks to be the ticket. The log file showed the correct address for v1.0 (01FB7F4D). I also very quickly tested 1.1 and DC and the correct address looks to be used for their respective binaries, as well. :)

However, it seems to block a lot of quick saves for me. For example when you start a new game and are in the bathroom you cannot do a quick save.

It's working for me with your newest test build. The purpose of this new address (full screen image event) is to disable quick saving throughout the entire game where it always should have been disabled. i.e. during events/moments that could otherwise possibly "break" the game.

So anywhere where text/subtitles is currently being shown in-game it'll disable quick save (speedrunners actually exploit this to break the game for faster times.). When James transcribes notes onto his map it'll now disable quick saving during this process. Etc etc. Normal in-game gameplay will allow you to quick save like normal.

And with this, the game will still inherently/correctly disable quick saving during cutscenes, browsing your inventory, viewing your map, etc, even if the (full screen image event) address is currently set to 1, so no worries there. What we've done here is add further disabling spots on top of what the game already correctly does.


So thank you for adding this in early! BMJ and I will take our time to fully test and try to break this. We'll report back once we're finished.

elishacloud commented 4 years ago

Code for this fix is checked in: 6e3556a919e9f9ab9d2d3e0e9e88a6260806b7b2

Polymega commented 4 years ago

A small addition to GameLoadFix as BMJ and I finish playtesting Aero_'s upcoming script:

If you load another save file in-game and the file you load has a 'game world' color that isn't black, this game world color will momentarily "flash" as the save file is loaded in: https://youtu.be/ueXQu3IIiIw

To fix this, on game launch, nop the following: 004EEA42 - mov [01F7D490],eax

elishacloud commented 4 years ago

To fix this, on game launch, nop the following: 004EEA42 - mov [01F7D490],eax

Done! Test build: d3d8.zip

elishacloud commented 4 years ago

Fixed in: f691d2b27eb6460274136078d5668345a9712299

AeroWidescreen commented 4 years ago

@elishacloud Big thanks to Polymega and Bigmanjapan for testing these for me.

Disable Quick Save Reset

I'm sorry speedrunners.

// nop's call responsible for resetting player's animation and stamina when saving
0053AE58 nop
0053AE59 nop
0053AE5A nop
0053AE5B nop
0053AE5C nop

Quick Save Soft-Lock Fix

Solves a bug that corrupts saves after attempting to quick save and pick-up an item at the same time. Note: this code is next to the call we nop'd.

0053AE5D jmp 0x00000000
00000000 cmp dword ptr [esi + 0x04], 0x00004214
00000001 je 00000005 // jumps to soft-lock fix if locked
00000002 mov ecx, dword ptr [esi + 0x04]
00000003 mov dword ptr [edi - 0x04], ecx
00000004 jmp 0x0053AE63

// soft-lock fix
00000005 mov ecx, 0x0000214 // unlocks
00000006 mov dword ptr [edi - 0x04], ecx
00000007 jmp 0x0053AE63

Quick Save Timer Fix

Disables timer when interactive text is displayed. The timer would remove the interactive text once it reached zero.

00402480 jmp 00000000
00000000 mov dword ptr [0x00932040], esi
00000001 cmp dword ptr [0x01F7AE80], 0x02
00000002 je 00000004 jumps to code exit if interactive text is displayed
00000003 call 0x0047EEE0

// code exit
00000004 jmp 0x0040248B

Pointers for Quick Save Timer Memory Address

0x00402465 = 0x00932040
0x004024D9 = 0x00932040
0x00402541 = 0x00932040
0x0040256F = 0x00932040

Pointers for Interactive Text Memory Address

0x0048AF9F = 0x01F7AE80
0x0048BB91 = 0x01F7AE80
0x0048BC08 = 0x01F7AE80
0x0048BC68 = 0x01F7AE80

Quick Save Text Overlap Fix

Stops quick save text from overlapping interactive text.

00402534 jmp 00000000
00000000 mov dword ptr [0x00932038], esi
00000001 cmp dword ptr [0x01F7AE80], 0x02
00000002 je 00000004 jumps to code exit if interactive text is displayed
00000003 call 0x0044C680

// code exit
00000004 jmp 0x0040253F

Pointers for Quick Save Text Memory Address

0x00454090 = 0x00932038
0x0045418C = 0x00932038
0x00454393 = 0x00932038
0x004547A6 = 0x00932038

Pointers for Interactive Text Memory Address

0x0048AF9F = 0x01F7AE80
0x0048BB91 = 0x01F7AE80
0x0048BC08 = 0x01F7AE80
0x0048BC68 = 0x01F7AE80
elishacloud commented 4 years ago

Thanks @AeroWidescreen!

Finished implementing this. Testing build: d3d8.zip

Polymega commented 4 years ago

My tests on all binaries look solid. Nothing out of the ordinary and all of Aero_'s features are accounted for. Well done gents!

elishacloud commented 4 years ago

Fix checked in: 8d1d2ee60ae4248ca0190d4c104f39ea216e508a

Polymega commented 4 years ago

Hi Elisha,

In reference to the "fix color flash on game load" part of this fix, may I ask for a test build that does the following?

The only difference here is the addition of the conditional statement to nop the instruction. 00932178 byte would be a new address we'd be using for the project. (I'm pretty sure we've never used it before.)

I'm not 100% sure if this change to nop the instruction will work as I'm expecting it to, but either way, 00932178 is a useful address and could likely help us down the road for other situations.

In more detail, 00932178 byte (event address index) signifies the following:

1 = reload/re-enter into current room
2 = fade back into in-game?
4 = in-game
5 = map
6 = inventory
7 = options menu
8 = bugged Xbox button config menu
9 = save menu
10/11 = pull up Game Results file
12 = "COMING SOON!" splash screen
13 = game over screen
16 = PC pause menu
elishacloud commented 4 years ago

@Polymega, I think I got this work as you requested.

It looks like event index is set to 0 when the screen flash happens. So you could probably change this to the following and it would also fix the screen flashing:

Anyways, I changed it as you requested. Here is the testing build: d3d8.zip

Polymega commented 4 years ago

Thanks Elisha!

On the Game Results screen, you see a message that says "Save Clear Data" and the screen will fade to red, and then to the save screen. The instruction we're nop'ing to fix the color flash on file loads messes up the fade to red on the Game Results screen, so we need to disable nop'ing that instruction during the Game Results screen.

The Game Results screen has a value of 9-11 for 00932178. However, I just tested it and it seems the instruction we're nop'ing is still being nop'ed during this time (maybe the value flashes to a non 9-11 value as the red fade instruction is triggered?).

My conditional statement was written that way because I wasn't sure if the color flash we're wanting to fix only happens on file loads when 00932178 value is set to 0. So...

So you could probably change this to the following and it would also fix the screen flashing:

  • If 00932178 byte (event index address) == 0

Let's try it this way then, please. As my != 9 || 10 || 11 statement didn't work.

elishacloud commented 4 years ago

Ok, try this one. I am only nop'ing if event index is 0.

Here is the testing build: d3d8.zip

Polymega commented 4 years ago

You're smart, Elisha! I'm going to test around more with it tomorrow, but very quick tests just now look to be good with your change. 👍

Polymega commented 4 years ago

This change looks solid. Tested on all binaries. Thank you!

elishacloud commented 4 years ago

Fixed in check-in: 594a1e080bececa1497d3a7e5073afc9496c7c66

Polymega commented 3 years ago

Thanks to Bigmanjapan for finding this issue. An addendum for GameLoadFix:

The game remembers the last item you highlighted in the pause menu. So when you pull up the pause menu again, it'll still be selected on what you last highlighted. If a user highlights "Save Game" then leaves the pause menu, enters an area where we disabled saving, and pulls up the pause menu again, they can still select "Save Game" (even though the option is greyed out) since it was the last thing they highlighted, which unravels much of our work here.

To fix this:

If EventIndexAddr != 16, set 009326B4 (Pause menu button index) byte to 0 (one write, no constant iteration)

I believe 009326B4 byte is a new address for the game. This address indicates what option is currently highlighted in the pause menu. This fix will reset the selected choice back to "Resume Game" when the pause menu is pulled up each time. This will prevent "Save Game" from being pre-highlighted when pulling up the pause menu.

Polymega commented 2 years ago

In regards to the post/request directly above this, it looks like someone has found this cheese and subsequently shot themselves in the foot doing it:

image

Polymega commented 2 years ago

@elishacloud

If EventIndexAddr != 16, set 009326B4 (Pause menu button index) byte to 0 (one write, no constant iteration)

009326B4 has recently been added to the project via TheMachineAmbassador's PR seen here: https://github.com/elishacloud/Silent-Hill-2-Enhancements/commit/d784c580924bc1458bf361a3d18fd38c77c48637#diff-6fbe6e89a20689aab89697bf2598a0efbe623f333af59b4c68d1abd4ee00dbdeR45