Differences Between the C++ and Lua API¶
Most of the API follows the conventions of the C++ API and can be used in exactly the same ways, although there are exceptions in cases where either:
- The Lua programming language does not have the same capabilities as C++, so things must be done a different way
- It makes more sense to do something in a “Lua way” rather than the “C++ way”
This page documents all such differences.
All classes¶
Every bound class has a static member function isInstance
which can be used to determine if a userdata
value (an instance of a C++ class) is an instance of that class.
function determineType(unknown)
if BWAPI.Position.isInstance(unknown) then
print("It's a Position")
elseif BWAPI.TilePosition.isInstance(unknown) then
print("It's a TilePosition")
elseif BWAPI.Unit.isInstance(unknown) then
print("It's a Unit")
else
print("It's something else")
end
end
Interface derived classes (Game, Player, Unit, etc)¶
registerEvent()
¶
Takes Lua functions for its action
and condition
parameters (note: condition
can be nil
)
local Broodwar = BWAPI.Broodwar
local pos = u:getPosition()
local lastErr = Broodwar:getLastError()
local action = function()
Broodwar:drawTextMap(pos, string.format("%c%s", BWAPI.Text.White, tostring(lastErr)))
end
Broodwar:registerEvent(action, nil, Broodwar:getLatencyFrames())
getClientInfo()
and setClientInfo()
¶
getClientInfo
/setClientInfo
have been removed in favor of a clientInfo
property that is a Lua table. This allows for storing arbitrary data in a more user-friendly way.
unit.clientInfo["test"] = 5
print(unit.clientInfo["test"])
Important
setClientInfo
has also been removed from Unitset
. Instead, you should simply iterate the Unitset
and operate on the clientInfo of each unit as needed.
local value = 5
for unit in set:iterator() do
unit.clientInfo["key"] = value
end
Functions that take a variable amount of string parameters in C++¶
All C++ functions that take variable amounts of strings now expect only a single string.
Note
Any formatting must be done in Lua first (string.format
), and then the formatted string can be passed into the function like normal.
Game.sendTextEx()
¶
A new convenience function has been added to send text to allies: sendTextToAllies()
, which fowards the method to sendTextEx()
with true
as the first parameter. The following two snippets are exactly equivalent:
BWAPI.Broodwar:sendTextEx(true, "your message")
BWAPI.Broodwar:sendTextToAllies("your message")
Unit¶
cancelTrain()
and getTrainingQueue()
¶
All methods that deal with training slots have been changed to be one-indexed (like Lua), rather than zero-indexed (like C++). For example, to cancel the first unit being trained, you would now pass a slot of 1
, whereas in C++ you’d pass a slot of 0
. List of affected methods:
BWAPI.Unit.canCancelTrainSlot()
BWAPI.Unit.cancelTrain()
BWAPI.Unit.getTrainingQueue()
BWAPI.UnitCommand.getSlot()
BWAPI.UnitCommand.cancelTrain()
BWAPI.Unitset.cancelTrain()
Similarly, getTrainingQueue()
returns a Lua array-like table (which is one-indexed) instead of a std::list
(which is zero-indexed). This allows for the following:
-- cancel the first dragoon found in the queue
local queue = building:getTrainingQueue()
for slot, unitType in ipairs(queue) do
if unitType == BWAPI.UnitTypes.Protoss_Dragoon then
building:cancelTrain(slot)
break
end
end
Warning
Iterating a training queue and canceling multiple slots while in the loop will result in unexpected behavior, as the slots will shift as things are canceled. For example, if you cancel slot 1 and then iterate to slot 2 and also cancel it, then you’ll actually be canceling what was originally in slot 3.
UnitType¶
requiredUnits()
¶
Returns a Lua table of the format { [<unitTypeID>] = <howMany> }
, where <unitTypeID>
is the integer ID/Enum of a required UnitType (equal to UnitType:getID()
) and <howMany>
is the required number of that unit.
local scv = BWAPI.UnitTypes.SCV
local requiredUnits = scv:requiredUnits()
for unitTypeID, howMany in pairs(requiredUnits) do
local requiredUnitType = BWAPI.UnitType(unitTypeID)
local str = string.format("%s requires %d %s",
tostring(scv),
howMany,
tostring(requiredUnitType)
)
print(str)
end
SetContainer implementations (Unitset, Playerset, etc)¶
The set can be iterated one of two ways:
for x in set:iterator() do
for i, x in ipairs(set:asTable()) do
Also, any SetContainer types of the format ClassName::set
are bound as ClassNameset
, to match the naming convention of the other SetContainer types (Playerset
, Unitset
, etc). For example, UnitType::set
is bound as BWAPI.UnitTypeset
.
An additional convenience method, filter
(e.g. BWAPI.Unitset.filter()
), has been added to easily filter a set using a predicate function, as well as some aliases for filter
and erase_if
(see eraseIf()
, keep_if()
, keepIf()
).
All lists (std::list, Position::list, UnitType::list, etc)¶
All C++ functions that return lists now return array-like Lua tables.
local nukeDots = BWAPI.Broodwar:getNukeDots()
for i, pos in ipairs(nukeDots) do
print(string.format("There's a nuke at %s", tostring(pos)))
end
UnitFilter¶
All functions that take a UnitFilter parameter now expect a Lua function that takes a unit and returns a boolean.
Note
BWAPI.Filter
functions can be used by calling them with a Unit
as the parameter (e.g. BWAPI.Filter.CanAttack(unit)
)
These filters can also be combined by using the normal Lua boolean operators and wrapping/returning the result in a function. The function can then be passed as an argument to functions that would normally take a UnitFilter
in C++, like so:
local myFilter = function(unit)
return BWAPI.Filter.CanAttack(unit) and not BWAPI.Filter.IsOrganic(unit)
end
local closest = unit:getClosestUnit(myFilter)
BestFilter¶
All functions that take a BestUnitFilter
parameter now expect a Lua function that takes two parameters: the current best unit, and the unit to compare to, and returns the best unit out of the two.
local bestFilter = function(a, b)
if b:getHitPoints() > a:getHitPoints() then
return b
end
return a
end
local best = BWAPI.Broodwar:getBestUnit(bestFilter, BWAPI.Filter.IsOrganic)
See also
Event and Game::getEvents¶
For now, the getEvents
function of BWAPI.Game
has been removed, and there are no bindings for the BWAPI.Event
class. This is subject to change if it’s shown to be necessary.