Dynamic Guards

Second part of the best game ever made.
Post Reply
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Dynamic Guards

Post by Norbert »

I've got the static guards all worked out (using docs, experimentation and Pr2LevEd; (*)), but the dynamic guards are still somewhat mysterious.
(*) I also tried RoomShaker II in Wine, but it crashes with an error ("The program RoomShaker2.exe encountered a serious problem and needs to close. We are sorry for the inconvenience.").

Attached is an Excel file with all the PoP2 dynamic guard settings of the rooms that are actually in use.
Each row has 34 bytes (columns) with decimal values I extracted from the PRINCE.DAT file, with help from PR.

David, it has been 6+ years since you created Pr2LevEd, but maybe you remember...
To me, the "Number of guards" and 3 columns of Pr2LevEd's pop-up don't make sense, because one of the 34 bytes contains the number of guards that will spawn (column AE) and they are of one type only.
Any ideas?
Also, I have no idea which column the "Max. guards alive" would be.

Below are, for each column, all used values.
The first column with numbers are all used values where AE is not 0 (so, guards are set to spawn), the second column with numbers just shows everything.

A | 0, 1 | 0-2, 9, 11, 16, 32 |
B | 0, 5, 6, 8, 9 | 0, 2, 5, 6, 8, 9, 10, 19, 20, 24, 90 |
C | 0, 4, 10, 15, 19 | 0, 2, 3, 4, 6, 10, 12, 15, 19, 22, 90 |
D | 0, 5, 10, 14, 19 | 0, 5, 9, 10, 11, 14, 15, 17, 19, 22, 24 |
E | 0, 1, 255 | 0, 1, 255 |
F | 0, 1 | 0, 1, 64 |
G | 0, 2, 3, 5 | 0, 2, 3, 5 |
H | 0, 3, 130 | 0, 1, 3, 130 |
I | 0 | 0 |
J | 0 | 0 |
K | 0 | 0 |
L | 0 | 0, 90 |
M | 0 | 0, 90 |
N | 0 | 0, 90 |
O | 0 | 0, 90 |
P | 0 | 0 |
Q | 0 | 0 |
R | 0 | 0, 90 |
S | 0-2 | 0-2 |
T | 0-9, 11 | 0-9, 11 |
U | 0 | 0 |
V | 0 | 0 |
W | 0 | 0 |
X | 1, 2 | 0-2 |
Y | 0-2 | 0-2 |
Z | 0, 6, 7, 9 | 0, 6, 7, 9 |
AA | 2, 5, 7, 8, 9, 10, 15, 16, 20, 25, 41, 50, 86 | 0, 2, 5, 7, 8, 9, 10, 15, 16, 20, 25, 41, 50, 86 |
AB | 2, 5, 7, 8, 9, 10, 15, 16, 20, 25, 41, 50, 86 | 0, 2, 5, 7, 8, 9, 10, 15, 16, 20, 25, 41, 50, 86 |
AC | 1, 255 | 0, 1, 255 |
AD | 0-2 | 0-2 |
AE | 1-5, 7, 9 | 0-5, 7, 9 |
AF | 1-6, 129-132 | 0-6, 129-132 |
AG | 0, 1 | 0, 1 |
AH | 0-2 | 0-2 |

My notes currently say:

S is apparently: activate guard (1 = true, 0 = false).
T is apparently: skill (8 = passive).
X is apparently: 0 or 1 waits until all guards are dead, 2 spawn even with alive guards.
Y is apparently: floor/row (0 = upper, 1 = middle, 2 = lower).
Z is apparently: column (0-5 face right; 6-9 face left).
AA is apparently: latency before spawn.
AB is apparently: latency between spawns.
AC is apparently: can jump.(?)
AE is apparently: number of guards that spawn.
AF is apparently: hit points.

Which leaves lots of stuff unexplained.
Like, 129 hit points, that an enemy is set to but doesn't actually have in-game.

So... any additional suggestions/ideas/info is welcome.
I could go with just what I've got so far, but maybe it's possible to move some puzzle pieces here and there. :)
Attachments
dynamic_guards.xls
All the PoP2 dynamic guard settings of rooms in use.
(607.5 KiB) Downloaded 112 times
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Dynamic Guards

Post by David »

First, it seems to me that your table is off by 18 bytes.
(That is, the contents of the "S" column should be in "A", "T" in "B", and so on. - You should extract them again from the correct offset.)
The dynamic guards' data starts at offset 0x26F9, counted from the beginning of the foreground tiles.
Maybe you counted it from the beginning of the PLV header?
Norbert wrote:To me, the "Number of guards" and 3 columns of Pr2LevEd's pop-up don't make sense, because one of the 34 bytes contains the number of guards that will spawn (column AE) and they are of one type only.
That caption is a bit misleading, it's actually the number of guard sets. The 3 columns are the 3 possible guard sets.
In most rooms there are 0 or 1 sets of dynamic guards, but in three rooms there are 2:
(You should add level and room numbers to the table you uploaded.)
- level 13 room 9
- level 13 room 2
- level 13 room 28
In these rooms, some guards come from the left, some from the right.
The left guards are in one set, and the right guards are in the other.

Each guard set is 10 bytes.
Of the 34 bytes, the last 30 bytes are the guard sets.
This will make A the number of sets, B the skill, C-D unknown,
E-N the first set, O-X the second, Y-AH the third.

I just realized that my editor is off by one byte, so what is shown as the last cell of the last guard set, is actually the first byte of the next room!
Oh, and thanks for discovering the skill!
Norbert wrote:Like, 129 hit points, that an enemy is set to but doesn't actually have in-game.
Looks like the top bit is ignored, or maybe it is used for something else.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Dynamic Guards

Post by Norbert »

David wrote:First, it seems to me that your table is off by 18 bytes. [...] The dynamic guards' data starts at offset 0x26F9, counted from the beginning of the foreground tiles.
Are you sure?

From what I know it's offset 0x26E7 (9959).
I don't know where you add 18 bytes.

Level foreground: 960 (32 rooms * 30 tiles)
Level modifier: 3840 (4 modifers * 960 foregrounds)
Door events: 1280 (5 bytes * 256 events)
Room links: 128 (32 rooms * 4)
Unknown I: 32
Start position: 3 (room, position, direction)
Unknown II: 4
Static guards: 3712 (32 rooms * 116)
----- +
9959

Next up are the dynamic guards.
I even checked the number of guards that spawn, for example, and it seems to be correct.
My start positions also seem to be correct.
David wrote:In most rooms there are 0 or 1 sets of dynamic guards, but in three rooms there are 2: [...]
Ah, interesting.
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Dynamic Guards

Post by David »

Ah, it seems to me you used FormatSpecifications.pdf . :idea:
Looks like it is not fully accurate.
There are 18 bytes between static and dynamic guards.
The first 4 bytes of this area store the places of the two checkpoints. (room+tile)
Norbert wrote:I even checked the number of guards that spawn, for example, and it seems to be correct.
My start positions also seem to be correct.
Yes, if you use only one guard set, then it will work, because you subtracted 18 from the address of the beginning of the structure and added 18 to the address within the structure. Therefore the sum of the two, the final address, won't change.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Dynamic Guards

Post by Norbert »

Okay, thanks; here's an updated version of the Excel file.
Attachments
dynamic_guards_v2.xls
All the PoP2 dynamic guard settings.
(57 KiB) Downloaded 68 times
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Dynamic Guards

Post by David »

I noticed something: The "sp. If al." is almost always the same as the row.
When it's different, row=0 and "sp. If al."=1.
These rooms are:
- level 1, room 10
- level 11, room 23
- level 13, room 9
What is common in these rooms is that the kid enters them on row 1, and the guards come from row 0.
So most probably the "sp. If al." is actually the row where the kid should be to activate the guards.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Dynamic Guards

Post by Norbert »

David wrote:So most probably the "sp. If al." is actually the row where the kid should be to activate the guards.
Nice find, I'll give that a try in the future to see if it works everywhere.
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Dynamic Guards

Post by David »

David wrote:
What makes the guards able to fall out of the screen when they die is apparently a flag in the dynamic guards infos.
I think I found it: It's the topmost bit of the hitpoints byte.
One more thing: that bit is set for the level 13 guards (after the checkpoint) in the IR levels, but apparently the game ignores it.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Dynamic Guards

Post by Norbert »

RoomShaker II's dynamic guards screen includes a setting on which row the prince is. This appears to be absent on apoplexy's PoP2 guards screen. Maybe it should replace the strange "spawn if guard(s) alive: N/N/Y". I have no idea (yet) what apoplexy currently defaults to, but maybe it just doesn't touch the prince row at all, which means in-game behavior - when dynamic guards enter - may appear to be quite random from a modders perspective.
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Dynamic Guards

Post by David »

If I remember right, the field you called "spawn if alive", is actually "prince row".
See here: viewtopic.php?p=14127#p14127
So the "spawn if guard(s) alive" in Apoplexy actually sets "prince row"!
Therefore you can (should) replace the first with the second.

More precisely, the guards will come if the kid is either in the (dynamic) guard's row, or the "prince row".

The function "should_dynguard_come" in the disassembly does this:

Code: Select all

// seg030:0CBE
int __pascal far should_dynguard_come(dynamic_guard_type *dyn_guard,char row) {
	return (dyn_guard->row == row || dyn_guard->prince_row == row)
		&& ABS(dyn_guard->column - Kid.col) > 2 && dyn_guard->how_many != 0;
}
While there, you might want to add this: viewtopic.php?p=14945#p14945 (Guards falling out of the screen)
According to the disassembly, a guard can fall out of the room, if in the current room, these is at least one incoming set with that bit set.

Code: Select all

// seg030:0E52
int __pascal far can_guard_fall_out(char room) {
	short result = 0;
	sbyte count = level.dynamic_guards[room-1].count;
	sbyte index = 0;
	if (count > 0) {
		do {
			if (result) break;
			dynamic_guard_type* dyn_guard = get_dynguard_addr(room, index);
			result = (dyn_guard != NULL) && ((dyn_guard->hitpoints & 0x80) != 0);
			++index;
		} while (index < count);
	}
	return result;
}
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Dynamic Guards

Post by Norbert »

Apparently I forgot to do something with the information in the two posts you link to.
Maybe I didn't understand it at the time, or something...

[Edit: I have moved some posts about the dynamic guards from other threads into this Dynamic Guards thread.]
Post Reply