Event and Plot Handler Module

This page is a discussion of the Event and Plot Handler module.

The Event and Plot Handler module is designed to handle the timing of planned events within the game, such as when messages are first available at Starport or when a star undergoes a catastrophic flare (to use an example from SF1). The basic architecture of the module is similar to other modules within the game that handle basic data types (such as integers and strings) and hash tables / dictionaries. This module is required by the core module and has an effect on most of the other modules in the game, particularly the Starport Module, the Encounter Module, and the Planetary Exploration Module. Victory conditions, objectives, and special occurrences are set via the Event and Plot Handler module; as such, it is vitally important to the game. All code for the Event and Plot Handler Module is located in the sf3_events.py file.

Summary Description
A clock object is created during the game's initial setup, and remains in memory until the game routine ends. Information on all in-game events are loaded into a dictionary, as well as any programmer-defined variables upon which certain events may be based. The clock will either be reset to the current time and hour when a previous game is loaded, or allowed to proceed to a set of default values if a new game is indicated. Other functions in the game will call the clock object for reports on the current time as necessary. A call to advance the clock triggers an "hourly check" or "event check" function, both of which procedurally goes down the event list to see if an event is scheduled to take place (the time check function also checks for certain scheduled events based on the player's current location). Events are based on "triggers", all of which must be fulfilled prior to any described "effects" actually occurring within the game.

Data Structure of the gameClock Object
The following list is an indication of the various variables and methods that will be included in the gameClock object; these are suggested methods and variables. gameClock objects are meant to be used as direct child objects of the game's core module, with no child objects. Only one gameClock object is are meant to be used in the game, and is meant to be loaded by the core module when the game routine initializes. The gameClock object's data structure is as follows:


 * Class: gameClock
 * Hash/Dictionary: hCalendar
 * Class: Event (see data structure discussion, below)
 * Hash/Dictionary: hFlagpole
 * Programmer-Defined Variables
 * Integer: nHour
 * Integer: nDay
 * Integer: nMonth
 * Integer: nYear
 * Method: _init(self, inHr, inDay, inMo, inYr)_
 * Method: advanceTheClock(self)
 * Method: sz_curTime (self)
 * Method: hourlyCheck
 * Method: checkTheCalendar(bNewHour, bNewDay, bNewWeek, bNewMonth)

Data Structure of the Event Object
The following list is an indication of the various variables and methods that will be included in an event object. This list contains suggested methods and variables. Event objects are meant to be used as children of the gameClock object, and only have XML parsers as child object (used to properly parse the XML files containing the pertinent data). Multiple Event objects are meant to be used in the game, which are created and seeded by the gameClock object as that object is being initialized (at the start of the game routine). Their data structure is as follows:


 * Class: Event
 * String: szTimeStamp
 * List/Vector: vArtifacts
 * ''Tuple/Array: Artifact and Action
 * String: Artifact_Name
 * String: Keyword (either "Possesses" or "Seed")''
 * List/Vector: vPlayerCoords
 * ''Tuple/Array: Player's Coordinate Set
 * String: Player Sector
 * Integer: Player X Coordinate
 * Integer: Player Y Coordinate
 * Integer: Player Orbit
 * Integer: Player Latitude
 * Integer: Player Longitude''
 * Integer: nPlayerZone
 * List/Vector: vEncSpecies
 * String: Species Names Causing a Trigger
 * List/Vector: vVariables
 * ''Tuple/Array: Variables, Adjustments and Actions
 * String: Program Variable Name
 * Flag/Integer/Float/String: Specified Value
 * String: Action (either Set, Adjust, Check, or Encprob (for changing encounter probabilities))''
 * List/Vector: vEventCoords
 * ''Tuple/Array: Event Coordinate Set
 * String: Event Sector
 * Integer: Event X Coordinate
 * Integer: Event Y Coordinate
 * Integer: Event Orbit
 * Integer: Event Latitude
 * Integer: Event Longitude''
 * Integer: nEventZone
 * List/Vector: vMessages
 * ''Tuple/Array: Message Specifics
 * String: Message_ID
 * String: Action (can be Unlock, Show or Seed)''
 * List/Vector: vShadows
 * ''Tuple/Array: Shadowing Specifics
 * Tuple/Array: Star or Planet Coordinate Set -OR- String: Starport or Civilization ID
 * String: Sector Name
 * Integer: X Coordinate
 * Integer: Y Coordinate
 * Integer: Orbital Lane
 * String: Action (Shadow or Unshadow)''
 * List/Vector: vAnims
 * String: Animation File Names in order of display
 * List/Vector: vTriggers
 * String: Encounter ID OR Acheivement ID
 * List/Vector: vSequences
 * String: Sequence Filenames, in order of execution
 * Flag: bEndgame=False
 * Flag: bOnceonly=False

_init(self, inHr, inDay, inMo, inYr)_
The gameClock's initializer begins by declaring the four main timekeeping holder integers, nHour, nDay, nMonth and nYear. The hCalendar and hFlagpole dictionaries are also created at this time as holders. Depending upon the arguments passed to the initializer, the values of the clock are then set to a pre-determined time by setting a holder integer's value equal to that of the corresponding argument (e.g. nHour is set equal to the value of inHr, and so forth). Should no arguments be passed to the initializer, the clock will be set to a default time value of 01.00-01-4655; this will be set programmatically, so there will always be a value set for the in-game clock. Once the time has been set, the routine will check to make sure that a valid time entry has been passed to each variable. Should an invalid time variable be detected (an hour value less than zero or above 23, a day value less than zero or above 28, or a month value less than zero or above 10), the corresponding value will be automatically reset to the lowest possible value for that variable (i.e. nHour will be set to zero, nDay to one, and nMonth to one).

The routine will then create an XML parser and tell the parser to ignore XML namespaces (this is used to ease the accessibility of the XML data). Once that's done, the method creates a SAX content handler object, which will then parse the event_list.xml file thereby seeding the hCalendar dictionary with the data from that file. Once that dictionary is seeded, a new content handler performs the same actions with the custom_variables.xml file to seed the hFlagpole dictionary. Once the dictionary is seeded with the necessary information, the initializer routine is complete and will go out of scope. Once created, the gameClock object itself will remain in active memory until the game routine is killed, but its data may be overwritten at any time if a new game is begun or if another game is loaded.

advanceTheClock(self)
This method's purpose is to advance the game clock and to check to make sure that a valid time stamp is maintained at all times. When called, the method declares local flags, bNewMonth, bNewWeek, and bNewDay, setting each of these flags to a value of False. The method then adds one to the value of the current hour. The method then goes through a series of if statements. If an hour above the 23rd hour of the day is currently indicated, the hour is reset to zero, the day counter is increased by one, and the bNewDay flag is set to True. The day is then checked; if it's value is above 28, it is reset to 1, the month counter is increased by one, and the bNewMonth flag is set to True. The month counter is then checked; if the value of the month is above 10, it is reset to one and the year counter is increased by one. Finally, the routine will check the modulus of the current value of the day counter divided by seven. If the modulus equals one, the bNewWeek flag is set to True. Regardless of whether or not these flags are activated, a call is made to the hourlyCheck method and then the checkTheCalendar method prior to the method going out of scope.

sz_curTime (self):
This method's purpose is to prepare the current time data stored by the gameClock object, turning it into a properly formatted string for on-screen display. When called, a local method simply constructs a string, recasting the four gameClock integers as string elements. nDay is appended to this new string first, followed by a period, which is then followed by nHour. A hyphen comes next, followed by nMonth. Finally, after another hyphen, nYear is appended and rounds out the contents of the string. This string is then passed back to the caller and the method goes out of scope at that point.

hourlyCheck
This method's purpose is to go through a short list of possible "cases" of things that can occur during the course of a game when a new game hour begins based upon the player's location and send calls to other modules as appropriate. It is called by the advanceTheClock method prior to that method going out of scope. When called, the first thing the method does is check the value of the player's location enumeration (for details, see the discussion under the Starship Module). Which set of instructions are executed is dependent upon this enumerated value. If the ship's location is either HYPERSPACE or IN_SYSTEM, a call is made to the appropriate transit module (the Hyperspace Module for HYPERSPACE and the Inter-Planetary Travel Module for IN_SYSTEM) to activate the appropriate encounterCheck method (for details, see the discussions under the Hyperspace Module and the Inter-Planetary Travel Module. If the ship's location is LANDED, a call will be made to the Planetary Exploration module to activate its wxCheck method (for details, see the discussion under the Planetary Exploration Module). Should the location enumeration be anything else (i.e. IN_ORBIT, STARPORT or ENCOUNTER), the routine does nothing (there shouldn't be any cases where this routine is called when the ship's location is ENCOUNTER, but this last generic "catch-all" case will be included in case that ever changes.). Regardless of the specific case, the checkTheCalendar method is called last, with the argument for the bNewHour boolean set to True. The routine passes control back to the advanceTheClock method once the checkTheCalendar method has been passed back.

checkTheCalendar(bNewHour, bNewDay, bNewWeek, bNewMonth)
The purpose of this method is to go through the list of programmed events, check to see whether or not the trigger conditions for those events have been fulfilled, and execute those events if necessary. The code for almost all of the game's modules incorporates at least one call to this method; a few of the modules that call this method include the Main Menu Module, Hyperspace Module, Planetary Exploration Module, Starport Module, and Encounter Module. The method has four arguments; by default, these are set to False (only the advanceTheClock method and hourlyCheck method should be allowed to set any of these flags to True). When called, the method begins by calling the sz_curTime and putting the returned value into a local holder. Next, the method retrieves the keys of all the entries in the event object's hCalendar dictionary, putting them in a local holder list. For each entry in the list, the indicated event object's szTimeStamp string is checked versus the values of the method's arguments; the indicated event object is put into a second local holder list if certain criteria are met. If bNewHour is set to True, all events with the szTimeStamp value of "hourly" are pulled. The same is true with the value of "daily" if bNewDay is True, "weekly" if bNewWeek is True, and "monthly" if bNewMonth is True. Any event that matches the value of the local date holder is pulled. Finally, if all four of the flags are set to False, any event that has a szTimeStamp value other than "hourly", "daily", "weekly" or "monthly" is pulled. At this point, the method will check the length of the second local holder list. If it's length is zero (i.e. if no events are pulled), then the method simply returns and nothing happens at that point.

If there are event records in the second holder list, the method will begin checking each event record one at a time. For each event, the method will begin checking the remaining trigger conditions for the event. It will begin by retrieving the player's current location from the Player's Fleet object (including latitude and longitude information from their terrain vehicle, should their flagship's location enum equal ON_SURFACE) and comparing that data to the trigger conditions indicated by the event object's vPlayerCoords list. If the vPlayerCoords list is empty or if the information matches the retrieved data (or at least if the player's coordinates are within the ranges specified in the vPlayerCoords list), the method proceeds to the next trigger condition to be checked. Otherwise, the method will check to see if the player is at least in one of the indicated Sectors for the event; if they are, the method will calculate the distance between the player's current position and the centerpoint of the event ranges; if that value is less than or equal to the value of the event's object's nPlayerZone integer, the method proceeds to the next trigger condition to be checked. If the value is greater than the value of the event's object's nPlayerZone integer or if the player is not in an indicated Sector, the method goes to the next event record; it does not trigger any of the effects indicated by the event.

Next, the method checks the Event object's vArtifacts list. If that list is empty, the method proceeds to the next trigger condition to be checked. Otherwise, the method will check the tuples in the list to see if any of them have the "possesses" keyword. If none of them do, these are effects instead of triggers and the method can ignore them, proceeding to the next trigger condition. Otherwise, the method will systematically check the contents of the cargo bays of all of the ships in the player's fleet for the indicated artifact. If the method finds the artifact in any ship in the player's Fleet object, the method immediately proceeds to the next trigger condition. Otherwise, it goes to the next event record at that point; it does not trigger any of the effects indicated by the event.

The method then checks the Event object's vEncSpecies list. If that list is empty, the method proceeds to the final check. Otherwise, the method will check the player's location enumeration; if it is anything besides ENCOUNTER, the method will go the next event record at that point without triggering any of the effects indicated by the event. If the player is in an encounter, the method will check to see if the name of the species encountered matches the name of one of the entries in the vEncSpecies list. If so, the method proceeds to the final check; otherwise, it proceeds to the next event record without triggering any effects.

Finally, the method will check the Event object's vVariables list. If that list is empty, then all of the event's trigger conditions have been fulfilled and the event will "fire" (as described below). Otherwise, the method will check the tuples in the list to see if any of them have the "check" keyword. If none of them do, these are effects instead of triggers; all of the event's trigger conditions have been fulfilled and the event will "fire". Otherwise, the method will check the value of the indicated variable, whether it is one in the gameClock object's hFlagpole dictionary or if it is a defined internal variable. If the value matches the amount indicated in the vVariables list, all of the event's trigger conditions have been fulfilled and the event will "fire". Otherwise, the method goes to the next event record at that point; it does not trigger any of the effects indicated by the event.

If the method has reached this point without proceeding to the next Event record, all trigger conditions for the event have been fulfilled and it is allowed to "fire" (all effects go into effect). At this point, the remaining object lists will be checked for data on what effects to execute. The method first checks to see if the vArtifacts list is empty. If it is, then the method proceeds to the next action without doing anything else. Otherwise, the method will check the tuples in the list to see if any of them have the "seed" keyword. If not, the method proceeds to the next action. If so, the method will retrieve the event location information from the Event object and will send that information along with the specified name of the artifact to the seedArtifacts(name, location) method (for details of the functioning of this method, see the discussion under the Planetary Exploration Module).

Next, the method checks the length of the Event object's vAnims list. If it is empty, the method proceeds to the next action. Otherwise, for each entry in the list in turn, the method will call the core module's animation display method, seeding the filenames to be displayed to that method one at a time. At the time of this writing, the name of this method is unknown, largely because the core module has not yet been fully defined.

The method then checks the Event object's vVariables list for items with the "set", "adjust" or "encprob" keywords. If there are no entries with these keywords or if the list is empty, the method skips this step. When one of these keywords is encountered, what happens depends on the keyword. If the "set" keyword is encountered, the method will change the value of the indicated variable to the value indicated. If the "adjust" keyword is encountered, the method will add the indicated value to the current value of that variable (note that this keyword can only be used for addition and subtraction functions). If the "encprob" keyword is encountered, the method will call the Encounter module's setProbabilities(species, prob) method (see that module for further discussion), passing along the indicated species and value as arguments to the function.

Next, the method checks the Event object's vMessages list. If there are no entries in the list, the method skips this step. Otherwise, the method takes action based on the indicated action keyword. If the keyword is "show", the method will check to see which user interface is currently active and will call the appropriate method that will allow the message to be instantly displayed. If the keyword is "unlock", the method will search for the provided message_ID in the message storage lists of the Starport and Communications Modules; when the message_ID is found, a call will be sent to the involved module's unlockMsg(msg_ID) method. If the keyword is "seed", the method will get the information on the event's location and send that information along with the message's ID to the Planetary Exploration Module's seedMessages(ID, location) method.

The method will then check the Event object's vShadows list. If there are no entries in the list, the method skips this step. Otherwise, the method takes action based on the action keyword provided. The method will check the length of the tuple in an attempt to find what is being affected: if the length is one, the method will search the data of all Sector objects for a matching Starport. Should it fail to find a match, it will then check for a matching civilization. Should it still fail to find a match, nothing happens and the method proceeds to the next step. A tuple length of three will indicate a star system; the first element of the tuple indicates the Sector and the other two elements are coordinates. The method will search for a matching system at that point, and will do nothing if a match is not found. Finally, a tuple length of four represents a planet; the first three elements are the same data as present for a star system, with the fourth element indicating a specific world. Once again, if a match is not found, the method does nothing. In all cases, if a match is found and the action word is "shadow", that element's bShadow flag will be set to True; it will be set to False in the event that the action word is "unshadow". In the case of the shadowing/unshadowing of a civilization, an additional call is made to the Encounter Handler object's setProbabilities(species, prob) method to change the shadowing status of the indicated civilization.

The length of the vTriggers list is checked next and no action is taken if there are no entries. Otherwise, the routine will call the Encounter Handler object's checkEncounters(ID) method. Should a match be found by the Encounter Handler object, the indicated encounter automatically begins; for more details, see the discussion under that module. If a match is not found, the routine will then check the hFlagpole dictionary for a matching variable name; if it is found, that variable's value is set to True. If not, or if it cannot set the value to True, the method skips this step and moves on to the next one. ''To properly handle achievements as I think they're intended to run, the trigger achievement event will need to be coupled with a "show_animation" event, and possibly an "adjust_variable" event if we are keeping track of some kind of meta-score (such as a player "rank") through the achievements. This may make the whole notion of a "trigger_achievement" event redundant, capable of being handled by a "set_variable" event; we'll keep it for now, in case we change something or decide it best to keep a separate command for achievements.''

Next, the length of the vSequences list is checked; if there are no entries in this list, the method skips this step and proceeds to the final check. Otherwise, in the order in which they are listed, the method will check for the existence of an Python extension module with the given name, and will try to run the main method of that module. Should the module not exist, or should it not contain a main method, the method simply skips to the next entry in the list. This can be used to execute scripts that are not necessarily programmed into the game itself; using these scripts will require intimate knowledge of the game's inner workings, and may ultimately require their own editor program.

Finally, the method will check the two loose flags of the Event object, bEndgame and bOnceonly. If bOnceOnly is True, the command will be sent to delete the key corresponding to the Event object from the hCalendar dictionary, removing the Event object from that dictionary. If bEndgame is True, the method will call the Main Menu module and instruct it to set its bGameInProgress flag to False; this will prevent the game from displaying the Main Menu option to save the game. Game control is then passed directly to the Main Menu module. The method will do nothing if a flag is False in both cases.

Once the flags have been checked, all events should have been checked and executed. Control of the game passes back to the calling method at that point.

XML
The Event Handler object is heavily dependent upon input from two XML files; these files define most of the events that can occur during the course of gameplay, and should set things up in such a manner that producing a future sequel would be possible simply by changing the XML files only (i.e. no future coding would be strictly necessary). Using XML to store this data, of course, keeps the module completely flexible up until SF3's design is finalized (i.e. definable events can be added and removed from the game freely based upon what data is available in the XML files). There are two XML handlers used by the Event Handler and two XML file types aree needed for its operation (the files event_list.xml and custom_variables.xml). The following briefly goes over what data is located in these XML file types.

event_list.xml
The file "event_list.xml" is designed as a master list of events that can take place within the framework of the game, acting as a checklist to introduce new plot elements or to adjust various statistics. Under the root element, actual entries in the XML file are empty elements with the name "event". Entries may have multiple elements, which are divided up into two broad categories: "triggers" and "effects" (neither of these words are actually used in the XML code). An event may have as many trigger conditions and effects as the coder wishes to cover, but to be valid an event must contain at least one trigger and one effect. The valid tags for each category and their usage are as follows:

Triggers :
 * init=: specifies the event is triggered when a new game begins.
 * date=: specifies the event will trigger on a specific date (provided all other triggers are also valid).
 * hourly=: specifies the event will trigger each hour in game-time (provided all other triggers are also valid).
 * daily=: specifies the event will trigger at 0000 hours each day in game-time (provided all other triggers are also valid).
 * weekly=: specifies the event will trigger on the first day of each week (on the first, eighth, fifteenth and twenty-second of each month) in game-time (provided all other triggers are also valid).
 * monthly=: specifies the event will trigger on the first day of each month in game-time (provided all other triggers are also valid).
 * artifact_possessed=: checks the player's cargo bay to see if they are in possession of a particular artifact.
 * player_x_coord=: checks to see if the player is at a particular x-coordinate position.
 * player_x_range=: checks to see if the player's current x-coordinate is within a range of possible values.
 * player_y_coord=: checks to see if the player is at a particular y-coordinate position.
 * player_y_range=: checks to see if the player's current y-coordinate is within a range of possible values.
 * player_orbit=: checks to see if the player is at a particular orbital lane position.
 * player_sector=: checks to see if the player is located within a specified sector.
 * player_zone=: requires a specified set of coordinates (x, y, sector) to define a circular area; checks to see if the player is within a given radius of a specified set of coordinates.
 * player_lat=: checks to see if the player's location is ON_SURFACE, and checks to see if they are at a specified planetary latitude.
 * player_long=: checks to see if the player's location is ON_SURFACE, and checks to see if they are at a specified planetary longitude.
 * encspecies=: checks to see if the player is in an encounter with a specified species.
 * check_variable=: checks a specified in-game variable. This can be specified to one included in the game (if the programmer is knowledgeable enough; a future event creation utility may be programmed with these) or for a programmer-defined variable. Usage is as a tuple, specifying first the variable to be checked followed by the value that variable must have to satisfy the trigger conditions.

Events :
 * event_x_coord=: Produces the specified event at the indicated x-coordinate.
 * event_x_range=: Produces the specified event over the given range of x-coordinates.
 * event_y_coord=: Produces the specified event at the indicated x-coordinate.
 * event_y_range=: Produces the specified event over the given range of y-coordinates.
 * event_orbit=: Produces the specified event in the indicated orbital lane.
 * event_sector=: Produces the specified event within the specified sector.
 * event_zone=: requires a specified set of coordinates (x, y, sector) to define a circular area; produces the specified event within a given radius of the specified set of coordinates.
 * event_lat=: requires a specified set of coordinates (x, y, orbit) to define a specific world; Produces the specified event at the indicated latitude.
 * event_long=: requires a specified set of coordinates (x, y, orbit) to define a specific world; Produces the specified event at the indicated longitude.
 * unlock_message=: Enables a specified locked message to be displayed (this requires the conditions under which a message of its type would ordinarily be displayed before it is actually displayed; for example, a comm message can be unlocked, but won't actually be displayed until communications with a specified race begins).
 * unlock_sequence=: Executes a specified external script (might ultimately use this to execute specific internal scripts as well; again, that would be something we could set up with an event creation utility.)
 * show_message=: Immediately display the specified message in whatever messaging area is currently available.
 * trigger_encounter=: Immediately begin a customized encounter. Requires that the encounter be defined; for more information, see the discussion under the Encounter Module.
 * trigger_achievement=: Runs the "achievement" sequence for the specified achievement. These have yet to be defined anywhere in the game, but they're a good idea.
 * remove_encounter=: Removes a customized encounter. Requires that the encounter be defined; for more information, see the discussion under the Encounter Module. Generally meant to be used by the Lounge Starport sub-module (see that discussion), but can be used for other purposes.
 * encprob=: Adds a specified amount to the encounter probability for a given race. Usage is as a tuple, with the race probability to affect first followed by the amount of adjustment. Can be positive or negative.
 * shadow_system=: Requires event coordinates (x, y, sector). Hides a star system from view (both on screen and on the starmap) and makes it impossible to visit.
 * unshadow_system=: Requires event coordinates (x, y, sector). If the indicated system has been hidden from view, this makes it visible and visitable once again.
 * shadow_planet=: Requires event coordinates (x, y, sector, orbit). Hides a planet from view and makes it impossible to visit.
 * unshadow_planet=: Requires event coordinates (x, y, sector). If the indicated planet has been hidden from view, this makes it visible and visitable once again.
 * shadow_starport=: Hides the specified starport (listed by name) from view and makes it impossible to visit.
 * unshadow_starport=: If the indicated Starport has been shadowed, this makes it visible and visitable once again.
 * shadow_civilization=: Hides all instances of the specified species (listed by name) everywhere (including homeworlds and starports; this also sets their encounter probabilities to zero).
 * unshadow_civilization=: If a species has previously been shadowed, this makes them visible once again. Can be set as a tuple, with the second value indicating that race's encounter probability; if left blank, it defaults to their normal amount.
 * show_animation=: Pauses everything and runs an animated sequence for display, then resumes the action.
 * endgame=: Ends the game after all other effects associated with the event have fired; after the event has fired, there will be a brief pause before the game returns to the Main Menu. This event is meaningless unless it is given the value of "True"; there is no point in including it otherwise.
 * seed_artifact=: Requires event coordinates (x, y, orbit, sector, lat, long). Places an instance of the indicated artifact at the specified location.
 * seed_message=: Requires event coordinates (x, y, orbit, sector, lat, long). Places a message at the indicated location; the player will not receive the message without proceeding to the indicated location. Upon arrival, they will receive the message in whatever messaging area is currently available.
 * set_variable=: sets the value of a specified in-game variable. This can be specified to one included in the game or for a programmer-defined variable. Usage is as a tuple, specifying first the variable to be modified followed by the value to which it will be set (this must match the established data-type for the variable).
 * adjust_variable=: modifies the value of a specified in-game variable. This can be specified to a variable included in the game or for a programmer-defined one. Usage is as a tuple, specifying first the variable to be modified followed by the amount by which it will be modified (this must match the established data-type for the variable).
 * onceonly=: Indicates that the event should only happen one time; if all other trigger conditions are satisfied but onceonly is set to True, the event will not fire. I'll need to figure out a way to keep track of events that have already fired at least once. Probably by deleting their key once they've fired; that'd be the easiest way, I think.

Sample structure of the event_list.xml file:

&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;root table-name="Event List" version="0.1"&gt; &lt;event date="02.00-01-4620" unlock_message="starport_msg_2" /> &lt;event event_x_coord="132" event_y_coord="165" event_orbit="1" event_lat="46" event_long="14" seed_artifact="Crystal Orb" /> &lt;event artifact_possessed="Crystal Orb" encspecies="Veloxi" unlock_message="veloxi_question_give_it_back" /> &lt;event event_sector_id="Alpha" event_x_coord="192" event_y_coord="152" event_orbit="1" check_variable="hasCrystalOrb, False" unlock_message="burning_up" unlock_sequence="burning_up" /> &lt;event check_variable="uhlek_brain_world_destroyed, True" show_message="uhlek_gone" shadow_civ="Uhlek" /> &lt;event date="01.00-01-4621" event_x_coord="125" check_variable="flaring, True" set_variable="flared, True" shadow_starport="Starport Central" /> &lt;event date="01.00-01-4621" check_variable="LOCATION, IN_SYSTEM" player_x_coord="125" show_animation="cooked_goose" endgame="True" /> &lt;event check_variable="crystal_planet_destroyed, True" set_variable="flaring, False" show_animation="medal" /> &lt;event artifact_possessed="Most Valuable Thing" encspecies="Tandelou Eshvey" encspecies="Tandelou Eshvara" unlock_message="tandelou_question_give_it_back" /> &lt;event encspecies="G'Nunk" check_variable="shieldsUp, False" set_variable="emoIndex, 100)" /> &lt;event event_sector="Delta" event_x_coord="117" event_y_coord="153" event_zone="63" unlock_sequence="humans_crazy" show_message="crazy_human_1" />  &lt;event encspecies="Dweenle" check_variable="gaveNidberries, True" adjust_variable="emoIndex, -50) />  &lt;event check_variable="LOCATION, IN-SYSTEM" show_animation="first_launch" trigger_acheivement="firstlaunch" onceonly="True" /> &lt;/root&gt;

custom_variables.xml
The file "custom_variables.xml" is designed as a way to programmatically define variables (particularly flags) without having to specifically add them to the game's code. In theory, this will allow a coder to more easily "mod" the game. Under the root element, entries in the XML file are empty elements with the name variable. They may have only two attributes, name (used by the program as the variable's name; this must follow all the normal conventions for a Python dictionary key; i.e. it cannot be a mutable value) and value (an optional variable used to set the initial value of that variable; if not provided, the default value assigned to the variable is "False"). Any other attribute assigned to the variable will be ignored by the program. When loaded into the hFlagpole dictionary, the value assoviated with the "name" attribute will become the key for the dictionary entry, and the "value" will be assigned as the value associated with that key.

Example structure of the custom_variables.xml file:

&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;root table-name="Custom Variables" version="0.1"&gt; &lt;variable name="crystal_planet_destroyed" /&gt; &lt;variable name="possesses_crystal_orb" value="False" /&gt; &lt;variable name="gnunk_ships_destroyed" value="0" /&gt; &lt;/root&gt;

Module Status
This is current as of December 13, 2010

This module is currently in the completed design phase; specific descriptions of the intended functions of modules have been written at this point, but no actual code has been written related to the module as yet (with the possible exception of XML files). Pretty much everything I wanted to incorporate into the design of this module is in at this point. I won't know how well it works, of course, until some actual coding takes place on the module itself.

NEXT: Onomastikon Module and Database PREVIOUS: Miscellaneous Modules TOP