Saturday 6 January 2018

The Hanging Woman bug

So I've taken a break from getting a 100% binary correct recompile as it's proving difficult!

Instead I thought I'd see if I can use what I have so far to fix some of the know bugs with the game within the game scripts so that they would work with all versions including the Steam one.

Somebody posted a list up here on steam so starting with the first one:

The Hanging Lady
This is a problem where you enter a room and there is a shock piece where your controls are frozen, your view is snap focused on the shock piece with some sound effects and then your controls are unfrozen.
The problem is that for people whose frame rates are higher than 60 this part crashes.
So I looked at the code for this that the decompiler had produced:

nVar767 = D_PlaySoundPositional("sound\sfx\01132.wav", ptVar763, 1.0, 900.0, 0);
D_SetGlobalInt("Hanging_Woman_Handle", nVar767);

nVar768 = D_GetInsanityShockTriggered("COURIER_HUNG_WOMAN_SHOCK");
if (nVar768 == 0)
{
  nVar768 = D_GetGlobalInt("Shock_Played");
  if (nVar768 == 0)
  {
    D_PlayerLockMove();
    D_EnableInsanityShock("COURIER_HUNG_WOMAN_SHOCK", 1);
    D_PlayerWatchObject("*REMOVEINSTATIC_BGANIM_HANGING", 1, "WatchRateVeryResponsive");
    D_EnableVisibilityTrigger("HOLY_SHIT", 0);
    D_SetGlobalInt("Shock_Played", 1);
    Wait(3.0);
    PlayerSayWithoutSuspend(4167, 1);
    D_PlayerUnlock();
    D_PlayerReleaseWatch();
  }
}
>
First it plays a positional sound and stores a handle to that sound so that it can later stop the sound from playing.
Next it checks if the shock has already played and if not then goes about playing the shock.
In the shock the player controls are locked out, the player is forced to watch the shock object, there is a pause of 3 seconds then the player controls and forced watch is released.
Within this some flags are set that are later going to be checked again to see if the shock has already been played.

Now my guess was that this was happening too fast when the fps was higher than 60 and that the handles and flags being set were being run multiple times at the same time.
The scripting engine handles this kind of problem by using BeginSafeBlock() and EndSafeBlock() to ensure that only one script is in this section at a time.

So this should fix it:

BeginSafeBlock();

nVar767 = D_PlaySoundPositional("sound\sfx\01132.wav", ptVar763, 1.0, 900.0, 0);
D_SetGlobalInt("Hanging_Woman_Handle", nVar767);

nVar768 = D_GetInsanityShockTriggered("COURIER_HUNG_WOMAN_SHOCK");
if (nVar768 == 0)
{
  nVar768 = D_GetGlobalInt("Shock_Played");
  if (nVar768 == 0)
  {
    D_PlayerLockMove();
    D_EnableInsanityShock("COURIER_HUNG_WOMAN_SHOCK", 1);
    D_PlayerWatchObject("*REMOVEINSTATIC_BGANIM_HANGING", 1, "WatchRateVeryResponsive");
    D_EnableVisibilityTrigger("HOLY_SHIT", 0);
    D_SetGlobalInt("Shock_Played", 1);
    Wait(3.0);
    PlayerSayWithoutSuspend(4167, 1);
    D_PlayerUnlock();
    D_PlayerReleaseWatch();
  }
}

EndSafeBlock();

And after testing, with help from a program called Special K, it does indeed fix the problem!

Will add this fix into the patcher when I get the chance :)