Saturday, 15 July 2017

Manually Repacking I76/Nitro Levels

Nitro Map Reprocessor

This is something that dropped out of a chat with one of the I76 forum posters about fixing up old maps.

There are a number of I76 & Nitro mission files that have issues, like misplaced objects or are crash prone, and could do with fixing. However without the sources this is a difficult process involving a hex editor and a lot of trial and error.

So, attached to this is a set of Ruby scripts which simplify some of the process, by decompiling missions into a text form (JSON), and then recompiling them back into runnable files.

The code is in This Tarball Here, and is in three scripts; a decompiler (main_ar.rb), a recompiler (main_raar.rb) and a utility library that handles the actual format data(objects.rb). It's a little "my first Ruby program" and needs cleaning up (we could use a smarter approach/library than pack() for a start), but it's functional enough to use.

This script extracts the mission information and this data is converted into JSON, with the decompiler taking care of some obvious conversions, such as to & from float, and also grouping data where we know what it is (position, rotation, etc).

This format is essentially the same described in earlier posts, with a few fixes - notably Erik's comment that the flag field we thought followed the object name is really a float (giving us a 3x3 transform matrix), and it also handles LDEF sections, which support linked arrays of objects and additional fields in the WDEF.

Although we could unpack the zone definitions and game scripting there's little that could be manually edited here, so they're left as "opaque" sections and the data in the JSON is just a byte array. The same is true of a couple of other sections (revision data, etc).

To Run Them

Unpack a File

To unpack a file try ruby -w ./main_ar.rb gumball.rac

Where gumball.rac is a level file. This produces a set of json files, one per section. These files have the original name with the segment name and ".json" attached to the end, so "gumball.racODEF.json" is the object section, "gumball.racWDEF.json" is the world section, etc.
It also produces an index file, ".idx", which contains the list of sections. In this case gumball.rac.idx

Repack a File

To repack use the main_raar script, and either give it an index file, or a list of the unpacked JSON sections, e.g. ruby -w ./main_raar.rb gumball.rac.idx

Which produces the file "tmp.dat" which is a mission file that can be placed in the game directory and run.

So, as an example, running ruby -w ./main_ar.rb gumball.cbt Then the output file gumball.cbtODEF.json contains the following definition (around line 400):
{
    "name": "bddonut1",
    "identifier_tag": 0,
    "rotation": [
      -4.371138828673793e-08,
      0.0,
      1.0,
      0.0,
      1.0,
      0.0,
      -1.0,
      0.0,
      -4.371138828673793e-08
    ],
    "position": [
      995.0,
      0.699999988079071,
      50300.0
    ],
    "trailing": [
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0
    ],
    "class_id": 2,
    "basicstop": 0
},
This is the Dount Stand: Viewing it from the front and overhead view then originally it's:
We can change the position by editing the position data, so for example:
    "position": [
      995.0,
      0.699999988079071,
      50300.0
    ],
to
  "position": [
      965.0,
      0.699999988079071,
      50300.0
    ],
And if we run the output processor, and copy the file back into the missions directory with
ruby -w ./main_raar.rb gumball.cbt.idx  
cp tmp.dat  ~/.wine32/drive_c/Program\ Files/Activision/I76Nitro/miss8/gumball.cbt
Then when we reload the map we've moved the Dount Stand forward.

Similarly we can copy the entire Donut stand section, and by creating 3 more copies and adding 30 to the X position each time we get....

which is the in car view at the top of this post

Known Bugs

Although it should produce the same output from a given input there are a couple of files where label strings with trailing spaces are cropped during string cleanup (so from " Foo " to " Foo"). It also doesn't do much in the way of syntax validation or checking.

updated 16/7: the file was opened in text mode, not binary. This is fine on Linux, but means that on Windows the read of mission files came up short. Fixed and uploaded V2 of the tarball.

No comments: