Fluffy's Prince of Persia

Threads about other remakes and ports.
User avatar
Alberto
Beylerbey
Beylerbey
Posts: 60
Joined: February 13th, 2019, 6:55 am

Re: Fluffy's Prince of Persia

Post by Alberto »

FluffyQuack wrote: December 31st, 2023, 7:23 pm So I'm 99% sure that gate bug you linked won't happen in my code.
That's alright, I'm all for improvements even if that means fixing fun/quirky bugs. When I first played PoP for SNES I was disappointed because it was so different, but now it is one of my favorites because it improved the performance, adds lots of new levels and has great visuals. I also played @Shauing 's 30th Anniversary port and I think it is impossible (don't quote me on that) to do integer overflow tricks.
FluffyQuack wrote: December 31st, 2023, 7:23 pm ...but it could be a fun competitive mode maybe to have one player control the prince and another player control a guard).
Co-op but inverted, sounds fun.

Overall, I'm pretty excited for your project, even if it were to advance at a snail's pace I'll wait for it patiently. :D
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

Alberto wrote: January 1st, 2024, 6:54 am That's alright, I'm all for improvements even if that means fixing fun/quirky bugs. When I first played PoP for SNES I was disappointed because it was so different, but now it is one of my favorites because it improved the performance, adds lots of new levels and has great visuals. I also played @Shauing 's 30th Anniversary port and I think it is impossible (don't quote me on that) to do integer overflow tricks.
Projects like that are neat. One thing I want to do with my project is make certain modifications easier to do and allow for more freedom. For instance, one reason why I'll be slow to implement "scripted events" (ie, every "shadow" interaction in POP1 or tiles automatically falling during last level) is that I want to add a simple scripting language so those scenes are driven by externalized scripts that are easy to modify. I'll probably end up implementing cutscenes the same way.

Other things I'm planning:
  • In-built level editor.
  • Support for campaigns that are longer than 14 levels (already done as my code has no limitation when it comes to level count).
  • Support for larger levels (already done, though my limit is currently hardcoded to 356x104 tiles per level. I'll probably make this dynamic in the long run).
  • Multiple tilesets within a level (this is already supported as my code defines tileset on a per-tile basis).
  • Better support for unique "skins" for characters. When replacing the graphics for the prince/guards in original POP you need to make sure the frame image sizes are the same, otherwise it'll affect gameplay (since image sizes affect the collision box), but I'll make the collision sizes pre-defined for each frame so you can replace the sprites with new sprites of any size without affecting gameplay (I'll also make it possible to change the render offset for each sprite frame).
Alberto wrote: January 1st, 2024, 6:54 amOverall, I'm pretty excited for your project, even if it were to advance at a snail's pace I'll wait for it patiently. :D
That's good to hear! I'm personally especially excited to work on support for POP2. We already have SDL-POP and MININIM as different modernized ways to play POP1 with new features and better modding support, but we've got nothing of the sort for POP2. It will probably be a huge challenge to implement POP2 support in a way that's very faithful, but I hope it's something I can accomplish.
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

I've been putting a lot more work into this the past few weeks thanks to a big boost in motivation (thanks FM Towns for all the function names!).

There were some tileset pieces I was not loading the right palette for, but I'm able to load the correct palettes now. For instance, here's the wharf with correct colours:
2024-11-18 00-19-58-242.png
This palette exists in the main palette file for the rooftops (resource id 3500), except you use it with an offset skipping the first 176 colour entries. This was one of my theories as to why I couldn't find the correct palettes, but finding them via brute force would have been a pain. It's easy when I can look up the relevant code (ie, @RoofCheckPalette).
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

I could not be bothered to figure out exactly how POP2 defines the drawing of custom rooms (I'm not sure if it's hardcoded or defined in the Custom files that exist for many levels), but most of the rooms are very easy to figure out just by looking at them so I went with the approach of taking screenshots and zooming in to figure out where each piece belongs. I just finished the drawing code for the first level (though I haven't implemented the colour cycling for the water, and the pillar reflections in the water might be slightly off, but everything else should be 1:1 identical).

It's funny to see some oddities when you see the entire level as one. For instance, wharf and its room above aren't aligned at all when you look at them like this. And, for some inexplicable reason, there's one building that becomes one pixel taller between two screens (4-5 screens left of starting room).

Edit: I just realized I forgot to include the side wall for the the tall building in the middle of the level. Everything else should be exact, though.
2024-11-20 21-46-16-723.png
jdbro
Sheikh
Sheikh
Posts: 20
Joined: June 23rd, 2019, 10:58 am

Re: Fluffy's Prince of Persia

Post by jdbro »

Nice Project! What language do you use and what is the graphics engine?
David
The Prince of Persia
The Prince of Persia
Posts: 2877
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Fluffy's Prince of Persia

Post by David »

FluffyQuack wrote: November 20th, 2024, 11:15 pm For instance, wharf and its room above aren't aligned at all when you look at them like this.
The map of level 1 on vgmaps and the map of level 1 here fix this by offsetting the bottom row of rooms.

The latter site even mentions it:
http://homepage.eircom.net/~seanhennessy/pop2/princeofpersia2.htm wrote: Another example is the house you drop off at the quayside at level one - the one you drop off doesn't quite match the one you land beside. Hence the funny offset windows.
There seems to be a difference in the perspective(?) as well:
In the top room, the prince is hidden behind the wall when he climbs down.
In the bottom room, the prince can (almost) walk up to the wall but he can't hide behind it.

FluffyQuack wrote: November 20th, 2024, 11:15 pm And, for some inexplicable reason, there's one building that becomes one pixel taller between two screens (4-5 screens left of starting room).
That's odd. I made screenshots from the original game, and here they seem to line up perfectly.
two_rooms.png

Two windows seem to be off by one tile in your map:
The first is the window under the guard shown above.
The second is in the top row of the next room (to the left), before the big jump.
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

jdbro wrote: November 22nd, 2024, 11:48 pm Nice Project! What language do you use and what is the graphics engine?
The project is written in C++ (though most of code is practically just C) and I'm using OpenGL for graphics. I'll make it open source when the project is further along and I've had a chance to clean up the code.

I'm trying to ensure the games stay as faithful as possible, but I am doing some stuff differently. The biggest thing is that I'm placing all tiles from a level into one big level, rather it being structured room-by-room like the original game. But the gameplay code still understands rooms as an abstract concept and it's used for many checks (ie, guards will lose interest in following you if you cross imaginary room boundaries while too far away).

I realize now this means my project will not support custom level sets that use unnatural room layouts (ie: you start in room 1, move up to room 2, but then room 2 leads into room 3 when moving back down).
David wrote: November 23rd, 2024, 10:42 am There seems to be a difference in the perspective(?) as well:
In the top room, the prince is hidden behind the wall when he climbs down.
In the bottom room, the prince can (almost) walk up to the wall but he can't hide behind it.
That reminds me of another oddity I didn't realize until I implementing drawing of those two rooms. A normal room in POP is 189 pixels tall (3 rows * 63) but it displays 3 rows of pixels from another room to total 192 pixels in height. A custom room is always 192 in height and it doesn't take pixels from any other room. So if I place custom rooms where they should logically exist and always draw all of them then three pixel rows will be different depending on which room I draw last.
David wrote: November 23rd, 2024, 10:42 amThat's odd. I made screenshots from the original game, and here they seem to line up perfectly.

two_rooms.png


Two windows seem to be off by one tile in your map:
The first is the window under the guard shown above.
The second is in the top row of the next room (to the left), before the big jump.
Yup, you're right. I felt pretty certain I was drawing those rooms correctly, but I when I looked more closely at it now I realize there were crenelations in three rooms I was drawing slightly off, but everything else was fine.

Now everything should be 1:1 exact (except for the pillar reflections I haven't aligned yet, and there's 3 pixel rows being overwritten between the wharf and the screen above):
2024-11-23 12-30-18-654.png
I'm keeping the weird misalignment between the wharf and its room above as I don't want to do anything super hacky to make them aligned. During gameplay I'll just make sure the camera doesn't show those two rooms at the same time, just like the original game.
jdbro
Sheikh
Sheikh
Posts: 20
Joined: June 23rd, 2019, 10:58 am

Re: Fluffy's Prince of Persia

Post by jdbro »

The project is written in C++ (though most of code is practically just C) and I'm using OpenGL for graphics. I'll make it open source when the project is further along and I've had a chance to clean up the code.

I'm trying to ensure the games stay as faithful as possible, but I am doing some stuff differently. The biggest thing is that I'm placing all tiles from a level into one big level, rather it being structured room-by-room like the original game. But the gameplay code still understands rooms as an abstract concept and it's used for many checks (ie, guards will lose interest in following you if you cross imaginary room boundaries while too far away).

I realize now this means my project will not support custom level sets that use unnatural room layouts (ie: you start in room 1, move up to room 2, but then room 2 leads into room 3 when moving back down).
Nice, i tried to make the same :) if you interested look at the MPrince on this forum (viewtopic.php?f=69&t=4322)
Also made level instead rooms, custom collisions (without tiles check, it was a hell in original game) :)
But didn't touch my project for 4 years, completed first level and all mechanics (AI, collisions, spikes, etc.)

Good luck on your project! PoP2 looks interested :)
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

jdbro wrote: November 23rd, 2024, 2:50 pmNice, i tried to make the same :) if you interested look at the MPrince on this forum (viewtopic.php?f=69&t=4322)
Also made level instead rooms, custom collisions (without tiles check, it was a hell in original game) :)
But didn't touch my project for 4 years, completed first level and all mechanics (AI, collisions, spikes, etc.)

Good luck on your project! PoP2 looks interested :)
That's pretty cool! I assume you weren't closely following the original source code in order to get the exact same logic for everything? That reminds me of my first attempt at remaking POP1 many years ago with a friend. We weren't looking up any source code (this was so long ago I think it was actually before Jordan Mechner even uploaded the POP1 code), so we were basically doing it by taking videos and screenshots of POP1 to figure out how everything should behave. We didn't get nearly as far as you did, though. I remember getting a basic level editor, very basic level drawing, movement, and rudimentary multiplayer implemented. I can remember posting about it on a POP forum. I thought it was this forum, but I can't find the thread anymore.

Anyway, I finally decided to give this idea another go two years ago and, while it's moving slowly due to me taking long breaks from the project, I'm getting very meaningful progress. This time, I'm using the Apple II and SDL-POP source code as reference, and reverse-engineering POP2, to ensure I get similar logic for everything implemented. I'd say I'm about 90% done with POP1 and early-ish with POP2 but I'm getting really good momentum with it.

By the way, if your wall drawing algorithm still isn't done and you find yourself randomly going back to your project, here's my parts of my code for rendering the walls which might be useful reference:

Code: Select all

static void Prince_DrawLeftWallWornBrickDecal(int pixelPosX, int pixelPosY, int decalVariant, int arg2, int arg1)
{
	static const int pos[] = {58, 41, 37, 20, 16}; //These coordinates are the Y coordinates, but they're meant for a coordinate system where 0 is the bottom of the tile. To correct this, we do this calculation: ((PRINCE_TILESIZEY - textureHeight) - pos[index]) (last entry seems to be unused)
	int tex;
	if (decalVariant % 2) tex = T_PRINCE_VDUNGEON_375_BRICK_WORN_BOTTOMLEFT;
	else tex = T_PRINCE_VDUNGEON_374_BRICK_WORN_TOPLEFT;

	int lv2 = 0;
	if (decalVariant > 3) lv2 = arg1 + 6;
	else if (decalVariant > 1) lv2 = arg2 + 6;

	pixelPosX += ((decalVariant == 2 || decalVariant == 3) * 8) + lv2;
	pixelPosY += ((PRINCE_TILESIZEY - 5) - pos[decalVariant]);
	AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, tex);
}

static void Prince_DrawRightWallWornBrickDecal(int pixelPosX, int pixelPosY, int decalVariant, int arg1)
{
	static const int pos[] = {52, 42, 31, 21}; //See note above regarding pos array (last entry seems to be unused)
	int tex;
	if (decalVariant % 2) tex = T_PRINCE_VDUNGEON_377_BRICK_WORN_BOTTOMRIGHT;
	else tex = T_PRINCE_VDUNGEON_376_BRICK_WORN_TOPRIGHT;

	if (decalVariant < 2) arg1 = 24;
	else arg1 -= 3;

	pixelPosX += ((decalVariant > 1) * 8) + arg1;
	pixelPosY += ((PRINCE_TILESIZEY - 10) - pos[decalVariant]);
	AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, tex);
}

[...]
if(tile->type == PRINCE_TILETYPE_WALL)
{
	unsigned int seed = x + (y * PRINCE_MAXLEVEL_SIZEX) + ((lvl->lvlIndex + 1) * PRINCE_MAXLEVEL_SIZEX * PRINCE_MAXLEVEL_SIZEY);
	
	int middleDivider = fastrand(&seed) % 2; //0 = thick middle brick divider, 1 = thin middle brick divider
	int middleDividerOffset = fastrand(&seed) % 5; //Horizontal render offset for middle brick divider

	//Same as above but for bottom brick dividers
	int bottomDivider = fastrand(&seed) % 2;
	int bottomDividerOffset = fastrand(&seed) % 5;

	if(leftTile->type == PRINCE_TILETYPE_WALL && rightTile->type != PRINCE_TILETYPE_WALL) //Left side is a wall, but right side isn't
	{
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, T_PRINCE_VDUNGEON_366_FULLWALL2);
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY + (PRINCE_TILESIZEY - 3), T_PRINCE_VDUNGEON_365_FULLWALL2_BOTTOM); //Bottom 3 pixels of a tile

		if(tile->tileSet == PRINCE_TILESET_POP1_DUNGEON)
		{
			if((fastrand(&seed) % 5) == 0)
				Prince_DrawRightWallWornBrickDecal(pixelPosX, pixelPosY, (fastrand(&seed) % 2) + 2, middleDividerOffset);
		}
	}
	else if(leftTile->type != PRINCE_TILETYPE_WALL && rightTile->type == PRINCE_TILETYPE_WALL) //Left side isn't a wall, but right side is
	{
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, T_PRINCE_VDUNGEON_370_FULLWALL4);
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY + (PRINCE_TILESIZEY - 3), T_PRINCE_VDUNGEON_369_FULLWALL4_BOTTOM); //Bottom 3 pixels of a tile

		if(tile->tileSet == PRINCE_TILESET_POP1_DUNGEON)
		{
			if((fastrand(&seed) % 5) == 0)
				Prince_DrawLeftWallWornBrickDecal(pixelPosX, pixelPosY, fastrand(&seed) % 4, middleDividerOffset - middleDivider, bottomDividerOffset - bottomDivider);
		}
	}
	else if(leftTile->type != PRINCE_TILETYPE_WALL && rightTile->type != PRINCE_TILETYPE_WALL) //Left and right sides aren't walls
	{
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, T_PRINCE_VDUNGEON_368_FULLWALL3);
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY + (PRINCE_TILESIZEY - 3), T_PRINCE_VDUNGEON_367_FULLWALL3_BOTTOM); //Bottom 3 pixels of a tile

		if(tile->tileSet == PRINCE_TILESET_POP1_DUNGEON)
		{
			if((fastrand(&seed) % 7) == 0)
				Prince_DrawLeftWallWornBrickDecal(pixelPosX, pixelPosY, fastrand(&seed) % 2, middleDividerOffset - middleDivider, bottomDividerOffset - bottomDivider);
		}
	}
	else //Left and right sides are walls
	{
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, T_PRINCE_VDUNGEON_364_FULLWALL1);
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY + (PRINCE_TILESIZEY - 3), T_PRINCE_VDUNGEON_363_FULLWALL1_BOTTOM); //Bottom 3 pixels of a tile
	}

	if(leftTile->type == PRINCE_TILETYPE_WALL || rightTile->type == PRINCE_TILETYPE_WALL) //Render middle divider
	{
		//When looking at SDL POP screenshots, it looks like the middle divider can be rendered somewhere between 8 to 12 pixels from zero X position (I counted the same rendering pos for small and wide divider textures)
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX + 8 + middleDividerOffset, pixelPosY + 21, T_PRINCE_VDUNGEON_371_BRICKDIVIDER + middleDivider);
	}

	if(leftTile->type == PRINCE_TILETYPE_WALL) //Left side is a wall
	{
		//Render bottom divider
		//When looking at SDL POP screenshots, it looks like the bottom divider can be rendered somewhere between 0 to 4 pixels from zero X position (I didn't try to count sepearately for small and wide divider textures)
		AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX + bottomDividerOffset, pixelPosY + 42, T_PRINCE_VDUNGEON_371_BRICKDIVIDER + bottomDivider);

		if(tile->tileSet == PRINCE_TILESET_POP1_DUNGEON)
		{
			if((fastrand(&seed) % 5) == 0)
				Prince_DrawLeftWallWornBrickDecal(pixelPosX, pixelPosY, fastrand(&seed) % 5, middleDividerOffset - middleDivider, bottomDividerOffset - bottomDivider);
		}
	}
	
	if(rightTile->type == PRINCE_TILETYPE_WALL) //Right side is a wall
	{
		if((fastrand(&seed) % 5) == 0)
			AddToRenderQueue_Layer(RD_FOREGROUND, pixelPosX, pixelPosY, T_PRINCE_VDUNGEON_373_DARKBRICK);

		if(tile->tileSet == PRINCE_TILESET_POP1_DUNGEON)
		{
			if((fastrand(&seed) % 5) == 0)
				Prince_DrawRightWallWornBrickDecal(pixelPosX, pixelPosY, fastrand(&seed) % 4, middleDividerOffset);
		}
	}
}
[...]
jdbro
Sheikh
Sheikh
Posts: 20
Joined: June 23rd, 2019, 10:58 am

Re: Fluffy's Prince of Persia

Post by jdbro »

That's pretty cool! I assume you weren't closely following the original source code in order to get the exact same logic for everything? That reminds me of my first attempt at remaking POP1 many years ago with a friend. We weren't looking up any source code (this was so long ago I think it was actually before Jordan Mechner even uploaded the POP1 code), so we were basically doing it by taking videos and screenshots of POP1 to figure out how everything should behave. We didn't get nearly as far as you did, though. I remember getting a basic level editor, very basic level drawing, movement, and rudimentary multiplayer implemented. I can remember posting about it on a POP forum. I thought it was this forum, but I can't find the thread anymore.
Yeah, i choosed my own way, without copying code :) But sometimes i had to look at original code (some animation tricks)
But original code had too many if statements on almost everything
i prefer using simple modern mechanics instead pixel hunting ;)

Just was doing it for fun :)
Anyway, I finally decided to give this idea another go two years ago and, while it's moving slowly due to me taking long breaks from the project, I'm getting very meaningful progress. This time, I'm using the Apple II and SDL-POP source code as reference, and reverse-engineering POP2, to ensure I get similar logic for everything implemented. I'd say I'm about 90% done with POP1 and early-ish with POP2 but I'm getting really good momentum with it.

By the way, if your wall drawing algorithm still isn't done and you find yourself randomly going back to your project, here's my parts of my code for rendering the walls which might be useful reference
Actually, i've returned to project and wanna finish WDA and refactor some things :) Thanks for code !

I'm going to try figure out by myself how it works ;) But i have an idea to put wall marks and dividers to level file with some modificators on every wall tile by script :) and after that load it to the game without algorithms ;) But haven't decided yet
Last edited by jdbro on November 23rd, 2024, 11:08 pm, edited 2 times in total.
jdbro
Sheikh
Sheikh
Posts: 20
Joined: June 23rd, 2019, 10:58 am

Re: Fluffy's Prince of Persia

Post by jdbro »

Anyway, I finally decided to give this idea another go two years ago and, while it's moving slowly due to me taking long breaks from the project, I'm getting very meaningful progress. This time, I'm using the Apple II and SDL-POP source code as reference, and reverse-engineering POP2, to ensure I get similar logic for everything implemented. I'd say I'm about 90% done with POP1 and early-ish with POP2 but I'm getting really good momentum with it.
POP2 looks more solid and harder to make, but there is no projects :)
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

jdbro wrote: November 23rd, 2024, 6:07 pmActually, i've returned to project and wanna finish WDA and refactor some things :) Thanks for code !

I'm going to try figure out by myself how it works ;) But i have an idea to put wall marks and dividers to level file with some modificators on every wall tile by script :) and after that load it to the game without algorithms ;) But haven't decided yet
That's cool! Any solution that gets you to the goal you're going for is good in my book. I'm being stubborn and I want my project to work using only the original game files, so I'm loading all assets that way. Though I'm considering to make an exception for POP2 music so I can have that in a specific version without adding a sound card emulator.
jdbro wrote: November 23rd, 2024, 6:09 pmPOP2 looks more solid and harder to make, but there is no projects :)
Yeah, that's a big motivator for adding POP2 to my project. I really like that game but there's no modern way to play it.
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

This is the current state of the "mega texture atlas" my project generates when loading game files. This should be every single graphical asset from POP1 and POP2, though a couple of cutscene assets are currently loaded with the wrong palette. I think it's neat to see all the graphics in one place like this:
POP-MegaTextureAtlas-invert.png
jdbro
Sheikh
Sheikh
Posts: 20
Joined: June 23rd, 2019, 10:58 am

Re: Fluffy's Prince of Persia

Post by jdbro »

Awesome! could you split pop1 and pop2 textures? :)
FluffyQuack
Vizier
Vizier
Posts: 121
Joined: June 6th, 2004, 7:05 pm

Re: Fluffy's Prince of Persia

Post by FluffyQuack »

jdbro wrote: November 25th, 2024, 11:53 am Awesome! could you split pop1 and pop2 textures? :)
Right now it's hardcoded to always load everything from POP1 and POP2. I'll definitely make it so it's okay with only loading assets from one game. That said, I don't think I need to optimize this. Even though it seems nutty to load and convert every asset immediately it takes less than 2 seconds in total.
Post Reply