The AIN file format (System 3.9)

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.