JASS Tools |
|
Library Functions Many native functions and constants are declared in common.j, common.ai, and Blizzard.j. This section will descibe several functions that are of note. Obviously, this section is incomplete; if you have written or have found a more thorough description of the native API, I would be happy to link it here. See the API Browser section for a listing of the API. Important Note: Others have observed that the following functions in common.j do not function correctly when used in AI scripts:
There are 3 common.ai functions that work for map scripts, once you manually add them to common.j , those functions are GetUnitGoldCost , GetUnitWoodCost and GetUnitBuildTime The current list of topics are: Usually only a single thread of execution is started for the AI. New threads can be started in an AI script with the function declared in common.ai: Map scripts, can simply use ExecuteFunc to create another thread. native StartThread takes code func returns nothing Calling this function via the statement
There are 6 thread slots per player. This includes the "main" thread,
so there is a slot for the main script and 5 extra slots.
If you have filled all 6 thread slots then further
calls to When a new thread is created, it receives time immediately. When the new thread yields (gives up the interpreter), the thread that created it resumes. Threads can yield in the following ways:
Threads can terminate in the following ways:
You should never let the main thread (the one that is started by
the game automatically) exit.
For example, you can call All threads for a single AI player share global state, so if you modify a global variable in one thread, the change will be visible in other threads in the same script. You can not start new threads in map scripts. A trigger, used in a map script, is a callback; that is, it an
event handler that is installed to execute when a particular event(s) occur.
Triggers do not function properly in AI scripts.
A trigger is of type New triggers are created with the function (in common.j): native CreateTrigger takes nothing returns trigger The actual trigger contains conditions and actions.
The conditions are a set of native Condition takes code func returns conditionfunc A condition is added to a trigger with the function: native TriggerAddCondition takes trigger whichTrigger, boolexpr condition returns triggercondition It returns a handle to the condition which can be used later in other trigger related functions (e.g., if you want to remove the condition from the trigger). Actions are just functions which execute when the event occurs and the
conditions are satisfied. They should have the signature
native TriggerAddAction takes trigger whichTrigger, code actionFunc returns triggeraction Again, the function returns a handle to the action, in case it must be refered to later. Once a trigger is created, it is must be registered with a game event(s) which indicate when it will be executed. This is accomplished using the functions that look like this in common.j: native TriggerRegister*Event takes trigger whichTrigger, ... returns event There are many other trigger manipulation functions in common.j that can help trigger management. During a game, there will be several independent JASS scripts executing; one for the map trigger script, and one AI script for each computer player. The global variables in each of these scripts are not shared, so setting a global value in one AI script will not affect the same global variable in another computer's AI script. The map script and AI scripts can communicate with each other using
commands. A command is a pair of integer values, a
native CommandAI takes player num, integer command, integer data returns nothing Each computer player has a command stack onto which new commands sent to them are placed. To determine how many commands are waiting on the stack, use the following function (declared in common.ai): native CommandsWaiting takes nothing returns integer To look at the command at the top of the stack, use the following functions: native GetLastCommand takes nothing returns integer native GetLastData takes nothing returns integer Which return the latest native PopLastCommand takes nothing returns nothing Remember that adding a new element to a stack places it on top, while popping an element off the stack also removes the first from the top. Although defining custom data structures in JASS is impossible due to the
lack of first class pointers, the native API does provide a crude
implementation of sets for certain handle types.
A set of The API for managing custom groups and forces is similar. For example, to create, add an element, and remove an element to a group and force respectively: // group management native CreateGroup takes nothing returns group native GroupAddUnit takes group whichGroup, unit whichUnit returns nothing native GroupRemoveUnit takes group whichGroup, unit whichUnit returns nothing // force management native CreateForce takes nothing returns force native ForceAddPlayer takes force whichForce, player whichPlayer returns nothing native ForceRemovePlayer takes force whichForce, player whichPlayer returns nothing A common design pattern used with a set is an iterator or enumeration. An enumeration is an interface that allows you to retrieve each element from the set and operate it. Usually, you want to express the notion "for each element in the set, do something to it" in the same way you would iterate through an array. For example, the standard way to process each element in a set in Java (and similarly in C++) is: // While the iterator of 'set' has more elements in it for (Iterator iter = set.iterator(); iter.hasNext(); ) { // Retreive the next element from the iterator Object element = iter.next(); // Do something with it... processElement(element); } In JASS, there is no way* to "look inside" a
// For each unit in 'whichGroup' call the 'callback' function native ForGroup takes group whichGroup, code callback returns nothing // For each player in 'whichForce' call the 'callback' function native ForForce takes force whichForce, code callback returns nothing A similar function exists to process each element in a destructable
set that consists of all destructables in a certain // For each destructable in 'r' that satisfies 'filter', call the 'actionFunc' function native EnumDestructablesInRect takes rect r, boolexpr filter, code actionFunc returns nothing Within the callback function, you retreive the next element to process with the functions (for groups, forces, destructable sets, respectively): constant native GetEnumUnit takes nothing returns unit constant native GetEnumPlayer takes nothing returns player constant native GetEnumDestructable takes nothing returns destructable (These enumerators to not work correctly in AI scripts so only use them in map scripts) For example, suppose you wanted to kill all the units in a group. You could use the following callback function: function KillGroupCallback takes nothing returns nothing // Get the next unit to process local unit nextUnit = GetEnumUnit() // Kill it call KillUnit(nextUnit) endfunction Then you can kill all the units in a group with the following statement:
call ForGroup(groupToKill, function KillGroupCallback)
Another common operation is to find the element(s) in a set that satisfies certain conditions in relation to the other elements in the set. For example, you might want to find the unit with the most life in a group. Unfortunately, because JASS relies on callbacks to process each element, the only way to maintain state across all the elements in a set is to use a global variable. For example, to find the unit with the most life in a group, you could use the code: globals real mostLifeSoFar unit unitWithMostLifeSoFar endglobals function MostLifeCallback takes nothing returns nothing local unit nextUnit = GetEnumUnit() local real life = GetUnitState(nextUnit, UNIT_STATE_LIFE) if life > mostLifeSoFar then set mostLifeSoFar = life set unitWithMostLifeSoFar = nextUnit endif endfunction ... // Initialize variables to find unit with max life in 'myGroup' set mostLifeSoFar = 0 set unitWithMostLifeSoFar = null // Process each element in 'myGroup' call ForGroup(myGroup, function MostLifeCallback) // Now 'unitWithMostLifeSoFar' refers to the desired unit, // or null if the group was empty ... Finally, you should note that you can achieve most of the same functionality with arrays instead of groups and forces, since an array can be viewed as a set. The drawbacks are that an array always uses up a certain amount of storage (see Types), you will end up with "holes" in your set if you remove elements in the middle of the array, and you can not use the filter functions described in the Filters subsection directly to create array sets (though you can use them to first create a group, then use enumeration callbacks to fill your array). In addition, you can not have an array of arrays, whereas you can have an array of groups or forces. The Enumerations subsection described one way
to create sets (groups and forces), but sometimes it is desirable to
dynamically create a set containing all elements with particular properties.
For example, you might want to create a group containing all the units with
less than 20 mana (then you can use There are several native functions that facilitate this. For example, the following functions can be used to fill groups. They take a group as an argument and add all units that satisfy a certain property to the group. // Add all units that are of type 'unitname' and satisfy the 'filter' native GroupEnumUnitsOfType takes group whichGroup, string unitname, boolexpr filter returns nothing // Add all units that belong to 'whichPlayer' and satisfy the 'filter' native GroupEnumUnitsOfPlayer takes group whichGroup, player whichPlayer, boolexpr filter returns nothing // Add up to 'countLimit' units of type 'unitname' that satisty the 'filter' native GroupEnumUnitsOfTypeCounted takes group whichGroup, string unitname, boolexpr filter, integer countLimit returns nothing // Add all units that are in the rectable 'r' and satisfy 'filter' native GroupEnumUnitsInRect takes group whichGroup, rect r, boolexpr filter returns nothing // Add up to 'countLimit' of units that are in 'r' and satisfy 'filter' native GroupEnumUnitsInRectCounted takes group whichGroup, rect r, boolexpr filter, integer countLimit returns nothing // Add all units that are within 'radius' of the point ('x','y') and // satisfy 'filter' native GroupEnumUnitsInRange takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing // Add all units that are within 'radius' of the point 'location' and // satisfy 'filter' native GroupEnumUnitsInRangeOfLoc takes group whichGroup, location whichLocation, real radius, boolexpr filter returns nothing // Add up to 'countLimit' units that are within 'radius' of the // point ('x','y') and satisfy 'filter' native GroupEnumUnitsInRangeCounted takes group whichGroup, real x, real y, real radius, boolexpr filter, integer countLimit returns nothing // Add up to 'countLimit' units that are within 'radius' of the point // 'location' and satisfy 'filter' native GroupEnumUnitsInRangeOfLocCounted takes group whichGroup, location whichLocation, real radius, boolexpr filter, integer countLimit returns nothing // Add all units that are selected by 'whichPlayer' and satisfy 'filter' native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer, boolexpr filter returns nothing A similar set of functions exist for adding players to forces: // Add all players that satisfy 'filter' native ForceEnumPlayers takes force whichForce, boolexpr filter returns nothing // Add up to 'countLimit' players that satisfy 'filter' native ForceEnumPlayersCounted takes force whichForce, boolexpr filter, integer countLimit returns nothing // Add all units that are allies of 'whichPlayer' that satisfy 'filter' native ForceEnumAllies takes force whichForce, player whichPlayer, boolexpr filter returns nothing // Add all units that are enemies of 'whichPlayer' that satisfy 'filter' native ForceEnumEnemies takes force whichForce, player whichPlayer, boolexpr filter returns nothing Each of these functions takes a native Filter takes code func returns filterfunc The argument's function signature should be constant native GetFilterUnit takes nothing returns unit constant native GetFilterPlayer takes nothing returns player constant native GetFilterDestructable takes nothing returns destructable For example, if I wanted to create a filter that is only satisfied by units with less than 20 mana, I can use the following callback funtion: function LessThan20ManaCallback takes nothing returns boolean // Get the next unit to examine local unit nextUnit = GetFilterUnit() // Check to see if it satisfies our condition return GetUnitState(nextUnit, UNIT_STATE_MANA) < 20 endfunction Then, I can use the following statements to add all units that are in a particular region and have less than 20 mana into my group: // Create the filter local filterfunc myFilter = Filter(function LessThan20ManaCallback) // Add all satisfying units in 'someRect' into 'myGroup' call GroupEnumUnitsInRect(myGroup, someRect, myFilter) // Destroy the filter if we are not going to use it again call DestroyFilter(myFilter) Note that we destroy the filter after we are done with it so there is not a memory leak. If no additional condition is required, then you can pass in the value
|
|||||
Copyright (c) 2003 Jeff Pang Not affiliated or endorsed by Blizzard Entertainment |