event_list.dat contains all of the events that can occur in a map. Events encompass almost everything that is not normal gameplay, including opening doors and chests, talking to NPCs, and getting frozen and attacked by Redeads. The file is located within the map's Stage.arc, at Stage/dat/event_list.dat.
The file contains a header with offsets and counts for the different sections. After this header are the different types of data, stored in the order of events, actors, actions, properties, a float bank, an integer bank, and a string bank.
As a flattened hierarchy, the event data uses many indexes to connect pieces of data together. Events have indexes to their actors; actors have the index of their first action; actions have the index of their first property; and properties have an index or offset to the data that they represent.
Actions and properties are chained to other actions and properties in a linked list-style format. Actors have the index to their first action. This action then has an index to the next action in the chain, and so on, until the index of the next action is 0xFFFFFFFF/-1. It is the same with properties - the first property that belongs to an action has the index to the next property, and this continues until the next property index is -1.
To-do: Explain flags.
The header is 0x38/56 bytes long, padded to 0x40/64 bytes with zeroes. It is laid out like this:
//0x40/64 bytes long /*0x00*/ int EventsOffset; /*0x04*/ int EventCount; /*0x08*/ int ActorsOffset; /*0x0C*/ int ActorCount; /*0x10*/ int ActionsOffset; /*0x14*/ int ActionCount; /*0x18*/ int PropertiesOffset; /*0x1C*/ int PropertyCount; /*0x20*/ int FloatBankOffset; /*0x24*/ int FloatBankCount; /*0x28*/ int IntegerBankOffset; /*0x2C*/ int IntegerBankCount; /*0x30*/ int StringBankOffset; /*0x34*/ int StringBankLength; /*0x38*/ int Padding1; // 0 /*0x3C*/ int Padding2; // 0
Events are the first layer in the event system. They have a name, indexes to actors, an array of flags, and a boolean that determines whether the famous "Puzzle solved!" jingle should play when the event is finished. Events are referenced by name by the EVNT chunk in the map's DZS file.
Their structure is as follows:
// 0xB0/176 bytes long /*0x00*/ string Name; //0x20/32 bytes /*0x20*/ int Index; /*0x24*/ int Unknown1; //0 or 1 /*0x28*/ int Priority; //Presumably, an event with a higher priority will override an event with a lower priority if one starts to play at the same time as the other. /*0x2C*/ int ActorIndexes; //Actor indexes are stored in an array of 0x14/20 integers. Unused slots in the array are filled with -1. /*0x7C*/ int ActorCount; /*0x80*/ int Flags; /*0x94*/ bool PlayJingle;
//These fields are always 0. It is assumed that they are used by the engine while the event is running to store various pieces of data. /*0x95*/ byte UnknownByte1; /*0x96*/ byte UnknownByte2; /*0x97*/ byte UnknownByte3; /*0x98*/ int Unknown6; /*0x9C*/ int Unknown7; /*0xA0*/ int Unknown8; /*0xA4*/ int EventState; //Always 0-initialized. Determines if the event is playing or has ended /*0xA8*/ int Unknown9; /*0xAC*/ int Unknown10;
The array of 5 integers for flags is not completely understood. The last valid flag, that is, the last flag that isn't -0xFFFFFFFF/-1, is the flag set by the last action or property that is executed during the event. This must mean that the flags in the event data are for keeping track of when the event begins or is finished. The reason for having more than two flags (one for beginning and one for ending) is unknown.
Actors are the second layer in the event system. They represent entities, such as Link or NPCs, along with more abstract objects such as the camera and dedicated timer objects. They have a name, a "Staff Identifier" with an unknown purpose, a flag to set when the actor is finished executing its actions, and a "Staff Type" which is also unknown.
//0x50/80 bytes long /*0x00*/ string Name; //0x20/32 bytes /*0x20*/ int StaffIdentifer; //Don't know what this is, J.H. wasn't sure either /*0x24*/ int Index; //Index of this actor /*0x28*/ int FlagID; /*0x2C*/ int StaffType; //0 is a special case, 02 is another special case... /*0x30*/ int InitialActionIndex; //First action the actor performs
//These fields are always 0. It is assumed that they are used by the engine while the event is running to store various pieces of data. /*0x34*/ int Unknown2; /*0x38*/ int CurrentActionIndex; //Probably used while the event is running /*0x3C*/ int ActIndex; //Apparently stores the string length of the current action? /*0x40*/ int Unknown3; /*0x44*/ byte Unknownb1; /*0x45*/ byte Unknownb2; /*0x46*/ byte IsAdvance; //Engine might set this when the actor is moving onto its next action /*0x47*/ byte Unknownb3; /*0x48*/ int Unknown4; /*0x4C*/ int Unknown5;
The third layer in the event system, actions allow actors to do something. For example, actions allow Link to walk to a certain location, or allow NPCs to animate or create message boxes. It is common for entities to have actions defined within their relocatable modules (their code) that are referenced by name by an action in the event_list.
//0x50/80 bytes long /*0x00*/ string Name; //0x20/32 bytes /*0x20*/ int DuplicateID; //For when two or more actions in the same actor share the same name. /*0x24*/ int Index; //Index of this action /*0x28*/ int FlagHaltArray; //The action will not be performed until all of the flags in this array are set. Empty slots are filled with -1. /*0x34*/ int FlagID; //The action sets this flag when it finishes executing. /*0x38*/ int PropertyIndex; //Index of a property. If there is no property, it's -1. /*0x3C*/ int NextActionIndex; //Next action to perform. If there is no next action, it's -1.
//These fields are always 0. It is assumed that they are used by the engine while the event is running to store various pieces of data. /*0x40*/ int Unknown6; /*0x44*/ int Unknown7; /*0x48*/ int Unknown8; /*0x4C*/ int Unknown9;
Properties are the last layer in the event system, and serve as parameters for actions. They provide actions with data that they can use to execute their functions. An example would be the position in space for Link to walk to for an action telling him to go somewhere.
//0x40/64 bytes long /*0x00*/ string Name; //0x20/32 bytes /*0x20*/ int Index; //Index of this property. /*0x24*/ int DataType; //01 means single float; 02 means vector3; 03 means int; 04 means string. /*0x28*/ int DataIndex; //Index of data (for single floats, vector3s, and ints) or offset (for strings) of the data in the relevant bank. /*0x2C*/ int DataLength; //Size of the data. Really only useful for strings, since floats, vector3s, and ints all have 1 in this field. /*0x30*/ int NextPropertyIndex; //Index of next property. It's -1 if there is none.
//These fields are always 0. It is assumed that they are used by the engine while the event is running to store various pieces of data. /*0x34*/ int Unknown1; /*0x38*/ int Unknown2; /*0x3C*/ int Unknown3;
At the end of the file are three banks of data that are referenced by properties. These banks are made up of floats, integers, and strings. For the float and integer banks, data is accessed by its index, which is stored in the property. For Vector3's, this means that the three component floats are stored at the initial index, the index + 1, and the index + 2 within the float bank.
The string bank is handled differently. Rather than accessing data by an index, strings are referenced by their offset within the bank. Strings are therefore extracted by the game by going to the offset in the string bank and copying out the amount of bytes given by the DataLength variable in the property data.