Dissecting Levels.PRX ===================== Values in Levels.PRX are in little-endian byte order. Many values are 4 bytes long while string lengths are 2 bytes long. Location $0 (byte 0): PRX HEADER 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; this seems to all be constant 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; and the same as other PRX files 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B 00 0B 00 00 00 ; except for the two $0B bytes ; which indicate num resources in file ; (little-endian 16-bit ints $0B 00 ?) Location $90 (byte 144): TABLE OF CONTENTS This section is an array of short entries providing an index to the contents of the rest of the file. The first entry seems to be a "dummy" entry: 01 00 00 00 ; table index (1) 00 00 00 00 FF FF FF FF ; offset (-1) 00 00 00 00 ; rsrc type; in ASCII '\0\0\0\0' 00 00 00 00 ; rsrc ID 00 00 00 00 The "real" entries follow. There are 11 of these entries in the Levels.PRX file that comes with LR2. All are of the 'LVS' type that indicates that the resources to follow are lists of the game levels that appear in other PRX resource files. I will refer to these 'LVS' resources as "world resources". Each of these entries is 24 bytes long in Levels.PRX. 02 00 00 00 ; table index (2) 00 00 00 00 ; always zero ? 4C 00 00 00 ; offset of 1st rsrc minus $194 ; (see comments below for explanation) 4C 56 53 00 ; rsrc type; in ASCII 'LVS\0' 50 46 00 00 ; rsrc ID: $4650 is 18000 (JungleL) C3 01 00 00 ; length of data portion of rsrc 03 00 00 00 00 00 00 00 ; table index (3) 2B 02 00 00 ; offset of 2nd rsrc minus $194 4C 56 53 00 ; 'LVS\0' 51 46 00 00 ; rsrc ID: 18001 (WackyL) 78 01 00 00 ; data length 04 00 00 00 00 00 00 00 ; table index (4) BF 03 00 00 ; offset of 3rd rsrc minus $194 4C 56 53 00 ; 'LVS\0' 52 46 00 00 ; rsrc ID: 18002 (TubeL) A0 01 00 00 ; data length 05 00 00 00 00 00 00 00 ; table index (5) 7B 05 00 00 ; offset of 4th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 53 46 00 00 ; rsrc ID: 18003 (GearL) 99 01 00 00 ; data length 06 00 00 00 00 00 00 00 ; table index (6) 30 07 00 00 ; offset of 5th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 54 46 00 00 ; rsrc ID: 18004 (MonaL) 8D 01 00 00 ; data length 07 00 00 00 00 00 00 00 ; table index (7) D9 08 00 00 ; offset of 6th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 55 46 00 00 ; rsrc ID: 18005 (CoopL) 4C 01 00 00 ; data length 08 00 00 00 00 00 00 00 ; table index (8) 41 0A 00 00 ; offset of 7th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 56 46 00 00 ; rsrc ID: 18006 (DeathL) DD 00 00 00 ; data length 09 00 00 00 00 00 00 00 ; table index (9) 3A 0B 00 00 ; offset of 8th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 58 46 00 00 ; rsrc ID: 18008; skips 18007! (IntroL) 33 00 00 00 ; data length 0A 00 00 00 00 00 00 00 ; table index (10) 89 0B 00 00 ; offset of 9th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 59 46 00 00 ; rsrc ID: 18009 (CreditL) E3 00 00 00 ; data length 0B 00 00 00 00 00 00 00 ; table index (11) 88 0C 00 00 ; offset of 10th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 5A 46 00 00 ; rsrc ID: 18010 (TutoL) CD 01 00 00 ; data length The last entry in Levels.PRX has an index of 0 instead of 12 for some reason. This seems just to signal that it is the last entry as other PRX files number their last entries 0 too. (Originally, I speculated that it might be a clue to the "Select Level" screen in the game to not include this entry since these are the hidden "joke credit" levels. Of course, the regular Credit World, Cooperative, & Deathmatch levels are not listed on that screen either, yet they are numbered normally above). 00 00 00 00 00 00 00 00 ; table index (0) 71 0E 00 00 ; offset of 11th rsrc minus $194 4C 56 53 00 ; 'LVS\0' 78 46 00 00 ; rsrc ID: 18040 (alternate CreditL) 59 00 00 00 ; data length $1B0 (432): END OF TABLE OF CONTENTS After the table of contents comes the ASCII string 50 52 53 20 46 6F 72 6D 61 74 20 52 65 73 6F 75 ; 'PRS Format Resource File' 72 63 65 20 46 69 6C 65 followed by 0D 0A 00 00 00 00 00 1A 00 00 00 00 00 00 00 00 00 00 00 00 0B 00 00 00 ; $0B 00 is num rsrcs again? $1E0 (480): RESOURCE DATA This section contains the sequence of game resources, in this case, 11 'LVS' resources. Each world resource contains a 28-byte header followed by the filename, world title, and level titles for one level set. This information is likely used by the "Select Level" screen of the game to create the menus listing the worlds and the titles of their levels. $1E0 (480): Resource #1 4C 56 53 00 ; ASCII 'LVS\0' 50 46 00 00 ; rsrc (world) ID: 18000 (Jungle) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; unknown (always 16 bytes of 00?) DF 01 00 00 ; length of entire rsrc (479 bytes) ; little-endian (LE) Int32 or Int16? 0B 1C 7E C3 ; unknown (magic number for LVS?) 0C 00 ; length of next string (LE Int16) 4A 75 6E 67 6C 65 4C 2E 50 52 58 00 ; null-terminated C string: "JungleL.PRX" ; This is the name of the file that ; contains the 'LVL' resources for ; this world. 0D 00 ; length of next string 4A 75 6E 67 6C 65 20 57 6F 72 6C 64 00 ; world title: "Jungle World" 01 ; $01 for "normal" 1-player worlds ? 18 00 ; number of level titles to follow (24) 51 46 00 00 ; level ID for 1st level in this world 18 00 ; str length 57 65 6C 63 6F 6D 65 20 74 6F ; level title (C string): 20 4A 75 6E 67 6C 65 20 57 6F 72 6C 64 00 ; "Welcome to Jungle World" 52 46 00 00 ; level ID for 2nd level 07 00 ; length 4D 6F 6E 6B 65 65 00 ; "Monkee" 53 46 00 00 ; level ID for 3rd level 0B 00 ; length 53 69 6D 70 6C 69 63 69 74 79 00 ; "Simplicity" 54 46 00 00 ; level ID for 4th level 0B 00 ; length 45 78 63 61 76 61 74 69 6F 6E 00 ; "Excavation" 55 46 00 00 06 00 4F 61 73 69 73 00 ; 5 "Oasis" 56 46 00 00 0B 00 46 6F 75 72 20 54 65 73 74 73 00 ; 6 "Four Tests" 57 46 00 00 0A 00 44 72 6F 70 20 44 6F 77 6E 00 ; 7 "Drop Down" 58 46 00 00 09 00 53 77 69 6E 67 65 72 73 00 ; 8 "Swingers" 59 46 00 00 09 00 43 61 6D 61 78 74 6C 69 00 ; 9 "Camaxtli" 5A 46 00 00 0E 00 4C 65 66 74 20 74 6F 20 52 69 67 68 ; 10 "Left to Right" 74 00 5B 46 00 00 0C 00 53 74 65 70 20 4C 69 76 65 6C 79 00 ; 11 "Step Lively" 5C 46 00 00 0E 00 44 69 67 2C 20 44 69 67 2C 20 44 69 ; 12 "Dig, Dig, Dig" 67 00 5D 46 00 00 0D 00 57 68 61 74 20 47 6F 65 73 20 55 70 ; 13 "What Goes Up" 00 5E 46 00 00 0C 00 4A 75 6E 67 6C 65 20 54 6F 77 6E 00 ; 14 "Jungle Town" 5F 46 00 00 06 00 57 65 6C 6C 73 00 ; 15 "Wells" 60 46 00 00 07 00 45 6E 63 6F 72 65 00 ; 16 "Encore" 61 46 00 00 08 00 4D 69 72 72 6F 72 73 00 ; 17 "Mirrors" 62 46 00 00 12 00 4F 6E 65 20 42 6C 6F 63 6B 20 6F 66 ; 18 "One Block of Hate" 20 48 61 74 65 00 63 46 00 00 0F 00 53 74 72 65 73 73 66 75 6C 20 44 61 ; 19 "Stressful Days" 79 73 00 64 46 00 00 07 00 54 65 6D 70 6C 65 00 ; 20 "Temple" 65 46 00 00 0B 00 42 69 67 20 42 6C 6F 63 6B 73 00 ; 21 "Big Blocks" 66 46 00 00 09 00 52 61 74 20 52 61 63 65 00 ; 22 "Rat Race" 67 46 00 00 08 00 5A 69 67 20 5A 61 67 00 ; 23 "Zig Zag" 68 46 00 00 13 00 54 68 65 20 54 6F 77 65 72 20 6F 66 ; 24 "The Tower of Babel" 20 42 61 62 65 6C 00 The next resource follows immediately. $3BF (959): Resource #2 4C 56 53 00 ; ASCII 'LVS\0' 51 46 00 00 ; rsrc (world) ID: 18001 (Wacky) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 01 00 00 ; length of entire rsrc (404 bytes) 0B 1C 7E C3 ; unknown (magic number for LVS?) 0B 00 57 61 63 6B 79 4C 2E 50 52 58 00 ; len, filename: "WackyL.PRX" 0C 00 57 61 63 6B 79 20 57 6F 72 6C 64 00 ; len, title: "Wacky World" 01 13 00 ; 19 level titles 51 46 00 00 17 00 57 65 6C 63 6F 6D 65 20 54 6F ; IDs, lens, & titles for 19 levels 20 57 61 63 6B 79 20 57 6F 72 6C 64 00 52 46 00 00 0C 00 46 75 6C 6C 20 43 69 72 63 6C 65 00 53 46 00 00 0B 00 4A 75 6D 70 20 48 6F 75 73 65 00 54 46 00 00 05 00 50 79 72 6F 00 55 46 00 00 0A 00 52 75 6E 61 72 6F 75 6E 64 00 56 46 00 00 0C 00 55 70 20 2D 4E 2D 20 4F 76 65 72 00 57 46 00 00 08 00 53 74 61 79 50 75 74 00 58 46 00 00 0B 00 44 6F 75 62 6C 65 73 68 6F 74 00 59 46 00 00 14 00 50 61 69 6E 74 20 42 79 20 4C 6F 64 65 52 75 6E 6E 65 72 00 5A 46 00 00 13 00 4C 65 76 65 6C 20 77 69 74 68 20 4E 6F 20 4E 61 6D 65 00 5B 46 00 00 0B 00 57 61 63 6B 79 20 57 61 6C 6C 00 5C 46 00 00 06 00 48 69 64 65 79 00 5D 46 00 00 0D 00 53 77 69 74 63 68 20 42 6F 61 72 64 00 5E 46 00 00 0A 00 4C 6F 6F 6E 79 20 42 69 6E 00 5F 46 00 00 0C 00 54 68 69 6E 6B 20 46 69 72 73 74 00 60 46 00 00 0B 00 4C 61 79 65 72 20 43 61 6B 65 00 61 46 00 00 07 00 4B 61 62 6F 6F 6D 00 62 46 00 00 0A 00 4D 6F 6E 6B 20 42 61 69 74 00 63 46 00 00 11 00 55 6E 73 74 61 62 6C 65 20 49 73 6C 61 6E 64 73 00 $553 (1363): Resource #3 4C 56 53 00 ; ASCII 'LVS\0' 52 46 00 00 ; rsrc (world) ID: 18002 (Industrial) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BC 01 00 00 ; length of entire rsrc (444 bytes) 0B 1C 7E C3 ; unknown (magic number for LVS?) 0A 00 54 75 62 65 4C 2E 50 52 58 00 ; len, filename: "TubeL.PRX" 11 00 49 6E 64 75 73 74 72 69 61 6C 20 57 6F 72 ; len, title: "Industrial World" 6C 64 00 01 13 00 ; 19 levels 51 46 00 00 1A 00 57 65 6C 63 6F 6D 65 20 74 6F ; IDs, lens, & titles for 19 levels 20 49 6E 64 75 73 74 72 79 20 57 6F 72 6C 64 00 52 46 00 00 08 00 53 68 61 6C 6F 6F 70 00 53 46 00 00 15 00 52 69 6E 67 20 27 52 6F 75 6E 64 20 74 68 65 20 50 6F 73 65 00 54 46 00 00 0E 00 48 69 64 65 20 2D 4E 2D 20 53 65 65 6B 00 55 46 00 00 0A 00 53 77 69 74 63 68 49 74 21 00 56 46 00 00 0C 00 57 61 67 6F 6E 20 54 72 61 69 6E 00 57 46 00 00 0B 00 45 6E 74 72 61 70 6D 65 6E 74 00 58 46 00 00 14 00 31 31 32 36 20 59 65 61 72 73 20 46 72 6F 6D 20 4E 6F 77 00 59 46 00 00 0F 00 43 68 61 69 6E 20 52 65 61 63 74 69 6F 6E 00 5A 46 00 00 0B 00 4A 61 69 6C 20 42 72 65 61 6B 00 5B 46 00 00 11 00 42 69 67 20 42 6F 78 20 6F 66 20 42 6F 78 65 73 00 5C 46 00 00 09 00 49 6E 64 75 73 74 72 6F 00 5D 46 00 00 06 00 52 61 63 65 21 00 5E 46 00 00 09 00 48 69 67 68 72 6F 61 64 00 5F 46 00 00 0B 00 52 6F 75 6E 64 61 62 6F 75 74 00 60 46 00 00 0F 00 43 6C 61 75 73 74 72 6F 70 68 6F 62 69 61 00 61 46 00 00 16 00 4F 6E 65 20 53 69 64 65 20 6F 72 20 74 68 65 20 4F 74 68 65 72 00 62 46 00 00 14 00 52 65 76 65 6E 67 65 20 6F 66 20 74 68 65 20 44 65 61 64 00 63 46 00 00 07 00 45 3D 4D 43 5E 32 00 $70F (1807): Resource #4 4C 56 53 00 ; ASCII 'LVS\0' 53 46 00 00 ; rsrc (world) ID: 18003 (Gear) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B5 01 00 00 ; rsrc length (437) 0B 1C 7E C3 0A 00 47 65 61 72 4C 2E 50 52 58 00 ; len, filename: "GearL.PRX" 0B 00 47 65 61 72 20 57 6F 72 6C 64 00 ; len, title: "Gear World" 01 14 00 ; 20 levels ; etc. $8C4 (2244): Resource #5 4C 56 53 00 ; ASCII 'LVS\0' 54 46 00 00 ; rsrc (world) ID: 18004 (Mona) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A9 01 00 00 ; rsrc length (425) 0B 1C 7E C3 0A 00 4D 6F 6E 61 4C 2E 50 52 58 00 ; len, filename: "MonaL.PRX" 0B 00 4D 6F 6E 61 20 57 6F 72 6C 64 00 ; len, title: "Mona World" 01 14 00 ; 20 levels ; etc. $A6D (2669): Resource #6 4C 56 53 00 ; ASCII 'LVS\0' 55 46 00 00 ; rsrc (world) ID: 18005 (Coop) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 01 00 00 ; rsrc length (360) 0B 1C 7E C3 0A 00 43 6F 6F 70 4C 2E 50 52 58 00 ; len, filename: "CoopL.PRX" 0C 00 43 6F 6F 70 65 72 61 74 69 76 65 00 ; len, title: "Cooperative" 10 ; THIS IS DIFFERENT from $01 above! 11 00 ; 17 levels ; etc. $BD5 (3029): Resource #7 4C 56 53 00 ; ASCII 'LVS\0' 56 46 00 00 ; rsrc (world) ID: 18006 (Death) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F9 00 00 00 ; rsrc length (249) 0B 1C 7E C3 0B 00 44 65 61 74 68 4C 2E 50 52 58 00 ; len, filename: "DeathL.PRX" 0B 00 44 65 61 74 68 6D 61 74 63 68 00 ; len, title: "Deathmatch" 20 ; THIS IS DIFFERENT from above! 0C 00 ; 12 levels ; etc. $CCE (3278): Resource #8 4C 56 53 00 ; ASCII 'LVS\0' 58 46 00 00 ; rsrc (world) ID: 18008 (Hub) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4F 00 00 00 ; rsrc length (79) 0B 1C 7E C3 0B 00 49 6E 74 72 6F 4C 2E 50 52 58 00 ; len, filename: "IntroL.PRX" 0A 00 57 6F 72 6C 64 20 48 75 62 00 ; len, title: "World Hub" 00 ; ANOTHER NEW VALUE 01 00 ; 1 level 51 46 00 00 ; level ID for the level 0D 00 ; str len 4A 75 6D 70 20 53 74 61 74 69 6F 6E 00 ; title: "Jump Station" $D1D (3357): Resource #9 4C 56 53 00 ; ASCII 'LVS\0' 59 46 00 00 ; rsrc (world) ID: 18009 (Credit) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 ; rsrc length (255) 0B 1C 7E C3 0C 00 43 72 65 64 69 74 4C 2E 50 52 58 00 ; len, filename: "CreditL.PRX" 0D 00 43 72 65 64 69 74 20 57 6F 72 6C 64 00 ; len, title: "Credit World" 0C ; ANOTHER NEW VALUE 0B 00 ; 11 levels 51 46 00 00 ; level IDs start w/ 18001 08 00 43 72 65 64 69 74 73 00 ; and continue in sequence 52 46 00 00 ; as for other worlds 06 00 43 68 65 61 74 00 53 46 00 00 0D 00 57 61 63 6B 79 20 53 70 72 61 77 6C 00 54 46 00 00 0C 00 4D 6F 6C 65 20 52 75 6E 6E 65 72 00 55 46 00 00 08 00 53 6B 79 6D 61 7A 65 00 56 46 00 00 0A 00 54 72 65 65 68 6F 75 73 65 00 57 46 00 00 0E 00 57 61 63 6B 79 20 41 74 74 61 63 6B 79 00 58 46 00 00 11 00 46 69 72 65 20 69 6E 20 74 68 65 20 48 6F 6C 65 00 59 46 00 00 08 00 4C 6F 64 65 4D 61 6E 00 5A 46 00 00 10 00 42 75 63 6B 65 74 20 27 6F 20 4D 6F 6E 6B 73 00 5B 46 00 00 ; last level ID is 18011 0D 00 54 72 61 69 6C 20 42 6C 61 7A 65 72 00 $E1C (3612): Resource #10 4C 56 53 00 ; ASCII 'LVS\0' 5A 46 00 00 ; rsrc (world) ID: 18010 (Tutorial) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 01 00 00 ; rsrc length (489) 0B 1C 7E C3 0A 00 54 75 74 6F 4C 2E 50 52 58 00 ; len, filename: "TutoL.PRX" 09 00 54 75 74 6F 72 69 61 6C 00 ; len, title: "Tutorial" 08 ; ANOTHER NEW VALUE 16 00 ; 22 levels ; etc. $1005 (4101): Resource #11 4C 56 53 00 ; ASCII 'LVS\0' 78 46 00 00 ; rsrc (world) ID: 18040 (Joke Credits) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 75 00 00 00 ; rsrc length (117) 0B 1C 7E C3 0C 00 43 72 65 64 69 74 4C 2E 50 52 58 ; same filename as real Credits: "CreditL.PRX" 0D 00 43 72 65 64 69 74 20 57 6F 72 6C 64 00 ; same title: "Credit World" 0C ; same as Credit World above 03 00 ; 3 levels 78 46 00 00 ; level IDs start w/ 18040 0C 00 4B 69 6E 67 20 41 6E 64 72 65 77 00 ; to avoid conflicts with ; real Credits 79 46 00 00 ; ID 18041 0C 00 43 72 61 7A 79 20 43 6C 69 6D 62 00 7A 46 00 00 ; ID 18042 0B 00 43 6F 6E 63 65 6E 74 72 69 63 00 COMMENTS The hidden "Joke Credit" levels are stored in the same file, CreditL.PRX, as the regular Credit World levels. But they are treated as a separate world in the lists here in Levels.PRX and probably must have unique ID numbers from the "real" Credit World levels. The "world type" code ($0C) is the same for them as for the regular Credits. I have not explored whether it would be possible to store several normal worlds in one PRX file and have the game find them via the Levels.PRX resources. Byte Offsets After examining a few other PRX files, it appears that the resource offsets in the table of contents are calculated by ignoring the length of that table and part of what I am calling the "PRX header". The bytes from $4C to the beginning of the first resource (after the 48 bytes that I am calling the "end of the table of contents") are skipped when counting the byte offsets. In Levels.PRX, this works out to $194 bytes. As a result, the offset of the first resource in a PRX file should always be $4C and the amount that needs to be added to the values in the table to find the correct offsets (from the beginning of the file) will vary from file to file. The advantage of this system is that the table of contents does not need to be recalculated every time an entry is added or deleted (unless resources are added or removed in the middle of the file). And if one measures from the beginning of the first resource instead, one can just subtract $4C from the values in the table to obtain the offsets. (Indeed, I wonder why Presage didn't just call this location "byte $0" and specify their offsets from there? *shrug*). "World Type" The byte of an LVS resource that follows the world title string and precedes the level count (it is not at a fixed offset) may be a code indicating how the game chooses which LVS contents to use and display in the various menus and parts of the game and/or affect the behavior of the game after the player finishes the last level of the world. I will call this the "world type" code. Possible values and meanings seem to be: code description end behavior * $00 world hub proceed to another world * $01 standard 1-player world return to world hub * $08 tutorial world return to game main menu $0C credits world return to game main menu + $10 2-player cooperative world ? + $20 multi-player competitive world ? * These worlds are displayed in the 1-player "Select Level" screen + These worlds are displayed in the multiplayer "Select Level" screen Note that the multiplayer "Select Level" screen has up and down arrows for choosing a world even though there is only one choice for each mode: cooperative or competitive. This suggests that if Levels.PRX had multiple world resources with types $10 and $20 that it would be possible to choose between them in the game. UPDATE: Just changing the world type for existing worlds does NOT change where they appear in the game menus. But it CAN affect what happens when a world is finished and it also affects whether the game tries to compare your time for each level to the "High Scores" times. For example, changing the world type code to $01 for the Credits levels turned on high scores and returned me to the world hub when I finished the world. Changing the world type code to $0C for Mona World turned off high scores and returned me to the main menu when I finished. I also tried setting the world type code to $10 for Wacky World. In this case, I still saw the high scores and was returned to the world hub at the end of the world, not to the multiplayer screen. However, I when I tried changing the world type of the World Hub to $01 and the type of Jungle World to $00, both seemed to behave normally. And when I changed the Joke Credits type to $00, I was returned to world hub after the last level.