• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Warcraft 3 Trigger Format Specification (WTG!)

Ralle

Owner
Level 77
Joined
Oct 6, 2004
Messages
10,098
Warcraft 3 Trigger Format Specification (WTG!)

The past few weeks I have been working on a tool to display the triggers of any map on the site. As some of you know, we had a similar system on the old site. The most difficult task in the creation of this tool is the parsing of the file "war3map.wtg" inside any (unprotected) Warcraft 3 map. It's problematic because it is a binary file format undocumented by Blizzard. There exist unofficial specifications but most of them are incomplete and incorrect.
Many years ago when I built the parsing used on the site it was not perfect either but better than the existing documentation. Today I am happy to say that I have written a parser that successfully parses a little over 16,000 maps uploaded to the site. The only cases where it fails to parse are cases where World Editor fails similarly.

Today I am sharing my improvements to the existing specifications in the hopes of furthering the third party tools for WC3. There are still some values which are not explained but everything needed to parse the whole structure succesfully every time is there.

The incomplete documentation used to get started is this frequently reposted W3M/W3X specification:

TriggerData.txt

To begin parsing this format you will need the latest version of TriggerData.txt (UI\TriggerData.txt) which can be extracted from the MPQs. We need this file because we must setup a mapping between functions and their number of arguments. It is assumed that we have this mapping prior to parsing WTG files.

This is a standard INI file (I expect that you can parse those, if not, Google it), we are interested in the following groups:
Code:
[TriggerActions]
...
[TriggerEvents]
...
[TriggerConditions]
...
[TriggerCalls]
...
Iterate over each key-value item (where the key does not start with '_') in these groups and count the number of arguments but filter out empty strings, numbers and the string 'nothing'.

For the group called 'TriggerCalls' one of the types is a return value, so the resulting count must be deducted by one.

Here is sample code for the setup of my mapping:
PHP:
$areas = [
    'TriggerActions',
    'TriggerEvents',
    'TriggerConditions',
    'TriggerCalls',
];
$lookup = [];
foreach ($areas as $area)
{
    foreach ($iniParser->data->groups[$area] as $key => $argsString)
    {
        if ($key[0] == '_')
        {
            continue;
        }
        $args = explode(',', $argsString);
        $args = array_filter($args, function($arg) {
            return $arg != '0' && $arg != '1' && $arg != 'nothing' && trim($arg) != '';
        });
        $r = count($args);
        if ($area == 'TriggerCalls')
        {
            $r--;
        }
        $lookup[$key] = $r;
    }
}

war3map.wtg

In the coming structures, the type 'string' is referenced. A string is a sequence of bytes terminated by a null (0x00).

The file is defined by the 'Root' structure as seen below. Everything else is nested within that. Some values display as 'Unknown'. If you can figure out what they are for, I'd love to update this specification to reach perfection some day.

Structure: Root
Code:
char[4]: File id (WTG!)
int32: File format version: 4 for Reign of Chaos, 7 for Frozen Throne (very important later on)
int32: Number "x" of trigger categories
struct TriggerCategory[x]: Repeat the TriggerCategory structure x times
int32: Unknown (always 0)
int32: Number "y" of variables
struct Variable[y]: Repeat the Variable structure y times
int32: Number "z" of triggers
struct Trigger[z]: Repeat the Trigger structure z times


Structure: TriggerCategory
Code:
int32: Id of the category
string: Name
int32: Is comment (1 = yes, 0 = no) (Version 7 only)


Structure: Variable
Code:
string: Name
string: Type
int32: Unknown (always 1)
int32: Is array (1 = yes, 0 = no)
int32: Array size (Version 7 only)
int32: Is initialized (1 = yes, 0 = no)
string: Initial value


Structure: Trigger
Code:
string: Name
string: Description
int32: Is comment (Version 7 only, 0 = no, any other = yes)
int32: Is enabled (1 = yes, 0 = no)
int32: Is custom (1 = yes, 0 = no)
int32: Is initially off (1 = yes, 0 = no)
int32: Run on initialization (1 = yes, 0 = no)
int32: Trigger category id
int32: Total number "x" of events/conditions/actions
struct ECA[x]: Repeat the ECA structure x times


Structure: ECA
Code:
int32: Type (0 = event, 1 = condition, 2 = action)
int32: Group for if-then-else (0 = condition, 1 = then action, 2 = else action) (Only exists if it is a child-ECA)
string: Name "x"
int32: Is enabled (1 = yes, 0 = no)
struct Parameter[y]: Repeat the Parameter structure y times (where y is found in our lookup table for the key x)
int32: Number "z" of child events/conditions/actions (Version 7 only)
struct ECA[z]: Repeat the ECA structure z times (these are child ECAs) (Version 7 only)


The parameter structure will be divided into separate versions for 4 and 7 because of slight nuances in whether various values exist or not.

Structure: Parameter (Version 4)
Code:
int32: Type "x" (0 = PRESET, 1 = VARIABLE, 2 = FUNCTION, 3 = STRING, -1 = INVALID)
string: Value
int32: Has sub parameters "y" (1 = yes, 0 = no)
struct SubParameters: (Only exists if y = yes)
int32: Unknown (Always 0, Only exists if "x" = FUNCTION)
int32: Is array "z" (1 = yes, 0 = no) (Only exists if "x" != 2)
struct Parameter: Array index (Only exists if z = yes)


Structure: Parameter (Version 7)
Code:
int32: Type "x" (0 = PRESET, 1 = VARIABLE, 2 = FUNCTION, 3 = STRING, -1 = INVALID)
string: Value
int32: Has sub parameters "y" (1 = yes, 0 = no)
struct SubParameters: (Only exists if y = yes)
int32: Unknown (Always 0, Only exists if "y" = yes)
int32: Is array "z" (1 = yes, 0 = no)
struct Parameter: Array index (Only exists if z = yes)


Structure: SubParameters
Code:
int32: Type
string: Name "x"
int32: Begin parameters "y" (0 = no, any other = yes)
struct Parameter[z]: Repeat the Parameter structure z times (where z is found in our lookup table for the key x)
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
You know you could have asked for a bit here and there since others like myself were also digging into file formats and parsers as the various uploaded tools hint at. Still, thanks for the specs :)

You are free to write your own specs or contribute to existing ones. I encourage you to do both. It's nice to have a repository of specs that are more-or-less updated compared to all of the specs posted elsewhere.
So far every time I tried implementing anything, it required cross-referencing multiple specs, and usually fixing errors. Even in the most finalized and accepted specs (specifically for me MDX and BLP).
 
There are some cope paste bugs (Autogenerating, over two maps) which removes/hides types this two i know:
Strings picking Models; new in 1.28.5 I never seen that in other versions.
Integers beeing loop variables and never be set.; but kb is set here?


Unbenannt.png

 
Last edited:
Top