- Joined
- Mar 19, 2008
- Messages
- 3,141
Introduction
More and more modders use script languages rather than GUI due to developer-friendly features and great possibilities that come with them.
Vexorian's jasshelper brought vJass to the community many years ago, which soon became a pillar of Warcraft 3 modding.
Unfortunately, project has not been maintained properly for years and none fixed the issues that arose during that time.
Newest addition to the family, Wurst, brings refreshment to the table.
While it might have been launched a bit too early given its previous state, its current form, without a doubt offers greater array of features and is a modern approach to war3 map development.
It is also coupled nicely with VSCode, although, after reading the guide you should be able to use VSCode for vJass too.
Goal of this short tutorial is to get user used to modern approach of map development and allow him to work with vJass and Wurst together in a single map.
Note:
This guide does not explain things in very detailed manner. Target is to present the problem and provide general answer.
Once you have firm grasp over the subject, you will surely conquer any monster that you might face.
Is it assumed that you are familiar with: jasshelper, vJass, Trigger Editor, wurst setup, basic wurst, and general usage of VSCode.
Helpful links:
Facts
In a world dominated by vJass, it might not be easy to sneak wurst into the map.
One cannot simply be told to rewrite entire map to wurst in one go.
Let's state some key facts:
- Compatibility is important, vJass cannot be simply just scrapped
- Vast majority of war3 modders use vJass
- Heavily favored over Wurst by new users because of streamlined learning curve: GUI -> Jass -> vJass
This is because wurst is not fully compatible with vJass, example:
- Different reserved keywords: construct
Solution: rename your variables
- Forbidden native TriggerRegisterVariableEvent
Solution: use TriggerEvaluate directly, rather than real variable manipulation
Target
Need of mechanism for handling situation when both, wurst and vjass code exist in the map.
Behind the scenes
vJass and jasshelper:
Pictures below show high-level view of build process
1) Input single .j file into jasshelper, which outputs pure jass file readable by Warcraft3.

2) Inject compiled.j file into template map to receive fully functional w3x file.

3) Via Warcraft3, players can experience beauty of our map.

Process path for wurst is similar with exception of jasshelper being replaced by wurst compiler.
Combing Wurst and vJass
An output for jasshelper compilation operation is .j file with name specified in the command containing compiled code to pure jass. For build operation, is it map w3x file given the name.
An output for standard build wurst map operation is compiled.j and map file e.g.: WurstRunMap.w3x. There is no separate compilation task.
The key thing to note, which we gonna take advantage of, is fact that wurst compiler searches for war3map.j file within <your_project_path>/wurst directory. This concept is shared with you during the "Hello World" of wurst, that is, creation of your first wurst project. Once saved, you will notice the new .j, war3map file, appearing in your wurst directory.
Wurst compiler will combine both, wurst scripts and war3map.j file together and attempt to compile them into a single compiled.j file.
Let's modify previously shown process path of map creation to reflect what we have just said:
1) Use jasshelper to create map script file and place it under /wurst directory.

2) Combine both, wurst and war3map to create compiled.j file.

Afterwards, the compiled.j will be used for map creation, just like for jass-only map.
Work, work
Pictures displaying origination of Happy gamer for vJass do not list .j file (notice the lack of plural) by mistake.
Let's checkout commands which we use when compiling vJass with jasshelper
Code:
// compile
jasshelper.exe --scriptonly <path_to_common.j> <path_to_blizzard.j> <path_to_input.j> <path_to_output.j>
// build
jasshelper.exe <path_to_common.j> <path_to_blizzard.j> <path_to_mapscript.j> <path_to_map.w3x>
We are tasked with the following:
- Extract and compile our vJass map code into a single war3map.j file
- Have the war3map.j under /wurst directory
- Run wurst compiler to generate final compiled.j file
Once you read this through and give yourself a moment for reflection, you will realize how tedious would be to work with a single .j file which might be tens of thousands lines long.
This is where our next player comes in.. the VSCode.
On wurst side, there not much left to do. As said already, it is coupled nicely with VSCode. Building and running map from the IDE is fully automated.
The highlighter and syntax checker are great, auto-completion is here too. You wouldn't tell a difference from working with typical programming language in VSCode.
Automation is key here. Launching everything manually once or twice is not a problem. However, doing this repeatedly will prove to be a nuisance.
Below are displayed the standard commands available for wurst map:

Ideally, we would like to see something similar for our old vJass friend:

To achieve our goal, we are going to take advantage of VSCode tasks.
It was mentioned previously that we need a single .j file for jasshelper to not complain about parameters. It was also noted that it is tedious to work with one big file on a daily basis.
However, nowhere it is said how the organization of files must look like before the compilation. We need that single file only for the moment of compilation. Before and after, doesn't matter.
Since the spirit of this tutorial is: a modern approach to war3 map development, we would like to keep things that way.
Our neighbour, wurst, already acts as a good example. All wurst files are kept under /wurst directory, and their organization is yours to decide.
We are going to copy that approach, and create /jass directory where all the .j files are going to reside.
If you want, you can even mirror script organization from World Editor's Trigger Editor. In such case, triggers would be replaced by .j files and categories by folders.
To sum up what we have just said:
- jasshelper expects single .j file as an input (apart from common.j and blizzard.j)
- Scripts have to be extracted and placed under single directory
- Content of those scripts has to be combined and only then passed to jasshelper for compilation

VSCode tasks can be used to execute simple task for current workspace which is great when we want to perform repeatable operations, such as building and running maps. Array of available tasks should be stored in task.json file under /.vscode directory.
What we need?
- task.json file to specify range of tasks available
- Scripts to perform actual tasks
Let's show an example, because example is worth more than a thousand words:
Code:
"tasks": [
{
"label": "Compile map",
"type": "shell",
"command": "powershell -ExecutionPolicy ByPass -File ./compile.ps1",
"group": {
"kind": "build",
"isDefault": true
}
}
]
Using VSCode task page reference, here is simple description of task fields:
- label: The task's label used in the user interface.
- type: The task's type. For a custom task, this can either be shell or process.
- command: The actual command to execute.
- windows: Any Windows specific properties. Will be used instead of the default properties when the command is executed on the Windows operating system.
- group: Defines to which group the task belongs. Usually it ends up being "test" or "build".
- presentation: Defines how the task output is handled in the user interface.
You give it name that is going to be depicted on the task list, kind, and command. This is the same command that you would execute from your shell so it is easy to test this out if something goes wrong.
Using this method, one can create several tasks. Personally, I recommend having:
- compile-only task, without map script injection
- compile-only task, without map script injection with --debug option added
- build task, which compiles map script and injects it to the map
- run task, which works as previous one, but runs the map afterwards
Code:
# Create GeneratedJ file from content of all .j and .zn files
$InputFiles = Get-ChildItem -Path $JassFolder -Include *.j, *.zn -Recurse
New-Item $GeneratedJ -ItemType File -Force
ForEach ($File in $InputFiles)
{
If ($File.Extension -eq '.zn')
{
Add-Content -Path $GeneratedJ -Value "//! zinc"
Get-Content -Path $File | Add-Content $GeneratedJ
Add-Content -Path $GeneratedJ -Value "//! endzinc"
}
Else
{
Get-Content -Path $File | Add-Content $GeneratedJ
}
}
# Run jasshelper to perform actual compilation of map script
$Params = $args + @('--scriptonly', $CommonJ, $BlizzardJ, $GeneratedJ, $OutputJ)
& $Jasshelper $Params
Notice the special care has been taken for Zinc. Preprocessor directives are appended before and after every .zn file to ensure that jasshelper will indeed treat them as Zinc files. If your .zn files already have those directives, you can drop the 'If'.
Summary
In order to compile map where vJass and Wurst are both present using VSCode task automation one needs to:
- Extract scripts from Trigger Editor and put them under single directory
- Create simple script for combining content of all files and launching jasshelper
- Have task.json prepared and present in his workspace directory
- Compile vJass scripts, using compile task. On successful compilation, war3map.j should be present in /wurst folder
- Run build or run wurst map task from VSCode
Live example of map which contains jass, GUI, vJass, Zinc and Wurst code combined: Island Troll Tribes. Map is currently under transition of becoming wurst-only map.
Is the reverse possible? Meaning, compiling wurst map script first, then appending some jass scripts and outputting compiled.j via jasshelper?
It is, afterall, wurst compiler outputs two files, compiled.j and w3x map file (e.g.: WurstRunMap.w3x) into _build directory.
You can use the exact same method described above for integrating Wurst code into vJass map - combine the /_build/compiled.j with your .j files and pass that to jasshelper. The output of this, the combined map script .j file, can be used with jasshelper build command to generate functional map.
However, before you proceed, ask yourself if perhaps, you are not doing something wrong. If you are planning to use wurst, you should not be thinking about injecting vJass code into it.
Something is missing? Not implemented? Frotty and the boyz are more than happy to hear you out!
You can meet them on github and their irc, see wurst contact page.
Last edited: