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.
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.
Up to and including version 0.1.6, C³ saved its data in plain text files containing a Python dictionary.
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:
<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>
The file is loaded by the following bit of Python code:
f = 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.
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
tonnage
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
0
|1
} Whether the ’Mech is built using Clan technology (0
) or Inner Sphere technology (1
).bv
cost
engine rating
10
–400
in steps of 5} The rating of the ’Mech's engine (this is equal to its tonnage multiplier by its walking MP).jump mp
heat sinks
heat sinks double
0
|1
} or {False
|True
} Whether the heat sinks are of the single (0
or False
) or double (1
or True
) type.armor
h
, ct
, ctr
, lt
, ltr
, rt
, rtr
, la
, ra
, ll
, rl
equipment
h1
through h6
ct1
through ct12
lt1
through lt12
rt1
through rt12
la1
through la12
ra1
through ra12
ll1
through ll6
rl1
through rl6
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).
mechData = {'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}
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.)
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
, 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.
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:
<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>
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
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.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)."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
display image
tonnage
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
0
|1
} Whether the ’Mech is built using Clan technology (0
) or Inner Sphere technology (1
).costs
bv1
bv2
cost
cv
origin
source
page
walking mp
heat sinks
heat sinks double
0
|1
} or {False
|True
} Whether the heat sinks are of the single (0
or False
) or double (1
or True
) type.masc
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
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
h
, ct
, ctr
, lt
, ltr
, rt
, rtr
, la
, ra
, ll
, rl
current
max
internal structure
h
, ct
, lt
, rt
, la
, ra
, ll
, rl
equipment
h
, ll
, rl
1
|2
|3
|4
|5
|6
} The number of the slot.#
(that is, the slot number, as an integer {1
|2
|3
|4
|5
|6
})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
0
|1
} or {False
|True
} Whether the item has been destroyed (True
or 1
) or not (False
or 0
).rear
0
|1
} or {False
|True
} Whether the item is rear-mounted (True
or 1
) or front-mounted (False
or 0
).slots
]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
1
|2
|3
|4
|5
|6
|7
|8
|9
|10
|11
|12
} The number of the slot.#
(that is, the slot number, as an integer {1
|2
|3
|4
|5
|6
|7
|8
|9
|10
|11
|12
})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
0
|1
} or {False
|True
} Whether the item has been destroyed (True
or 1
) or not (False
or 0
).rear
0
|1
} or {False
|True
} Whether the item is rear-mounted (True
or 1
) or front-mounted (False
or 0
).slots
]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
.
mechData = {'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'}}
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:
mechData
;walking mp
becoming the element name walking_mp
for example) because spaces are not allowed in XML element names;0
through 9
) are prefixed with the letter n
because XML element names may not begin with a number (for example, the key 10
becoming the element name n10
);xml
(regardless of case), an x
is prefixed to it to make it xxml
, because once again, XML element names may not begin that way;True
and False
, respectively (in other words, the boolean values are replaced by strings);&
, <
, >
, '
and "
respectively;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.
<?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>
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.
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
data version
in mechData.py, but in C³, the value of this key is compared against the constant
common.DATA_VERSION_PILOT
."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
gunnery
piloting
hits
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}
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.
<?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>