Guide
Requirements
- Windows 7 or greater
- .NET 6.0 Desktop Runtime x64
- Warcraft III 1.28.5 or greater
Installation
- Download and extract the tool anywhere in your filesystem.
- Run 'Better Triggers.exe' to launch the program.
- When launching for the first time it will ask you to locate your Warcraft III installation directory. Example: 'C:\User\Program Files\Warcraft III'.
You're now ready and set!
Create a project
To create a project select 'File -> New Project' in the top navigation menu. There are two options when creating a new project:
Empty project
This option creates a project and creates a new map in the 'map' directory. No triggers are created with this option.
Copy triggers from an existing map
This option creates a project and extracts all categories, triggers, variables, and scripts from a map, into the 'src' folder in your project. Comments in the Trigger Explorer menu are ignored when converting. The editor then makes a reference to the map you selected, and you can continue working on that map in the World Editor.
NOTE: If you're copying triggers from a map that contains variables with upper-/lower case variations of the same name e.g. "myVar" and "MyVar" the latter ones will be renamed. This is because the filesystem isn't case sensitive by default and conflicts would occur.
As a result, you may experience compile errors in your project.
Folder structure
Creating a project generates a folder with a project file and three subfolders:
- The project file contains essential information about your project, and is the file you should point to when opening a project.
- The 'map' folder is not required, but it is the default map location when creating an empty project.
- The 'src' folder contains all source files i.e. triggers, variables, scripts etc.
- The 'dist' folder contains the final map when you click 'Export Map'.
Workflow
Trigger Explorer
The trigger explorer in this editor works a lot different than the one in the World Editor,
because it's actually a live view of your filesystem from your src
folder.
The editor responds to actions you perform in the filesystem, like creating, renaming, copy-pasting, moving and deleting files and folders.
For script files (.j
and .lua
), you can work directly in external text/code editors
without the need to copy-paste the contents into the editor like we are used to in the World Editor.
Here is an example of using VSCode to edit and save a script file, which Better Triggers immediately registers:
NOTE: While you certainly can copy-paste files and entire folders of content in Windows Explorer, it is recommended you do these operations through Better Triggers. The generated script creates triggers and variables with names based on filenames. If two variables or triggers have the same name it will cause script errors. Better Triggers makes sure this doesn't happen and properly renames your files when copy-pasting.
Script files (.j
and .lua
) are not affected by this, however.
Working between Better Triggers and the World Editor
Since Better Triggers is an external tool it only knows about map data from the latest save. All changes in the World Editor must be saved before Better Triggers can detect the changes. This is illustrated below where Better Triggers locks itself when you save the map in the World Editor.
Once the map has saved Better Triggers reloads all map data, and notifies you if any triggers changed as a result of the updated map data.
Exporting the final map
When you're ready to export the final map you click the "Export Map" button. This will create a separate map file with the generated script in the 'dist' folder in your project.
Moving your trigger changes back into the map
If you no longer wish to work in Better Triggers or for other reasons want to move all trigger changes back into the map, all you need to do is enable the 'Include Trigger Data' option when exporting the map.
However, if your project contains 'Better Triggers'-only features you will get an error-popup message with a list of triggers using these features.
Expanded GUI Tips
Local Player
Better Triggers has implemented 'GetLocalPlayer
' in GUI which is shown as 'Local Player' in GUI.
This should only be used in if-then-else actions:
It's generally not recommended to use 'Local Player
' if you're unfamiliar with it, as it's the number 1 cause of desyncs.
However, it enables you to display things on a per-player bases like UI elements (frames), special effects, text-tags, multiboards etc.
Frames
Since Blizzard has not implemented a generic event for frames, Better Triggers has done a workaround to bring
frame natives to GUI triggers. The generic frame event actually uses 'TriggerRegisterVariableEvent
' under the hood,
but is made more user-friendly for GUI users. There are a few points to make about this:
When referring to the player that triggered the event you cannot use 'Triggering Player' or 'GetTriggerPlayer()
'.
You must use 'Triggering Frame Player' or 'GetTriggerFramePlayerBT()
' as shown here:
This is also the case for a number of other natives, though is mostly relevant for scripting:
- '
GetTriggerFrame()
' -> 'GetTriggerFrameBT()
' - '
BlzGetTriggerFrameEvent()
' -> 'GetTriggerFrameEventBT()
' - '
BlzGetTriggerFrameValue()
' -> 'GetTriggerFrameValueBT()
' - '
BlzGetTriggerFrameText()
' -> 'GetTriggerFrameTextBT()
'
Other than that you use the frame natives in GUI just like you would in scripting.
E.g. you show/hide frames for individual players showing/hiding them inside a 'Local Player' if-statement:
The above GUI trigger generates the following script:
//****************************************************************************
//* Trigger Untitled_Trigger
//****************************************************************************
function If_Trig_Untitled_Trigger_0 takes nothing returns boolean
if (not(GetTriggerFramePlayerBT() == GetLocalPlayer())) then
return false
endif
return true
endfunction
function Trig_Untitled_Trigger_Conditions takes nothing returns boolean
if (not(GetTriggerFrameBT() == udg_frameButton)) then
return false
endif
if (not(GetTriggerFramePlayerBT() == Player(0))) then
return false
endif
return true
endfunction
function Trig_Untitled_Trigger_Actions takes nothing returns nothing
if (If_Trig_Untitled_Trigger_0()) then
call BlzFrameSetVisibleBT(false, GetTriggerFrameBT())
else
endif
endfunction
//****************************************************************************
function InitTrig_Untitled_Trigger takes nothing returns nothing
set gg_trg_Untitled_Trigger = CreateTrigger()
call TriggerRegisterGenericFrameEventBT(gg_trg_Untitled_Trigger, 1.0, EQUAL, "bt_genericFrameEvent")
call TriggerAddCondition(gg_trg_Untitled_Trigger, Condition(function Trig_Untitled_Trigger_Conditions))
call TriggerAddAction(gg_trg_Untitled_Trigger, function Trig_Untitled_Trigger_Actions)
endfunction
For a more in-depth guide on how to use frames refer to Tasyen's tutorial: Types of Frames