And uh, yeah, some mysteries here could be solved by simply disassembling the game, however, I felt lazy and just poked at the files on this one—as I said, maybe this will spark something for someone a little more interested than I was, heh.
If you’re not familiar with Wild Water Adrenaline, it’s a uh, not fantastically well-received PlayStation 2 game produced by Fresh3D; essentially the guys that were involved in working on Outcast 2 (which, I’m not going to lie, is the sole reason for my interest).
While Fresh3D still seems to exist in some capacity, it turned out Franck Sauer, who is listed on it’s website, no longer actually works there, leaving just Yann Robert I guess. Unfortunately, I did not have any luck getting in touch with Yann, but it seems they’ve since moved on to work for Epic Games.
So that’s another reason why this piece is so short, or another excuse.
I’ll confess, though, as I’m sure you can appreciate from the footage above, Wild Water Adrenaline is absolutely gorgeous for a PlayStation 2 title. Though that makes it all the more disappointing that the tech behind it didn’t get used to produce something a little more compelling (you know, like Outcast 2…)
You can read more about Wild Water Adrenaline’s development here, as written up by one of the developers involved with the game.
If you’d like to learn more about the ill-fated Outcast 2, there’s some great information available here written up by the same developer. That said, I’ll throw a spoiler warning in there as I understand this was later removed from their current website as elements of this earlier design are being used in the upcoming Outcast: A New Beginning title.
Anyway, I digress, let’s get on with it.
When viewing the contents of the disc for the game, we see the following.
.
├── DATA.BIN
├── PS2
│ ├── IRX300
│ │ ├── IOPRP300.IMG
│ │ ├── LIBSD.IRX
│ │ ├── MCMAN.IRX
│ │ ├── MCSERV.IRX
│ │ ├── MTAPMAN.IRX
│ │ ├── PADMAN.IRX
│ │ ├── SDRDRV.IRX
│ │ ├── SIO2MAN.IRX
│ │ └── STREAM.IRX
│ └── NAMES.BIN
├── SLES_535.95
└── SYSTEM.CNF
Can you guess where the actual data for the game is stored? If you guessed DATA.BIN
then you guessed correctly!
It’s a pretty uninteresting package format, and the content within is aligned to blocks of 2,048 bytes, which was quite likely done for more effectively streaming the data off the disc.
The header of the package is as follows.
struct Header
{
char ident[ 8 ];
int32_t unk0[ 2 ]; // <- these are 0, so I've no idea
uint32_t numFiles;
Index indices[numFiles];
};
And each Index
is the following.
struct Index
{
char name[ 12 ];
uint32_t blockNum;
uint32_t size;
};
The blockNum
variable confused me for a little bit before I realised it’s just simply how many blocks of 2,048 bytes to reach the offset of the file in question.
Oh, and note that the names are not null terminated but instead space terminated, which you’ll want to account for if you decide to write your own tools to dump/repack the files.
If this isn’t sufficient for you to understand the format, for whatever reason, I’d thrown together an implementation here.
We’re finally left with this.
Right, so we’ve got that out the way and extracted the DATA.BIN
file - what are we left with?
A big ol’ blob o’ more files… (click here if you want to skip)
.
├── 111.DAT
├── 112.DAT
├── 114.DAT
├── 211.DAT
├── 213.DAT
├── 214.DAT
├── 222.DAT
├── A_CA_1.MIC
├── A_FR_1.MIC
├── ALTISS.PSS
├── AMBIENT.LUA
├── ANIM.LUA
├── ANIMS.PAK
├── A_NZ_1.MIC
├── ASTICK.PAK
├── A_US_1.MIC
├── AUTOEXEC.LUA
├── BONUS.LUA
├── BONUS.PAK
├── BOOT.TGA
├── CA_BACK.PAK
├── CA_BONUS.GAM
├── CA_CAM.PAK
├── CA_COLL.PAK
├── CA.CPS
├── CAMTRIG.LUA
├── CA_OCCL.PAK
├── CA.PAK
├── CA_SFX.PAK
├── CA_SNOW.PAK
├── CA_STREA.GAM
├── CA.TEX
├── CA_TRIG.GAM
├── CD.LUA
├── CHARS.TEX
├── CREDIT.MIC
├── CREDITS.LUA
├── CURVE.PAK
├── E_CREDIT.VAG
├── EFFECTS.LUA
├── ELEC1.MIC
├── ELEC2.MIC
├── EMITTER.ANM
├── ENDRACE.LUA
├── ENGLISH.LUA
├── E_TIME.VAG
├── F3DSPLAS.ANM
├── F3DSPLAS.PAK
├── F3DSPLAS.TEX
├── FEMA_M.PAK
├── FEMA.PAK
├── FEMB_M.PAK
├── FEMB.PAK
├── FEMC_M.PAK
├── FEMC.PAK
├── FEMD_M.PAK
├── FEMD.PAK
├── FIELD.ANM
├── FINISH.VAG
├── FLAGS.TEX
├── FLUID.PSS
├── FONTS.PAK
├── FONTS.TEX
├── FR_BACK.PAK
├── FR_BONUS.GAM
├── FR_CAM.PAK
├── FR_CLOUD.PAK
├── FR_COLL.PAK
├── FR.CPS
├── FRENCH.LUA
├── FRESH3D.LUA
├── FRESHENG.LUA
├── FRESH.LUA
├── FRESH.MIC
├── FRESH.PAK
├── FRESH.TEX
├── FR_FLARE.PAK
├── FR_OCCL.PAK
├── FR.PAK
├── FR_PART.PAK
├── FR_SFX.PAK
├── FR_STREA.GAM
├── FR.TEX
├── FR_TRIG.GAM
├── GAME.LUA
├── GAMEPLAY.LUA
├── GERMAN.LUA
├── GETREADY.LUA
├── GLOBALS.LUA
├── HELMET.PAK
├── HELP.LUA
├── HOMA_M.PAK
├── HOMA.PAK
├── HOMB_M.PAK
├── HOMB.PAK
├── HOMC_M.PAK
├── HOMC.PAK
├── HUD.LUA
├── I_BALISE.VAG
├── I_BAR.VAG
├── I_CANCEL.VAG
├── ICON.SYS
├── I_NAV.VAG
├── INDIE.PSS
├── INTERF1.TEX
├── INTERF2.TEX
├── INTERF.PAK
├── ITALIAN.LUA
├── I_TEXT.VAG
├── I_VALID.VAG
├── KAYAK.LUA
├── KAYAK.PAK
├── KIMPACT1.VAG
├── KIMPACT2.VAG
├── LANG.LUA
├── LOADING.PAK
├── LOADSAVE.LUA
├── MAIN.LUA
├── MEMCARD.LUA
├── MENU.COL
├── MENU.LUA
├── MENU.PAK
├── MENU.PSS
├── MENU.VAG
├── MSCREAM1.VAG
├── MSCREAM2.VAG
├── MSCREAM3.VAG
├── MSCREAM4.VAG
├── MSCREAM5.VAG
├── NAMES.BIN
├── NZ_BACK.PAK
├── NZ_BONUS.GAM
├── NZ_CAM.PAK
├── NZ_COLL.PAK
├── NZ.CPS
├── NZ_OCCL.PAK
├── NZ.PAK
├── NZ_PART.PAK
├── NZ_RAIN.PAK
├── NZ_SFX.PAK
├── NZ_STREA.GAM
├── NZ.TEX
├── NZ_TRIG.GAM
├── OCCLUDE.LUA
├── PADDLE.PAK
├── PAGAIE.PAK
├── PARTICLE.ANM
├── RAFTG.PAK
├── RAFTKAYA.TEX
├── RAFT.LUA
├── RAFT.PAK
├── RANKING.LUA
├── RECORDER.LUA
├── RECT.LUA
├── RIMPACT1.VAG
├── RIMPACT2.VAG
├── RKMENUS.LUA
├── ROCK1.MIC
├── ROCK2.MIC
├── ROOT1.MIC
├── ROOT2.MIC
├── ROW.VAG
├── RWATER1.VAG
├── RWATER2.VAG
├── SMOO1.MIC
├── SMOO2.MIC
├── SOUND.LUA
├── SPANISH.LUA
├── SPLASHG.PAK
├── SPLASHG.TEX
├── SPLASHM.PAK
├── SPLASHM.TEX
├── STICK.LUA
├── STYLES.LUA
├── TEAMMATE.LUA
├── TEXT.LUA
├── TIME_OUT.VAG
├── TRAINING.LUA
├── TR_BACK.PAK
├── TR_BONUS.GAM
├── TR_COLL.PAK
├── TR.CPS
├── TRIGGERS.LUA
├── TR.PAK
├── TR.TEX
├── UI.LUA
├── UNDWATER.VAG
├── US_BACK.PAK
├── US_BONUS.GAM
├── US_CAM.PAK
├── US_COLL.PAK
├── US.CPS
├── US_OCCL.PAK
├── US.PAK
├── US_PART.PAK
├── US_RIDE.PAK
├── US_SFX.PAK
├── US_STREA.GAM
├── US.TEX
├── US_TRIG.GAM
├── UTILS.LUA
├── VIEWER.LUA
├── VISUAL.LUA
├── WATFALLL.VAG
├── WATFALLM.VAG
├── WATFALLS.VAG
├── WSCREAM1.VAG
├── WSCREAM2.VAG
├── WSCREAM3.VAG
├── WSCREAM4.VAG
├── WSCREAM5.VAG
├── WSTREAM.LUA
├── WWA2.PSS
└── WWA.ICO
sigh
So one of the files in here actually has a duplicate stored outside under the PS2
directory, and that’s NAMES.BIN
. What does it do? I don’t exactly know, but it looks like a list of symbol names such as classes/structs, variables, and more. I’m not sure how much of it is actually used as some of them are nonsensical for a PlayStation 2 title, such as several Direct3D specific classes.
IDirect3D8
IDirect3DDevice8
IDirect3DResource8
IDirect3DBaseTexture8
IDirect3DTexture8
IDirect3DVolumeTexture8
IDirect3DCubeTexture8
IDirect3DVertexBuffer8
IDirect3DIndexBuffer8
IDirect3DSurface8
IDirect3DVolume8
IDirect3DSwapChain8
Anyway, as I was reading through the strings in this file, I’d realised something was a little bit amiss when there were references to guns, explosions, worms and other things that didn’t really make much sense for a game about rowing a boat through water (unless there’s some incredibly hardcore and well hidden bonus mode I was unaware of).
mClipSize
mBullets
mDamageType
mFireRate
mLastFire
mBulletSpeed
mTeamSoldierLifeCycle
mTeamSoldierFlee
mSoldierPos1
mSoldierPos2
mSoldier1
mSoldier2
mExploding
BULLET_IMPACT_NEAR
mIsCutterSeen
mAssaultGun
mShootSound
mHandgunBulletSpeed
mHandgunBulletDamage
mHandgunClipSize
mHandgunFireRate
mSniperBulletSpeed
mSniperBulletDamage
mSniperClipSize
mSniperFireRate
mSniperDamageType
“What? Rowing boats with guns!?”
It’s actually likely these are carry-overs from the Outcast 2 prototype that can be seen below, as some of the symbol names here seem to align with some of the features we see. To support that theory too, some of the symbol names explicitly mention Cutter, the protagonist from Outcast.
What I posted above is not everything, otherwise you’ll be scrolling forever, so I’ve just dumped all the strings to a file you can find here. Obviously, the meaning behind some of these strings is going to be up to speculation (unless a prototype is released 👀), but some implications are rather intriguing.
Also, before you get too excited, I’ve got a hunch that none of this functionality still exists in Wild Water Adrenaline, but I’d be happy to be proven wrong.
Oh, Lua! We know Lua. Yeah, not too surprising when you read up the specs of the engine here (see Fresh Scripting); much of the game logic for this game is actually implemented through Lua which is certainly a first for me when it comes to PlayStation 2 games.
This lead to an interesting thought, what if we could make changes to the scripts here and then repack the game? Hehe, delightfully devilish!
With the files already unpacked, I proceeded to whip up a tool to just repack the data and then recreated the ISO using the following command.
mkisofs -udf -o WILDMOD.ISO ./Wild\ Water/
Aaaaand, nothing.
To troubleshoot, I proceeded to edit a file in the original package just to rule out that there wasn’t some sort of checksum on the package, and that seemed fine.
After some further fiddling and some fixes to my repacking tool, there was still no luck, so on a whim I decided to repack the files in the original order they were in (so basically making a 1:1 copy), and that worked. Okay.
Next I went ahead and edited one of the Lua scripts with some extra additions, but again, nothing.
Long story short, it seems that if the files are any larger, then it doesn’t work, but if the files are smaller they will work fine. This suggests to me that the files are possibly loaded into some sort of fixed-size buffer in the engine. Or as my notes put it…
[...] changing 'English' to 'Butt' worked fine...
But changing it to 'ButtButtButt' did not work, file size increased marginally.
Once again, this is something I probably could confirm by just checking the disasm, but I’ll leave that to someone with a little more time and motivation on their hands. You can find the source code for my repacking tool here (just be aware it depends on this).
They did have documentation for Lua available on their website at some stage (seen here), but much of that has unfortunately been lost.
Wild Water Adrenaline never came out on PC, as far as I could see anyway, but a game that also used the same engine, Mountain Bike Adrenaline, did. Unfortunately, though, the way the data is stored in that version of the game seems different, and again, I decided it probably wasn’t worth the time. Not sure how the PlayStation 2 version looks in that respect either, but my bet is that it’s the same as the WWA.
So many of the other formats here are proprietary, and I’d elected not to bother getting too in-depth with those, but have some theories as to how they’re structured. Though, the key one here seems to be the ‘PAK’ format.
Each PAK (PAK, GAM, ANM and TEX) appears to be a collection of different classes, each holding either just general data, textures, models or something else, and these are combined into the scene via the merge
function that’s executed through the Lua scripts.
It seems once these are ‘merged’ into the scene, they can then be looked up to then perform whatever action as necessary. I’ve presented some examples below.
merge (EFFECTS_DIR.."splashM.pak")
ShaderSpriteParticlePS2.find("lambert2__X"):name("splash2")
ShaderSpriteParticlePS2.find("lambert3__X"):name("splash3")
ShaderHeatParticlePS2.find("lambert4__X"):name("splash4")
[...]
merge(LEVEL_DIR.."CA_Snow.pak")
local snow =Transform.find("SnowEffect")
self.rain = Transform.new("Snow")
snow:parent(self.rain)
snow:position(0,10,0)
[...]
local mesh = SkinMesh.find("Raft")
mesh:visible(false)
World.getActive():remove(mesh)
I don’t think the header for the PAK format is too complex and threw this together at a glance. Might provide a good starting point. But keep in mind it’s just an educated guess!
Should add, if it’s not obvious, but packageClass
is a sized string, so the first byte determines it’s size.
It also seems that their tooling stored the original paths for much of the content used in the game within the PAK files. Some of these even seem to suggest Wild Water Adrenaline had a different title at some point during its development.
R:/XTeam_Rafting/Gfx/Textures/Tex_balise_bonus.tga
P:/XTremeRafting/Gfx/Textures/Tex_Raft_H.tga
I’d figure ‘XTeam’ was a typo there.
Anyway, apologies for the sudden end but that’s about all I’ve got in me, but I do hope it was informative! As usual, if you have any feedback for us, feel free to leave a comment.
For the library, we’ll be making various pieces of documentation and more, easily accessible for anyone to read and search online. Right now, you can find copies of earlier DirectX and MSDN documentation available, and we’ll aim to add and expand on it over time.
You can find the new section here. We haven’t yet updated the homepage of The Data Dungeon to link to the library yet but will be doing so soon.
As usual, if you have any feedback, you can submit it in the dedicated channel in our server.
]]>But nothing is ever quite that simple, is it?
After excitedly extracting everything from the ISO and examining it, it turned out that the ISO that was uploaded appeared to be corrupted in some way, resulting in some files to overlay others upon extracting. This is obviously a big issue as it would stop the build from running correctly on hardware and obviously puts a dent in efforts at examining the content.
Upon investigation, both myself and Daniel soon realised that, fortunately, it just seemed to be a matter of the offsets in the ISO being shifted back by 2048 bytes in certain (and most) cases. After some fiddling, we believe we’ve resolved this and you can find the data extracted correctly here (you can find the original ISO here).
As of yesterday, despite doing this, we still didn’t have any actual luck getting it running on physical hardware (even our “dev kit” with additional memory), so there’s evidently still something not quite right. That said, this has allowed us to view what’s here!
Many of the assets should happily open under any version of Unreal Engine 2, equal or greater than version 2226, if you want to check them out yourself, though this is barring the UKX meshes/animations as it seems they might have made modifications to the animation format. Viewing those in UE Viewer will require you to disable the animation option.
Happy spelunking! If you have any luck getting it running or want to collaborate a bit, feel free to join our Discord.
]]>Aiming to change that, we decided to make an offer to the individual behind the channel, and after acquiring some better capture equipment and sending our Xbox off to have more RAM soldered onto the motherboard, here we are today!
If you’re just interested in downloading the prototype, then click here to skip to the end, otherwise read on!
Usually, before we get too deep in examining anything, we’ll try and verify when it’s actually from. When we checked the file timestamps on the Xbox XBEs in this prototype, we were a little puzzled as they did not align with when this particular build was supposedly thrown together. Odd. Pun not intended.
After using a tool to further inspect the other accompanying executables alongside the Xbox XBEs, it appears this prototype is probably from around the 22nd of May 2004 - that’s at least the time the builds were actually compiled, it seems.
Because the timestamps for executable files were wrong, it casts a little bit of doubt over whether any other timestamps in this build are necessarily correct, but unfortunately, we’ve not got much else we can use to date them. Generally, we’re dubious of any timestamp going as far back as 2000 or earlier as it appears to be the general pattern.
To add a little bit to the confusion, when you start the prototype up, there’s a brief splash screen that appears displaying ‘JANUARY 2004’ on the bottom right (ignore the blue box on the top left, that’s being displayed by our HD upscaler).
We figure there was probably some other build produced at that time, either produced for preview purposes or some internal milestone (we don’t know), and that splash screen was simply not replaced before this build. It may suggest that the build we have here is a little less formal than whatever was created back then.
As you probably noticed from the screenshot earlier, this prototype also includes the PDBs. If you’re unfamiliar with these, they’re essentially debug symbols that contain heaps of useful information! In summary, this is going to be a massive help to anyone reverse engineering both this prototype and the final game.
One of the things I personally also love about PDBs, besides the fact that they’re an abundant source of information, is that they usually include references to the original files used in the source tree during compilation, so from that we can get a rough idea of how the project was set up at the time it was compiled. You can see the results of that here.
You’ll likely note the root “exoddus” directory that Oddworld Inhabitants (OWI) used for the project, we’ll get to that shortly.
Going into this, we actually knew next to nothing about Stranger’s Wrath, especially when it came to the technology behind the game, so this has been quite educational. As it turns out, Stranger’s Wrath uses OWI’s own proprietary game engine, which is unlike the Oddworld Munch’s Oddysee title released prior, which instead used NetImmerse/Gamebryo (we actually confirmed this independently ourselves too, as we’re always a little wary when no citation is provided).
To my knowledge, there’s no formal name provided for the engine that Stranger’s Wrath used, but we’ll refer to it as “Stranger’s engine”, which is a term Lorne Lanning, a founder of OWI, used himself.
The capabilities of the engine were quite respectable for their time, with support for pixel shaders, shadow maps (only from characters), level streaming, SWF-based UI system, a C-like scripting language, a skeletal animation system utilizing Granny 3D, lightmaps, and more. Fancy! Additionally, as evident from nosing at the PDB, the game was written in C++ which isn’t too surprising for the time.
Like many others, OWI of course used a few third-party libraries to aid the development of the engine.
But for the most part, excluding the Xbox SDK and other trivial libraries they might’ve used, that appears to be it and otherwise everything else is home-grown. I was especially impressed by their decision to write their own SWF player to use for the UI, which appears to have been quite ahead of the curve, as other engines later into the decade would adopt Scaleform to support flash-based interfaces rather than rolling their own solution.
It’s actually a bit of a shame as it’s the only title OWI ended up releasing to use this technology, despite plans to use it in their follow-up ill-fated title, The Brutal Ballad of Fangus Klot.
“[…] We wanted to take Stranger’s engine and basically re-skin something more hardcore […]”
Source
Fortunately, while described as an “Xbox-exclusive engine” during an interview, Just Add Water Ltd. eventually gave the engine a bit of love and brought Stranger’s Wrath to Sony’s PlayStation 3 in 2011, eventually followed by a myriad of other platforms.
And that leads onto a little bit of poking and prodding at some formats here. This section is a bit shorter than planned, but we’re sure the community is going to be quick to fill in the rest.
From comparing the final game to this build, it became apparent there were a number of additional folders that the final game didn’t include, such as the following.
data/fonts
data/geometry
data/levels
data/prefs
data/scripts
data/shaders
data/ui
I’d suspected that the prototype did not actually pull data from some of these locations, given their absence from the final game, and as it appeared a bulk of the data was packed into SMB
files just as they also are in the final game (they’re a kind of package file, we’ll talk about them shortly).
We ended up confirming this is probably the case when we tried to run the prototype with the levels
and geometry
locations removed.
It’s quite likely most of these folders were left-overs from the packaging process used to produce the SMB
packages under the data/bundles
and data/global
locations. Though, oddly enough there should also be a left-over directory for textures too, which appears to be missing, so that might get removed during some other stage of the process.
Let’s get the big one out the way first, I guess. ‘SMB’ here stands for Shared Memory Block, and the files are essentially a collection of separate data blobs. You could basically consider it a type of package/container file.
From the standpoint of reverse-engineering, the format is terrible to reverse because there doesn’t appear to be any mechanism for knowing up-front how large a given struct/class is going to be (meaning we can’t cleanly skip the ones we don’t want or don’t have reversed), but fortunately using the available PDBs, it was pretty easy to deduce elements of the format.
struct OIStringBuffer
{
int32_t size;
char buffer[ size ];
};
/**
* There is an older version of the format that uses
* 0x600ddea1 as it's magic instead and does not have
* a version number (engine interprets it as version '0')
*/
struct SMBHeader
{
uint32_t magic;// 0x3a4b5c6d
if ( magic == 0x3a4b5c6d )
{
int32_t version;// 5
}
struct OIStringBuffer fileName;
int32_t fileOffset;
int32_t headerStreamEnd;
int32_t numContiguousBytes;
int32_t numSystemBytes;
if ( magic == 0x3a4b5c6d )
{
// if old format, both the below are the same as above
int32_t contiguousSizeUnpadded;
int32_t systemSizeUnpadded;
if ( version >= 3 )
{
int32_t numResources;
}
if ( version >= 4 )
{
int32_t ioMode;
}
}
uint32_t endHeaderMagic;// 0xbeef1234
};
struct SMBHeader header;
As you can see, there are various checks for different versions of the format indicating that the format was expanded on overtime, and the team were obviously keen to retain backwards compatibility. I was a little curious if the final game (or at least the HD PC version) could load any of the SMBs from the prototype, but sadly had little success with shuffling various files around—there are many reasons why this probably didn’t work.
Oh, and this format gets used for models too, which use a geo
extension instead of smb
.
I’d made a slightly further effort before deciding it was a bit more than I wanted to focus my time on at the moment. Below you can find the main MaterialDef
structure outlined, but this is then used as part of the many other subclasses such as MaterialDef_Transparent
, MaterialDef_SimpleTextured
, MaterialDef_NormalMapped
, and so on and so on.
struct MaterialDef
{
int32_t version;
if ( version < 19 )
{
uint32_t flags;
}
else
{
uint32_t flags[ 6 ];
}
float glareStartFade;
float glareEndFade;
float reflectionStrength;
float mipmapLodBias;
uint32_t glareColor;
float lmTexelSize;
float lmCreaseAngleDegrees;
float lmNormalHardness;
};
struct MaterialDef_NormalMapped
{
int32_t version;
struct MaterialDef materialDef;
// i gave up here...
};
The MaterialDef_*
classes are just one collection of many other classes that are serialised as part of the SMB, as you also have the actual geometry classes such as IndexedRenderableVB
, PBIndexedRenderableVB
and many others for all the various different sets of data that get serialised.
Something I’ll perhaps return to eventually, though I’m fairly sure the community will likely leap at this sooner and faster than I will.
There are seemingly two types of TAG files here, some are in a binary form and others just plaintext. A subset of the latter format can be seen below.
There are multiple types of tags here, which together appear to make up everything that’s featured in the given level.
// TagFile (version: 0, comment lines: 5)
// ** EDITS TO THIS FILE ARE NOT PRESERVED **. Change the .mb file instead
//
// Tags Exporter, version 0.93
// - File Exported as: d:/Exoddus/Build/Game/data/levels/Region_01/transition_01_1.tag
//
<WorldGeometry>
begin
m_tagName: ""
m_tagZone: -1
m_isInProxyZone: false
m_tagTransform: 1 [3F800000] 0 [00000000] 0 [00000000] 0 [00000000] 1 [3F800000] 0 [00000000] 0 [00000000] 0 [00000000] 1 [3F800000] 0 [00000000] 0 [00000000] 0 [00000000] 1 [3F800000]
m_illuminationColor: 1 [3F800000] 1 [3F800000] 1 [3F800000] 1 [3F800000]
m_snapToGround: false
m_groupName: ""
m_startsInPurgatory: false
m_castLightmapShadows: true
m_scriptFile: ""
m_scriptArgs: ""
m_scriptEmb: ""
m_pathToken: ""
m_levelPrefs: block
begin
[...]
My guess is that the plaintext files get converted into the binary format at some stage for speed (or the plaintext files are just an older version), given the binary variations of the format seem to contain the same data within them anyway and would be more optimal to parse.
There don’t seem to be that many ‘test’ models left hanging around, though I can’t speak for the rest of the models available (it would take someone with a bit more knowledge on Stranger’s Wrath than us to identify what is of interest).
There were two test models amongst the files that I was particularly interested to take a look at; test_ajb.geo
and test_dummy.geo
. Given the annoying complexity of parsing the file format right now I instead opted to brute-force it by just identifying the given tag and then pulling the vertex coordinates directory, though unfortunately neither of these appear to be quite as interesting as I had originally hoped.
This first one seen below is the test_dummy.geo
mesh, which is hard to recognise.
The second one here is test_ajb.geo
which looks like a collection of shapes.
There are a few other test models and other leftovers amongst the files, but they didn’t sound particularly interesting to me, so I didn’t get round to taking a look at them. And no, as far as I could tell there don’t appear to be any particularly interesting characters or cut enemies as far as I could see, but I’m hopefully wrong!
It would be great to see the community whip up a model viewer which probably wouldn’t be too difficult at all with the information available in the PDBs, and such a thing could be used to more easily identify the models and any differences.
When poking around various files, we stumbled upon references to “Exoddus”, which appears to be the internal location that Stranger’s Wrath project was developed under, at least.
But why “Exoddus”? Given our own lack of knowledge on the Oddworld franchise at the time, Abe’s Exoddus sprung to mind, which didn’t make any sense given that was a 2D game developed with an incredibly different engine, quite a significant amount of time before Stranger’s Wrath. It was doubtful Stranger’s Wrath was built upon the engine used for Abe’s Exoddus.
As we soon learned, there was intended to be a follow-up to Munch’s Oddysee dubbed “Munch’s Exoddus”, which obviously didn’t see a release in the end. Initially, the only piece of information we could find was on the Oddworld Wiki - no citations though (the administrator has since added a notice on the front page underlining the situation with dubious content on the site). We tried a few other fan sites, such as this, this, and stumbled upon this video, but again, no citations. There was a reference here but again, it’s just a passing reference of the title.
All we wanted to determine was 1) was Munch’s Exoddus actually a title in development at some point, or just a rumor, and 2) did Stranger’s Wrath have any relationship with it?
Grinding my teeth into paste at this point, I eventually jumped onto the Oddworld Discord and asked for help, and fortunately, the community there pointed us in the right direction and introduced us to the fantastic site, Magog On The March, and there it was…
Stranger’s Wrath was Munch’s Exoddus, and actually there is a build somewhere, on Xbox, which has Stranger and Munch hopping round the world. And it’s like OK, this is a bit weird now.
Source
Given that then, it seems reasonable to conclude that the Exoddus directory then that Stranger’s Wrath was seemingly located under during it’s development was a result of it being originally intended as the follow-up to Munch’s Oddysee before it evolved into the game we know it as today.
We thought it’d be interesting to see if any sounds here were different from what ended up shipping in the final game. Originally I was going to write our own tool for doing this, and then realised tools already existed after wasting about a day on it. Me smart. Brain big. Smack rock.
On Windows, WinMerge is usually a great tool for this sort of thing, as it lets you quickly compare multiple directories for instance so we can point it on one side to the prototype and on the other, the retail release (if you’re a Linux user, like us, Meld seems to be alright too, but I’ve not used it quite as much).
Initially, it looked pretty promising.
Unfortunately, as it turns out, the XWB files in the retail release don’t seem to retain the unique names for each of the audio tracks within, making quick comparisons tricky without spending a lot of time on it. It means some of these might actually be exactly the same, but the difference is just the lack of names.
To add to the pain, the number of banks stored in some of these files has changed between the final release and the prototype, so some new sounds have been added and some old sounds have been removed, and it’s difficult to quickly determine what’s what because of the lack of names in the release.
You could probably diff the audio_master.h
file between the release and prototype to determine what new banks have been added (or removed) to aid in the process of plundering the XWB files, but we didn’t have time to do this ourselves.
That said, it at least looks like some of the music tracks in the prototype are higher quality than those in the final release, which may be the case for some sound effects too.
So we’re not sure many people are going to be able to run this right now. As it stands, we weren’t able to successfully get this running under Cxbx-Reloaded or Xemu. In the end we resorted to good ol’ hardware instead, but obviously not everyone has access to a modded Xbox with more RAM or an Xbox development kit, so we decided to record as much footage of the prototype as possible for others to analyse.
If you do have an ability to run this, you’ll need to move one of the Xbox executables (the ‘xbe’ files) into the same directory as the ‘data’ folder.
Originally the plan was to split these videos up based on the bounty, but that didn’t quite work out due to issues with video editing software, so you’re getting these videos pretty much untouched… So, forewarning; I absolutely suck at playing this game, so apologies for that.
There are so many differences here, mind that I’m not going to point out every single one but rather those that stood out to me the most.
For instance, as you can see upon starting a new game (1:11), there is nothing prior to the moment you start playing. We drop in at the first town immediately! No introduction cutscene, either. As a matter of fact, you’ll notice that the tutorials originally featured at the start of the final game in their own unique area (see here) are instead integrated with the rest of the general flow here.
As we move through the tunnel towards our goal (3:56), we meet two characters talking over the body of another character which then introduces us to the capture mechanic. This is all completely absent from the final game.
These two characters are in the same area in the final game but are simply wondering around instead.
Following this, we see how the bridge gets destroyed and are subsequently introduced to jumping in order to reach the area on the other side. When the player approaches this area in the final game, the bridge is already destroyed.
It’s curious why OWI decided to change this approach towards teaching the player the mechanics, as what they’ve done here certainly felt more natural. Instead, the tutorial introduced in the final game is, in my opinion, significantly more intrusive (as a matter of fact, I believe the Nintendo Switch release of the game introduced an option to skip the entire tutorial section).
Another curious change is at the Water Facility, which appears to feature a separate area for the boss fight, which is found at the top of the tower (34:20).
And again, much to our surprise, a cutscene plays out here introducing us to our bounty that’s not featured in the final game.
You likely noticed a few other differences on our approach to the Water Facility, and at the facility itself, such as along the top of the building, there are additional barriers, making it much harder to hit the enemies on the roof (30:55).
Or that the door leading into the inner room of the building is wooden instead (31:13), allowing the player to break it (which makes sense given that in the final game this was likely changed to accommodate the change in location for the boss fight).
As stated earlier, there are just so many differences throughout this build it would be probably impossible for us to easily list them all, which is all the more reason why it’s going to be great to see this build out there for others to explore.
If there’s a desire to see more footage, let us know!
And this is probably what most of you have been after; grab it here.
If you want to support what we do, we’re not accepting donations at this time, but any and all feedback is appreciated; feel free to join our Discord or leave a comment letting us know what you think!
]]>This article is a bit different to what we usually post - its a behind-the-scenes look at how we handle our data storage needs, ensuring our collection is backed up and nothing is ever lost or corrupted.
When the TalonBrave.info file archive first came around, the collection wasn’t that huge, the local copies of everything lived on some external USB hard drives, got manually FTP’d into place on the web server and got backed up, uh, sometimes.
As the collection grew the stack of external drives got replaced with a little home NAS unit, and then we finally moved to a more “serious” solution - a server running TrueNAS (formerly known as FreeNAS). The best part of this is that TrueNAS uses ZFS, which has filesystem-level mirroring and integrity checking, so it should be close to impossible for anything in the collection to silently be corrupted by a hardware failure and it should be able to recover from a single disk failure without any data loss (and it has, once, so far).
In addition, around the time we migrated to the new NAS, we also put a proper backup plan into place. Everything on the server is regularly dumped to… uh, tape. Yeah, not my favourite storage medium either. It’s historically slow and ridiculously expensive for what you get… but it still (just about) makes sense when you’re storing multiple copies of multiple terabytes of data, potentially kept on the shelf for several years between uses, assuming you buy a second-hand drive.
I had lots of crazy ideas about how to do our backups at the time, from writing a program that would span all the individual files from the archive across a collection of Blu-Ray M-Discs and maintain a database of what versions of what files were on what disc, to a collection of hard drives, to various solutions around S3, but in the end settled on tapes for simplicity and cost. Yes, even tapes wound up being cost effective (by a huge margin) compared to M-Disc and Amazon S3. Hard drives would probably come in similar (to the 4th generation LTO tapes we’re currently using), but they’re inherently a bit more fragile than tapes should be.
The backup format is about as simple as it can get - tar. POSIX (“pax”) tar archives specifically. In the worst-case scenario I don’t want to be messing around trying to recover from a blank slate and finding that some fancy (or proprietary) backup software has changed under my feet or added any unexpected difficulties to restoring the backups.
Every 6 months or so I do a full dump of the system and in the interim I take differential backups. Our backup script also produces full text listings of the files/directories written to tape and the checksums of each file, so if there is ever any doubt about the integrity/correctness of something we can go back and see when/if it was ever changed, or find something that was unintentionally deleted and know which tape to recover it from without me having to index dozens of tapes at the time.
The physical backup tapes are stored offsite, individually labeled with what set they are from and also catalogued in a LibreOffice Base database (chosen to be accessible even if we have to start from a blank slate).
With all of that in mind, I want to remind everyone that the best way to preserve something is to share it - don’t assume nothing will ever happen to us, TalonBrave.info or any particular thing on the site, if you think it needs preserving, then make a copy!
I hope this brief glimpse into the exciting world of copying data around was interesting, if there’s anything else you’re curious about, then do go ahead and reach out to us.
]]>Below are some of my highlights of the year, keeping in mind this isn’t a definitive list.
I pretty much finished this list, thought that was it for the year, and then another one hit us!
Wow, didn’t expect that one! This was a super exciting one to see for me and something I’m sure I’ll write about at some point in the future.
Honestly it’s been a real struggle trying to keep up with it all, not that I’m complaining. I hope that list might bring to light something you might’ve missed yourself during the busy year, and if there’s anything else, feel free to let us know in the comments.
It’s worth pointing out that I’ve also uploaded a few more interesting pieces to archive.org since my post in July.
A massive thanks to Lemurboy12 for adding pages to Hidden Palace for my earlier releases, I really appreciate it!
There’s more on the way.
Anyway, with all that out of the way, here’s my Christmas gift to everyone; a build of Prey from 1995!
I’m sure many of you know how much of an obsession I have over Prey, so being able to share this with everyone is an incredible honor, and I’m so happy that this can finally be preserved and available for everyone to see.
Here’s to another great year of preservation.
]]>Additionally, if you’ve not noticed already, the old file archive is no more and now directs to our new Data Dungeon website.
We’ve spent a lot of time ensuring that redirects are available for everything but can’t make an absolutely 100% guarantee that some links won’t be broken, and in such a case do let us know and we’ll examine why or what happened, and see if it can be resolved.
This is something that we had been planning to do for a long long time now. The Data Dungeon was the first step towards that and now we’ve finally finished that process - and can get back to writing new articles hopefully a little more consistently.
]]>This is something I deeply wanted to change and something we’ve started working on.
So, today, after some delay, I’m happy to finally unveil the future of our archive in the form of The Data Dungeon! It’s faster, we can update it more frequently and we have our own in-house indexing tool for generating the whole thing.
This is of course a first step for the new archive and right now it’s very raw, but this will change over the coming weeks (and months) as we provide our indexing tool with more metadata and make further improvements.
If you’ve got any feedback for us too we now have a GitHub repository open for tickets and of course our Discord.
As mentioned, this initial release is very raw but we have a number of features we’re already working on which you will see introduced over the coming weeks.
This blog will continue to exist and ‘TalonBrave.info’ will continue being the face for The Data Dungeon.
For now it will remain but as the new archive matures we will eventually be looking to shut it down. That said, we will be looking at setting up redirects for everything under the Dynamic directory.
]]>That said, there’s nothing yet on the new archive (besides some random Final Fantasy XV bits which were thrown up as a test) as I’ve been wrestling with myself to get on with indexing our offline archive so we can get significantly more up than we had before.
Anyway I digress, the whole reason for mentioning the above is a rather poor explanation as to why I’ve not been uploading to our current archive so much as of late and instead I’ve been dumping software onto archive.org.
Below are a couple of discs I’ve recently dumped that may be of interest to _someone _out there. Some of these aren’t particularly rare but weren’t yet on archive.org so I’ve seen to it they’re now available for anyone to download.
This isn’t everything, just some of the highlights. You can find the rest on my profile available here. There is some more stuff on the way but my time has been limited as of late (and this heatwave isn’t helping any!)
We did have an alpha copy of Battlefield 1943 come in too from early 2009, however it turns out that the disc is pretty damaged (underside is pierced through). Sigh. We’ll take a crack at scraping off everything we can and will submit any results we get, otherwise I’ll throw it over to anyone else willing to take a crack at it.
When the new archive is available, I’ll likely continue uploading any new dumps to archive.org in addition to the new archive.
Anyway with that out the way I’ve been planning on rolling through a few pieces on Final Fantasy XV soon, hopefully, so either the first of those or the new archive will come next. Probably more likely the latter.
A while back (last year as a matter of fact), I published a copy of the source tree for Final Fantasy XV which was generated from data available in the debug symbols which had been shipped with the game by accident when it was first released (from my understanding). You can find the article regarding the source tree here. Debug symbols themselves can be found here. Since then I’ve noticed there’s a lot of weird information out there regarding the development of the game which doesn’t really align with the way the source tree is organised, so I thought it might be interesting to go through that a bit.
And I must confess that I’m just really fascinated (or obsessed, depending on who you ask) with the development of the game in general and have been really itching to write about my observations for a while.
Until next time!
]]>If you’ve perhaps been living under a rock, the drop is available here. There’s a little under 500 maps to look at here.
I’d had the best success running it by plonking the contents of the October directory under a C:\DNF\
location and then applying the ‘megapatch’ on top of it. If it fails to run the first time, just try again.
Also worth adding that, unlike most Unreal Engine based games, your user config is stored under the Players
directory, which will then depend on which profile you selected. So if you want to make any tweaks, such as forcing fullscreen or windowed, or whatever, then that’s the place to do it.
A working pool table and pinball machine - which work pretty much the same as they do in the final game.
Keep in mind that the build in this state was of course not intended to be seen by the general public and has likely been scraped off a developer workstation - there’s quite a bit of porn to be found in the menus, if you’re sensitive to that sort of thing.
It seems to be possible to finish the first chapter from start to end, however other chapters are in a rougher and rougher state the further into the game you go. It gives the impression that the chapters were being worked on in order.
There are a lot of interesting maps demonstrating various “features”, though whether these would’ve found their way into the game or were just simple experiments, we don’t know.
Because of what’s here, which is more than many expected, it’s interesting seeing all the percentages and estimates people have been throwing around as to how close this was to being a shipped project (myself included.) But at the end of the day, we weren’t there and don’t know the specific constraints or internal thought processes of the people involved - it’s why it’s been a shame to see quite a bit of renewed drama arise from this, and it seems even the founders of 3D Realms are getting into a bit of a finger-pointing match.
Personally I think it’s better to celebrate the fact that this work can finally be appreciated, experienced and preserved, or to just keep silent on the matter.
Also as much as it would be great to see the community “finish” this, it is a bit of a Half-Life 2 leak situation, in which there are no doubt going to be different interpretations or visions. And thus far I’m not aware of any coherent effort to actually pursue completing the project beyond some very vague fledgling projects and trivial bug fixes. So I think expectations should be tempered there.
An enemy using some pretty cool effects!
One thing that’s been a little disappointing is that the timestamps were not retained in the drop we received. Fortunately, after a little investigation, it turned out that the CPJ files, which are the Cannibal (Duke Nukem Forever’s model editor) Project files, actually store timestamps so I whipped up a tool to dump them.
None of these timestamps go further back than 2000, so I suppose either the CPJ format was introduced in that year or didn’t record timestamps prior to that time.
A similar area to this is seen in the final game; something of a museum or gallery to the Duke’s exploits.
Part of me was hoping that some code or assets would’ve been recycled from Prey, or left amongst the files for whatever reason, but alas, thus far there’s been nothing I’ve stumbled upon.
I don’t have much more to say about it other than it’s still processing in my mind that this has seen the light of day and that I’d recommend checking it out.
An update! So I’d originally done a very quick scan through via UnrealEd for textures and didn’t see anything. Stupidly called it a day. However it looks like DevilMaster found a few textures which kicked me to take a look, and indeed, it looks like there are quite a few textures from Prey amongst the files.
Above is just some of those textures, because there are a lot more I’m not 100% sure on. Many of those that appear to be from Prey are appended with ‘sah’, which I can only guess is Stephen A. Hornback whom was a texture artist on Prey back when 3D Realms were developing it in-house.
]]>