A silly April Fools project; would you believe something that looks like a stupid little level mod is worthy of a technical write up? Well, I think it is, considering how young the Frontiers modding scene really is (at the time of writing and mod creation), so here we go.
The first question that likely came to mind upon seeing a mod utilising stages from Ninjabread Man is probably, simply “Why?”. The real answer for this was… Because I thought it’d be funny. There was also the fact that the Sonic ’06 stage imports I was working on at the time were starting to frustrate me, so I wanted to do something else, and seeing as the idea to do SOMETHING with Ninjabread Man’s levels had been in my mind for ages, back in 2020 even!
Of course, this meant doing the thing that is both thrilling and INCREDIBLY frustrating for me, reverse engineering. And being that Ninjabread Man is a shovelware game no one gives a shit about, I was basically on my own.
Ninjabread Man Reverse Engineering
All of Ninjabread Man’s files are contained in a proprietary WAD archive format. When I initially looked at the format, I assumed it’d be a simple job, as all the data was uncompressed, it was just a matter of understanding how stuff within the archive pointed to different files and write some code to extract them.
How wrong I was.
While my memory of the process is very hazy at this point (I like to think I just blocked out the memory of doing so), me and Hyper (using an incomplete format specification found in Game Extractor) eventually managed to get files dumping with their names, however, folders would endlessly elude us. Nevertheless, we had files, so it was simply a matter of using the GTA3 tools to get the Renderware DFFs imported into 3DS Max to screw around with.
Except it wasn’t.
Seemingly, the version of Renderware used for Ninjabread Man just isn’t supported by any Renderware importer I could find (which really just boils down to an old 3DS Max one and DragonFF for Blender). So, me being me, I went and did something stupid.
Looking at a model in RWAnalyze (a tool designed to… well, analyse Renderware files) I was able to confirm that the models were actually DFFs, rather than some custom format using the extension. But for whatever reason, nothing wanted anything to do with it. So game over right? Wrong.
RWAnalyze has an option to export a section’s data, so a crazy idea came to me. Why didn’t I try and inject the Geometry section into a DFF that the 3DS Max importer CAN import?
And somehow, this worked.
Of course, doing this by hand for each model would have been painful (considering the fact that there’s 167 DFFs in Ninjabread Man with no indication of what is what). Thankfully, Hyper hacked a thing together for me purely to automate the process.
So with every model now a GTA3 one instead, I was able to import all of them into 3DS Max, from there it was just a matter of finding the right models for the stages and going from there. Though nothing ever came of this for ’06 back in the day, and it was just one of many things that ended up on my backburner.
Directories, AKA My Mortal Enemy
For whatever reason, sometime in July of 2022, I randomly had another stab at reverse engineering the WAD format based on our original code. And yet, I ran into the same hurdle, folder names being nonsensical.
But I’m nothing if not stubborn (except when I’m not), so I just kept trying stupid shit until one solution worked. At last, I had all the files extracted into their proper subdirectories, rather than just all being shoved in the root. But I still had no idea of what to actually DO with these files, so I just kept the code around on my old Misc Tools repo, but never did anything with it.
As expected, once Sonic Frontiers launched and HedgeModManager got support for it, I did some experimental imports of ’06 stages (because of course I did). Doing these allowed me to get familiar with some of Frontiers’ formats, as they did change a few things around from Sonic Forces. Notably, Sonic Team finally replaced the format they previously used for model instancing; thankfully the replacement format was nice and simple (to the point that it was reverse engineered before the game came out thanks to the Switch version leaking a week or so ahead of schedule), so no worries there.
Object Placement Data, known as
gedits, were my biggest stumbling block early on for the ’06 stuff, as object parameters are done in a positively infuriating way in the gedit format, and my code to try and read and write them was very much insufficient. However, something would eventually come around that proved to be an absolute blessing.
HedgeSet, AKA How I Learned To Stop Worrying And Love JSON
The idea for HedgeSet was being thrown around for a bit sometime after Frontiers launched, with me getting my hands on an early test build on Christmas Day of 2022, although I wasn’t able to actually do anything with it for a few more days.
With HedgeSet in hand, I was able to start working on object placement stuff for my ’06 imports, but over time fatigue and frustration ended up setting in, so I needed to take a break from it and eventually rethink the project. But me being me, taking breaks is hard, as I often find myself tempted to just continue fruitlessly or start tinkering around with something else at complete random. I still wanted to do SOMETHING with Frontiers, but ’06 stages weren’t appealing to me at the time, so I needed to think of something. That’s when my desire to do something stupid for April Fools Day sparked, despite it being January.
Unlike my previous April Fools Day mod for Sonic ’06, I wanted to do something more than just a static model swap. So I got to thinking of dumb shit I could do, which is when it hit me.
Finally do something with those Ninjabread Man models. And thus, the process began.
Reusing the old code Hyper wrote, I once again “converted” all the Ninjabread Man DFFs into Grand Theft Auto III ones so I could get them imported into 3DS Max. Picking apart the models until I had the ones for Level 1 isolated. From there, it was a quick process of mirroring them (as for some reason the models didn’t have the same X direction in Max as they did in the original game), exporting them to an FBX, using HedgehogConverter to convert them to Hedgehog Engine terrain models and writing some code to make an instance file for the stage (simply containing each model with a position and rotation of 0, 0, 0 and a scale of 1, 1, 1).
Collision was just done by using the model itself with no modifications, as it was always planned to be temporary. The model itself was converted using code Skyth had slapped together to generate the new Bullet Physics based collision.
Plugging these files into the appropriate w6d01 pac archives led to the expected cursed sight. A Ninjabread Man stage, in Sonic Frontiers. The stage was empty yes, but it was a proof of concept that proved the thought might be doable.
Beginning SET Work
Of course, what good is a level without anything in it? Thus it was time to begin getting a basic object layout going. This was done simply by dumping the stage into SonicGLVL, placing an object where I wanted it (either by eye or by typing in coordinates from 3DS Max) then manually typing the resulting position (and in some cases rotation data) into a HSON file by hand.
Initially, I had planned for moving platforms to be done by replacing the Green Hill NormalFloor models. But I quickly found out that the collision for those objects is hardcoded into the game, so I couldn’t use that solution. The alternative? Use a Gismo.
Gismos can be considered props, with their own mesh, collision data and other attributes applied to them. While there is no option to have a Gismo move, they CAN be parented to another object and inherit its position value. Therefore, I just had to make a Gismo for the platform and parent it to a moving NormalFloor object, making sure that the NormalFloor would be hidden inside the platform.
I also used this trick on another set of platforms that moved in a circle, however this proved to be a bit more difficult. As there is no option for a NormalFloor to rotate around a point. Initially I had hoped to find a rotating object I could pair the Gismo to; but that search turned up empty. So I settled on pairing the NormalFloor to a spline, which did work, except for the part where it would stop moving after one full loop. I’ll get back to that, as fixing it wasn’t a high priority early on.
Just four days later, I’d sorted myself out a TODO list for the project, as having a cohesive list of tasks had proven to help me in the past (I utilised one for ’06 Seaside Hill to decent effect). Even at this point I was toying with the idea of including the other two levels and the Wii version’s training level as a HUB world, but they weren’t exactly a priority.
MAT_DAMAGE, AKA Why I Hate Sonic Team
One of the things I had to handle at some point was the stage’s collision, for the most part I could just use the terrain itself, with some things stripped out. To actually apply the surface type tags, I ended up splitting the collision into different objects by surface type and then applying the tag for the surface I wanted in a Hex Editor by hand. This was all fine.
Until it came to the lava (or boiling candy whatever you want to call it).
Present within the list of material types we have, is a material type called
MAT_DAMAGE, so logically I thought “Excellent just apply that to the lava collision and it’ll hurt the player on contact.”
No. That was not how that went.
No matter what I did, I couldn’t get the damage tag to work at all. In fact, I couldn’t get anything that implied damage or death to work, even when going through every tag available on the object the surface list comes from, nothing worked. At the time I just ignored it, but closer to the end of the project, I needed to sort this hurdle. So what was my solution?
A LOT. Of Spikes.
The process to place all of these is awful in itself, I opted to make a plane mesh over the pit in 3DS Max, divide it to be small enough, export it to an OBJ then use some code to convert each vertex point on the mesh to a spike in GLVL. The extra, out of bounds spikes were then deleted by hand and converted over to a Frontiers gedit, where they were given pitifully tiny draw distances. In addition, I had to modify the CommonObject pac file to completely remove the materials for the spikes to make them invisible, as them just popping in and out would just be stupid lets be honest.
However, this process was done far closer to the end of development, so let’s step back to what came before. As I had most of Level 1 done FAR earlier than expected and just had stuff left that I was too lazy to do, I decided “Fuck it lets just do all three.” And this, Level 2 began.
Level 2, AKA Fun With Lasers And Invisible Walls
Level 2 initially worked in the same sort of way as Level 1 did. Building a basic object layout through GLVL and converting it to a HSON by hand. Although I knew from the beginning something that would be a slight challenge, and that was progression blocking.
Now’s a good time to talk about how levels in Ninjabread Man actually work. In that game, the goal is to collect eight keys (power cells?) in the level to unlock the exit teleporter. While I COULD have replicated that behaviour with switches in Frontiers, I don’t believe switches can have their state preserved between checkpoints, which would create a problem. So I opted to ditch that and only use switches in specific points.
For Level 1, three switches are used to spawn the stage goal, placed after the last checkpoint in the stage in roughly the same locations as three of the keys in the original game. For Level 2, there are two sections where you have to go off the main path to collect a key, so my solution here was to simply block the way ahead. The solution for that? Lasers!
I could easily rig up a switch to turn off the lasers, so no problem, idea done issue checked off the list. Except no, being Frontiers, there’s a twist that infuriated me. You can clip through these lasers. Simply air boosting into them would usually be enough to shove the player through them. So another solution was needed, and in typical Knuxfan24 Fashion, it’s a complete hack.
Alongside the lasers is a Gismo, the Gismo is simply an invisible block of collision, placed in such a way that the lasers can damage the player, but not let them through. However, there’s no way to disable a Gismo, which would cause the wall to still be there when the lasers were turned off. The solution to that problem? A NormalFloor placed underneath the stage with the Gismo paired to it, upon pressing the switch, this floor moves much further down at a very rapid pace, pulling the Gismo down with it and getting it out of the way.
Besides setting up this solution, and fixing a problem where the Gismo wouldn’t get moved (which I believe ended up being due to it being unloaded thanks to me not understanding how to properly set up the RangeSpawning tags on the objects), Level 2’s development doesn’t have much else to talk about, other than making some rotating platforms.
Initially, I wanted the rotating platforms in this level to be two rings of three, as they are in the original game, but the solution I ended up using for rotation platforms (which was making the splines in the gedit, as it turns out object splines can be smoothed out by the game itself) would have proven frustrating to make three platforms with, so I just gave up and replaced them with a single ring of four cookie platforms instead.
The same can really be said for Level 3 as well. Being a fairly small set of rooms, I opted to go with using all eight switches for this stage. While this meant having no checkpoints, the stage itself doesn’t have any pits or lava, so I was more willing to accept the loss.
The only real problem that occurred when making this level was an inconsistency in an object working. Previously, I had wanted to make the Island Puzzle Solved Jingle play when all eight switches were hit, and I had that working even!
Sometimes… For whatever reason, it just wouldn’t work sometimes, seemingly at complete random. I was getting impatient at the time, so I just said screw it and threw it out.
I had also planned to add this to Level 1’s three switches as well, alongside the Level 2 laser gate switches, but didn’t as a result of not having the patience to fix it here.
The Wii Version Throws A Curveball
Seeing as I still had plenty of time, I wanted to go through and do one of the other things I had on my list from the beginning. Replace an island with the tutorial level to act as a HUB. The problem there is that only Ninjabread Man’s Nintendo Wii version has it; all my work was based around the PC version. While I had my code for the WAD support the Wii version (as it is different), it turns out that the model format in the Wii version is different. While RWAnalyze seemed to imply that they were still Renderware DFFs (although they had a new WIF extension), the injection trick didn’t work this time. So I had two choices, reverse engineer the format. Or take a cop out solution.
I chose the cop out.
Enter NinjaRipper. By using this tool and injecting it into a copy of the Dolphin Emulator I was able to get a rip of the tutorial map. Mercifully, it was properly intact, as I’ve had bad experiences trying to use NinjaRipper (the results it gets out of Saints Row especially are… interesting).
Getting the basic map playable was as simple as with any other stage. At the time I didn’t have anything major in mind for it; I was thinking I’d just put Portal Gates and call it a day. The tutorial map is also the only public hint towards this project I’ve posted before release. Much like I did with Sea Gate for ’06 Seaside Hill, I posted a mostly black image, simply showing my Forces Avatar in a black void. Over exposing the image however would reveal the terrain around them and the Frontiers island HUD.
Save File Spaghetti
Due to how Frontiers handles its New Game option, I wanted a way to just skip straight to the island, as the game normally forces the intro cutscenes and a playthrough of 1-1 before hand. However, as I’m no code modder, I took a different approach. Utilising HedgeModManager’s save file redirection to use specially set up saves. Actually creating these saves was not the most fun task.
Thankfully there was an 010 Editor for the format, so I wasn’t flying completely blind. In time, I managed to make save files that have a fresh Sonic with no upgrades or stats in the w1r03 map with the message that would normally force the Homing Attack tutorial removed; the save date was also set to the 1st of April 2023 and the playtime set to 0:00:00. Then it was simply a matter of copying this save over all three slots.
I’d elaborate more on what I had to do, but I honestly don’t remember much, I think it just mostly boiled down to starting a new game and setting things up in the way I needed then manually hex editing the save from there.
Besides adding objects around the map, I also added Guardians and locked the Portal Gates behind Gears, frustratingly, this required more screwing around with the save file and the portals themselves, as loading the save would end up unlocking all the portals.
Final Tidying Up
Beyond this point, there wasn’t much that had to be done, besides just tidying up the files and checking things off my TODO list. This was around the time the spike hack was implemented, as much as I hate it, I just couldn’t think of any other solution. And hey, it works so bleh.
This was also the time I FINALLY named the mod, settling on Ninjabread Land and creating the thumbnail and filling in the information for it (humorously I somehow set the year to 2024 by accident, which I was quickly informed of (thank god for showing small groups ahead of time!))
Setting all the ranking times was also a part of this process. I knew from the start that I was going to make the S-Rank times fairly harsh, as I knew some tricks in Level 1 that’d I been using since starting development. When setting these times, I opted to use some of this movement for the S-Rank times and go as fast as I could, while the A-Rank times omitted these tricks but still went quickly; the rest of the times were gotten by just knocking time off of the A-Rank one.
With this, I was done (way ahead of schedule, the mod went gold in early February!). While I almost certainly could have polished things up a bit more, I’ve always been bad at the polishing part of mod creation, so I just kinda gave up and considered it good enough. So here we are. Happy April Fools.
But wait! There’s more!
Or I WOULD have considered the mod done, if the first content update for Frontiers hadn’t dropped a week before the April Fools release date. Thankfully, the HE2ModLoader seemed to still work fine, so I went through and gave the mod a check for compatibility. Everything was fine, except…
For the Hint Rings in Levels 1 and 3, as well as the message in the HUB, I replaced three unused messages in the Tips text container. All fine at the time, but it turns out that Update 1 used some of them. As I had to replace the whole container, the old placeholders were restored, leading to things like “tip134” appearing on loading screens from time to time.
For a bit, I couldn’t be bothered fixing it (yet more evidence that I’m bad at the polishing phase), until I decided “Fuck It!” and bothered to do so. In the process, a conversation regarding expanding the Island Jukebox got me thinking. What if I could SHRINK the Jukebox and then take advantage of it in someway?
The Great ISO Hunt of 2023 (that lasted 10 minutes)
So I did some poking around, finding ISOs for the other platformers that Data Design Interactive were known for in Ninjabread Man’s era. Those being Anubis II, Myth Makers: Trixie in Toyland and Rock ‘n’ Roll Adventures. Oddly, despite a PC version seemingly existing for all of these games, I wasn’t able to find one for Rock ‘n’ Roll Adventures at all and had to settle on a Wii ISO instead.
As it turns out, while Myth Makers was such a shameless rip of Ninjabread Man (or maybe Ninjabread Man was a shameless rip of it instead) and had the exact same music, Anubis II and Rock ‘n’ Roll Adventures had different music. So I did some more digging around in the Frontiers files, armed with Skyth’s 010 Editor templates, and found the file that controls the unlocking of the Island Jukebox songs.
From there, it was a simple matter of unlocking the first 12 options on the Jukebox and locking the remaining ones (which can go up to 128 for some reason), and replacing the songs in the Criware ACB file. This did also lead to me going in and removing unused tracks, as the solution that would be used to only inject changed songs doesn’t work on Frontiers, so the whole ACB had to be repacked, which lead to large file sizes for no reason.
Frustratingly, my choice to replace unused tracks turned into a slight game of whack-a-mole, first finding that I’d accidentally removed the Portal Usage Event song, then finding I’d also removed the “Got [x] Vault Keys” jingle as well. So that was a fun back and forth!
Are we actually done now?
Hopefully everything with this mod in the future will continue to work, but if not, we’ll see if I ever end up being bothered to go through and hotfix it. Alternatively, I may end up expanding it, considering I now have the files for the other DDI Platformers, what’s to say I won’t import their levels too?
Oh god please help me that sounds horrific. So will it be much of a surprise if I actually end up doing it?