System 3.9 AIN files contain the information required to link DLLs so that they can be called from scenario code, plus the information required to add named functions and variables to the System3.x language, and messages used by the scenario.
struct ain_file {
BYTE magic1[4]; // "AINI"
// the below is encrypted
BYTE reserved1[4]; // reserved
BYTE magic2[4]; // "HEL0"
BYTE reserved2[4]; // reserved
LE32 nr_dlls; // number of DLLs
struct dll dlls[nr_dlls]; // DLL info
struct functions funs; // (optional) function info
struct variables vars; // (optional) variable info
struct messages msgs; // (optional) messages
};
All of the data in an AIN file minus the first 4 bytes is encrypted by rotating every byte 2 bits to the right. The following code decrypts an AIN file.
void decrypt_ain(struct ain_file *ain, size_t size)
{
BYTE *p = (BYTE*)ain + 4;
for (int i = size - 4; i > 0; i--, p++) {
*p = (*p >> 6) | (*p << 2);
}
}
After a couple magic words and reserved areas, we get a list of (variable length) structures describing the DLLs that should be dynamically linked with the game.
struct dll {
BYTE name[?]; // name of the DLL (null terminated)
LE32 nr_funs; // number of functions in the DLL
struct { // function info
BYTE name[?]; // name of the function
LE32 argc; // number of arguments
LE32 argv[argc]; // argument types
} functions[nr_funs];
};
This should be fairly self-explanatory. Each DLL has a name and information about a number of functions exported by the DLL. Each function has a name and a number of arguments.
After the DLL information, an AIN file optionally contains function names/addresses, the names of variables, and the text of messages used by the scenario.
If function info is present, the following structure is placed following the DLL information.
struct functions {
BYTE magic[4]; // "FUNC"
LE32 nr_functions; // the number of functions
struct { // function info
BYTE name[?]; // name of the function
LE16 page; // page of the function in the scenario file
LE32 index; // index of the function in the page
} functions[nr_functions];
};
Then, if variable names are present, the following structure.
struct variables {
BYTE magic[4]; // "VARI"
LE32 nr_variables; // the number of variables
BYTE names[?]; // list of (null terminated) variable names
};
Then, if messages are present, the following structure.
struct messages {
BYTE magic[4]; // "MSGI"
LE32 nr_messages; // the number of messages
BYTE messages[?]; // list of (null terminated) messages
}
NOTE: All text in an AIN file (and System 3.x in general) is encoded in shift-jis.