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);
}
}
}
[...]