DOCUMENTATION FOR DATFILES MODULE
Part 6: Reading Attributes, FX, Campaign Definitions, Display Strings, and Game Setup, with Examples

By Stumpy

Once is a while, a scripter might have some reason to know the data in the DAT files for attributes, campaign definitions, or FX as they are seen on the corresponding FFEdit pages. What is the prestige cost of an attribute, what mission came before the current one, is there a melee FX that plays from the left hand? Et cetera.

The module file datfiles.py can go in the Scripts directory. Any python file that uses these functions should import datfiles or from datfiles import *.

 

Reading attributes.dat, campdef.dat, fx.dat, strings.dat and game setup

Notes On Use

For calls to most of the following functions made in the game, not specifying FileName will cause the function to try and read the appropriate DAT file for the current mod. Generally, this means these functions can be called without any arguments.

None of these functions in the datfiles module use the ff, js, cshelper or other Freedom Force-specific modules, so they can be run from a python shell outside the game to summarize or explore DAT file entries, if desired. In that case, FileName must be specified.

The Functions

The following three functions read information from attributes.dat, campdef.dat, and fx.dat files and return it in dictionary objects. They each can take any of the following arguments.

FileName is the path and filename of the DAT file to be read. As noted above, it can usually be left blank when used during a running mission.

ForceRead forces the DAT file to be re-read, even if it has been read before.

verbose prints some info as each object is read from the DAT file.

Campaign_ReadAttributes(FileName='',ForceRead=0,verbose=0)

Returns a dictionary whose keys are the character names in the attributes.dat file. Each value in that dictionary is the prestige cost of the attribute.

Campaign_ReadCampaignDefinitions(FileName='',ForceRead=0,verbose=0)

Returns a dictionary with a 'totalMissions' key whose value is the total number of missions (including sub-missions) in the campaign; a 'missions' key which is a list of strings of the mission names, in mission order; and one key for each mission and submission whose name is that mission's mission name (as listed in the 'missions' list).

These missions keys each correspond to a dictionary that itself has three keys. There is a 'missionName' key whose string with that mission's name (that will be the name of the sub-folder in the Missions directory, for example). There is an 'isSubmission' key whose value is 1 if the mission is a sub-mission, 0 otherwise. There is a 'numAllowed' key whose value is the maximum number of heroes the player can choose for his squad in the squad-selection screen. There is a 'required' key whose value is a list of strings which are the names of heroes required for the mission and a similar 'disallowed' key whose value is a list of heroes that will be unavailable to the player at the squad-selection screen.

Campaign_ReadFX(FileName='',ForceRead=0,verbose=0)

Returns a dictionary whose keys are the names of the FX and the corresponding values are themselves dictionaries that have several keys.

The 'FXName', 'NIF', 'NodeStart', 'NodeCore', 'NodeEnd', and 'NodeLaunch' keys have the string values shown on their FFEdit pages. 'NodesTrackRot' is a logically ORed value whose bits from (low to high) correspond to whether the start, core, end, and launch nodes track the mesh rotation. (Note that the launch nodes are new to FFvsT3R and the corresponding keys will not be present in the dictionaries for the first game.)

The 'PowerType' key corresponds to a number showing the power type the FX is for; it will be one of the PT_POWER_TYPES values described in the Campaign_ReadPowers() page. Similarly, the 'SubType' key corresponds to the power subtype for ranged powers and will have one of the PT_ATTACK_SUBTYPES values.

Campaign_ReadLangDAT(FileName='',ForceRead=0,verbose=0)

Returns a dictionary with the strings.dat information in it. That is, the keys of the dictionary are the tags of each string and the corresponding value for that key is the text describing the tag. Note that the tag strings are generally lower-case, though the associated strings can be mixed case.

This and the following function can be useful for generating friendlier in game strings, as might be used for speech, for Mission_StatusText() messages, and for custom commands.

Campaign_FindDisplayString(tag,FileName='')

This is a direct index into the dictionary returned by the previous function. It returns the description string associated with the tag. The tag can contain upper-case characters, but they are converted to lower-case for purposes of finding the associated description string.

If the tag does not exist as part of the strings.dat file, None is returned. That can occur even if it is in strings.txt , if the language files have not been properly recompiled.

ffver(default = 0)

Determine which version of FF is running. Returns default if not run from within the game. Otherwise returns 1 for Freedom Force and 2 for Freedom Force vs. The Third Reich.

GetFFPath(gameVersion=-1)

Returns FF directory when run from within the game. If run from outside the game, gameVersion must be specified as either 1 or 2 and it will grab the FF directory from the Windows registry.

WARNING: If run from within the game, gameVersion is ignored and the version of the running game is returned.

GetModPath(ForceCheck=0)

Find the path where the basic mod DATs (e.g. characters, powers, objects, etc.) are when run during a mission. This path is returned lower-case.

GetWinTempPath(ForceCheck=0,ModPath='')

Find the path where temporary files are saved. This path is returned lower-case. This is NOT TESTED for the first game! Intended for use with the second game where this stuff is stored in places like 'C:\Documents and Settings\vivalalibertad\Local Settings\Application Data\Irrational Games\Freedom Force vs the 3rd Reich\'. Warning:Need to see if this works on pre-Win2000 machines.

If AssumeVersion is not 0, we assume that to be the desired version and return a path accordingly. This makes some assumptions about the location of the install (for version 2, for version 1 it just returns the mod path).

GetMissionDatFile(ForceCheck=0)

Try to guess where the current mission.dat file is (when run during a mission). Note: Apparently, skirmish missions run from a mod can use maps and mission data from the main campaign directory, so we return that if we can't find anything in the corresponding mod directory.

NOTE: FFvsT3R supports the zipfile module for scripting, so this function checks for the mission.dat file and, if it does not find it, attempts to unzip the files for that entire mission. I have found instability if only the mission.dat file is unzipped.

GetDatFile(fname)

For the basic mod DATs (e.g. characters, powers, objects, etc.), try to determine the full filepath (when run during a mission). If it doesn't find a current modpath tries to use the main campaign (the Data mod). fname is the local DAT file name, e.g. 'objects.dat', without any path information.

 

Examples

Example 1, Typical Entries for Each Function's Dictionary

Something very straightforward. To show all the show the typical dictionary returned by this function, we might look at the FX entry for one of the minion powers.

Code:

>>> import datfiles
>>> print datfiles.Campaign_ReadFX()['alienguard_plasmarocket']
{'PowerType': 2, 'SubType': 2, 'NodeStart': 'weapon', 'NIF': 'library\\fx\\alien_rocketguard\\plasma_rocket', 'NodeCore': 'weapon', 'FXName': 'alienguard_plasmarocket', 'NodesTrackRot': 0}

And a typical attribute prestige cost

Code:

>>> import datfiles
>>> print datfiles.Campaign_ReadAttributes()['blitzkrieg']
200

And, as a campaign definition example from the new game, this is the list of campaign missions and the entry for the Cuba mission.

Code:

>>> import datfiles
>>> CDefs = datfiles.Campaign_ReadCampaignDefinitions()
>>> print CDefs['missions']
['01_dream', '02_cuba', '03a_red', '03b_inside', '03c_inside2', '04_winter', '05a_berlin', '05b_fortissimo', '06a_redsun', '06b_codebreak', '07a_euros', '07b_bullet', '08a_skyking', '08b_explosives', '08c_waiting', '08d_witness', '09a_blitzkrieg', '09b_entropy', '10_symphony', '11_elementals', '12_disappear', '12b_timemaster']
>>> print CDefs['02_cuba']
{'isSubmission': 0, 'numAllowed': 3, 'required': ['alchemiss', 'el_diablo', 'mentor'], 'missionName': '02_cuba', 'disallowed': []}

Note that the keys of a python dictionary are not usually sorted.

(Of course, this is assuming we have unzipped the attributes, FX, and campdef DAT files from data.ff into the Freedom Force\Data directory.)

Example 2, Looking Up In-Game Strings

The following illustrates getting the strings a player would see in-game for an attribute and for a built-in character.

Code:

>>> import datfiles
>>> print Campaign_FindDisplayString('attrib_airscout_01')
aerial scout
>>> print Campaign_FindDisplayString('the_ant_desc_01')
college outcast imbued with the powers of his insect friends

 

Notes

First, for this function to work, there must actually be an powers.dat file, either in the mod folder for whatever mission is running or where specified by FileName.

I wrote this module with an eye on keeping delays minimal. Because of that, the Campaign_ReadWhatever() function try to avoid re-reading the powers.dat file every time it is called and that should keep disk I/O pretty low. The first read, however, isn't necessarily quick. On my laptop machine, I read the 200 KB FFvsT3R main campaign fx.dat (the first time) in about 0.75 seconds and the small 15 KB campdef.dat file in about 0.02 seconds. Subsequent calls are much faster (under a millisecond). If this function is to be called during a mission, it is a good idea to put a call to it during the (or, better yet to Campaign_ReadCharacterData(), which reads the characters, objects, and powers DAT files all at once) in the onPostInit() after the cut-scene, so that the file is read in the background.

Finally, I didn't fully decode every byte of the DAT files. There was certain information that I wanted to extract and I tried to ignore the rest. However, that means that there may be parts of a DAT file that confuse the reader functions, though I have tested each of these functions at least on the main campaign DATs. If you have a working DAT file (everything looks fine in FFEdit) with which these functions do not work, PM me and I will check into it.