Level conversion from PC to SNES for Total Pack

A user-friendly interface for downloading, tweaking and playing mods.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Level conversion from PC to SNES for Total Pack

Post by starwindz »

I am trying to make PoP1 PC to SNES level converter in order to convert many PC version of levels made by PoP fans and random levels generated my Random Tournament Mod.

The most important thing I have to do for this is understanding the level format of SNES version. But the level structure of SNES version is very different from other platforms such as PC, MAC and Commodore 64 version of PoP1.

Today I have come to know understanding tiles(Foreground and Background) and layers(Foreground and Background) is very crucial but I could not understand it even after examining the source codes in SNESLevelEditor.

Code: Select all

typedef struct{
   unsigned char bg[24][3][10];
   unsigned char fg[24][3][10];
   unsigned char md[24][3][10];
   unsigned char block_gg[256];
   unsigned char block_fg[256];
   unsigned char block_ob[256];
   unsigned char block_fl[256];
   unsigned char rm_links[24][4];
   unsigned char start_rm,start_ps,start_dr,zero;
   unsigned char guard_ps[24];
   unsigned char guard_tp[24];
   unsigned char guard_sk[24];
   unsigned char guard_uk1[24];
   unsigned char guard_uk2[24];
   unsigned char guard_uk3[24];
   unsigned char door1[256];
   unsigned char door2[256];
}TLevel;
Please help me and let me know any information if you have any ideas.
Last edited by starwindz on August 9th, 2013, 3:15 pm, edited 1 time in total.
User avatar
AuraDragon
Sultan
Sultan
Posts: 146
Joined: March 3rd, 2009, 11:03 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by AuraDragon »

Most of the changes in the engine between the PC and SNES versions are purely cosmetic, hence the multiple layers of backgrounds and foregrounds.

Also, the tiles' Foreground and Background graphics and independent of how the tile itself behaves, you can have empty space being a wall as well as a wall being a normal floor, that would be covered in this:
unsigned char block_ob[256];
unsigned char block_fl[256];
Also each map uses a defined list/array of 256 unique tiles, different and modifiable for each level, that's what this part covers:
unsigned char block_gg[256];
unsigned char block_fg[256];
unsigned char block_ob[256];
unsigned char block_fl[256];
There are [24] rooms, [3] rows, [10] columns, and each tile points to one of the 256 unique tiles defined above.

Door1 and Door2 are, I'm guessing, connections for triggers...


P.S. I usually suck at explaining, so I apologize if you get more confused by that.
I post on the forum at weird times of the day
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by David »

You're right, the block_xx arrays define the 256 foreground tiles.
block_fg determines what graphics to use in the layer behind the prince, but in front of the background. (3rd dropdown in the editor)
block_gg determines what graphics to use in the layer in front of the prince. (4th dropdown)
block_ob determines what object (trap, potion, door etc.) does this tile have. For a list of object IDs see the source (the string array called "ob"). (the dropdown above the checklistbox)
block_fl determines whether this tile has a floor (1), a wall (2), or none of them (0). (the checklistbox)

fg determines for each tile of each room, which of these foreground tiles should be used. (1st dropdown)
bg determines the background graphics. (2nd dropdown)
md determines the modifier, used e.g. for buttons. (rightmost dropdown)

rm_links stores the room links, but the rooms are numbered differently: 0-23, instead of 1-24, and 255 is the "no room", instead of 0.
door1 and door2 store the door links. Their format is similar to the DOS version, but again the rooms are numbered differently.

guard_ps stores the position of the guards. (255 if no guard)
guard_tp stores the type of the guards (lower 7 bits) and the direction (highest bit, 0=right, 1=left).
guard_sk was believed to store the skill, but it seems that it doesn't do anything. The skill is determined by the type.
The purpose of guard_uk1/2/3 are unknown.

start_rm,start_ps,start_dr store the starting room, position and direction (255=left, 0=right). Again, the rooms are numbered differently from the DOS version.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

AuraDragon wrote:... Also each map uses a defined list/array of 256 unique tiles, different and modifiable for each level, that's what this part covers ...
Thank you for your comment. :)
Last edited by starwindz on November 6th, 2011, 5:07 pm, edited 1 time in total.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

David wrote:You're right, the block_xx arrays define the 256 foreground tiles.
block_fg determines what graphics to use in the layer behind the prince, but in front of the background. (3rd dropdown in the editor)
block_gg determines what graphics to use in the layer in front of the prince. (4th dropdown)
block_ob determines what object (trap, potion, door etc.) does this tile have. For a list of object IDs see the source (the string array called "ob"). (the dropdown above the checklistbox)
block_fl determines whether this tile has a floor (1), a wall (2), or none of them (0). (the checklistbox)

fg determines for each tile of each room, which of these foreground tiles should be used. (1st dropdown)
bg determines the background graphics. (2nd dropdown)
md determines the modifier, used e.g. for buttons. (rightmost dropdown)

rm_links stores the room links, but the rooms are numbered differently: 0-23, instead of 1-24, and 255 is the "no room", instead of 0.
door1 and door2 store the door links. Their format is similar to the DOS version, but again the rooms are numbered differently.

guard_ps stores the position of the guards. (255 if no guard)
guard_tp stores the type of the guards (lower 7 bits) and the direction (highest bit, 0=right, 1=left).
guard_sk was believed to store the skill, but it seems that it doesn't do anything. The skill is determined by the type.
The purpose of guard_uk1/2/3 are unknown.

start_rm,start_ps,start_dr store the starting room, position and direction (255=left, 0=right). Again, the rooms are numbered differently from the DOS version.
@David
Thank you very much for your quick and kind advice. :) All I have to do is now understanding your advice and then making some kind of algorithm for PC-to-SNES conversion. It will take some time and there may be some more questions for this.
Thank you again, David.
salvadorc17
Calif
Calif
Posts: 553
Joined: August 27th, 2011, 2:04 am

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by salvadorc17 »

You're right, the block_xx arrays define the 256 foreground tiles.
block_fg determines what graphics to use in the layer behind the prince, but in front of the background. (3rd dropdown in the editor)
block_gg determines what graphics to use in the layer in front of the prince. (4th dropdown)
block_ob determines what object (trap, potion, door etc.) does this tile have. For a list of object IDs see the source (the string array called "ob"). (the dropdown above the checklistbox)
block_fl determines whether this tile has a floor (1), a wall (2), or none of them (0). (the checklistbox)

fg determines for each tile of each room, which of these foreground tiles should be used. (1st dropdown)
bg determines the background graphics. (2nd dropdown)
md determines the modifier, used e.g. for buttons. (rightmost dropdown)

rm_links stores the room links, but the rooms are numbered differently: 0-23, instead of 1-24, and 255 is the "no room", instead of 0.
door1 and door2 store the door links. Their format is similar to the DOS version, but again the rooms are numbered differently.

guard_ps stores the position of the guards. (255 if no guard)
guard_tp stores the type of the guards (lower 7 bits) and the direction (highest bit, 0=right, 1=left).
guard_sk was believed to store the skill, but it seems that it doesn't do anything. The skill is determined by the type.
The purpose of guard_uk1/2/3 are unknown.

start_rm,start_ps,start_dr store the starting room, position and direction (255=left, 0=right). Again, the rooms are numbered differently from the DOS version.
I dont understand anithyng that youre saying here, but i have a question, how the pc version works with the palettes diferent to Snes, because in pc the leves are in Dat format, and in Snes i cant uncompile level by one...

If you can help us to create a conversor to Pc/Snes we will say greetings for a long time...
User avatar
mk1995
The Prince of Persia
The Prince of Persia
Posts: 1160
Joined: February 27th, 2009, 10:09 pm
Location: Germany

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by mk1995 »

That's exactly what they're trying to do here. For me all the tech talk is a tl;dr, too, but all the English should make it clear that starwindz is working on a way to have Total Pack convert mods not only into Mac and PoP2 format, but also C64 and SNES.
Image
Just to make something clear: I will not reply to daft PMs like "Where can I find X?" or "Can you give me a link to Y?". Most of your questions are likely answerable if only you took your bloody time to look through these forums and use Google if all else fails. Sheesh...
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

I finally figured out the SNES level format of tiles and layers only. However SNES PoP has so many graphic tiles and basically the PC tiles are not compatible with SNES tiles. So PC to SNES conversion table should be made but that work is time consuming. :(
Last edited by starwindz on November 8th, 2011, 5:29 pm, edited 1 time in total.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

@David
Could you please make the graphic files extractor for SNES POP rom file? The extracted file names should be something like 'blue_dungeon_fg_000.bmp', 'blue_dungeon_fg_001.bmp', ..., 'blue_dungeon_gg_000.bmp', 'blue_dungeon_gg_001.bmp', ... . That is [dungeon_type]_[fg or gg]_[nnn].bmp' and the files include palette information.

I am going to make the conversion table and wall drawing algorthim for PC-to-SNES converter. It will be very helpful for the converter development if you make this utility. Thank you.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

There are another questions for level conversion.

1. Where is the starting offset of level data in SNES rom file? (3940 bytes in sequence)
(I think that 0x20078 is the starting offset. Is that right?)

2. What is the algorithm for decoding/encoding level data block in SNES rom file? I think David can explain it. I use Delphi for development and found following related source codes of SNESLevelEditor for encoding and decoding level data, but I could not understand it. I think I have to convert this C++ codes to Delphi.

Code: Select all

void TSMC::decodelevel(TMemoryStream* ms_in,TMemoryStream* ms_out,int len){
   int st=ms_out->Position,end=ms_out->Position+len,i,n;
   unsigned char ch,*p; unsigned __int16 ad;
   while(ms_out->Position<end){
      ms_in->Read(&ch,1);
      if(ch&0x80){
         if(ch&0x7F) ms_out->CopyFrom(ms_in,ch&0x7F);
      }else{
         switch(ch){
            case 1: ms_in->Read(&ch,1); n=ch?ch:256; ms_in->Read(&ch,1);
               for(i=0;i<n;i++) ms_out->Write(&ch,1);
            break;
            case 2: ms_in->Read(&ch,1); n=ch?ch:256; ms_in->Read(&ch,1);
               for(i=0;i<n;i++,ch++) ms_out->Write(&ch,1);
            break;
            case 3: ms_in->Read(&ch,1); n=ch?ch:256; ms_in->Read(&ch,1);
               for(i=0;i<n;i++,ch--) ms_out->Write(&ch,1);
            break;
            case 4: ms_in->Read(&ch,1); n=ch?ch:256; ms_in->Read(&ch,1);
               p=(unsigned char*)ms_out->Memory+st+ch;
               for(i=0;i<n;i++,p++) ms_out->Write(p,1);
            break;
            case 5: ms_in->Read(&ch,1); n=ch?ch:256; ms_in->Read(&ad,2);
               p=(unsigned char*)ms_out->Memory+st+ad;
               for(i=0;i<n;i++,p++) ms_out->Write(p,1);
            break;
            default: return ShowMessage("error in decodelevel : "+IntToStr((int)ch));
         }
      }
   }
}  

void TSMC::encodelevel(TMemoryStream* ms_in,TMemoryStream* ms_out,int len){
   int st=ms_in->Position,en=ms_in->Position+len;
   unsigned char ch,*sp=(unsigned char*)ms_in->Memory+st;
   unsigned char *p=sp,*ep=(unsigned char*)ms_in->Memory+en;
   unsigned char *cp;
   unsigned char dl=0,dt[128],tp;
   unsigned __int16 l[5],sa,ln;
   int i;
   while(p<ep){
      for(i=0;i<5;i++) l[i]=0;
      for(ln=0;p+ln+1<ep&&ln<256;ln++) if(*(p+ln)  !=*(p+ln+1)) break; if(ln>3) l[1]=ln;
      for(ln=0;p+ln+1<ep&&ln<256;ln++) if(*(p+ln)+1!=*(p+ln+1)) break; if(ln>3) l[2]=ln;
      for(ln=0;p+ln+1<ep&&ln<256;ln++) if(*(p+ln)-1!=*(p+ln+1)) break; if(ln>3) l[3]=ln;
      l[4]=0;
      for(cp=sp;cp<p;cp++){
         for(ln=0;ln<256&&p+ln<ep;ln++){
            if(*(p+ln)!=*(cp+ln)) break;
         }
         //ln++;
         if(ln>l[4]&&(ln>4||cp-sp<0xFF&&ln>3)){ sa=cp-sp; l[4]=ln; }
      }
      ln=0; tp=0;
      for(i=1;i<=4;i++) if(l[i]>ln){ ln=l[i]; tp=i; }
      if(ln<2){
         dt[dl++]=*(p++);
         if(dl==0x7F){
            dl+=0x80; ms_out->Write(&dl,1); dl-=0x80;
            ms_out->Write(dt,dl); dl=0;
         }
      }else{
         if(dl){
            dl+=0x80; ms_out->Write(&dl,1); dl-=0x80;
            ms_out->Write(dt,dl); dl=0;
         }
         if(tp==4){
            if(sa>=0x100){
               tp=5; ms_out->Write(&tp,1); ms_out->Write(&ln,1); ms_out->Write(&sa,2);
            }else{
               ms_out->Write(&tp,1); ms_out->Write(&ln,1); ms_out->Write(&sa,1);
            }
         }else{
            ms_out->Write(&tp,1);
            ms_out->Write(&ln,1);
            ms_out->Write(p,1);
         }
         p+=ln;
      }
   }
   if(dl){
      dl+=0x80; ms_out->Write(&dl,1); dl-=0x80;
      ms_out->Write(dt,dl); dl=0;
   }
//   ShowMessage(p-ep);
   ms_in->Position=en;
}
Last edited by starwindz on November 9th, 2011, 4:31 am, edited 1 time in total.
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by David »

I've extracted all the graphics from the game, including the level graphics:
Link: http://www.freeweb.hu/princepersia/en/s ... ics_dl.htm
starwindz wrote:Where is the starting offset of level data in SNES rom file?
At 0x20000, there is an address list. Each address is 3 bytes, the levels are the pointed by the 41st-67th addresses (numbering is started from 0).
An address consists of two parts: the first part is 2 bytes, the second is 1 byte. The real address can be calculated this way: (first-0x8000)+(second<<15)
starwindz wrote:What is the algorithm for decoding/encoding level data block in SNES rom file?
You're right, the decodelevel function contains the decompression algorithm, but openlevel is also important.
I'll try to explain the algorithm:

Code: Select all

procedure decompress_a_part(input:stream of bytes,output:stream of bytes,LEN:integer)
 clear output
 repeat while you don't have LEN bytes in the output:
  read a byte to X
  if X>=128 then
   copy X-128 bytes from input to output
  else
   read a byte to Y, if Y=0 then Y:=256
   if X=1: read a byte to D, write D to output Y times
   if X=2: read a byte to D, write D,D+1,D+2,... to output, Y bytes total
   if X=3: read a byte to D, write D,D-1,D-2,... to output, Y bytes total
   if X=4: read a byte to A, copy Y bytes from the A-th byte of the output to after the end of the output
   if X=5: read a 2-byte integer to A, copy Y bytes from the A-th byte of the output to after the end of the output
   // note that the source and destination may overlap in the above two cases
   otherwise: error
  end if
 end repeat
end procedure

You have to call the above procedure with these values of LEN, and concatenate the outputs: 720,720,720,256,256,256,256,244,256,256
Each input part begins directly after the end of the previous.
Calling with LEN=3940 at once won't work, because at the X=4 and X=5 cases, A is counted from the beginning of the current part, not the beginning of the whole level data.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

[Edited again]

@David
Thank you very much for your detailed answers. I have some more questions.

1.
At 0x20000, there is an address list. Each address is 3 bytes, the levels are the pointed by the 41st-67th addresses (numbering is started from 0).
An address consists of two parts: the first part is 2 bytes, the second is 1 byte. The real address can be calculated this way: (first-0x8000)+(second<<15)
I have made some test codes for understanding the real starting addresses of level data blocks. BTW the size of level data block in the SNES rom file is also 3940 bytes?

2.
You're right, the decodelevel function contains the decompression algorithm, but openlevel is also important. I'll try to explain the algorithm:
Could you please also exlplain the compression algorithm of the encodelevel function?

3. I have already used your C++ source code of Pr1SnesLevEd in order to develope the PC-to-SNES level converter. I think there will be no problem since you have released the source codes with the editor executable. But I think I have to get your permission before release the converter. If there is a problem about using the source code, I should translate the C++ source codes into Delphi codes. (It is an extremely hard work. :( ) How do you think about that?
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by David »

1. The level is 3940 bytes in the uncompressed form, the compressed size is smaller than this.
2. I've seen that you already have a working converter, but I'll try to explain:
In each step, the function checks if the following bytes are identical (X=1, like RLE), or are an ascending series (X=2), or are a descending series (X=3), or are identical to a previous part of the bytestream (X=4, X=5, like LZ).
If yes, then it outputs the corresponding X,Y and D (see my previous post).
If no, then it appends the byte to the current uncompressed run.
3. Yes, you can use the source code.
User avatar
starwindz
Sultan
Sultan
Posts: 133
Joined: March 8th, 2009, 4:48 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by starwindz »

David wrote:1. The level is 3940 bytes in the uncompressed form, the compressed size is smaller than this.
2. I've seen that you already have a working converter, but I'll try to explain:
In each step, the function checks if the following bytes are identical (X=1, like RLE), or are an ascending series (X=2), or are a descending series (X=3), or are identical to a previous part of the bytestream (X=4, X=5, like LZ).
If yes, then it outputs the corresponding X,Y and D (see my previous post).
If no, then it appends the byte to the current uncompressed run.
3. Yes, you can use the source code.
Regarding the converter, I made a command-line utility for level importing by using the C++ source code of the level editor. Anyway I think I have to know how to encode and encode the data internally. Thank you.
dspprince
Efendi
Efendi
Posts: 9
Joined: January 29th, 2012, 10:46 pm

Re: [HELP] Level conversion from PC to SNES for Total Pack

Post by dspprince »

so is there any progress? i would like to see the levels in total pack in SNES version.
Post Reply