Oddworld Forums > Zulag One > Oddworld Discussion > Oddworld Mods & Hacks


 
Thread Tools
 
  #1  
10-16-2010, 08:30 AM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)
Save file format

Hey! I've been researching a bit, and I've found out a lot of details about the .sav format.
A screenshot is included to demonstrate what I can do so far. Do not hope for a .sav based level editor, but a really advanced .sav editor might come.

So far I have documented:
The flashing landmine object. I get it to activate, deactivate, trigger an explosion, and change its pattern to an all-red one.
Mudokuns are partially documented, and I can change their position, direction, scaling, coloring etc.
Abe is partially documented, it's in a slightly different format than other muds.
"Blockers" (Like on the screenshot) are partially documented too. I haven't managed find their object sizes.

Limitations:
Some objects, like landmines and blockers, can't be moved to any position, but to pre-set positions defined by the levels.
Attached Thumbnails
Click image for larger version

Name:	Screen shot 2010-10-16 at 18.21.22.png
Views:	549
Size:	336.5 
ID:	11995  
Reply With Quote
  #2  
10-16-2010, 08:35 AM
NovaMan's Avatar
NovaMan
Howler Punk
 
: Jun 2009
: ?
: 345
Rep Power: 16
NovaMan  (15)

Can i replace a mudokon with a scrab in the save file???


Can i replace a paramite with mine car???

Last edited by NovaMan; 10-17-2010 at 10:54 AM..
Reply With Quote
  #3  
10-16-2010, 08:38 AM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

It might be possible. It should be even possible to add objects. Or delete them.
Reply With Quote
  #4  
10-16-2010, 09:29 AM
lismati's Avatar
lismati
Spark Stunk
 
: Jul 2010
: Poland
: 384
Rep Power: 15
lismati  (25)

Why one mudokon in the background is bigger than the second one?
Reply With Quote
  #5  
10-16-2010, 09:36 AM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

For the same reason there are two blue-colored Muds, testing.
Reply With Quote
  #6  
10-16-2010, 11:33 AM
Chubfish's Avatar
Chubfish
Grubb Fisherman
 
: Apr 2007
: England
: 907
Blog Entries: 4
Rep Power: 18
Chubfish  (538)Chubfish  (538)Chubfish  (538)Chubfish  (538)Chubfish  (538)Chubfish  (538)

Very, very nice work LIJI! Good to see you back too, unless you came back earlier, which I didn't notice...
__________________
FrankerZ

Reply With Quote
  #7  
10-16-2010, 02:05 PM
Crashpunk's Avatar
Crashpunk
cun't spill
 
: Feb 2008
: Nottingham, UK
: 7,291
Blog Entries: 47
Rep Power: 24
Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)

Ohh snap thats amazing!
__________________

Twitter | Discord: Crashpunk#0025

Reply With Quote
  #8  
10-16-2010, 02:22 PM
Phylum's Avatar
Phylum
No Artificial Colours
 
: Sep 2008
: Rock bottom
: 4,911
Blog Entries: 94
Rep Power: 23
Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)Phylum  (5748)

:
Can i replace a mudokon with a scrab in the save file???
Yes, but it would crash or be unusable. Scrabs would probably be unresponsive to the objects they aren't programmed to respond to (duh). Alternatley, the 2 objects on the same screen would cause the game to crash.

Also, I don't believe that there are scrab sprites in the mines .lvl file (although in other areas it may be possible).

Last edited by Phylum; 10-16-2010 at 02:25 PM..
Reply With Quote
  #9  
10-16-2010, 06:28 PM
mlg man's Avatar
mlg man
Howler Punk
 
: Nov 2006
: Australia
: 346
Rep Power: 18
mlg man  (171)mlg man  (171)

I recently made a program to Open the save files and show the Exact background the save was on, what level, abes position, how many mudokons on screen. there was much more, but it was too glitchy for a release. It was pretty cool though.
__________________
I make games, programs, music and stuff so yeah

Reply With Quote
  #10  
10-17-2010, 02:25 AM
Chubfish's Avatar
Chubfish
Grubb Fisherman
 
: Apr 2007
: England
: 907
Blog Entries: 4
Rep Power: 18
Chubfish  (538)Chubfish  (538)Chubfish  (538)Chubfish  (538)Chubfish  (538)Chubfish  (538)

:
Also, I don't believe that there are scrab sprites in the mines .lvl file (although in other areas it may be possible).
I was thinking about that. At least we have ways of putting those files into a .lvl file.
__________________
FrankerZ

Reply With Quote
  #11  
10-17-2010, 10:12 AM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

Here's the format of the area I'm researching of the .sav file:
All addresses are in decimal, values are in hex.
The area starts at 1372.
It is a list of objects, each having a different size, terminated by 0000 0000. There are 3 types of objects; dynamic, static, and semi-static. The list only covers dynamic and semi static. Some objects can be deleted by simply deleting them! (Despite changing the file size!) It might be possible to add objects by inserting them.

Some of the objects I've documented:

All values are 16 bits unless otherwise specified.

:
Flashing Landmine (24 bytes)
Type: Semi-static
ID (8F00 0000)
POSITION ID (32bit)
TIME (32 bit; the offset in the pattern, in frames)
State (0-1 is on, 2 is trigger explosion, 3 is inactive, 4+ is all red)

Mudokun (136 bytes)
Type: Dynamic
ID (5100 0000)
unknown
unknown
X
unknown
Y
//+24 bytes
Scaling (32bit)
Red
Green
Blue
Direction
Animation
//+96 bytes
GivesRedRing
//+118 bytes
Mood

Abe (216 bytes)
Always the first object. The first 136 are the same as a normal Mudokun, with the exception of the ID being 4500 0000.

Path Blocker (8 bytes)
Type: Semi-Static
ID (7A00 0000)
PositionID (32Bit)

Wheel (16 Bytes)
Type: Semi-Static
ID (9400 0000)
PositionID (32Bit)

Platform (28 Bytes)
Type: Dynamic
ID (4E00 0000)
unknown
X
unknown
Y

Flying Slig (184 Bytes)
Type: Dynamic
ID (3600 0000)
Unknown
X
Unknown
Y
//+56 bytes
Speed? (8 bits, change to 1 if possessing)
//+144 bytes
Possession (8 bits, change to 0C to possess)

Paramite (128 bytes)
Type: Dynamic
ID (6000 0000)
Unknown
X
Unknown
Y
//+26 bytes
Scale (32 bits)
Red
Green
Blue
//+118 bytes
Possession (Change to 41 to possess)

Bird Portal (8 bytes)
Type: Semi-Static
ID (6300 0000)
PositionID (32Bit)
Edit: found out PositionID also includes the scaling.
Edit 2: Added Bird Portal object

Last edited by LIJI; 10-17-2010 at 10:58 AM..
Reply With Quote
  #12  
10-17-2010, 10:21 AM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

This is really cool, I hope you manage to figure out lots more
Reply With Quote
  #13  
10-17-2010, 10:34 AM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

Forgot to include info about the second list:

Followed by the terminator on the first list, 0000 0000, comes a list of sublists that represents information on some static and semi-static objects.
The list is delimited by 0400. Sometimes a delimiter might be another number, which might mean something about the following sublist(s) .The order of screens is probably defined the the .lvl, and has nothing to do with the CAM name.

Each sublist consists of two bytes, where each two bytes match an object. (Not sure which types of objects yet, but it surely includes static objects and some/all semi-static ones). The order of objects is probably defined the the .lvl.

The first byte is usually either 0 or 2, where 0 is exists and 2 is destroyed. The second byte only affects some of the objects, and it is a parameter. For example, fart vending machines use it to represent their counter, where (1-31 (decimal) represents the number itself, 32+ represents 0, and 0 represents the default value defined for the machine in the .lvl file)

Some objects (Like animated backgrounds and levers) can not be destroyed by putting 02 on them, however the last object can ALWAYS be deleted by deleting two bytes from the sublist. (I.e. resizing the file)
Reply With Quote
  #14  
10-17-2010, 11:22 AM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

When moving from the screen before the one in your screen shot the game script loads these:


4F = load_work_wheel
3C = load_lcd_font
21 = nop
4d = load_wdrop_splash
20 = load_slig
31 = load_mud
55 = load_slam_door
58 = ?
11 = load_switch_lever
21 = nop
06 = ?
06 ?
61 = load_STATUSLT.BAN
06 ?
02 = abe_hoist
02 = abe_hoist
02 = abe_hoist
03 = abe_hoist2
03 = abe_hoist2
03 = abe_hoist2
3C = load_lcd_font
30 = ?
06 ?
06 ?
3D = load_stone_spotlite
55 = load_slam_door
31 = load_mud
31 = load_mud
3C = load_lcd_font
19 = load_ubx_blow
19 = load_ubx_blow
31 = load_mud
3C = load_lcd_font
1C = load_portal
55 = load_slam_door
32 = nop
40 = load_lcd_font2
02 =
06 ?
06 ?
06 ?
2E = nop
21 = nop


Each number is 32bit hex. The names are the names of functions I've named based on what BND/BAN file names are used in them. It comes from the path, strange how they don't seem to match which what you have for portals etc? Maybe you can double check for these magic numbers in the save file?

Edit: I got it, there is another function for loading save files, maybe it dosent contain part of the path file after all I the type Id is also an index into a list of functions that loads data, I'm just collecting al list of what each type is for a save in the screen shot screen

Edit again:

Here is the list and order my save gets loaded.

45 = load_state_savefile (sets tons of vars)
51 = load_mud_savefile
51 = load_mud_savefile
51 = load_mud_savefile
51 = load_mud_savefile
8F = load_bomb_savefile
8F = load_bomb_savefile
51 = load_mud_savefile
63 = load_portal_savefile
7A = load_slamdoor_savefile

Last edited by Paul; 10-17-2010 at 11:49 AM..
Reply With Quote
  #15  
10-17-2010, 11:48 AM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

I checked these values in quite a lot saves and lvl files. The full list I have: (Including objects which doesn't have documented sizes yet)
8F Mine
45 Abe
51 Mud
7A Blocker
94 Wheel
2D Fart
4E Platform
36 Flying Slig
60 Paramite
7D Slig
63 Portal

Why would it load slam door? There's only one door in this path, and it can't be slammed anyway. How these numbers are stored? Are they just followed by each other? (I.e. 4F00 0000 3C00 0000 ...)
Reply With Quote
  #16  
10-17-2010, 11:56 AM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

Purely because thats the name of those doors, it loads "SLAM.BAN"? So I assume the name is slam door? Also the game seems to add the Id as the length to get to the next item/Id? Not checked but that's what the function is seems to be doing:

.text:004C9BF1 more_save_items:
.text:004C9BF1 xor eax, eax
.text:004C9BF3 push ebp
.text:004C9BF4 mov ax, [ebp+0] ; Type, 51 = mud, and so on
.text:004C9BF8 call dword_560C34[eax*4] ; Call the function using the id an index
.text:004C9BFF add ebp, eax ; ebp is index in save file data, eax is D8 for type 51, which is added to get to the next object
.text:004C9C01 add esp, 4
.text:004C9C04 cmp dword ptr [ebp+0], 0 ; Keep looping until we get to id of 0
.text:004C9C08 jnz short more_save_items

Here is the captured sizes too:


45 size = D8
51 size = 88
8F size = 18
63 size = 08
7A size = 08


Strange that 63 and 7A are the same.

Last edited by Paul; 10-17-2010 at 12:02 PM..
Reply With Quote
  #17  
10-17-2010, 12:07 PM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

From what I understand from my experiments, doors are not objects, (They're just like ledges, which are defined in the path file) but the object that blocks the door from being access is. (It's static I believe, not semi) I'm not completely sure, but that's what made me surprised about this.

The asm code is very interesting and useful, I might disassemble the exe myself too. The only thing that bothers me - 0xD8 (216) is the size for Abe, not Mudokuns, which is 0x88 (136). Are you sure about this number?
Reply With Quote
  #18  
10-17-2010, 12:25 PM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

Ah, that must mean that:

45 size = D8 = abe
51 size = 88 = mud?

Type 45 sets tons of variables, maybe it contains lots of game state stuff too.

Edit: Doh of course it is, you've already said so in a previous post! I'm just wondering, do you know if the list of objects always starts at the same offsets? Should be pretty easy to parse the list or add new objects if thats true

Edit again: Must have stepped over or whatever in the code listing since its certainly wrong (the comment that is)

Last edited by Paul; 10-17-2010 at 12:29 PM..
Reply With Quote
  #19  
10-17-2010, 12:27 PM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

Yes, Abe includes a lot of data. I'm pretty sure it also includes a copy for saved/killed Muds. And yes, as documented in my previous post, Abe is 45, and muds are 51.
I'm disassembling the code, I hope I can find something with my only recently gained asm skills.

Edit: 63 and 7A can have the same sizes, because each represent another object. 63 represents a bird portal, and 7A represents a path blocker.
Edit 2: Yes! It always starts at 1372! And that's what makes it VERY easy to parse once all information is gathered!

Last edited by LIJI; 10-17-2010 at 12:31 PM..
Reply With Quote
  #20  
10-17-2010, 12:49 PM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

Some interesting path file info:

Search for 19000000 in the first path, you will find:

19000000730664058B067C050200C5040000000002000000

With a length of 1C, this is one of the UBX bombs. Right after this we have another UBX bomb:

19000000A5066405BD067C050200C504000000000200000000003000

.. And what after this? A mud!

310000008C066405A50678050000000000004D0100000000000001000000000000000100010000000000000000001C00

.. And now?

3C00000000067D05C406910547000000

3C is load_lcd_font..

The length of the type is before the Id, looks like a really good finding on Path format here

Edit: Yay, I'm 99% certain that this is it! How the hell did I never notice this before now? Its:

16bit, magic (04=end of screen)
16bit, length of object
32bit, object id
XXXX object data

Last edited by Paul; 10-17-2010 at 12:59 PM..
Reply With Quote
  #21  
10-17-2010, 01:22 PM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

Paul you're awesome! Thanks you you I've figured out what PositionID is! It's a pointer to these! It has much more information than position then, it explains why I could move the mines to the Mud's position but not the path blocker!
Reply With Quote
  #22  
10-17-2010, 01:28 PM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

:
Paul you're awesome! Thanks you you I've figured out what PositionID is! It's a pointer to these! It has much more information than position then, it explains why I could move the mines to the Mud's position but not the path blocker!
I'm pretty sure I can parse most of the path file now (for AE at least). It might just mean collecting some hard coded offsets. I think each screen must point somewhere in to the massive list of objects, then it loads them all until it hits 04 and it skips 03 (03 = already loaded).

Edit: If we can figure out exactly how to link these things and what the params mean then it should be fairly simple to edit objects in any level
Reply With Quote
  #23  
10-17-2010, 01:42 PM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

The first mine has the position ID 1015 0101 (0x01011015) in the save file. The second one has 2C15 0101. The difference between them is 1C, which is exactly the difference between them in bytes in the path file, which means position ID is some kind of an offset.

So far, given a Path file without any previous information, we could parse the screen array and the collision map (although we don't know where it ends). I believe the next step is to find the delimiter for the collision map.

Edit: Figured it out! The last short in the collision mask structure is mostly random, but when it's 6400, it means "end". Right after that comes your list, in your format. You can see five Muds over there (And the LCD sign, which also includes its position and other data btw, and the ledges.)! This is screen MIP1C36 BTW, the topmost and leftmost screen in the path.

Last edited by LIJI; 10-17-2010 at 01:56 PM..
Reply With Quote
  #24  
10-17-2010, 02:13 PM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

:
The first mine has the position ID 1015 0101 (0x01011015) in the save file. The second one has 2C15 0101. The difference between them is 1C, which is exactly the difference between them in bytes in the path file, which means position ID is some kind of an offset.

So far, given a Path file without any previous information, we could parse the screen array and the collision map (although we don't know where it ends). I believe the next step is to find the delimiter for the collision map.

Edit: Figured it out! The last short in the collision mask structure is mostly random, but when it's 6400, it means "end". Right after that comes your list, in your format. You can see five Muds over there (And the LCD sign, which also includes its position and other data btw, and the ledges.)! This is screen MIP1C36 BTW, the topmost and leftmost screen in the path.

Seems I already wrote an app that does most of this path stuff, this is how it calcs where to start for a given screen

// S1 to S2
std::cout << "\nS1 to S2\n";
ParsePath( &data[0], 0, 3, 1, -1 );
ParsePath( &data[0], 0, 2, 1, -1 );

// S2 to S3
std::cout << "\nS2 to S3\n";
ParsePath( &data[0], 0, 4, 1, -1 );
ParsePath( &data[0], 0, 3, 1, -1 );

// S3 to S4
std::cout << "\nS3 to S4\n";
ParsePath( &data[0], 0, 5, 1, -1 );
ParsePath( &data[0], 0, 4, 1, -1 );

The 2nd arg is most important, this is used with a magic offset to get the starting pos in the path for the objects in the current screen. The game seems to always load one ahead which must be why you hear sounds for things in the next screen

Edit: the screen number seems to be the index into the array of screen names too, for 0 in R1 in AO it gets no objects, since the first screen is null

Edit: Confirmed that is certainly it That means I can figure out which objects are where for which screen but it requires the hard coded offset data. I guess the main thing to figure out is where does the array of screens end, unless its just a case of checking for null and then none null / none valid screen?

Edit: Boom headshot!

To know where the index table starts, subtract the cam name array size from the end of the file, to know where the end of the collision data is use the "lowest" offset from the index table

I can certainly write a path file parser now Woo!

Final edit: Well.. it looks like the collision data will be the only way to know how the screens fit together.. no idea how you know which collision data is for what screen, I think this is the final missing link (besides the params for each game object).

Last edited by Paul; 10-17-2010 at 02:42 PM..
Reply With Quote
  #25  
10-17-2010, 03:19 PM
LIJI's Avatar
LIJI
Howler Punk
 
: Mar 2007
: Israel
: 318
Rep Power: 18
LIJI  (206)LIJI  (206)LIJI  (206)

"the screen number seems to be the index into the array of screen names too, for 0 in R1 in AO it gets no objects, since the first screen is null"
I'm not sure if I got it right, do you mean that the ID is the order in which the screen appears in the screen array? I.e. in AE mi it's "C36 -> 0, C1 -> 1, C9 -> 2 etc"?

Well, to match collision data with the screen, you should first find the position of the screen in the 2d screen array. For example, MIP1C36 is in (2,1) (0-based).
Then, multiply the x position by 375 (Screen width in units) and the y position by 260 (screen height in units) and you'll get it's starting point, (750,260) in game units. Add 375 and 260 and you'll get the ending point. So the rect for the screen is:
(750,260)-(1125,520). Then matching the collision mask should be easy.

Edit: Btw, I think that the parts of background which are displayed above Abe are stored as objects type 4B, can you confirm?
Edit2: Turns out that in the .sav file, the first 2 bytes are simply the offset from the beginning of the object list in the level file. No clue what the other two bytes are, but the game crashes if they change.

Last edited by LIJI; 10-17-2010 at 04:02 PM..
Reply With Quote
  #26  
10-18-2010, 04:51 AM
Crashpunk's Avatar
Crashpunk
cun't spill
 
: Feb 2008
: Nottingham, UK
: 7,291
Blog Entries: 47
Rep Power: 24
Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)Crashpunk  (5534)

That made my brain and my eyes hurt
__________________

Twitter | Discord: Crashpunk#0025

Reply With Quote
  #27  
10-18-2010, 05:12 AM
Paul's Avatar
Paul
Outlaw Sniper
 
: Jun 2007
: MilkyWay
: 1,535
Rep Power: 19
Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)Paul  (718)

:
That made my brain and my eyes hurt
It filled me with joy as path format is now pretty much reversed.
Reply With Quote
  #28  
10-18-2010, 01:12 PM
mlg man's Avatar
mlg man
Howler Punk
 
: Nov 2006
: Australia
: 346
Rep Power: 18
mlg man  (171)mlg man  (171)

So this means a custom path editor? Finaly?!!
__________________
I make games, programs, music and stuff so yeah

Reply With Quote


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 








 
 
- Oddworld Forums - -