C3 Developer Documentation

This page details some of the behind-the-scenes things that you may need to know if you want to tinker with C³ or its files.

Save Files

This section describes the layout of C³'s save files. There are two types: old-style save files for C³ versions up to and including 0.1.6, and new-style files for later versions.

Old Style (C³ version ≤ 0.1.6)

Up to and including version 0.1.6, C³ saved its data in plain text files containing a Python dictionary.

File Recognition

These files have the extension btrs (for BattleTech Record Sheet) and, provided C³ is installed, Mac OS X will determine them to be of the type BattleTech Record Sheet. The following is the full document type information declared in C³ v0.1.7's Info.plist file:

V<dict> <key>CFBundleTypeExtensions</key> <array> <string>btrs</string> </array> <key>CFBundleTypeIconFile</key> <string>Record Sheet</string> <key>CFBundleTypeMIMETypes</key> <array> <string>text/plain</string> </array> <key>CFBundleTypeName</key> <string>BattleTech Record Sheet</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSTypeIsPackage</key> <false/> <key>NSDocumentClass</key> <string>BattleMech</string> <key>NSPersistentStoreTypeKey</key> <string>Binary</string> </dict>

Loading Save Files

The file is loaded by the following bit of Python code:

Vf = open(file, "r") lookingFor = "mechData = {" for line in f.readlines(): if line.lstrip()[:len(lookingFor)] == lookingFor: exec(line) f.close()

Basically, the file is opened for reading, then each line is stored in a list (what many other languages call an array), and the list is walked through. If a line starts with the exact string mechData = { (with no leading whitespace or anything), it gets executed using the exec statement. This works because the line contains a dictionary with data, and by executing it that becomes a normal Python object.

This way of loading was chosen for convenience, as it removed the need to write a routine to parse a file and extract the data in it: the dictionary can be referenced right away. However, it needed a precaution against malicious code being inserted into save files: simply executing the entire file (by means of the execfile() function) would have meant that any Python code in it would get run, no questions asked.

File Structure

Save files are plain text files which should preferably use UTF-8 encoding (though ASCII is probably not a problem) and any common style of line ending: CR, LF or CR-LF (files produced on a Mac will have LF line endings).

As mentioned, a save file contains only one item that is actually used: a Python dictionary defining the ’Mech's data. Only the line with this definition on it is used; all other lines may contain anything desired, as they will be completely ignored.

The line containing the ’Mech's data should start with the following string, spelled exactly like this:

mechData = {

Note that there is a single space after mechData and another one after the =-symbol; these are required. There may not be any whitespace before the word mechData.

After the { should come a series of key:value pairs separated by commas; the keys are always strings, while the values may be numbers (integers or floating-point), strings, or dictionaries—see the Python documentation for details on how to write or create all of these: string and numeric literals and dictionaries (note that if a string contains non-ASCII characters, precede it by the letter u to indicate it is a Unicode string). At the end of the dictionary should be the character }.

The order in which the key:value pairs are included in the dictionary does not matter, as dictionaries in Python are not iterable. Whitespace between keys and values is ignored.

There may be no line breaks anywhere in this dictionary—the Python rule that a logical line can be split over multiple physical lines by ending the latter with a backslash (\) is not followed. However, it is allowed to have more than one mechData = {-line in the file, but each new one would overwrite the data contained in the previous one so that only the last one defined would actually be used.

The following list shows the keys used in the dictionary, the type of value each represents, and (where necessary) their allowed values. Keys must be spelled exactly as shown, and all keys must be present else there is a chance of errors; specify an empty string ("") or 0 for keys that have no real value.

name
String The ’Mech's name.
tonnage
Integer {10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95|100} The weight of the ’Mech in tons.
tech base
Integer {0|1} Whether the ’Mech is built using Clan technology (0) or Inner Sphere technology (1).
bv
Integer The ’Mech's Battle Value. Note that the file does not make a difference between the different BV systems that have been used in BattleTech, so this number can represent any of these.
cost
Integer The ’Mech's cost in C-Bills.
engine rating
Integer {10400 in steps of 5} The rating of the ’Mech's engine (this is equal to its tonnage multiplier by its walking MP).
jump mp
Integer The number of Movement Points the ’Mech has for jumping.
heat sinks
Integer The number of heat sinks installed in the ’Mech.
heat sinks double
Integer {0|1} or {False|True} Whether the heat sinks are of the single (0 or False) or double (1 or True) type.
armor
Dictionary The armor values of each of the ’Mech's hit locations, with the following keys:
h, ct, ctr, lt, ltr, rt, rtr, la, ra, ll, rl
Each an Integer Armor value of the location.
equipment
Dictionary The contents of all the critical hit slots on the ”Mech, with the following keys:
h1 through h6
String Item stored in slots No. 1 through 6 in the ”Mech's head.
ct1 through ct12
String Item stored in slots No. 1 through 12 in the ”Mech's center torso.
lt1 through lt12
String Item stored in slots No. 1 through 12 in the ”Mech's left torso.
rt1 through rt12
String Item stored in slots No. 1 through 12 in the ”Mech's right torso.
la1 through la12
String Item stored in slots No. 1 through 12 in the ”Mech's left arm.
ra1 through ra12
String Item stored in slots No. 1 through 12 in the ”Mech's right arm.
ll1 through ll6
String Item stored in slots No. 1 through 6 in the ”Mech's left leg.
rl1 through rl6
String Item stored in slots No. 1 through 6 in the ”Mech's right leg.

Example

The following is the contents of an actual save file for a WHM-6R Warhammer created by an early version of C³. Note that the items in the equipment dictionary especially are in what amounts to random order, because Python dictionaries do not have a fixed order (unlike lists).

VmechData = {'bv': 1299, 'cost': 6051383, 'tonnage': 70, 'jump mp': 0, 'name': u'WHM-6R Warhammer', 'armor': {'rt': 17, 'ltr': 8, 'ctr': 9, 'la': 20, 'h': 9, 'll': 15, 'lt': 17, 'ra': 20, 'rtr': 8, 'rl': 15, 'ct': 22}, 'tech base': 1, 'engine rating': 280, 'equipment': {'la5': u'PPC', 'h2': u'Sensors', 'h3': u'Cockpit', 'h1': u'Life Support', 'h6': u'Life Support', 'h4': u'Heat Sink', 'h5': u'Sensors', 'la4': u'Heat Sink', 'la8': u'', 'lt12': u'', 'lt11': u'', 'lt10': u'', 'rl5': u'Heat Sink', 'rl4': u'Foot Actuator', 'la6': u'PPC', 'rl6': u'Heat Sink', 'rl1': u'Hip', 'la1': u'Shoulder', 'rl3': u'Lower Leg Actuator', 'rl2': u'Upper Leg Actuator', 'ct4': u'Gyro', 'ct5': u'Gyro', 'ct6': u'Gyro', 'ct7': u'Gyro', 'lt7': u'', 'ct1': u'Engine', 'ct2': u'Engine', 'ct3': u'Engine', 'ra8': u'', 'lt9': u'', 'lt8': u'', 'ct8': u'Engine', 'ct9': u'Engine', 'ra9': u'', 'ra10': u'', 'la2': u'Upper Arm Actuator', 'ra11': u'', 'lt2': u'Small Laser', 'la3': u'Lower Arm Actuator', 'la7': u'PPC', 'ra12': u'', 'lt3': u'Machine Gun', 'ct12': u'', 'ct10': u'Engine', 'ct11': u'Ammo (Machine Gun) 200', 'll3': u'Lower Leg Actuator', 'll2': u'Upper Leg Actuator', 'll1': u'Hip', 'll6': u'Heat Sink', 'll5': u'Heat Sink', 'll4': u'Foot Actuator', 'rt5': u'Machine Gun', 'rt4': u'Small Laser', 'rt7': u'', 'rt6': u'Ammo (SRM 6) 15', 'rt1': u'SRM 6', 'ra3': u'Lower Arm Actuator', 'rt3': u'Medium Laser', 'lt1': u'Medium Laser', 'rt2': u'SMR 6', 'rt9': u'', 'rt8': u'', 'ra5': u'PPC', 'lt6': u'', 'ra6': u'PPC', 'ra1': u'Shoulder', 'lt5': u'', 'ra7': u'PPC', 'lt4': u'', 'la12': u'', 'ra4': u'Heat Sink', 'la10': u'', 'la11': u'', 'rt11': u'', 'rt10': u'', 'rt12': u'', 'ra2': u'Upper Arm Actuator', 'la9': u''}, 'heat sinks': 18, 'double heat sinks': 0}

New Style (C³ version ≥ 0.1.7)

Starting at version 0.1.7, the flat file described above has been replaced by a package containing multiple files. The reason for this is that it makes it easier to store different types of data inside a save file: not only that of the ’Mech represented by the file, but also images of the ’Mech, data for the pilot, versions of this data that are more easily read by other applications, and in future possibly such things as multiple configurations of the ’Mech, a pre-created Quick Look version of the record sheet, etc. (Some of this, of course, could also be stored in the same file as the ’Mech data, but by putting it in a separate file, access to it is easier: there is no need to parse a file to extract only the image data, for example.)

About Packages

Here is a short overview of the concept of packages, mainly intended for non-Mac-users, as a basic understanding of these is necessary for working with the internals of C³ save files for version 0.1.7 and later.

In Mac OS X (as well as its predecessor NeXTSTEP, OpenStep, and their derivatives), a package is a directory containing files and/or subdirectories, the whole of which is presented to the user as if it were a single file. On a Macintosh, this means the Finder (the application used to browse the computer's hard drive, like Windows Explorer, GNOME's Nautilus or KDE's Dolphin) shows an icon for the top-level directory of the package, rather than a basic directory icon; if the package represents a document, double-clicking the icon opens it in the associated application. Most Mac applications are also packages, and double-clicking the icon starts the actual executable file contained in it.

The Finder knows how to do this in the same way most similar programs work: by the top-level directory having an extension, and the Finder having been told to treat directories with that extension as a package. When the application is installed on the computer, the Finder is notified of any file types the application knows how to open, and whether they are packages or not. The extension for the package is determined by the author of the application and registered in a file called Info.plist inside the package that makes up the application itself. (Incidentally, this means packages that are not claimed by any application installed on the computer will show as directories with an extension to their name.)

Although Mac users see, and interact with, packages as if they were files, it is possible to access their contents by right-clicking or Ctrl-clicking on the icon of a package. Doing this, a popup menu opens that includes the option Show package contents, which opens a Finder window with the contents of the package directory, allowing the user to work with the actual files and directories inside. This, however, is not something Mac users do on a daily basis—in fact, many probably do not even know this is possible, because they don't know (and don't need to know for their normal computer use) that such things as packages even exist.

All this means, though, that what appears to Mac users to be a file, will look like a directory to anyone using a different operating system. For example, should an application on another operating system be able to open C³ files, its users will see directories rather than files, and so have access to the contents of the package. This is something to take into account when writing C³ import routines for applications on operating systems other than Mac OS X.

File Recognition

These packages have the extension mech and, provided C³ is installed, Mac OS X will determine them to be of the type BattleTech Mech Record Sheet. The following is the full document type information declared in C³ v0.1.7's Info.plist file:

V<dict> <key>CFBundleTypeExtensions</key> <array> <string>mech</string> </array> <key>CFBundleTypeIconFile</key> <string>Record Sheet</string> <key>CFBundleTypeName</key> <string>BattleTech Mech Record Sheet</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSTypeIsPackage</key> <true/> <key>NSDocumentClass</key> <string>BattleMech</string> <key>NSPersistentStoreTypeKey</key> <string>XML</string> </dict>

mechData.py

This is a plain text file which should preferably use UTF-8 encoding (though ASCII is probably not a problem) and any common style of line ending: CR, LF or CR-LF (files produced on a Mac will have LF line endings).

As with the old file, this one contains only one item that is actually used: a Python dictionary defining the ’Mech's data. Only the line with this definition on it is used; all other lines may contain anything desired, as they will be completely ignored. Note: this alone is not entirely safe because executable code can be put into a dictionary, and will get run when the dictionary is executed. For this reason, C³ version 0.1.7 and higher include a security check that tries to make sure the dictionary does not contain anything other than numbers and strings. If it finds a key or value in the dictionary that is neither, it will refuse to open the file and display a warning to the user that includes the option to view a help file entry with more information.

The line containing the ’Mech's data should start with the following string, spelled exactly like this:

mechData = {

Note that there is a single space after mechData and another one after the =-symbol; these are required. There may not be any whitespace before the word mechData.

After the { should come a series of key:value pairs separated by commas; the keys are always strings, while the values may be numbers (integers or floating-point), strings, or dictionaries—see the Python documentation for details on how to write or create all of these: string and numeric literals and dictionaries (note that if a string contains non-ASCII characters, precede it by the letter u to indicate it is a Unicode string). At the end of the dictionary should be the character }.

The order in which the key:value pairs are included in the dictionary does not matter, as dictionaries in Python are not iterable. Whitespace before, between and after keys and values is ignored.

There may be no line breaks anywhere in this dictionary—the Python rule that a logical line can be split over multiple physical lines by ending the latter with a backslash (\) is not followed. However, it is allowed to have more than one mechData = {-line in the file, but each new one would overwrite the data contained in the previous one so that only the last one defined would actually be used.

The following list shows the keys used in the dictionary, the type of value each represents, and (where necessary) their allowed values. Keys must be spelled exactly as shown, and all keys must be present else there is a chance of errors; specify an empty string ("") or 0 for keys that have no real value. Any value that contains a colon (:, Unicode code point U+003A) should have this replaced by a vertical bar symbol (|, Unicode code point 007C). Actual vertical bar symbols occuring in a string should be doubled (to ||) in order to escape them. (The reason for this is C³'s security check, which will mistakenly report files as unsafe if any string contains a colon. However, because the check is based on treating the dictionary as a string and separating keys from values by splitting that string everywhere a colon occurs, it is easier to replace colons than to write a routine that will recognize legal colons inside strings.)

data version
Integer or Float The version number of the data contained in the rest of the dictionary. Note that this does not refer to the revision of the ’Mech's data but to the format of the dictionary, so that C³ can recognize data meant for older or newer versions of the application, and take appropriate action when loading the data (such as converting things that have since been renamed or warning the user about possibly unsupported features in newer data).
This will be determined by simple comparison of the desired data format for the version of C³ to the data version specified: if mechData["data version"] < self.DATA_VERSION_MECH it is a file for an older version of C³, etc. Note: this does mean that version 1.2 < version 1.21 < version 1.3, for example, but version 0.80 == version 0.8.
Due to the way floats are stored on a computer, minor errors may occur; for example, even though the code for C³ currently contains the line DATA_VERSION_MECH = 0.1, save files will actually contain a value of 0.10000000000000001 when that constant is written to them. Programs reading the file should be tolerant of such errors (any Python program which reads the value should not have any issues with this).
Files saved with C³ 0.1.7 contain "data version" = 0.1. (C³ v0.1.7 ignores this entirely because it is the first version that supports this feature, but future versions may not.)
name
String The ’Mech's name.
display image
Integer The number of the image to display for the ’Mech (see mechImages/, below). This should be the number of the image when the contents of the mechImages/ directory inside the package are sorted alphabetically (the Unix way—that is, capital letters before lower-case ones); note that the first image is No. 0 (zero). Negative values are not allowed.
tonnage
Integer {10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95|100} The weight of the ’Mech in tons.
tech base
Integer {0|1} Whether the ’Mech is built using Clan technology (0) or Inner Sphere technology (1).
Additional values may be added later to account for mixed-tech ’Mechs.
costs
Dictionary The various costs for the ’Mech (unadjusted for the pilot's skills or any other factor that does not depend on the ’Mech itself), with the following keys:
bv1
Integer The ’Mech's Battle Value calculated using the original BV rules from Maximum Tech.
bv2
Integer The ’Mech's Battle Value calculated using the BV 2.0 rules from TechManual.
cost
Integer The ’Mech's cost in C-Bills.
cv
Integer The ’Mech's Combat Value calculated using the rules in the BattleTech Tactical Handbook.
origin
Dictionary The source of the ’Mech, with the following keys:
source
String The book, web site, or other source in which the original of the ’Mech can be found.
page
String The page number in the source (if applicable) for the ’Mech.
walking mp
Integer The ’Mech's number of Walking Movement Points; must be 1 or higher.
heat sinks
Integer The number of heat sinks on the ’Mech; must be 0 or higher.
heat sinks double
Integer {0|1} or {False|True} Whether the heat sinks are of the single (0 or False) or double (1 or True) type.
masc
Integer {0|1} or {False|True} Whether or the ’Mech has myomer accelerator signal circuitry (1 or True) or (0 or False). This value is currently ignored in C³
tsm
Integer {0|1} or {False|True} Whether or the ’Mech has triple strength myomers (1 or True) or (0 or False). This value is currently ignored in C³
armor
Dictionary The armor values of each of the ’Mech's hit locations, with the following keys:
h, ct, ctr, lt, ltr, rt, rtr, la, ra, ll, rl
Each a Dictionary Armor value of the location, with the following keys:
current
Integer Amount of armor remaining in the location; must be 0 or higher.
max
Integer Maximum (non-damaged) amount of armor on the location; must be 0 or higher.
internal structure
Dictionary The internal structure values of each of the ’Mech's hit locations, with the following keys:
h, ct, lt, rt, la, ra, ll, rl
Each an Integer Amount of internal structure remaining in the location; must be 0 or higher. (Note that the maximum internal structure is not stored because this is determined from the ’Mech's tonnage.)
equipment
Dictionary The contents of all the critical hit slots on the ’Mech, with the following keys:
h, ll, rl
Each a Dictionary The slots for each location.
The key for each slot is an Integer {1|2|3|4|5|6} The number of the slot.
Each slot a Dictionary The item stored in the slot, with the following keys:
# (that is, the slot number, as an integer {1|2|3|4|5|6})
String Name of the item in the slot. This may be any valid string and is not checked against a database. For items that take up multiple slots, the name is only actually stored in the first slot; when the data is loaded, the slots key is checked to find the number of required slots for the item, and these will be automatically filled directly below the first one. (Items that do not have slots given will be checked against the database to find the required slots, and if they are not in the database they always take up one slot.)
destroyed
Integer {0|1} or {False|True} Whether the item has been destroyed (True or 1) or not (False or 0).
rear
Integer {0|1} or {False|True} Whether the item is rear-mounted (True or 1) or front-mounted (False or 0).
[slots]
Integer How many slots the item requires on the critical hit table. Must be 0 or a positive integer; if 0, the number of slots is determined from C³'s internal equipment list corresponding to the ’Mech's tech base. This key is only needed for a slot that contains a named item, and even then only if the item requires more than one slot.
ct, lt, rt, la, ra
Each a Dictionary The slots for each location.
The key for each slot is an Integer {1|2|3|4|5|6|7|8|9|10|11|12} The number of the slot.
Each slot a Dictionary The item stored in the slot, with the following keys:
# (that is, the slot number, as an integer {1|2|3|4|5|6|7|8|9|10|11|12})
String Name of the item in the slot. This may be any valid string and is not checked against a database. For items that take up multiple slots, the name is only actually stored in the first slot; when the data is loaded, the slots key is checked to find the number of required slots for the item, and these will be automatically filled directly below the first one. (Items that do not have slots given will be checked against the database to find the required slots, and if they are not in the database they always take up one slot.)
destroyed
Integer {0|1} or {False|True} Whether the item has been destroyed (True or 1) or not (False or 0).
rear
Integer {0|1} or {False|True} Whether the item is rear-mounted (True or 1) or front-mounted (False or 0).
[slots]
Integer How many slots the item requires on the critical hit table. Must be 0 or a positive integer; if 0, the number of slots is determined from C³'s internal equipment list corresponding to the ’Mech's tech base. This key is only needed for a slot that contains a named item, and even then only if the item requires more than one slot.

Following is an example of a save file for an Adder (Puma)-Prime OmniMech, with some armor, internal structure and hit locations damaged. Notice that the Python interpreter has prefixed most string values (not string keys) with a u to indicate Unicode strings, even though this is not technically necessary unless the string actually contains characters beyond what can be encoded in plain ASCII. The reason it has done so is because the values were retrieved from the various controls using the stringValue_() method (PyObjC's counterpart to Objective C's - stringValue), which returns an object of type pyobjc_unicode rather than str or unicode.

VmechData = {'tonnage': 35, 'walking mp': 6, 'internal structure': {'rt': 8, 'la': 6, 'h': 3, 'll': 8, 'lt': 4, 'ra': 0, 'rl': 8, 'ct': 11}, 'tsm': False, 'masc': False, 'name': u'Adder-Prime', 'equipment': {'rt': {1: {'destroyed': False, 1: u'XL Engine', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'XL Engine', 'slots': 1, 'rear': False}, 3: {'destroyed': False, 'slots': 2, 3: u'Double Heat Sink', 'rear': False}, 4: {'destroyed': False, 4: '', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Targeting Computer', 'rear': False}, 6: {'destroyed': False, 'slots': 1, 'rear': False, 6: u'Targeting Computer'}, 7: {'destroyed': False, 'slots': 1, 'rear': False, 7: u'Targeting Computer'}, 8: {8: u'Endo Steel', 'destroyed': False, 'slots': 1, 'rear': False}, 9: {'destroyed': False, 9: u'Ferro-Fibrous', 'slots': 1, 'rear': False}, 10: {'destroyed': False, 10: u'Ferro-Fibrous', 'slots': 1, 'rear': False}, 11: {'destroyed': False, 11: u'', 'rear': False}, 12: {'destroyed': False, 12: u'', 'rear': False}}, 'la': {1: {'destroyed': False, 1: u'Shoulder', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'Upper Arm Actuator', 'slots': 1, 'rear': False}, 3: {'destroyed': False, 'slots': 2, 3: u'ER PPC', 'rear': False}, 4: {'destroyed': False, 4: '', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Ferro-Fibrous', 'rear': False}, 6: {'destroyed': False, 'rear': False, 6: u''}, 7: {'destroyed': False, 'rear': False, 7: u''}, 8: {8: u'', 'destroyed': False, 'rear': False}, 9: {'destroyed': False, 9: u'', 'rear': False}, 10: {'destroyed': False, 10: u'', 'rear': False}, 11: {'destroyed': False, 11: u'', 'rear': False}, 12: {'destroyed': False, 12: u'', 'rear': False}}, 'h': {1: {'destroyed': False, 1: u'Life Support', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'Sensors', 'slots': 1, 'rear': False}, 3: {'destroyed': False, 'slots': 1, 3: u'Cockpit', 'rear': False}, 4: {'destroyed': False, 'slots': 1, 4: u'Ferro-Fibrous', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Sensors', 'rear': False}, 6: {'destroyed': False, 'slots': 1, 'rear': False, 6: u'Life Support'}}, 'll': {1: {'destroyed': False, 1: u'Hip', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'Upper Leg Actuator', 'slots': 1, 'rear': False}, 3: {'destroyed': False, 'slots': 1, 3: u'Lower Leg Actuator', 'rear': False}, 4: {'destroyed': False, 'slots': 1, 4: u'Foot Actuator', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Endo Steel', 'rear': False}, 6: {'destroyed': False, 'slots': 1, 'rear': False, 6: u'Endo Steel'}}, 'lt': {1: {'destroyed': True, 1: u'XL Engine', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'XL Engine', 'slots': 1, 'rear': False}, 3: {'destroyed': True, 'slots': 2, 3: u'Double Heat Sink', 'rear': False}, 4: {'destroyed': False, 4: '', 'rear': False}, 5: {'destroyed': False, 'slots': 2, 5: u'Double Heat Sink', 'rear': False}, 6: {'destroyed': False, 'rear': False, 6: ''}, 7: {'destroyed': False, 'slots': 1, 'rear': False, 7: u'Endo Steel'}, 8: {8: u'Ferro-Fibrous', 'destroyed': False, 'slots': 1, 'rear': False}, 9: {'destroyed': False, 9: u'Ferro-Fibrous', 'slots': 1, 'rear': False}, 10: {'destroyed': False, 10: u'', 'rear': False}, 11: {'destroyed': False, 11: u'', 'rear': False}, 12: {'destroyed': False, 12: u'', 'rear': False}}, 'ra': {1: {'destroyed': False, 1: u'Shoulder', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'Upper Arm Actuator', 'slots': 1, 'rear': False}, 3: {'destroyed': True, 'slots': 2, 3: u'ER PPC', 'rear': False}, 4: {'destroyed': False, 4: '', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Ferro-Fibrous', 'rear': False}, 6: {'destroyed': False, 'rear': False, 6: u''}, 7: {'destroyed': False, 'rear': False, 7: u''}, 8: {8: u'', 'destroyed': False, 'rear': False}, 9: {'destroyed': False, 9: u'', 'rear': False}, 10: {'destroyed': False, 10: u'', 'rear': False}, 11: {'destroyed': False, 11: u'', 'rear': False}, 12: {'destroyed': False, 12: u'', 'rear': False}}, 'rl': {1: {'destroyed': False, 1: u'Hip', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'Upper Leg Actuator', 'slots': 1, 'rear': False}, 3: {'destroyed': False, 'slots': 1, 3: u'Lower Leg Actuator', 'rear': False}, 4: {'destroyed': False, 'slots': 1, 4: u'Foot Actuator', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Endo Steel', 'rear': False}, 6: {'destroyed': False, 'slots': 1, 'rear': False, 6: u'Endo Steel'}}, 'ct': {1: {'destroyed': False, 1: u'XL Engine', 'slots': 1, 'rear': False}, 2: {'destroyed': False, 2: u'XL Engine', 'slots': 1, 'rear': False}, 3: {'destroyed': False, 'slots': 1, 3: u'XL Engine', 'rear': False}, 4: {'destroyed': False, 'slots': 1, 4: u'Gyro', 'rear': False}, 5: {'destroyed': False, 'slots': 1, 5: u'Gyro', 'rear': False}, 6: {'destroyed': False, 'slots': 1, 'rear': False, 6: u'Gyro'}, 7: {'destroyed': False, 'slots': 1, 'rear': False, 7: u'Gyro'}, 8: {8: u'XL Engine', 'destroyed': False, 'slots': 1, 'rear': False}, 9: {'destroyed': False, 9: u'XL Engine', 'slots': 1, 'rear': False}, 10: {'destroyed': False, 10: u'XL Engine', 'slots': 1, 'rear': False}, 11: {'destroyed': False, 'slots': 1, 11: u'Flamer', 'rear': False}, 12: {'destroyed': False, 'slots': 1, 12: u'Endo Steel', 'rear': False}}}, 'display image': 0, 'tech base': 0, 'data version': 0.10000000000000001, 'armor': {'rt': {'current': 4, 'max': 12}, 'ltr': {'current': 4, 'max': 4}, 'ctr': {'current': 6, 'max': 6}, 'la': {'current': 10, 'max': 12}, 'h': {'current': 7, 'max': 9}, 'll': {'current': 11, 'max': 14}, 'lt': {'current': 0, 'max': 12}, 'ra': {'current': 0, 'max': 12}, 'rtr': {'current': 4, 'max': 4}, 'rl': {'current': 9, 'max': 14}, 'ct': {'current': 11, 'max': 16}}, 'costs': {'bv2': 2083, 'bv1': 1560, 'cost': 7021688, 'cv': 2476}, 'heat sinks': 10, 'double heat sinks': True, 'original': {'source': u'Technical Readout 3050 (8614)', 'link': u'http|//www.sarna.net/wiki/Adder', 'page': u'18'}}

mechData.xml

This file contains the same data as mechData.py, but in XML format. It is provided so that applications that know nothing about Python dictionaries can still import the data; C³ itself does not use this file other than creating it.

The XML is automatically generated from the Python dictionary and therefore contains the exact same keys and values, with the following notes:

Below is the same ’Mech data as above but now as XML. Notice that the data version is shown as 0.1 rather than 0.10000000000000001 as in the Python dictionary; this is due to the same rounding problems mentioned above.

V<?xml version="1.0" encoding="UTF-8"?> <mechData> <tonnage>35</tonnage> <walking_mp>6</walking_mp> <internal_structure> <rt>8</rt> <la>6</la> <h>3</h> <ll>8</ll> <lt>4</lt> <ra>0</ra> <rl>8</rl> <ct>11</ct> </internal_structure> <tsm>False</tsm> <masc>False</masc> <name>Adder-Prime</name> <equipment> <rt> <n1> <destroyed>False</destroyed> <n1>XL Engine</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>XL Engine</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>False</destroyed> <slots>2</slots> <n3>Double Heat Sink</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <n4></n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Targeting Computer</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n6>Targeting Computer</n6> </n6> <n7> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n7>Targeting Computer</n7> </n7> <n8> <n8>Endo Steel</n8> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> </n8> <n9> <destroyed>False</destroyed> <n9>Ferro-Fibrous</n9> <slots>1</slots> <rear>False</rear> </n9> <n10> <destroyed>False</destroyed> <n10>Ferro-Fibrous</n10> <slots>1</slots> <rear>False</rear> </n10> <n11> <destroyed>False</destroyed> <n11></n11> <rear>False</rear> </n11> <n12> <destroyed>False</destroyed> <n12></n12> <rear>False</rear> </n12> </rt> <la> <n1> <destroyed>False</destroyed> <n1>Shoulder</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>Upper Arm Actuator</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>False</destroyed> <slots>2</slots> <n3>ER PPC</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <n4></n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Ferro-Fibrous</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <rear>False</rear> <n6></n6> </n6> <n7> <destroyed>False</destroyed> <rear>False</rear> <n7></n7> </n7> <n8> <n8></n8> <destroyed>False</destroyed> <rear>False</rear> </n8> <n9> <destroyed>False</destroyed> <n9></n9> <rear>False</rear> </n9> <n10> <destroyed>False</destroyed> <n10></n10> <rear>False</rear> </n10> <n11> <destroyed>False</destroyed> <n11></n11> <rear>False</rear> </n11> <n12> <destroyed>False</destroyed> <n12></n12> <rear>False</rear> </n12> </la> <h> <n1> <destroyed>False</destroyed> <n1>Life Support</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>Sensors</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>False</destroyed> <slots>1</slots> <n3>Cockpit</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <slots>1</slots> <n4>Ferro-Fibrous</n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Sensors</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n6>Life Support</n6> </n6> </h> <ll> <n1> <destroyed>False</destroyed> <n1>Hip</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>Upper Leg Actuator</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>False</destroyed> <slots>1</slots> <n3>Lower Leg Actuator</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <slots>1</slots> <n4>Foot Actuator</n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Endo Steel</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n6>Endo Steel</n6> </n6> </ll> <lt> <n1> <destroyed>True</destroyed> <n1>XL Engine</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>XL Engine</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>True</destroyed> <slots>2</slots> <n3>Double Heat Sink</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <n4></n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>2</slots> <n5>Double Heat Sink</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <rear>False</rear> <n6></n6> </n6> <n7> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n7>Endo Steel</n7> </n7> <n8> <n8>Ferro-Fibrous</n8> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> </n8> <n9> <destroyed>False</destroyed> <n9>Ferro-Fibrous</n9> <slots>1</slots> <rear>False</rear> </n9> <n10> <destroyed>False</destroyed> <n10></n10> <rear>False</rear> </n10> <n11> <destroyed>False</destroyed> <n11></n11> <rear>False</rear> </n11> <n12> <destroyed>False</destroyed> <n12></n12> <rear>False</rear> </n12> </lt> <ra> <n1> <destroyed>False</destroyed> <n1>Shoulder</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>Upper Arm Actuator</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>True</destroyed> <slots>2</slots> <n3>ER PPC</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <n4></n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Ferro-Fibrous</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <rear>False</rear> <n6></n6> </n6> <n7> <destroyed>False</destroyed> <rear>False</rear> <n7></n7> </n7> <n8> <n8></n8> <destroyed>False</destroyed> <rear>False</rear> </n8> <n9> <destroyed>False</destroyed> <n9></n9> <rear>False</rear> </n9> <n10> <destroyed>False</destroyed> <n10></n10> <rear>False</rear> </n10> <n11> <destroyed>False</destroyed> <n11></n11> <rear>False</rear> </n11> <n12> <destroyed>False</destroyed> <n12></n12> <rear>False</rear> </n12> </ra> <rl> <n1> <destroyed>False</destroyed> <n1>Hip</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>Upper Leg Actuator</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>False</destroyed> <slots>1</slots> <n3>Lower Leg Actuator</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <slots>1</slots> <n4>Foot Actuator</n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Endo Steel</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n6>Endo Steel</n6> </n6> </rl> <ct> <n1> <destroyed>False</destroyed> <n1>XL Engine</n1> <slots>1</slots> <rear>False</rear> </n1> <n2> <destroyed>False</destroyed> <n2>XL Engine</n2> <slots>1</slots> <rear>False</rear> </n2> <n3> <destroyed>False</destroyed> <slots>1</slots> <n3>XL Engine</n3> <rear>False</rear> </n3> <n4> <destroyed>False</destroyed> <slots>1</slots> <n4>Gyro</n4> <rear>False</rear> </n4> <n5> <destroyed>False</destroyed> <slots>1</slots> <n5>Gyro</n5> <rear>False</rear> </n5> <n6> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n6>Gyro</n6> </n6> <n7> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> <n7>Gyro</n7> </n7> <n8> <n8>XL Engine</n8> <destroyed>False</destroyed> <slots>1</slots> <rear>False</rear> </n8> <n9> <destroyed>False</destroyed> <n9>XL Engine</n9> <slots>1</slots> <rear>False</rear> </n9> <n10> <destroyed>False</destroyed> <n10>XL Engine</n10> <slots>1</slots> <rear>False</rear> </n10> <n11> <destroyed>False</destroyed> <slots>1</slots> <n11>Flamer</n11> <rear>False</rear> </n11> <n12> <destroyed>False</destroyed> <slots>1</slots> <n12>Endo Steel</n12> <rear>False</rear> </n12> </ct> </equipment> <display_image>0</display_image> <tech_base>0</tech_base> <data_version>0.1</data_version> <armor> <rt> <current>4</current> <max>12</max> </rt> <ltr> <current>4</current> <max>4</max> </ltr> <ctr> <current>6</current> <max>6</max> </ctr> <la> <current>10</current> <max>12</max> </la> <h> <current>7</current> <max>9</max> </h> <ll> <current>11</current> <max>14</max> </ll> <lt> <current>0</current> <max>12</max> </lt> <ra> <current>0</current> <max>12</max> </ra> <rtr> <current>4</current> <max>4</max> </rtr> <rl> <current>9</current> <max>14</max> </rl> <ct> <current>11</current> <max>16</max> </ct> </armor> <costs> <bv2>2083</bv2> <bv1>1560</bv1> <cost>7021688</cost> <cv>2476</cv> </costs> <heat_sinks>10</heat_sinks> <double_heat_sinks>True</double_heat_sinks> <original> <source>Technical Readout 3050 (8614)</source> <link>http://www.sarna.net/wiki/Adder</link> <page>18</page> </original> </mechData>

mechImages/

This is a directory in which one or more images of the ’Mech can be put, in one of the following file formats:

The extension of the files is not relevant, since the file type should be determined from its contents regardless of its filename or extension (C³ uses the Python imghdr module, which explains the file formats: they are the overlap between those recognized by imghdr and those supported by Cocoa).

C³ itself saves all images in this directory as LZW-compressed TIFF files, with the same basic filename as the package (minus its mech extension), followed by a number and then the extension tiff added (for example, if the package is called LCT-1V Locust.mech, the first image will be LCT-1V Locust 1.tiff, the second LCT-1V Locust 2.tiff, etc.).

C³ will attempt to load all images it finds in this directory into the image for the ’Mech on the ’Mech & Warrior Data tab. Files in an unrecognized format will be ignored.

It is recommended not to store images that are much larger (in height and width) than the image view into which they are loaded in C³, which is 138 pixels high and wide in C³ version 0.1.7. Though in C³ the image height and width are automatically scaled down (but not up) proportionally to fit in the available area, storing overly-large images is a waste of disk space.

If the mechImages directory would be empty, it may be omitted from the package.

pilotData.py

This file is similar to mechData.py and loaded in an almost identical way. It contains data about the MechWarrior, such as name and skill levels.

The line containing the pilot's data should start with the following string, spelled exactly like this:

pilotData = {

Note that there is a single space after pilotData and another one after the =-symbol; these are required. There may not be any whitespace before the word pilotData.

The following list shows the keys used in the dictionary, the type of value each represents, and (where necessary) their allowed values. Keys must be spelled exactly as shown, and all keys must be present else there is a chance of errors; specify an empty string ("") or 0 for keys that have no real value.

data version
Integer or Float The version number of the data contained in the rest of the dictionary. The same notes apply as for data version in mechData.py, but in C³, the value of this key is compared against the constant common.DATA_VERSION_PILOT.
Files saves with C³ 0.1.7 contain "data version" = 0.1. (C³ v0.1.7 ignores this entirely because it is the first version that supports this feature, but future versions may not.)
name
String The MechWarrior's name.
gunnery
Integer The Gunnery Skill level of the MechWarrior.
piloting
Integer The Piloting Skill level of the MechWarrior.
hits
Integer {0|1|2|3|4|5|6} The number of hits (points of damage) the MechWarrior has sustained.

Following is an example of a pilotData.py file:

pilotData = {'data version': 0.10000000000000001, 'hits': 0, 'name': u'John Smith', 'piloting': 4, 'gunnery': 3}

pilotData.xml

This file contains the same data as pilotData.py, but in XML format. It is provided so that applications that know nothing about Python dictionaries can still import the data; C³ itself does not use this file.

See the notes for mechData.xml, above for some things to beware of when parsing this file.

V<?xml version="1.0" encoding="UTF-8"?> <pilotData> <data_version>0.1</data_version> <hits>0</hits> <name>John Smith</name> <piloting>4</piloting> <gunnery>3</gunnery> </pilotData>