i have found out the sounds.dat compression. its a signed 16 bit PCM little endian. raw file. i was able to replace sounds in game. AMAZING!
|
:
|
Ok, i'm not that smart. But i will be posting a video on how to replace sounds in audacity. But they have to be same or shorter sound length. I replaced abe's "hello" with the mean muduckon "hi!". Now abe is a badass!
|
Hmmm.. That opens a lot of doors to localization hacks.
|
i am willing to post a stream of sounds, and the first 3 people to send me a modified version of the sound stream, will get it compiled. And after that, i will make a thread on how to replace the sounds yourself.
|
Regarding localization, do we not already have ways of replacing the backgrounds and the LED messages? If you can now replace in-game sounds, what else is there besides the FMV audio that would require editing for new, custom localizations?
|
-LED Messages. Can easily be edited.
-Some textual graphics such as the "Elum hates bees" sign (or something like that. Can't remember what it was exactly). Should be editable with the CAM tool. -The chant messages like "Watch out for that bat". No idea about those. -FMVs, yeah. I don't know what format they're in, but I guess if one can re-encode, it shouldn't be too hard. Voice actors are a different thing, heh. -Sounds. Possible. That's all I can give from the top of my head. |
I'm sure I've seen the hint fly messages in the same, um, file as the LED messages.
This is quite exciting. I'd be very interested to see a fan-made localization of the game. |
So... this means you can change everything except the physical placement of game objects and platforms?
|
Here is version 0.1 of my editor (remove .tff extension, everything else has a file size limit ;))
You can -View cam images -View whats in a lvl archive -View lvl file "chunks" -Add files -Delete files You can't -View anything other than a cam image -Many other things If you find anything you consider to be a bug then explain it to me in detail long with what OS you are running etc and I'll see about fixing it :) Edit: Forgot to mention I stole all icons and images from somewhere on this forum :( |
I haven't had time to have a proper look, but viewing CAM files is working perfect so far.
Also, is it possible to Import/Export them to or from BMP in the GUI version yet? |
:
|
WOW, good work on the editor! its so noob friendly! :D if someone complains about not knowing how to convert cams now, there the dumbest thing on the planet.
|
Hi,
I've been (and I'll be) busy, but I've managed to understand most of FG1 format (and it's on the hg repo). By the way, Paul, can you tell me everything you discovered about the Bits (if you've find something more than me), Path (same), Anim, and Font formats? |
I did have Font figured out but lost the docs.. Bits in AO is very simple in AE in has a small 1kb or so hard coded table that is then decompressed or something into a much bigger 8kb table. This table is then used to decompress each segment of the cam file. After this something else is done to the segment in some recursive complex function that extracts the RGB values :(
Anim isn't too hard but i lost the docs on that too, I'll get it back eventually so don't worry about it ;) Path has a hard coded offset for every path id to where the "real" data starts. It appears that each chunk of data is an offset into an array of function pointers (possibly a class VTable) and also some arguments to go to that given function. I managed to replace a slig with a mud from changing the values at run time with the debugger. Also I can't see your FG1 docs yet ;) Hopefully they are the same as the AO versions. |
This sounds bad... So many hard-coded values...
The "something else" that is done to each Bits segment, are you sure it involves a recursive function? Considering that the game was originally on playstation and that the segments are 16px-wide, isn't the "something else" done by the Motion Decoder? http://jpsxdec.googlecode.com/files/...format0-56.txt (2.3 MDEC emulation) Ok, I'll wait for Font and Anim docs, then :) Again, values hardcoded in the exe... Damn. Function pointers... The hard part begins, it seems... Sorry for the FG1 docs, I forgot to push my changes to the server. That's done, now! |
Yes its a recursive function and has what looks like an unrolled loop with around 18 iterations in it. It copys "Bits " into "VLC " blocks in memory (var length code MDEC blocks?) but almost all of the MDEC emulation functions have a debug string in them and they don't get called when processing a cam file.
I Have a text file with what I think is almost or is all of the hard coded array that it applies the phase 1 processing to I can upload it if you like? Just to make it clear its this data 1. Game decodes a small hard coded table into a bigger one 2. This bigger table is the one I ripped from the games memory and format a little to make it look nicer ;) 3. Each 16x240 pixel segment of cam file is then processed using this big table 4. Finally the big recursing unrolled loop function of doom does a lot of bit manipulation on it to get R G B values and throws em in the emulated psx vram. Even though I don't think this might be MDEC it could be because of the following reasons: 1. They did write an MDEC emulator for the game to play videos maybe? Not sure what it is actually used for. 2. They also wrote masher as a separate static lib, now this one might not have had debug strings in it and might be ANOTHER copy of similar code in the binary since the old school linkers where too stupid to know it was the same thing and remove references to it (although if the debug print isn't there then I guess it actually is not the same code!) I do think the function was checking for the files of FF FE that you mention in your FG1 docs though! Also this is not the same as the AO ones because the AO ones are not using MDEC or whatever compression. If it is MDEC then the uncompressed table of lookup data must be in other psx emulators or something? Edit: Attached the array |
Huffman tables are not in the MDEC part, but in the common movie file format (STR).
So, the table haven't anything to do with the emulator. It's in the software, not the hardware, and althought there is a common table, each game may implement its own format. But if it's processed by a recursive function, I don't really think it's MDEC... However, 16*240 is 15 blocks of 16*16 pixels, and that makes sense for MDEC, which works by 16*16px macroblocks. I didn't look at your table yet, but I'll. By the way, have you a convinient way to extract Path offsets, strings, and things like that from the exe? I don't think the Bits decoding part use FE FF, since in FG1, its meaning is "the specified macroblock is completly opaque" and there is no way a 16*16px macroblock would contain pixels of the same exact color. I'm almost sure it's using a VLC, since messing with a byte will corrupt everything from this byte. So, if your table is correct, it should be useful :) (but a way to extract this table would be far better!). Edit: Is this table from the PS1 version or the PC version? Can you post the corresponding compressed table? For now, I haven't been capable of anything with it :( |
The only way to extract the table is from reversing the code since that table is generated by a function in the game. The function that does that pulls it from some other smaller table so I guess you could pull the data from that offset, copy what the function is doing to make the bigger table (which looks far from simple) and then you have your data.
FYI the loop to decode the last stage of the pixels is doing something like this: :
The function of intrest is the one that uses the array i posted which looks something like this: :
Also I found an old function I wrote to decode part of a specific path file which looks like this: :
Edit: Also attached an image of when I replaced a slig with a mud from changing the op codes at run time. |
:
|
@Paul, nice! Thanks for the RE-ed code! One little question, though... Is this code the PS1 code or the PC code? I mean, the system on which this code is ran is in Little Endian or Big Endian?
Edit: and what's the type/size of g_cam_look_up_table_q? byte? word? double word? I guess word...? |
:
@Varrok: Nope that wouldn't be too hard, I'll likely add it in the next version if I can (there is a ton of stuff that needs fixing or sorting out before that though) |
@Paul, ok, thanks.
I'm trying to get it work, but for now, I haven't managed to do anything. So, some questions: Are you 100% sure that the table is correct? Do you think it could change with the locale of the game? camSegPtr is a pointer to the cam segment (just after the size information), isn't it? |
I think its correct and I don't expect it would change the only problem is that it might not be all of it, e.g there could be X amount more bytes needed to complete it.
As for camSegPtr segDWord = *(_WORD *)(camSegPtr + 2) | (*(_WORD *)camSegPtr << 16); v8 = camSegPtr + 4; Yeah that looks like what it is, its switching the two words of the cam segment dword around and then advancing to the next cam segment dword (so that suggests the cam data is an array of either words or dwords). |
:
Anyway, I've tried this function, and it doesn't work it seems (either a segfault, or an infinite loop, depending on the endianness I use). |
:
|
@Paul, the table may indeed be incomplete. Can you post a bigger dump?
If my code is right, when decoding the first cam segment of MIP01C04.CAM, it tries to access the 2037th chunk of the lookup table, but the one you posted only contains 1986 chunks. If the code is right, it should just "work", I mean, the output may not be directly usable, but at least, it'll read all the input without segfault or infinite loop. Edit: the maximum number of chunks is 2048, even is my code is wrong. So, please provide a table of 2048 chunks (2048 * 4 words, that is, 16kB). |
I'll try to re-rip it later if I get time, I tested it with STP01C25.CAM which is the very first cam file with the black and white text that the game displays and decoding the first 16x240 segment worked with it (Although i lost my converted version of the RE'ed code) :(
So its likely worth trying that one to see if your code works, if not then you know you have an issue. It will be strange if some is missing since I ripped the array from the first and last element written to the heap. Edit: Found an old text file that might be useful. It shows decoded seg1 of the above cam file with some of my silly ramblings in it. Don't ask me what half of it means cause its from over a year ago ;) |
:
|
:
|
Paul, take a look at this. http://www.oddworldforums.net/showthread.php?t=18954
Why don't we use saves to make levels, they contain where muds are, and items. But we can only change position of things. Its a start, right? |
This thread confuses me. For all that I know, you guys could be Al Qaeda operatives planning your next horrific attack by using an innocent web forum and a set of codewords.
|
:
|
Ok, Heres what i'm gonna do. Using ddcheat in abes oddysee i will see where the floor are placed. x and y value, look for values in it, and hopefully change something. Just a question, is dos more easy to reverse engineer, if so, the abe's oddysee pc comes with the dos files in a folder called dos. why dont u decompile that.
@Nate :D |
:
So in AO when you save a game and you kill a slig in the 2nd screen for example.. what happens when you load the game save? Is that slig still dead until abe dies and restarts that part of the level? Edit: To make hexing it more clear 256bytes of the game save are path data. |
@mlg man, interesting stuff, I'll have a look :)
I've already started that, though. You can have a look at doc/formats/nxtp.h to have an overview of what I have figured out. @Paul, ok, gonna try STP01C25.CAM then. Edit: I can't decode this, even with the code you've posted... |
:
|
@ThibG But i have no idea where the values are. it doesn't say where they are and stuff. Its hard to hex edit without Addresses. @paul But the dos version has what the names of values are called. And i think a decompresser called. dcc or something can give you source code.
|
:
Edit: By the way for offsets.. struct PlainSavFile { // 8096 bytes char unknown1[32]; // Unknown, zeros char unknown2[32]; // Unknown, non-zero char unknown3[448]; // Unknown, zeros char unknown4[4]; // Unknown uint32_t gnframes; // Global frame counter char unknown5[2]; uint16_t level_part; // first integer in sublevel name %sP%02dC%02d uint16_t level_component; // second integer in sublevel name char unknown6[2]; uint16_t hero_x; uint16_t hero_y; // In fact, hero_y - 1 char unknown7[2]; int16_t score_saved; // Number of escaped mudokons int16_t score_killed; // Number of killed mudokons // 0x021d char unknown8[937]; // 0x05c6 uint16_t have_ring_1; uint8_t number_of_projectiles; uint8_t unknown9; // WTF?! // 0x05ca char unknown10[82]; // 0x061c uint16_t have_soulstorm_fart; // And many other unknown things... }; You calculate it from the size of each element so: uint32_t gnframes; // Global frame counter is at offset char unknown1[32]; // Unknown, zeros char unknown2[32]; // Unknown, non-zero char unknown3[448]; // Unknown, zeros char unknown4[4]; // Unknown uint32_t gnframes; // Global frame counter 32+32+448+4 = 516, or in hex 0x204 |
@Paul, I know that, I'm trying to decode the first segment.
@mlg man, try and search for character identifiers. Abe is 0x45 0x00. Now that you've found that, it corresponds to uint16_t id |