Castlevania: Resurrection Dreamcast
Special thanks to:
Sifting of the forum "Obscure gamers"
To read on a PC:
A lot of the game appears scriptable in plain text, including AI. Entities are also composed in a component style model in plain text, and adding new ones seems easy enough. Levels are entirely described in plain text, including entity placement and lighting data. Level geometry is in binary, however, and is referenced in these level scripts. In fact, everything seems to be oriented around the concept of a 'level', very much like how a scene works in Unity and such. Overall, it's a super modern impression that I got from this well over 20 year old prototype! Some examples
0 0 0 0
1 0 0 0
Note that the entity placements reference level geometry with the RigidModel tag.
The AI script reminded me the original Quake, where AI routines were built up on small, generic atomic actions, but in form it reminded me more of Half Life, which regimented the Quake style into a more data-oriented style. See here for a comparison! It's not really surprising though, the game programmer world is pretty small. As an aside, if you've ever read DeLoura's book you've probably noticed the castlevania team really took it to heart!
Another fun curiosity is this script file for a font tool they were using, which was left on disk:
/ * Font database. * /
/ * setdir: set the path for font textures for subsequent fonts * /
DIRSYS #basepath, (# subpath1, # subpath2, ...) - set path from dirpaths.txt * /
/ * DIRPATH #fullPath - set path directly; path must be a string (ie enclosed in double quotes, with '\' at end) * /
/ * type: 0 - fixed width, 1 - proportional * /
asciirange 32 126
celldimension 21 17
The actual file is quite a bit larger, but all follows this same format.
It's likely that all these files would have been converted into some binary form for production, but imagine how cool it would have been if the game had shipped with this system intact? we could have a very modifiable castlevania!
Moving on, there are no major surprises on disk from what I can tell. The other character is not present in any form, and some of the creatures seen in other screenshots are not here either. No extra levels seem to be left on disk either. It's unfortunate, but then again, we're very fortunate to have just this release as is! There are some neat trivia about the assets though:
All textures are 16 bit, encoded in either ARGB1555, ARGB4444 or RGB565 format. Larger textures use the VQ encoding, while smaller ones are just morton coded. None use the bump map format, though there are two textures, 'b_brick_01_bump' and 'b_brick_01_bump' which appear to be meant to be, and may possibly be used, as bump maps. Sonia is a single 512x512 texture, as well as Medusa and the Evil Cleric characters. Lesser ones are 256x256. Environmental textures run the gamut. Animated effects like the candle flames have each frame of animation stored in separate images, which are then referenced in a binary file that appears to describe the animation. The script dumps these into png format, in case anyone is wondering, and I've attached a few for those interested in art appreciation.
Characters all use skeletal animation. The skeletal hierarchies are described in separate binary files from the meshes. I'm unsure of the exact number of vertex weights at the moment, but it's likely to be a limit of one per vertex. If I have time I'll get the script to dump the assets in gltf so people can play around with them in Unity or whatever. The script itself should be available soon for anyone else interested in diving into the guts of this.
Okay, I've cleaned up the script for any one else who wishes to use it. it may be found here. I hope it helps in some small way. It requires python3 and pypng to work; run it with -h to see the help text, but really you just need to pass the .bin files to the script and it should do The Right Thing, but your mileage may vary as always.
Over the next few days I intend to document the file formats, and if anyone's interested, I'll publish that stuff too.
For the astute, you may have noticed there are no audio files. I believe they are stored in the .MLT file, but has a different structure so there's no way to pull anything out at the moment, or at least as far as I know. There's not really a lot of audio in the prototype though, so it's kind of a low priority for me.
Here's hoping someone finds a secret or two lurking on disk
I have the skeleton files part way figured out. these can be found in the .ssk directory that the script generates. For the most part they're pretty straight forward, but I've hit a bit of a snag with them. While the hierarchy was easy to figure out, the exact way it stores the bone transform (s) is kind of bizarre. I've worked with stranger stuff before though, so we'll see how it goes. For the technically inclined people, the problem is this:
typically each bone in a skeleton has a transform matrix used to deform the vertices that are assigned to it. this usually takes the form of one of the follow:
1. A 4x4 transform matrix (16 floats)
2. A 3x4 transform matrix (12 floats)
3. A versor and a vector (7 floats)
4. Euler angles and a vector (6 floats)
Sometimes there may be an extra value for scale (1-3 floats), but this is uncommon.
But here though, we have 21 floats worth of information, and none of it seems to fit any of the above patterns. It's quite a puzzle, so I decided to look at the .scf files, which is where character geometry is stored, and as far as I can tell, they are the same format as the .smf files used for static geometry, perhaps with some extra fields to weight vertices to their skeletons. This is good news, since it means once one format is known, then we know the other. More interesting, it appears that vectors may be stored as 4D, with an extra 1.0 padding the end, which makes them homogeneous. This is all subject to change though.
I've also loaded the code into ghidra to help get some more insight. I'd kill for IDA, but the free version does not support super H, unfortunately, but I digress. I poked around for some strings and found some fun things to share:
0008f374 "% s.bin"
000a10c8 "% s.scf"
000c7100 "% s.smt"
000a10d0 "% s.ssk"
000a10d8 "% s.ssn"
This appears to confirm some of the file extensions, which are not encoded in the .bin files.
0007bc40 "% s_actors.txt"
000af0c8 "% s_AIDefs.txt"
0006cc70 "% s_animsets.txt"
0008f37c "% s_e"
000dfdc8 "% s_emitters.txt"
00078320 "% s_entities.txt"
0007c3e4 "% s_fountain.txt"
0007bc50 "% s_items.txt"
0007c3f4 "% s_lightning"
00087c28 "% s_lightsets.txt"
00078330 "% s_nibillboards."
The engine seems to organize around the concept of a 'level', this appears to be broadly similar to a 'scene' in Unity or UDK. A level is composed of multiple text files, and these strings appear to confirm the naming scheme for them. Upon loading a level, the engine will look for the above text files and load their contents to produce the level. the% s is a place holder for a level name. These files may be found in the ramdisk directory, where there are ones like s2_01_items.txt, s2_01_lightsets.txt and so on. It appears not all files have to be present, as many levels are lacking a _fountain.txt.
00073eb0 ". \\\\ SOURCE / AISys. | 0 \ t"
000bb864 ". \\\\ SOURCE / AnimUtil.c"
00079e30 ". \\\\ SOURCE / canimt"
0006ab6c ". \\\\ SOURCE / cmesh.c"
00015e2c ". \\\\ SOURCE / CollSrvr.c"
000217ec ". \\\\ SOURCE / cskelsys.c"
000ec40c ". \\\\ SOURCE / cskinsys.c"
0009b824 ". \\\\ SOURCE / database.c"
000cc8e4 ". \\\\ SOURCE / dirsys.c"
000eb820 ". \\\\ SOURCE / Entity.c"
00076c34 ". \\\\ SOURCE / Fo"
00098ea0 ". \\\\ SOURCE / gameloader.c"
000a1c64 ". \\\\ SOURCE / GMain.c"
000d4654 ". \\\\ SOURCE / It"
00011828 ". \\\\ SOURCE / kc_light.c"
0008c760 ". \\\\ SOURCE / kc_vbuf.c"
0008d534 ". \\\\ SOURCE / kct exception in% s ()."
0001e0a0 ". \\\\ SOURCE / lightsys.c"
0009482c ". \\\\ SOURCE / msgsys.c"
000868a0 ". \\\\ SOURCE / NIBillboardSys.c"
0006c654 ". \\\\ SOURCE / nm"
00069fb4 ". \\\\ SOURCE / pa"
000c16e8 ". \\\\ SOURCE / pdfsys.c"
000a278c ". \\\\ SOURCE / smf.c"
000e4408 ". \\\\ SOURCE / smfuser.c"