Reverse Engineering Earth 2150, Part 2: Data Types
Since writing my last entry on reverse engineering Earth 2150, I’ve been in touch with the small community that still plays the game online. They don’t have any deep insights into the PAR file format, but they were able to point me at the SDK documentation. That doesn’t describe the format, but it does list various attributes that objects have for use in AI scripts, so I’ve got a bit more information to go on.
Revisiting types
Type 1: Units
Fields 18 and 19 can be identified using the SDK document. It specifies the existence of the functions GetMaxElectronics()
and getMaxTemperature()
in that order, so from this I assume that field 18 is electronic health and 19 is temperature capacity.
There are also functions for electronic, temperature, ammo, and shield regeneration. I suspects some of these these map up to fields 20–22, but the connection’s still a little unclear.
Type 4: Buildings
I thought field 63 was harvest rate, but the nice folks on the InsideEARTH discord suggested that it might be ticks per container produced, since the LC actually mine slower than everyone else. I’ll have to dig into how much is in a container.
New type interpretations
Type 3: Projectiles
Projectiles have 36 fields and a subtype code of 66561.
Field 1 is, as before, a string, but it doesn’t match up with the entity name like before. These also have no entries in the language file, so I now believe field 1 for all the types I’ve looked at so far are model names.
Fields 2 and 3 are always zero, so I’m not sure what their purpose is. These fields have been cost and build time for other types, so these zeroes may be that for the unbuildable projectiles.
Field 4 is only nonzero for bombs and ballistic rockets. It’s always a multiple of 500 for rockets, and of 10 for bombs. As these are strategic weapons and strategic weapons cost money to operate, I think this is the money cost per shot on reload. Nukes are expensive at 5000 a shot, so I think this matches up with that mysterious 4000 in the building fields being the plasma cannon’s cost to fire.
Field 5 is, again, always zero, so again no idea what this means.
Field 6 is a string beginning with SND_
where present, so can be assumed to mean what sound the projectile makes while in flight. This is followed, as in previous types, with the customary -1 in the next field.
Field 8 is another string, beginning with SMOKE_
, so it can reasonably be assumed to be the smoke trail rockets leave behind.
Fields 10 and 12 are always empty strings, so at best I can guess about meanings, but for other types smoke has been followed by death explosion and wreckage references.
Fields 14 through 20 are all always zero, so no clue what’s going on there.
Field 21 varies from 1 all the way up to 32, and is the same within projectile upgrade groups. Not sure what this refers to yet.
Field 22 is 0 for most things, but increases from 1 through 4 for rockets as they’re upgraded. I think this defines the rocket’s tracking ability. It’s probably an enum value referencing one of four tracking behaviours in the game engine, but it might also indicate maximum turn rate.
Field 23 is our old friend, the is-kinetic boolean. 1 for kinetic shots, 0 for energy weapons.
Field 24 is a string. Only ballistic missiles have this, and their values are something like PA_MIS_HR#
. This is a reference to an entity in a type 5 group, together with CONTAINER
. This may refer to some kind of non-orderable unit that the missile uses to track its way across the world.
Field 26 is either 0 or 1, 1 for heavy rockets and 0 for everything else. Something specific to heavy rockets that I’m not aware of?
Field 27 covers a range of values from a low as 7 for ballistic missiles up as high as 120 for UCS plasma bolts. For sonic cannon shockwaves, it’s a big fat 0. No idea what this represents.
Field 28 is 0 for most weapons except lasers and lightning cannons. At a guess, I’d say this is the light level emitted by the projectile.
Field 29 is an odd one. It’s mostly 0 or small numbers, increasing by 1 for some upgrades. But for ballistic missiles, it goes all the way up to 45 at the top end. Area of effect?
Field 30 is 0 for most things and 1 for ballistic missiles and strategic plasma cannons. Might indicate that the weapon has to be manually fired?
Field 31 is 1 for most things, but larger numbers for bombs and strategic weapons. Another candidate for area of effect? If so, what is field 29?
Field 32 is in the 2-5 range. Most things are 2, a few things are higher. Plasma bombs increase with upgrades but conventional bombs do not.
Field 33 is the damage the projectile does. This can get silly big for some of the strategic weapons.
Field 34 is an EXP_
string, probably the impact effect.
Type 6: equipment
Type 6 can have between 19 and 43 fields depending on the subtype:
Code | Type | Fields |
---|---|---|
514 | Repairer | 44 |
1026 | Carrier | 23 |
2050 | Banner | 25 |
2 | Solar Cell | 19 |
Do you notice what I did about those type codes? They’re all exactly 2 more than a power of 2. What I’ve been calling a “type code” is actually a bitmasked field! It seems to determine which kinds of fields an object has. Having a value of 2 in there (the 2nd least significant digit) seems to indicate a base set of 19 fields that all equipment has. With the 512, 1024, and 2048 bits adding on 25, 4, and 6 extra fields respectively.
Let’s look back at the weapons, which are closely related to the equipment here. These have a code of 258 - again, 2 more than a power of 2 - and have 36 fields. Want to bet that the first 19 will be repeated here?
The 19 common fields
We’ve seen a lot of these before.
Field 0 is the type code, which we now know is a bitmask.
Field 1 is the model name.
Field 2 is always 10, same as with the weapons.
Field 3 was a mystery with the weapons, and so too here. Most things are, again, 0 or 1, except for repairers which are 2, and solar panels which get to be 11 for some reason. But we’ve got some new patterns here. It’s not a strict LC/non-LC split. Most of the LC’s junk is 1, except banners which are 0. But carriers are 1, as are ED radars and one of the ED’s two banners. UCS? Still all 0s. Still don’t know what any of this means, but more data is good, right?
Fields 4 and 5, build cost and time, as before.
Field 6 is sounds again.
Fields 8, 10, and 12 are all empty strings, but we know what this trio means from other unit types: damage smoke, death explosion, and wreckage model.
Field 14 was another unknown for weapons, and there are still no hard answers to be had, but we’ve got some new patterns to look at here. Almost all 2s and 3s for equipment, but for the LC detector and regenerator, it bumps up from 2 to 3 when upgrading from m1 to m2. Solar panels get a 0, the only one we’ve seen for this field.
Field 15 is a lot of powers of 2, so we can assume it’s a bitmasked field - the slot types it can go in, as for weapons.
Field 16 is always 0, which is consistent with it being the subweapon slot; no non-weapon equipment has a sub slot.
Field 17 is 3 for everything except the solar cell, which is 0. Still no idea what it means.
And finally, field 18 is a mixture of 0s and 3s without much clear pattern.
That all looks very similar to the weapon fields, doesn’t it? I want to take a step back before getting into the extension fields.
More on type codes and common fields
I definitely feel I’m onto something big here. It’s now clear these are bitmasked values defining sets of fields an entity can have.
So let’s look at what all the types I’ve looked at so far have in common. The first 14 fields go: type code, model, unknown, unknown, cost, build time, sound, -1, smoke, -1, explosion, -1, wreckage, -1.
On top of those 14 universal fields, we’ve got a variable number of extra ones based on entity subtypes. With this in mind, I tweaked my script yet again to spit out the type codes in a few formats.
The first thing I learned is that only object types 1–7 have integers in field 0. It’s something different for types 8–10. But within those first seven types, let’s see what we’ve got:
Type | Code (hex) | Code (binary) |
---|---|---|
1 | 0101c000 | 00000001 00000001 11000000 00000000 |
1 | 0101c001 | 00000001 00000001 11000000 00000001 |
1 | 0101c002 | 00000001 00000001 11000000 00000010 |
1 | 0101c004 | 00000001 00000001 11000000 00000100 |
1 | 0101c008 | 00000001 00000001 11000000 00001000 |
2 | 02010000 | 00000010 00000001 00000000 00000000 |
3 | 01040100 | 00000001 00000100 00000001 00000000 |
4 | 01010100 | 00000001 00000001 00000001 00000000 |
5 | 01020000 | 00000001 00000010 00000000 00000000 |
5 | 01080000 | 00000001 00001000 00000000 00000000 |
5 | 02100000 | 00000010 00010000 00000000 00000000 |
5 | 04000100 | 00000100 00000000 00000001 00000000 |
5 | 01020100 | 00000001 00000010 00000001 00000000 |
5 | 01010200 | 00000001 00000001 00000010 00000000 |
5 | 01020200 | 00000001 00000010 00000010 00000000 |
5 | 01040200 | 00000001 00000100 00000010 00000000 |
5 | 01040400 | 00000001 00000100 00000100 00000000 |
5 | 01010800 | 00000001 00000001 00001000 00000000 |
5 | 01040800 | 00000001 00000100 00001000 00000000 |
5 | 01020201 | 00000001 00000010 00000010 00000001 |
5 | 01040201 | 00000001 00000100 00000010 00000001 |
5 | 01010401 | 00000001 00000001 00000100 00000001 |
5 | 01041001 | 00000001 00000100 00010000 00000001 |
5 | 01010402 | 00000001 00000001 00000100 00000010 |
5 | 01041002 | 00000001 00000100 00010000 00000010 |
5 | 01010404 | 00000001 00000001 00000100 00000100 |
6 | 02000000 | 00000010 00000000 00000000 00000000 |
6 | 02020000 | 00000010 00000010 00000000 00000000 |
6 | 02040000 | 00000010 00000100 00000000 00000000 |
6 | 02080000 | 00000010 00001000 00000000 00000000 |
7 | 64000000 | 01100100 00000000 00000000 00000000 |
7 | c8000000 | 11001000 00000000 00000000 00000000 |
7 | 90010000 | 10010000 00000001 00000000 00000000 |
There are a few definite patterns in there. I’m not convinced that 7 follows the same scheme as 1–6. And there’s a lot going on with type 5. To make it easier to read, I’ll restrict this table to types 1, 3, and 4, to examine what these types have in common.
Type | Code (hex) | Code (binary) |
---|---|---|
1 | 0101c000 | 00000001 00000001 11000000 00000000 |
1 | 0101c001 | 00000001 00000001 11000000 00000001 |
1 | 0101c002 | 00000001 00000001 11000000 00000010 |
1 | 0101c004 | 00000001 00000001 11000000 00000100 |
1 | 0101c008 | 00000001 00000001 11000000 00001000 |
3 | 01040100 | 00000001 00000100 00000001 00000000 |
4 | 01010100 | 00000001 00000001 00000001 00000000 |
Much better. Based on the common fields between units (1) and buildings (4), I can surmise that the 1 bit in the 1st byte and the 1 bit in the 2nd byte, which they both share, add the various HP values and the equipment slots. Interestingly, projectiles also have 01 in the first byte. Perhaps that string of zero fields is their HP values? At this point, it occurs to me that I’m using the base Earth 2150 files - the standalone expansion, The Moon Project, added antimissile systems. Will be interesting to see if rockets have nonzero HP in that. From this, it would follow that 01 in the second byte adds the equipment slots, which projectiles don’t have.
After that, we’ve got c0 in the third byte for all units - that’ll probably be speed and movement values plus all those random things I couldn’t identify. 01 for buildings, which would seem to be all the economic values, but… projectiles also have 01 in the third byte, and they’ve got a different set of fields. Clearly there is more to this than I thought.
And then there’s the 4th byte, which just has a different bit for each set of extensions on various specialized unit types.
So everything with these fits my idea, except what’s going on with byte 3 for projectiles. If I was completely correct, I’d expect at least the last few fields in projectiles and buildings to follow the same pattern, but you just have to look at the field types to see that isn’t true: the last projectile field is a string (not counting its trailing -1, still don’t know what those are for), the last building field is an integer. Perhaps fields 2 and 3 also play a role? Or maybe each byte’s meaning depends on the value of the one before; is this a four-level type hierarchy?
Every time I think I’ve figured something out with this file, it poses more questions.
Posts in this series:
{% for post in site.tags[‘Reverse Engineering Earth 2150’] reversed %}
- {{post.title}}{%endfor%}