The first commit had that problem. It should be fixed in the second commit.
https://github.com/dstarosta/SDLPoP/com ... baff6bR268
If you can reproduce it, please post a video or a replay file.
Here is some information about how prince saves guards. There is a "Guard" variable that represents the guard in the prince's room. Normally it is only applicable to the current room but this change allows you to have the active guard to fall into a different room or follow prince from a room above.
However, if prince exits a room without a guard following him the "leave_guard" function saves guard coordinates into multiple arrays such as "level.guards_tile", "level.guards_seq_hi" and a few others that display the guard's coordinates, whether the guard is alive (by saving the sequence for dead guards and setting it to 0 for non-dead guards), direction, skill, etc. The array index is the room number which limits guards to 1 per room. This way the Guard variable can be reused for the next room. The "enter_guard" function uses those arrays to construct the Guard variable instance.
If a guard is following prince, then "leave_guard" is not called and the guards coordinates switch to the new room as prince exits it. The guard is also cleared from the previous room the in the arrays. But because of the limitation of 1 guard per room, guards cannot follow or fall into a room with an active guard without causing him to disappear.
Quicksave saves the Guard variable and the arrays. The problem happens in the "leave_function" that determines whether the guard is alive or not by checking whether the "Guard.alive < 0". But there is also a "guardhitp_curr" variable that stores the number of guard's lives/hit points. And it takes a frame to set the "alive" variable for the guard after there are no more hit points left.
This is not a problem when leaving rooms since it takes a few frames to switch the room. However, if you "quickload" on a perfect frame, the "leave_guard" function is going to store the guard as alive since the "alive" variable is still set to -1.
In order to store the fallen guard in a different room, I have to call the "leave_guard" function explained in a few posts above. But when after the guard falls and dies, the "take_hp" method only zeros out the hit points which caused the "leave_function" to store the guard as alive. But unless you re-enter the room or quickload the "Guard" variable is still going to show a dead guard.
Setting the "alive" variable to 0 manually kinda works. But the problem is the "on_guard_killed" function is not going to get called because it is normally called where the code checks guard's hit points and sets the "alive" variable. Calling the "on_guard_killed" function manually is also not ideal because you would not get the splash/spiked sound. There could be other side effects in edge cases as that function does other things like opening the last level door after Jaffar is killed.
To get around this behavior, I had to set the "alive" variable to -128 and modify the "leave_guard" function to store the guard as dead while the game still thinks he is alive for a few more frames. That allowed all the sounds and special events to work correctly as well as getting rid of the bug. Quicksave/load also works fine because it stores all of the variables.
I have no idea why Mechner did not use a Guard (char_type) array which would have made things way simpler. Instead there is a lot of different logic, as you can see in my commits, where guards were restricted to a single room. The original logic also can save guards in mid-air as there are no arrays for fall_x/fall_y data. If you enter the room back, the guard will appear in mid-air but the fall speed is going to be reset causing glitches as in level 7 during speed runs. With the new logic guards can continue falling as long as there is no new guard in the other room. In that case the "Guard" variable gets overwritten and the falling guard in the other room disappears.