JASS (scripting language)
JASS and JASS2 is a scripting language provided with an event-driven API created by Blizzard Entertainment. It is used extensively by their games ' and StarCraft for scripting events in the game world. Map creators can use it in the Warcraft III World Editor and the Starcraft Editor to create scripts for triggers and AI in custom maps and campaigns.
Blizzard Entertainment has replaced JASS with Galaxy' in Starcraft II''.
Features
The language provides an extensive API that gives programmers control over nearly every aspect of the game world. It can, for example, execute simple GUI functions such as giving orders to units, changing the weather and time of day, playing sounds and displaying text to the player, and manipulating the terrain. JASS can also create powerful functions such as trackables, which detect if a mouse goes over or hits a position. It has a syntax similar to Turing and Delphi, but unlike those languages, it is case sensitive. JASS primarily uses procedural programming concepts, though popular user-made modifications to Blizzard's World Editor program have since added C++-like object-oriented programming features to the syntax of JASS.Sample code
The following function creates a string containing the message "Hello, world!" and displays it to all players:function Trig_JASS_test_Actions takes nothing returns nothing
call DisplayTextToPlayer
endfunction
or if you want this only for one player:
function Trig_JASS_test_Actions takes player p returns nothing
call DisplayTextToPlayer
endfunction
And if you want to print the message 90 times and show the iterator:
function Trig_JASS_test_Actions takes player p returns nothing
local integer i=0
loop
exitwhen i90
call DisplayTextToPlayer
set i=i+1
endloop
endfunction
Basic syntax
of JASS is similar to Turing. It is context free. Examples of basic syntax are shown below:function syntax_Example_Sum takes integer i, real r returns real //function declaration must include: the keyword "function",
//the function name, parameters and return type
return i + r //return statements must begin with the keyword "return"
endfunction //the keyword "endfunction" signals the end of a function block
function syntax_Example takes nothing returns nothing
local integer i //declaring a local variable requires the modifier "local", the variable's data type, and the variable name
local real r = 5.0 //local variable declarations must come before anything else in a function and variables may be
//initialized on declaration
//separated statements MUST be placed on separate lines
set i = 6 //the keyword "set" is used to rebind variables
call syntax_Example_Sum //function calls must be preceded by the keyword "call"
set r = syntax_Example_Sum //the "call" keyword is omitted when accessing a function's return value
endfunction
Types
JASS is statically-typed, and its types can be separated into two classes: natives and handles.The native types are:
- integer
- real
- string
- boolean
- code
function garbage_Collection_Example takes string effectPath, real x, real y returns nothing
local effect specialEffect = AddSpecialEffect //uncleaned handle types will continue to take up system resources
endfunction
function garbage_Collection_Example2 takes string effectPath, real x, real y returns nothing
local effect specialEffect = AddSpecialEffect
set specialEffect = null //setting the variable to null is not enough, since it is only a reference to the handle;
//the handle still exists
endfunction
function garbage_Collection_Example3 takes string effectPath, real x, real y returns nothing
local effect specialEffect = AddSpecialEffect
call DestroyEffect //we destroy the handle to free up memory
set specialEffect = null
endfunction
function garbage_Collection_Example4 takes effect e returns nothing
//do stuff
call DestroyEffect
//parameters do not have to be nullified
endfunction
Another property of handle types worth noting is that all handle types are treated as if they were children of the "handle" type. Some of these children types have their own children types, and so on. Handle variables may reference its own specific handle type or any children type. For example:
function Trig_JASS_handle_Example_Child takes widget w, widget w2 returns nothing
//do stuff
endfunction
function handle_Example takes real x, real y returns nothing
local widget w //widget is a handle type with children type unit and destructible
local unit u = CreateUnit
local destructible d = CreateDestructible
set w = u //acceptable
call Trig_JASS_handle_Example_Child //acceptable
//Don't forget to null every extends agent variable.
set u = null
set d = null
set w = null
endfunction
agent
Since patch 1.24b there is a new handle-based type called "agent" which has been introduced to separate handle types of which objects has to be deleted manually and handle types of which objects are deleted automatically.For example, types "unit", "rect" or "destructable" which refer to dynamic allocated objects do extend type "agent" now whereas types such as "race" or "alliancetype" which actually are only some kind of wrappers for the native type "integer" and can be compared to enumerated types do still extend type "handle".
Type casting
Of the primitive types, type casting between integer, real, and string is officially supported by the language. JASS supports both implicit and explicit type casting.Implicit casting only occurs from integer to real. For example:
function type_Casting_Example takes nothing returns real
local integer i = 4
local real r = 5 //implicit cast of 5 to real to satisfy variable type
if then //implicit cast of i to real
set r = r / i //implicit cast of i to real in order to carry out real division
endif
return i //XXX: NOT allowed; JASS does not allow implicit casting from integer to real to satisfy return types
endfunction
The JASS library provides several functions for explicit type casting:
- I2R: casts integer to real
- R2I: casts real to integer
- I2S: casts integer to string
- R2S: casts real to string
- S2I: casts string to integer
function H2I takes handle h returns integer
return h
endfunction
If the game ever reached the line "return h", it would in fact actually cast the handle to an integer and return the value. However, Blizzard never intended for JASS to be used this way, and so the JASS compiler will actually throw an error, warning the programmer that the function isn't returning the correct type. However, JASS programmers have found and exploited a now famous bug in the JASS compiler's syntax checker: the so-called "return bug". Essentially, the compiler will only make sure that the last return statement in a function returns the correct type. Therefore, the following code compiles without error and can be used to cast handles to integers
function H2I takes handle h returns integer
return h //the function will stop executing after the first return statement, i.e. this one
return 0 //the compiler will only check this statement for syntax accuracy, but it is in reality unreachable code
endfunction
This bug has been fixed in patch 1.23b, although it was not completely fixed until patch 1.24b. Users have to use new hashtable natives instead of their return bug counterparts.
While this bug has been fixed in patch 1.24b, another return bug has been discovered by users, known as the Return Nothing bug. The Return Nothing bug has been fixed by Blizzard in patch 1.23c.
The return nothing bug lets the user get the last value returned by any function, even as another type. To properly utilize the bug, the desired return must be made in a separate function and a return in the calling function should be made impossible.
function ReturnHandle takes handle h returns handle
return h
endfunction
function H2I takes handle h returns integer
call ReturnHandle //This sets the last returned value to 'h'.
if false then
return 0 //This can never occur, so the game uses the last returned value as this function's returned value instead.
//It will even return the last returned value as a different type, in this case an integer.
endif
endfunction
Arrays
JASS supports one-dimensional arrays of any type. The syntax to declare arrays and access members in an array is outlined in the code below.function array_Example takes nothing returns nothing
//arrays cannot be initialized at declaration and their members will hold arbitrary values
local integer array numbers
local unit array units
local boolean array booleans
local integer i = 1
set numbers = 1 //the syntax to initialize an array member is identical to that for any other variable, only a set of
//brackets: must immediately follow the variable name with the index value of the specific member
//to initialize inside the brackets
set units = CreateUnit //indexes for arrays always start at 0
loop
exitwhen i >= JASS_MAX_ARRAY_SIZE //The maximum size for arrays in JASS is defined by the JASS_MAX_ARRAY_SIZE constant.
//This means that the last index of any array is JASS_MAX_ARRAY_SIZE - 1.
//JASS_MAX_ARRAY_SIZE is 32768 at time of posting but originally was 8192.
set numbers = i //variables can substitute for constants when specifying the index value in the brackets
set units = true //arithmetic operations are also acceptable
set i = i + 1 //increments the index value
endloop
if booleans then //to access an array member, again the syntax is the same as for normal variables, only
//with the addition of the brackets with the index value inside
set numbers = -200 //you can re-assign members of the array to different values
endif
endfunction'
One limitation of arrays in JASS is that they cannot be returned by functions or passed as parameters to other functions, though array members may be returned.
Return Bug Security Vulnerability and Patch 1.24
In 2009 the return bug was shown to allow arbitrary code execution, a registered security vulnerability. Blizzard Entertainment shortly thereafter released patch 1.24 which fixed the vulnerability and the JASS bug. Once the patch is deployed, any map that contains the script code with returns bugs will not run properly. All maps using return bugs therefore need to be re-written to use the newly available hashtable natives.The patch is currently applied on all Battle.net servers.
vJass
vJass is a set of user-made extensions to JASS. It introduces object-oriented programming features to the language, such as structs, encapsulation, and polymorphism. Strictly speaking, vJass does not add anything to the JASS library but instead mostly uses JASS arrays and integers used as their indices. The extension relies on a custom-made compiler that compiles vJass code to strict JASS code. In this manner, no additional mods for either the World Editor program or Warcraft III are required, and maps made using vJass code are fully compatible with any copy of the game, even those without the compiler.Originally the most convenient tool to use vJASS was Jass NewGen Pack however JNGP suffered from lack of maintenance leaving it incompatible with newer Warcraft III versions. JNGP was superseded by World Editor Extended but work on WEX stopped also leaving it incompatible with newer Warcraft III versions. JassHelper is now part of Warcraft III allowing vJASS to be used without any third party tools.
Known issues
The JASS interpreter of Warcraft III up to version 1.23 doesn't check memory region boundaries. This allows execution of arbitrary bytecode through a map, meaning that practically anything, including malware, can be engineered into a map to be executed and infect a computer. Blizzard Entertainment is aware of this issue and applied a temporary workaround to games hosted on Battle.net. They are also preparing a permanent fix for LAN and single-player games. This issue was addressed with the release of version 1.24.Preload exploit
It is possible to exploit the I/O capabilities of the Preload JASS native to indirectly run code on a computer having certain builds of the Windows Operating System via writing batch files to the Startup folder. This exploit is rather limited however, as it requires a path, which is impossible to retrieve since reading environment variables is impossible. Despite the limitations, it is possible to use the Preload native along with its corresponding natives such as PreloadGenEnd to write files to a player's computer.The preload exploit was made secure and is now an officially supported feature of Warcraft III. Files written using the preload exploit are stored in the user folder Documents\Warcraft III\CustomMapData where they cannot cause any harm. The preload exploit is now commonly used by custom maps for more convenient persistent save/load systems.
Sample code
The following function creates an empty file in redist\miles folder. This used to interfere with Warcraft III program files making Warcraft III error when next run.
function Trig_JASS_testPreloadExploit_Actions takes nothing returns nothing
call PreloadGenEnd
endfunction...
Lua Interoperability
Warcraft III as of version 1.31 can run using either a JASS2 or Lua virtual machine. When specified to operate with the Lua virtual machine all JASS code is transpiled into Lua before being combined with Lua code to make the Lua code file. To facilitate this the Lua virtual machine has declarations which match JASS2 declarations as well as some helper userdata to easily and accurately emulate JASS language features such as arrays. By converting all the code into Lua and using a single virtual machine it is possible for JASS and Lua code to seamlessly interact with each other. This allows for custom map developers to start using Lua without having to manually port all existing JASS and vJASS code and also avoids problems such as lack of interoperation support and increased overhead that would occur if both JASS2 and Lua virtual machines were used at the same time.Due to the vastly different and larger language feature set of Lua, the JASS2 virtual machine does not have any compatibility with Lua code. Developers wanting to use any Lua code have to use the Lua virtual machine.