Page 1 of 2

Keep guards after they fall offscreen

Posted: March 20th, 2022, 12:57 pm
by David
Shauing wrote: January 22nd, 2022, 11:07 am How can it be made that all guards can fall to other rooms without dying?
In addition to the hex edit, I also implemented this in SDLPoP, on a new branch:
https://github.com/NagyD/SDLPoP/compare ... llen_guard

Re: SDLPoP; David's open-source port of PoP

Posted: March 21st, 2022, 4:02 pm
by dmitry_s
David wrote: March 20th, 2022, 12:57 pm In addition to the hex edit, I also implemented this in SDLPoP, on a new branch:
https://github.com/NagyD/SDLPoP/compare ... llen_guard
This is an interesting feature. I think it can be improved in a couple of ways.

1. "leave_guard" function should return if the "Guard.action" is 3 or 4 so that the guard does not get stuck in the air when you exit the room.

There is also going to be an edge where you leave the room when the guard is standing on a loose tile. The tile is going to fall but the guard will not.

2. "leave_guard" should be called after the guard had landed in a room that is not "drawn_room".

Re: SDLPoP; David's open-source port of PoP

Posted: March 27th, 2022, 9:46 am
by David
dmitry_s wrote: March 21st, 2022, 4:02 pm 1. "leave_guard" function should return if the "Guard.action" is 3 or 4 so that the guard does not get stuck in the air when you exit the room.
I tried this:

Code: Select all

void __pascal far leave_guard() {
	word room_minus_1;

#ifdef KEEP_FALLEN_GUARD
	if (Guard.action == actions_3_in_midair || Guard.action == actions_4_in_freefall) {
		//follow_guard();
		return;
	}
#endif
But then a new bug appears:
If the guard is falling when I leave the room, he will return to his original position when I re-enter the room!

If I uncomment follow_guard() then the guard will still stop mid-air when I exit the room.
But then at least he will continue with his previous speed when I re-enter the room.

dmitry_s wrote: March 21st, 2022, 4:02 pm 2. "leave_guard" should be called after the guard had landed in a room that is not "drawn_room".
I added this at the end of land():

Code: Select all

#ifdef KEEP_FALLEN_GUARD
	if (Char.charid != charid_0_kid && Char.room != drawn_room) {
		leave_guard();
	}
#endif
Was this intended to fix the bug I described above?
This doesn't fix it.

At this point, Guard.action == 4, so leave_guard() doesn't even do anything because of the change above.

What am I doing wrong?


Attached is the levelset I used for testing.
Start level 4.
keep_fallen_guard_test_level_4.zip
(8.47 KiB) Downloaded 108 times

Re: SDLPoP; David's open-source port of PoP

Posted: March 27th, 2022, 8:26 pm
by dmitry_s
Here are my changes as well as some scenarios that I have tested.

https://github.com/dstarosta/SDLPoP/com ... f76cdc9848






Re: SDLPoP; David's open-source port of PoP

Posted: March 29th, 2022, 6:03 am
by atrueprincefanfrom18
OMG!! :shock:

Re: SDLPoP; David's open-source port of PoP

Posted: March 29th, 2022, 7:00 am
by dmitry_s
Added a bugfix where dead fallen guards got saved as alive.

https://github.com/dstarosta/SDLPoP/com ... e6a5d8bc62

Re: SDLPoP; David's open-source port of PoP

Posted: March 29th, 2022, 6:02 pm
by VelCheran
dmitry_s wrote: March 27th, 2022, 8:26 pm Here are my changes as well as some scenarios that I have tested.
That's great!
Now shauing can port his Queen of Light mod to DOS :D

Re: SDLPoP; David's open-source port of PoP

Posted: March 29th, 2022, 6:45 pm
by dmitry_s
I am wondering if it would be better to extend the "FIX_OFFSCREEN_GUARDS_DISAPPEARING" setting to include this behavior.

Re: SDLPoP; David's open-source port of PoP

Posted: March 31st, 2022, 1:50 am
by dmitry_s
I added a couple of commits to fix bugs and allow guard to follow kid down the room.
https://github.com/dstarosta/SDLPoP/com ... llen_guard

All this logic allows to create some interesting levels where you have to get the guard down several rooms without killing him. Guards are useful to hold gates open.


Re: SDLPoP; David's open-source port of PoP

Posted: April 1st, 2022, 8:18 pm
by dmitry_s
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.

Re: Keep guards after they fall offscreen

Posted: April 3rd, 2022, 3:54 pm
by David
(Moved posts to a new thread.)

Re: SDLPoP; David's open-source port of PoP

Posted: April 9th, 2022, 2:23 pm
by yourantumayel69
dmitry_s wrote: March 31st, 2022, 1:50 am I added a couple of commits to fix bugs and allow guard to follow kid down the room.
https://github.com/dstarosta/SDLPoP/com ... llen_guard

All this logic allows to create some interesting levels where you have to get the guard down several rooms without killing him. Guards are useful to hold gates open.

Can you please give me SDLPoP ZIP file? I wait for you

Re: Keep guards after they fall offscreen

Posted: April 9th, 2022, 6:36 pm
by dmitry_s
SDLPoP_fallen_guard.zip
(1.86 MiB) Downloaded 115 times

Re: Keep guards after they fall offscreen

Posted: April 14th, 2022, 8:22 am
by yourantumayel69
dmitry_s wrote: April 9th, 2022, 6:36 pm SDLPoP_fallen_guard.zip
Thanks for ZlP file for test play. It's simple if I test keep fallen guard. If possible, I suggest you: multiple keep fallen guard, multiple death guard offscreen, and guard die by loose floor like your mod (Prince 1.5)

Re: Keep guards after they fall offscreen

Posted: May 22nd, 2022, 4:25 am
by dmitry_s
yourantumayel69 wrote: April 14th, 2022, 8:22 am
dmitry_s wrote: April 9th, 2022, 6:36 pm SDLPoP_fallen_guard.zip
Thanks for ZlP file for test play. It's simple if I test keep fallen guard. If possible, I suggest you: multiple keep fallen guard, multiple death guard offscreen, and guard die by loose floor like your mod (Prince 1.5)
In the standard PoP1 implementation there is only 1 guard slot per room that can store a dead or alive guard. Storing dead guards separately can be done (like in my mod) at the expense of breaking binary compatibility of saves and replays.

But guards can fall or get pushed into other rooms and that requires a lot of code changes since a fallen/pushed guard is not a dead guard and has to move across rooms which already have the guard slot taken by another guard.

In my mod I have separate slots and a additional (mini) sequence table for those scenarios and that involves a lot of code. But it also supports 2 alive guards per room (only 1 guard can be stabbed, the other one will perfectly block all attacks or step back) and up to 5 total guards.

Prince of Persia 2 does has a few more tricks. The fight sequence has been completely rewritten so you do not just deal with 2 variables at a time (Char and Opp) but I think the fight physics became worse. They also have multiple death frames per guard. And once you have over 2 guards in a room stabbed guards start to randomly fall out of the screen so they do not have to be tracked while falling.

https://www.youtube.com/watch?v=dhwU33IPmVQ&t=4552s