Disassembly of PoP1 SNES

Discuss PoP1 for SNES here.
Post Reply
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Disassembly of PoP1 SNES

Post by David »

This package contains the disassembly of Prince of Persia 1, SNES version.
It is far from being complete. All suggestions are welcome.
Attachments
Prince_SNES_disasm.zip
(887.38 KiB) Downloaded 136 times
User avatar
spartacus735
Wise Scribe
Wise Scribe
Posts: 215
Joined: November 20th, 2011, 12:41 pm
Location: France

Re: Disassembly of PoP1 SNES

Post by spartacus735 »

What is supposed to do ? I'm not expert in this domain.

This tool can extract files from the rom for example ? Like sprite,sound,background ? Or it's very different ?
>>>>>>>>>>>>>>>>>>>> http://www.youtube.com/user/spartacus735 <<<<<<<<<<<<<<<<<<<< the channel of prince of persia snes mod
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

The disassembly is useful for finding out what needs to be hex-edited for a certain effect.
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

Here is the newest version of the disassembly.
I added many new names/comments, including special events and many names from the Apple II source.

EDIT: As a supplement to the disassembly, I also extracted the sequence table.
[The DOS sequence table is here: viewtopic.php?p=15726#p15726 ]
Attachments
SNES_sequence_table_2015-11-19.zip
(42.5 KiB) Downloaded 117 times
Prince_SNES_disasm_2015-11-19.zip
(917.57 KiB) Downloaded 143 times
badnest
Efendi
Efendi
Posts: 5
Joined: July 15th, 2021, 6:08 am

Re: Disassembly of PoP1 SNES

Post by badnest »

Since a fair amount of code has been disassembled, I was wondering how far this disassembly would be from being able to be rebuilt? Like, with a compiler that could adjust the offsets and stuff so we could theoretically add code anywhere we wanted? Like a Sonic disassembly?
User avatar
Shauing
Calif
Calif
Posts: 423
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Disassembly of PoP1 SNES

Post by Shauing »

I want to ask if inside the game's code, is there an area where it keep track of the potions you've taken and the guards you have killed throughout the game. On the speedrun community we're trying to create the 100% category, and because the game itself doesn't have any gallery or anything similar that displays what have you grabbed, we were wondering maybe inside the game's memory/coding, there's something that keeps track of these things.
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

Shauing wrote: November 8th, 2022, 8:12 pm I want to ask if inside the game's code, is there an area where it keep track of the potions you've taken and the guards you have killed throughout the game. On the speedrun community we're trying to create the 100% category, and because the game itself doesn't have any gallery or anything similar that displays what have you grabbed, we were wondering maybe inside the game's memory/coding, there's something that keeps track of these things.
These are kept track only for the current level, so a potion you've already drunk won't reappear and such.
They are reset when you restart the level.

The level objects (including potions) are stored starting from RAM address 7F:E170, on 24*30 bytes (one byte for each tile of each room).
When the player drinks a potion, the corresponding byte changes to zero.

For example, consider the first potion on level 1, under the green guard.
It's in room 8, at tile 27 (row 2, column 7), so its RAM address is 0x7FE170 + 8*30+27 == 0x7FE27B.
(This calculation assumes that rooms, rows, and columns are all counted from 0, as in Pr1SnesLevEd.)
When that byte changes to 0 (from 0x12), you know the player picked up this potion.

In an AutoSplit file, that offset translates into this:

Code: Select all

	byte Potion_1_8_27 : "snes9x-x64.exe", 0x008D8C38, 0x1E27B; // 7F:E27B
(Assuming you are using snes9x-1.60-win32-x64.)

The final offset is calculated as: 0x7FE27B - 0x7E0000 = 0x1E27B.

Now of course you need to check if the current level is level 1 before checking any potions on level 1.

Here is the AutoSplit offset for the current level:

Code: Select all

	byte CurrentLevel  : "snes9x-x64.exe", 0x008D8C38, 0x0579; // 7E:0579
I'll see if I can find something for the guards.
User avatar
Shauing
Calif
Calif
Posts: 423
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Disassembly of PoP1 SNES

Post by Shauing »

Nice. If you manage to find something that tracks the guards you kill, that would be awesome and most likely will allow us to have a way to track them via splits in Livesplit with autosplitter, thus maybe use game end and continue for faster strategies, and make Level 11 possible to complete without an intentional death.
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

Shauing wrote: November 13th, 2022, 5:32 pm Nice. If you manage to find something that tracks the guards you kill, that would be awesome
I came up with this:

Code: Select all

state("snes9x-x64")
{
	byte CurrentLevel    : "snes9x-x64.exe", 0x008D8C38, 0x0579; // 7E:0579
	sbyte Guard_alive    : "snes9x-x64.exe", 0x008D8C38, 0x0486; // 7E:0486
	byte Guard_room      : "snes9x-x64.exe", 0x008D8C38, 0x0482; // 7E:0482
	byte Guard_direction : "snes9x-x64.exe", 0x008D8C38, 0x047A; // 7E:047A
}

update
{
	//print("Guard_direction = " + current.Guard_direction);
	// 0x00=right, 0x80=left, 0x7F=no guard
	if (current.Guard_direction != 0x7F) // if there is an active guard
	{
		//print("Guard_alive = " + current.Guard_alive);
		// -1 (0xFF) if alive, 0 if dead
		//print("Guard_room = " + current.Guard_room);
		if (current.Guard_alive == 0 && old.Guard_alive == -1)
		{
			print("A guard died in room " + current.Guard_room + " of level " + (current.CurrentLevel+1));
		}
	}
}
Caveat: A guard may die in a room different from where he starts the level.
This can be a problem if you need to know which guards died.
If you only need the number of guards who died on a level, then you can increase a counter every time a guard dies, then check its value when the level ends.

Problem: This does not seem to work with the skeleton on level 3.
Guard_alive stays -1 even when the skeleton is crushed.
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

David wrote: November 19th, 2022, 1:50 pm Problem: This does not seem to work with the skeleton on level 3.
Guard_alive stays -1 even when the skeleton is crushed.
Here is a version which fixes that.

Code: Select all

state("snes9x-x64")
{
	sbyte Guard_alive    : "snes9x-x64.exe", 0x008D8C38, 0x0486; // 7E:0486
	byte Guard_room      : "snes9x-x64.exe", 0x008D8C38, 0x0482; // 7E:0482
	byte Guard_direction : "snes9x-x64.exe", 0x008D8C38, 0x047A; // 7E:047A
	byte Guard_hp        : "snes9x-x64.exe", 0x008D8C38, 0x050B; // 7E:050B
	byte Guard_frame     : "snes9x-x64.exe", 0x008D8C38, 0x0477; // 7E:0477
}

update
{
	//print("Guard_direction = " + current.Guard_direction);
	// 0x00=right, 0x80=left, 0x7F=no guard
	if (current.Guard_direction != 0x7F) // if there is an active guard
	{
		//print("Guard_alive = " + current.Guard_alive);
		// -1 (0xFF) if alive, 0 if dead
		//print("Guard_room = " + current.Guard_room);
		//print("Guard_hp = " + current.Guard_hp);
		//print("Guard_frame = " + current.Guard_frame);
		// 184 = crushed
		if ((current.Guard_alive == 0 || current.Guard_frame == 184) && (old.Guard_alive == -1 && old.Guard_frame != 184))
		{
			print("A guard died in room " + current.Guard_room + " of level " + (current.CurrentLevel+1));
		}
	}
}
User avatar
Shauing
Calif
Calif
Posts: 423
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Disassembly of PoP1 SNES

Post by Shauing »

Sweet; so if I understand correctly, with these findings the autosplitter will check for the potions per level (does this include the kill potion on level 18 or not?) and the number of guards per level as well. I assume that if you die, the counter for the potions already drunk and guards killed will reset?
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2756
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Disassembly of PoP1 SNES

Post by David »

Shauing wrote: November 20th, 2022, 9:33 am Sweet; so if I understand correctly, with these findings the autosplitter will check for the potions per level
(does this include the kill potion on level 18 or not?) and the number of guards per level as well.
Only if someone writes the code for that.
I only searched for the memory locations needed for these checks.
The code blocks in my previous posts just print a debug message when a guard dies, they don't count anything.
Shauing wrote: November 20th, 2022, 9:33 am I assume that if you die, the counter for the potions already drunk and guards killed will reset?
I have not yet looked into how to detect when the level is restarted.

By the way, how would these checks appear to the users of the autosplitter script?
As I see it, autosplitter scripts have limited interaction features.
They can tell LiveSplit the game time, tell when a level of the game ended, or reset the times.
They can also output debug messages which only developers can see.
But, unless I missed something, they can't directly display things on the GUI of LiveSplit.
User avatar
Shauing
Calif
Calif
Posts: 423
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Disassembly of PoP1 SNES

Post by Shauing »

David wrote: November 26th, 2022, 1:54 pm By the way, how would these checks appear to the users of the autosplitter script?
As I see it, autosplitter scripts have limited interaction features.
They can tell LiveSplit the game time, tell when a level of the game ended, or reset the times.
They can also output debug messages which only developers can see.
But, unless I missed something, they can't directly display things on the GUI of LiveSplit.
As Livesplit lets you add splits for what the speedrunner needs them (an item, a location, a fight, a boss, just to mention a few examples), I myself was theorizing that, if the game kept track of the guards killed and potions drank, we could assign a split for each time it checks for when a guard is killed and a potion has been drunk, and/or at the end of each level if all the potions and guards have been drank/killed, also have a split there and continue with the first one for the next level.

For example:
Level 1 splits:
- Heal potion at room 8, tile 27
- Heal potion at room 12, tile 4
- Sword (if there's a check for it)
- Heal potion at room 23, tile 1
- Guard at room 8, tile 6
- Guard at room 1, tile 17
- Level exit

Or if it can't be specific due to the guards if they move, just check when they die:
- Heal potion
- Heal potion
- Sword (if there's a check for it)
- Heal potion
- Guard
- Guard
- Level exit
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
Post Reply