Difference between revisions of "Scripting 018"
Martin bede (Talk | contribs) m (→CoreItems, ResourceItems, SoccerBallItems, and TestItems) |
|||
Line 1: | Line 1: | ||
+ | {{TOC right}} | ||
+ | |||
This is a temporary page for documenting the scripting changes for release 018. | This is a temporary page for documenting the scripting changes for release 018. | ||
Revision as of 06:31, 31 March 2013
This is a temporary page for documenting the scripting changes for release 018.
TODO: FlagItem:getCaptureZone & FlagItem:getShip functions (verify w/ sam); make sure all items have getLoc, getRad, getVel, getTeamIndx, and isItem; hasFlag(); engineer-deploy-object (??), ship/bot:getMountedItems(); document libopt (or at least or inclusion of such with summary and pointer to docs) -- need to do require("getopt") to activate it. mention inspect.lua under debugging section.
Server admins can program their own robots in addition to designing their own levels. Robots are coded in Lua, and have a number of special functions available to them.
For examples of fully functional bots, see the Robot Gallery.
Robot coding is still fluid, and the information here is subject to change. You might want to read about the general structure of Bitfighter scripts before proceeding.
How to read the function notation:
- returnType functionName(argType1, argType2)
- Description of function is here. If the function returns no value, returnType will be omitted.
Return types:
Unlike most languages, Lua does not differentiate between integers and floating point numbers. Instead, everything is simply a number. In fact, Lua often will let you interchange strings and numbers, converting dynamically on an as-needed basis. However, relying on this automatic type coercion is bad practice and can get you into trouble.
Some functions take or return special data types:
Point - A Point is an object that contains an x and a y coordinate. When used as an argument in the functions below, in most cases you can replace a Point object with a pair of numbers representing the x and y coordinates.For example:
local a = Asteroid.new() -- Create a new asteroid object local p = Point(110, 80) a:setLoc(p) -- Specify the asteroid's location a:setLoc(110, 80) -- Equivalent statement
In many cases, using the pair of points will perform slightly better because it avoids the step of constructing a Point object, but when choosing between the two, you should always prefer the one that produces clearer code.<p>
Geometry - Geometry is not itself an object, but rather a placeholder for a Point or a table of Points. When dealing with objects that are inherently point-like, such as a TestItem or a CoreItem, Geometry is simply a single Point object (or a pair of coordinates as explained above). In the context of a Zone or LineItem, Geometry is a Lua table of Points (or individual coordinates).<P>
Points to remember in Lua:
- Lua arrays are 1-based: the first index is 1 rather than 0 as is the case in programming languages such as C++ and Java
- Lua is case sensitive. That means that the variable foo is different than Foo and FOO
- Any variable not declared as local will be global. Accessing global variables is slower than local ones, and being sloppy about variable scope can lead to unexpected problems. Use the local keyword whenever appropriate.
We will follow the Lua formatting conventions used in the Programming in Lua book.
Object Model
Starting with release 018, Bitfighter objects follow a true inheritance model -- that is, each object has a parent and may have one or more children. Each object has the same methods as the parent, and may have one or more methods specific to the object. For example, all objects that can appear in a game have a getLoc() method that returns the object's position, but only objects that can move have getVel() method to return their speed. Therefore, knowing understanding the object model is an important step towards discovering what methods an object implements.
The Bitfighter object model can be viewed by running Bitfighter with the -luadocs option.
The current Bitfighter object model:
BfObject +----- Item | +----- CoreItem | +----- EngineeredItem | | +----- Turret | | +----- ForceFieldProjector | +----- MoveObject | | +----- MoveItem | | | +----- FlagItem | | | +----- SoccerBallItem | | | +----- HeatSeeker | | | +----- Burst | | | | +----- SpyBugItem | | | | +----- MineItem | | | +----- ResourceItem | | | +----- TestItem | | | +----- Circle | | | +----- Asteroid | | +----- Ship | | +----- Robot | +----- PickupItem | +----- EnergyItem | +----- RepairItem +----- Projectile +----- Teleporter +----- WallItem +----- Zone +----- LoadoutZone +----- NexusZone +----- GoalZone
BfObject
BfObjects are the granddaddy of all Bitfighter's game objects. Any method defined here is available on all child objects unless specifically noted otherwise.
- classId getClassID()
- Get an object's class id. See the ItemTypes section for a list of possible return values.
- getLoc()
- Get an object's position. Returns a Point object representing the object's current position. For objects that are not points (such as a Loadout Zone), will return the object's centroid.
- setLoc(Point)
- Set the object's location.
- int getTeamIndx()
- Returns the index of the team this object is associated with. See Special team constants for details on how neutral and hostile teams are represented.
- setTeam(Team index)
- Assigns the object to a team. Use the special team constants to make an item neutral or hostile. Will have no effect on items that are inherently teamless (such as a NexusZone).
- addToGame()
- Add the specified object to the current game or editor session. A given item can only be added to a game once. For most objects in a game, updating characteristics such as position will immediately be reflected in the game or editor.
- removeFromGame()
- Removes the object from the game. May not be implemented for all objects.
- Geometry getGeom()
- Returns an object's geometry. For point objects, this will be a single Point. For more complex objects (such as a WallItem or a Zone), will return a Lua table containing a list of Points.
- setGeom(Geometry)
- Sets an object's geometry. Note that not all objects support changing geometry if an object is in a game.
- BfObject clone()
- Returns an exact duplicate of an object. If an object that is in a game is cloned, the copy will not be added to the game until it is explicitly added with the addToGame() method.
Item
- num getRad()
- Returns the radius of the item in pixels.
- bool isOnShip()
- Returns true if the Item is mounted on a ship, false otherwise. Most Items cannot be mounted on ships.
- Ship getShip()
- Returns the Ship the Item is mounted on. If the Item is not mounted, returns nil.
- bool isInCaptureZone()
- Returns true if the item is in a capture zone, false otherwise. Currently, only Flags and SoccerBallItems can be in capture zones, and only in some games. Always returns false for other Items.
- GoalZone getCaptureZone()
- Returns the GoalZone in which the Item is captured. If the Item is not captured, this function will return nil.
CoreItem
- CoreItems implement all BfObject methods, plus the following:
- num getHealth()
- Returns total health of all panels on the core item. There is currently no way to query the health of an individual panel.
- setHealth(num)
- Sets the overall health of all panels on the core item; Each panel will be given 1/10th the specified health. Health of 1 is the same health a ship has, so to give each panel a health equivalent to a ship, do setHealth(10).
EngineeredItem
- bool isActive()
- Returns true if the EngineeredItem is "alive" and active, or false if it is dead.
- num getHealth()
- Returns health of the item. Health is specified as a number between 0 and 1 where 0 is completely dead and 1 is totally healthy.
- setHealth(num)
- Set the current health of the item. Health is specified as a number between 0 and 1 where 0 is completely dead and 1 is totally healthy. Values outside this range will be clamped to the valid range.
- num getMountAngle()
- Gets the angle (in radians) at which the EngineeredItem is mounted.
ForceFieldProjector
- ForceFieldProjectors implement all the EngineeredItem methods.
Turret
- Turrets implement all the EngineeredItem methods plus the following:
- num getAimAngle()
- Returns the angle (in radians) at which the Turret is aiming.
- getAimAngle(num)
- Sets the angle (in radians) at which the Turret is aiming.
PickupItem
- PickupItems implement all the Item methods, plus the following:
- bool isVis()
- Returns true if the PickupItem is currently visible to players and is available for pickup.
- setVis(bool)
- Sets whether the PickupItem is visible to players and is available for pickup.
- setRegenTime(num)
- Sets the time (in seconds) for the PickupItem to regenerate itself. Default is 20 seconds. Setting regen time to a negative number will produce an error.
EnergyItem
- EnergyItems implement all the PickupItem methods.
RepairItem
- RepairItems implement all the PickupItem methods.
Projectile
Implements all methods implemented by BfObjects, and also the following:
- WeaponType getWeapon()
- Returns the type of the projectile. See WeaponType constants for valid values.
- Point getVel()
- Returns the projectile's velocity.
- setVel(Point)
- Sets the projectile's velocity.
Teleporter
Teleporters, of course, teleport ships from one place to another. Each Teleporter will have a single "intake", which is considered the Teleporter's location, and can be obtained with the getLoc() method. Teleporters must have at least one "outlet" (or destination), but could have several.
Teleporters implement all BfObject methods, plus the following:
- addDest(Point)
- Add a destination to the teleporter.
- delDest(int)
- Remove the specified destination from the teleporter. Remember, in Lua, indices start with 1, so to remove the first destination, do tel:delDest(1) If you specify an invalid index, an error will be generated.
- clearDests()
- Remove all destinations from the teleporter. Teleporter will not be displayed if it has no destinations.
- Point getDest(int)
- Retrieves the specified destination. Remember that the first destination will have an index of 1. Specifying an invalid index will generate an error.
- int getDest()
- Returns the number of destinations the teleporter has.
Zone
Zones are invisible objects, used mainly for generating events. Zones implement all BfObject methods.
GoalZone
Implements all Zone methods, plus the following:
- bool hasFlag()
- Returns true if the GoalZone has a flag, false otherwise. Always returns false in games where GoalZones don't hold flags (e.g. Soccer).
NexusZone
Implements all Zone methods, plus those listed below.
Note that the following methods act as passthroughs to the underlying Game object, and as such, will affect ALL NexusZones in the game. They are provided as object methods because that seems more intuitive, though this may change in the future.
- setOpen(bool)
- Pass true to open the Nexus, false to close it.
- bool isOpen()
- Returns true if the Nexus is open, false if not.
- setOpenTime(num)
- Set the time (in seconds) that the Nexus will remain open. Pass 0 if the Nexus should never close.
- setClosedTime(num)
- Set the time (in seconds) that the Nexus will remain closed. Pass 0 if the Nexus should never reopen.
LoadoutZone
Implements all Zone methods.
Events
Lua robots are designed to respond to many in-game events using event handlers. To respond to an event your bot must have an appropriately named function (described below), and must subscribe to any events it is interested in. You can also unsubscribe to an event at any time to stop receiving event notifications.
Currently defined events
Event ID | Associated function | Description |
---|---|---|
TickEvent | onTick(timeSinceLastTickInMs) | Called every frame of the game. Unlike other events, robots are subscribed to this event by default. |
ShipSpawnedEvent | onShipSpawned(ship) | Called when any ship or robot spawns (not including your robot). Spawning ship is passed as the first argument. |
ShipKilledEvent | onShipKilled(ship) | Called when any ship or robot is killed (not including your robot). Dead ship is passed as the first argument. |
MsgReceivedEvent | onMsgReceived(message, senderPlayerInfo, global) | Called when a player or robot sends a message. Message itself is first argument, a PlayerInfo for the sender is the second argument, and the third argument is a boolean that will be true if the message was global, false if sent to teammates only. Note that senderPlayerInfo can be nil if message is sent by a Controller script. |
PlayerJoinedEvent | onPlayerJoined(playerInfo) | Called when a player or robot joins the game (not when they spawn). Note that when hosting a game locally, local player does not necessarily trigger this event due to the uncertain order of creation of game objects. First argument is playerInfo for the joining player. |
PlayerLeftEvent | onPlayerLeft(playerInfo) | Called when a player or robot leaves the game. Note that event may not be fired when robots or local player leaves game due to server shutting down. First argument is playerInfo for the leaving player. |
NexusOpenedEvent | onNexusOpened() | Called when Nexus opens in a Nexus game. Never fires in other game types. |
NexusClosedEvent | onNexusClosed() | Called when Nexus closes in a Nexus game. Never fires in other game types. |
Example:
function main() ... subscribe(ShipSpawnedEvent) -- Subscribe so onShipSpawned() will be called ... end -- Since we are subscribed to the ShipSpawned event, the onShipSpawned() function -- will be called whever a ship or robot spawns. function onShipSpawned(ship) logprint("Ship spawned: ".. tostring(ship:getLoc())) angle = bot:getLoc():angleTo(ship:getLoc()) logprint("angle to spawned ship = "..angle) end
Example:
-- Keep track of all players/robots in the game. This may be more efficient than -- reading the list every time it is needed if it is used frequently. function main() ... subscribe(PlayerJoinedEvent) subscribe(PlayerLeftEvent) ... players = GameInfo():getPlayers() -- Vars defined in main() will be global end function onPlayerJoined() players = GameInfo():getPlayers() -- Player joined: get updated player list end function onPlayerLeft() players = GameInfo():getPlayers() -- Player left: get updated player list end
You can also use timers and events to create a basic sleep function:
function sleep(time) -- Sleep time in ms unsubscribe(TickEvent) -- Stop getting tick events until... Timer:scheduleOnce("subscribe(TickEvent)", time) -- ...we resubscribe! end
There are two general methods for getting the current game time:
- number getTime()
- number getCPUTime()
These functions will return slightly different results. Generally speaking, if you are timing things in the "real world", i.e. you want to pause for exactly 1 second, use getCPUTime(). If you want to use a timer to make the robot move smoothly around a mathematically derived course, use getTime(), as that is what is used internally when calculating ship movement.
Example:
lastTime = thisTime thisTime = bot:getCPUTime() local delta = thisTime - lastTime logprint(delta .. " ms have elapsed in the real world since last frame.")
Example:
-- Will fly robot in a circular orbit around an item. -- Assume we've already found one and stored it in "item" local botLoc = bot:getLoc() local itemLoc = item:getLoc() local dist = botLoc:distanceTo(itemLoc) -- For this example, we'll define orbitRadius as a local variable. In a -- real robot, this might be better declared a global variable in the header. local orbitRadius = 300 -- Here we use the getTime() function to make the motion look smooth. -- If we just advanced orbitAng by a fixed amount each frame, it would -- appear jerky, as each frame represents a slightly different length in time. -- .0015 determined experimentally orbitAng = orbitAng + .0015 * bot:getTime() -- orbitAng is a global variable local dest = nil if(dist <= orbitRadius * 1.1) then dest = itemLoc dest:setxy(itemLoc:x() + orbitRadius * math.cos(orbitAng), itemLoc:y() + orbitRadius * math.sin(orbitAng) ) else dest = itemLoc end bot:setThrustToPt(dest) -- Travel towards calculated point
- Point getZoneCenter(x, y)
- Point getGatewayFromZoneToZone(a, b)
- number getZoneCount()
- number getCurrentZone()
- number getAngle()
- Point getLoc()
- number getTeamIndx()
- void setAngle(ang)
- void setAngle(pt)
Example:
-- This code in onTick() local items = bot:findItems(AsteroidType) -- Get list of all asteroids local asteroid = findClosest(items) -- Finds closest if(asteroid == nil) then -- Make sure we found one return end local loc = bot:getLoc() -- Our location (Point object) local ang = loc:angleTo( asteroid:getLoc() ) bot:setAngle(ang) -- Aim ship toward asteroid bot:fire()
- void setAnglePt(Point)
- number getAnglePt(Point)
- boolean hasLosPt(Point)
- boolean hasLosPt(x, y)
- number getFiringSolution(item)
Example:
local loc = bot:getLoc() -- Current location local items = bot:findGlobalItems(SoccerBallItemType) -- Find soccerball -- Loop through all returned items and find the closest -- This code here for learning purposes... could be replaced with -- much simpler single line: -- local ball = findClosest(items) local minDist = 99999999 local ball = nil for sb in values(items) do local l = sb:getLoc() -- Ball's location -- Distance from ship to ball (use distSquared because -- it is easy to compute and good for comparison) local d = loc:distSquared(l) if(d < minDist) then ball = sb minDist = d end end -- End replaceable code section -- Check to make sure we found a soccer ball ... could be out of view if(ball == nil) then return end local ang = bot:getFiringSolution(sb) -- Get shoot angle to hit moving ball -- Always check for nil: could happen if ball were behind a wall or -- friendly ship. Running setAngle(nil) will do nothing. if(ang == nil) then return end bot:setAngle(ang) -- Ready... aim... bot:fire() -- ...fire!
- number getTeamIndx()
- boolean hasFlag()
- WeaponType getActiveWeapon()
Example:
weap = bot:getActiveWeapon() -- Get info about our currently active weapon weapInfo = WeaponInfo(weap) -- Get information about it logprint(weapInfo:getName() .. " has a range of " .. weapInfo:getRange())
Modules are automatically disabled at the end of each game cycle. Therefore, if you want to keep a module on for a sustained period of time, you must activate it each time onTick() is called. To activate a module, use one of the activateModule() commands.
- void activateModule(ModuleType)
Example:
-- Note that this line will do nothing if we don't have shields bot:activateModule(ModuleShield) -- Shields up!
- void activateModuleIndex(indx)
Example:
-- Must specify an index, currently either 1 or 2 bot:activateModuleIndex(1) -- Activate first module, whatever it is
- void setReqLoadout(Loadout)
- Loadout getCurrLoadout()
Example:
loadout = bot:getCurrLoadout() -- Retrieve current bot configuration weapType1 = loadout:getWeapon(1) -- Get the first weapon weapType2 = loadout:getWeapon(2) -- Get the second weapon weapType3 = loadout:getWeapon(3) -- Get the third weapon -- Check to see if the first weapon is a phaser if (weapType1 == WeaponPhaser) then logprint("First weapon is a phaser!") end -- Print a list of our three current weapons logprint("My three weapons are: " .. WeaponInfo(weapType1):getName() .. ", " .. WeaponInfo(weapType2):getName() .. ", and " .. WeaponInfo(weapType3):getName())
- Loadout getReqLoadout()
Navigation
- [Item list] findItems(ObjectType, ...)
- [Item list] findGlobalItems(ObjectType, ...)
Example:
-- Find all resource items in the normal viewport local items = bot:findItems(ResourceItemType) -- You can specify multiple item types if you want -- Get a list of all TestItems or Asteroids that are visible anywhere -- (note that items that are out-of-scope will be omitted) local globItems = bot:findGlobalItems(TestItemType, AsteroidType) -- Now iterate over the list ... there are many examples in the documentation! for item in values(globItems) do -- Do something with item ... perhaps figure out which is closest, -- which is heading towards us, etc. end
- Point getWaypoint(Point)
- Point getWaypoint(x, y)
Ship control
- void setThrust(vel, angle)
- void setThrustPt(vel, Point)
- void setThrustToPt(Point)
- void fire()
- void setWeaponIndex(index)
- void setWeapon(WeaponType)
- boolean hasWeapon (WeaponType)
Example:
if(bot:hasWeapon(WeaponMine)) then bot:setWeapon(WeaponMine) -- Make mine layer active if it's -- part of our current loadout bot:fire() -- Lay a mine end
Logging & Sending Messages
- void globalMsg(msg)
- void teamMsg(msg)
- void logprint(msg)
When sending a team or global message, some basic variable substitutions are available. %playerName% will be replaced with the receiving player's name. %controlName% will be replaced with the appropriate key binding on the receiving player's machine. A full list of controlNames can be found in the KeyBinding section of the bitfighter.ini file. Examples include %SelWeapon1% and %ShowScoreboard%. While this capability is also available to player manually typing chat messages, it is mostly intended for tutorial bots to help the player along. Variable names are case insensitive.
GameItems
The Lua object structure generally follows that used by Bitfighter. The GameItems group conisists of Ships, Robots, RepairItems, Asteroids, ResourceItems, SoccerBallItems, Flags, NexusFlags, and TestItems. These all share similar properties, and have similar methods. All of these implement the getLoc(), getVel(), and getRad() methods for querying location, velocity, and radius respectively. Some items have additional methods that apply only to them. See below for details on these additional methods.
Ships & Robots
Unless otherwise noted, all of these methods will work both on a ShipItem object as well as the local bot object.
- boolean isAlive()
Rather than checking isAlive() every tick, it may be more efficient to keep track of dying ships by subscribing to ShipKilledEvent.
Example:
-- Assuming we've subscribed to ShipKilledEvent, and that target is a global function onShipKilled(ship) if target == ship then target = nil -- check for target == nil elsewhere and reacquire a target end end
Note: All of the following functions will return nil if they are called on a dead ship. When in doubt, check for nil!
- Point getLoc()
- number getRad()
- Point getVel()
- number getAngle()
- number getTeamIndx()
- PlayerInfo getPlayerInfo()
The following two methods return a number between 0 and 1 where 1 means full health or energy, 0 means no health or energy.
- number getHealth()
- number getEnergy()
- boolean isModuleActive(ModuleType)
- boolean hasFlag()
- number getFlagCount()
- void dropItem()
- WeaponType getActiveWeapon()
CoreItems, ResourceItems, SoccerBallItems, and TestItems
These items all have the same methods and behave in a very similar manner.
Category: GameItem
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
The coordinates of ResourceItems and TestItems can simply be passed to their constructors:
local testItem1 = TestItem.new(100,200) local testItem2 = TestItem.new(point.new(100,200)) local resourceItem1 = ResourceItem.new(200,100) local resourceItem2 = ResourceItem.new(point.new(200,100))
CoreItems have one additional method:
- number getHealth()
Example:
local items = bot:findItems(TestItemType) -- Find all TestItems in view -- Now cycle through all returned items and find the fastest one local maxSpeed = -1 local fastest = nil for indx, ti in ipairs(items) do -- getVel() returns a point representing the x and y components of -- the velocity. Need to use len() to get actual speed. Or, in this -- case, since actual speed isn't important, we can use lenSquared() -- which is less computationally intensive, and will yield perfectly -- good results for comparison purposes (such as finding the fastest). spd = ti:getVel():lenSquared() if(spd > maxSpeed) then fastest = ti maxSpeed = spd end end -- Better check to make sure fastest isn't nil before using it! -- Could be nil if there are no TestItems in view if(fastest != nil) then -- Do something end
Asteroids
Category: GameItem
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
- number getSize()
- number getSizeCount()
Example:
local asteroids = bot:findItems(AsteroidType) local target = asteroids[1]:getLoc() -- Pick first asteroid
RepairItems
Category: GameItem
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
- boolean isVis()
Example:
local ri = bot:findItems(RepairItemType) -- Get list of all known RepairItems local pos = ri[1]:getLoc() -- Get position of first
Flags
Category: GameItem
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
- boolean isInInitLoc()
- boolean inCaptureZone()
- boolean isOnShip()
Turrets and ForceFieldProjectors
Category: GameItem
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
- number getHealth()
- boolean isActive()
GoalZones and LoadoutZones
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
Nexus Related
The following functions only have meaning in a Nexus game.
- number getNexusTimeLeft()
- boolean isNexusOpen()
Example:
if isNexusOpen() then local timeLeft = getNexusTimeLeft() / 1000 if timeLeft < 10 then teamMsg("Hurry! Nexus closes in " .. timeLeft .. " seconds!") end end
Bullets, Mines, and SpyBugs
Category: GameItem
There are three GameItem types that have to do with bullets, mines, and spybugs: BulletType, MineType, and SpyBugType respectively. They all have the same methods, and can be used somewhat interchangeably, as shown in the example below. However, as shown, they can also be found independently.
<p>
BulletType encompases Phaseser, Bounce, Triple, Burst, and Turret shots, the properties of which can be retrieved with the WeaponInfo object.
- Point getLoc()
- number getRad()
- Point getVel()
- number getTeamIndx()
- WeaponType getWeapon()
Example:
local bullets = bot:findItems(BulletType, MineType, SpyBugType) <some code> -- Code here to select one of the found items local weap = selectedBullet:getWeapon() local weapInfo = WeaponInfo(weap) logprint("Selected " .. weapInfo:getName())
Weapon Information
All WeaponInfo data will remain constant throughout the game. Therefore, if you need some information about a weapon (mines, say, for a minesweeping bot), it might make sense to retrieve it in the bot's main() function, and store it in a global variable rather than instantiating a new WeaponInfo object during every iteration of the robot's onTick() method.
Example:
local weap = bot:getActiveWeapon() -- Get bot's currently active weapon logprint(weap:getName() .. " shoots with a speed of " .. weap:getProjVel())
-- In main()... we'd better not declare these variables as local! function main() ... turretInfo = WeaponInfo(WeaponTurret) -- Get info about the infernal turrets safeDist = turretInfo:getRange() -- Be safe and stay this far away ... end
- string getName()
- WeaponType getID()
- number getRange()
- number getFireDelay()
- number getMinEnergy()
- number getEnergyDrain()
- number getProjVel()
- number getProjLife()
- number getDamage()
- number getDamageSelf()
- boolean getCanDamageTeammate()
WeaponType constants
Commands that return a WeaponType will return one of the following values:
WeaponPhaser | WeaponBounce |
WeaponTriple | WeaponBurst |
WeaponMine | WeaponSpyBug |
WeaponTurret |
Module Information
All ModuleInfo data will remain constant throughout the game. Therefore, if you need some information about a module (for example, the energy consmption of shields), it might make sense to retrieve it in the bot's main() function, and store it in a global variable rather than instantiating a new ModuleInfo object during every iteration of the robot's onTick() method.
Example:
local mod = ModuleInfo(ModuleBoost) logprint("This is a lame example!")
- string getName()
- ModuleType getID()
ModuleType constants
Functions that return a ModuleType will return one of the following values:
ModuleShield | ModuleBoost |
ModuleSensor | ModuleRepair |
ModuleCloak | ModuleEngineer |
ModuleArmor |
Loadouts
- void setWeapon(index, WeaponType)
- void setModule(index, ModuleType)
- WeaponType getWeapon(index)
- ModuleType getModule(index)
Example:
-- Get a new loadout (comes pre-filled with default values) local loadout = Loadout() -- Configure the loadout to suit our needs loadout:setWeapon(1, WeaponPhaser) loadout:setWeapon(2, WeaponBurst) loadout:setWeapon(3, WeaponMine) loadout:setModule(1, ModuleShield) loadout:setModule(2, ModuleCloak) -- Set the loadout, will become active when bot hits loadout zone -- or spawns, depending on game bot:setReqLoadout(loadout) if(loadout:getWeapon(1) == WeaponPhaser) then logprintf("This line always gets printed!") end
- boolean isValid()
- boolean equals(Loadout)
GameInfo
You can get information about the current game with the GameInfo object. You only need get this object once, then you can use it as often as you like. It will always reflect the latest data.
Example:
game = GameInfo() -- Create the GameInfo object gameType = game:getGameType() if(gameType == SoccerGame) then logprint("This bot is not very good at soccer!") else gameTypeName = game:getGameTypeName() logprintf("I just love playing " .. gameTypeName .. "!") end
Example:
-- Create the GameInfo object in main() (don't declare it local!!) function main() ... game = GameInfo() -- In main non-local variables become globals ... end ... -- Even though we only create our GameInfo once, it is always current ... -- Later, in onTick(): local remTime = game:getGameTimeReamaining() local totTime = game:getGameTimeTotal() local percent = (totTime - remTime) / remTime logprint("Game is " .. percent .. "% over)
- GameType getGameType()
- string getGameTypeName()
- number getFlagCount()
- number getWinningScore()
- number getGameTimeTotal()
- number getGameTimeRemaining()
- number getLeadingScore()
- number getLeadingTeam()
- number getTeamCount()
Example:
-- Create the GameInfo object main() (don't declare it local!!) function main() ... game = GameInfo() -- In main non-local variables become globals ... end -- Then later, in onTick() or other function ... local leadingTeam = game:getLeadingTeam() local team = TeamInfo(leadingTeam) bot:teamMsg("Hurry up! Team " .. team:getName() .. " is winning!" )
- PlayerInfo list getPlayers()
Example:
players = GameInfo():getPlayers() for player in values(players) do if player:isRobot() then logprint(player:getName().." is a bot!") else logprint("Hello "..player:getName()) end end
- string getLevelName()
- number getGridSize()
- boolean getIsTeamGame()
- void getEventScore(ScoringEvent)
GameType constants
Functions that return a GameType will return one of the following values:
BitmatchGame | CoreGame |
CTFGame | HTFGame |
NexusGame | RabbitGame |
RetrieveGame | SoccerGame |
ZoneControlGame |
ScoringEvent constants
Functions that return a ScoringEvent will return one of the following values:
KillEnemy | KillSelf |
KillTeammate | KillEnemyTurret |
KillOwnTurret | CaptureFlag |
CaptureZone | UncaptureZone |
HoldFlagInZone | RemoveFlagFromEnemyZone |
RabbitHoldsFlag | RabbitKilled |
RabbitKills | ReturnFlagsToNexus |
ReturnFlagToZone | LostFlag |
ReturnTeamFlag | ScoreGoalEnemyTeam |
ScoreGoalHostileTeam | ScoreGoalOwnTeam |
TeamInfo
- string getName()
- number getIndex()
- number getPlayerCount()
- number getScore()
- PlayerInfo list getPlayers()
Example:
local gameInfo = GameInfo() local teams = gameInfo:getTeamCount() -- Note that while the number of teams will not change throughout the game, -- the number of players on each team might. Also, the robot may be initialized -- before the players have been added, so if you run this code in the bot header, -- it may report some teams having 0 players. for i = 1, teams do -- First team has an index of 1 team = TeamInfo(i) logprint("Team " .. i .. " is called " .. team:getName() .. " and has " .. team:getPlayerCount() .. " players") end
Special team constants
Two special team constants are available to make your programs simpler and easier to read. In addition to the normal player teams, Bitfighter has two pseudo teams, "Neutral" and "Hostile". These constants can be used to identify those teams:
NeutralTeamIndx - Neutral team
HostileTeamIndx - Hostile team
Example:
team = turret:getTeamIndx() if team == NeutralTeamIndx then -- Neutral - can be repaired mode = repair else if team == HostileTeamIndx then -- Hostile - must be destroyed! mode = attack end
PlayerInfo
Provides information about a player or robot. The PlayerInfo object will remain valid and will contain current information as long as the player is in the game.
string getName() - return player's name
Ship getShip() - return player's ship (note: can be nil)
string getScriptName() - for robots, returns name of script; for players, returns nil
number getTeamIndx() - return team's index, index of first team is 1
number getRating() - return player's rating
number getScore() - return player's score
boolean isRobot() - returns true if the PlayerInfo is a robot, false if it is a human
Timers
Timer is a utility class that makes it easier to manage timing periodic or delayed events. The timer code is based on a very nice library written by Haywood Slap
A timer object that can be used to schedule arbitrary events to be executed at some time in the future. All times are given in milliseconds.
Usage
There are four basic timer functions:
-- Execute the event once in 'delay' ms Timer:scheduleOnce(event, delay -- Execute the event repeatedly, every 'delay' ms Timer:scheduleRepeating(event, delay) -- Execute the event every 'delay' ms while event returns true Timer:scheduleRepeatWhileTrue(event, delay) -- Remove all pending events from the timer's queue Timer:clear()
Timer Events
The 'event' used can either be the name a function, a table that contains a function named 'run', or a bit of arbitrary Lua code.
Any Lua function can be called by the Timer.
Examples:
function onLevelStart() -- Compiles and runs string in five seconds. -- Note that the string here is in quotes. Timer:scheduleOnce("logprint(\"Once!\")", 5000) -- Runs the always function every 30 seconds Timer:scheduleRepeating(always, 30000) -- Runs "run" method of maybe every two seconds -- until method returns false Timer:scheduleRepeatWhileTrue(maybe, 2000) end -- Standard function function always() logprint("Timer called always") end -- Table: run method will be called maybe = { count = 3 run = function(self) logprint("Count down " .. self.count) self.count = self.count - 1 return self.count > 0 end }
When using a table as an 'event' the first parameter to the run function should always be a parameter named "self" (or "this" if you prefer). The "self" parameter can be used to access the other fields in the table, that is, the "self" parameter will refer to the table that contains the run function. If you do not need to refer to any of the other fields in the table then you do not need to include the self parameter.
Points
Point is a utility class to make handling coordinates or vectors simpler. You can create your own point objects using the constructor, or you can get them as return values from many functions.
- Point Point(x, y)
- number x()
- number y()
- void setxy(x, y)
- void setx(x)
- void sety(y)
- void setAngle(ang)
- void setPolar(r, ang)
- number len()
- number lenSquared()
- boolean equals(Point)
- void normalize(length)
- number distanceTo(Point)
- number distSquared(Point)
- number angleTo(Point)
- number angleTo(x, y)
Example:
local point = Point(0, 0) -- Create a new point if point:equals(Point(1, 1)) then logprint("This never gets printed") end if point:distanceTo(Point(1, 1)) < 5 then logprint("This always gets printed") end -- Same thing, but with a little less overhead if point:distanceTo(1, 1) < 5 then logprint("So does this, but more efficiently") end -- Here we'll use a point to represent a velocity, which has x & y components local xspeed = 10 local yspeed = 15 local velocity = Point(xspeed, yspeed) logprint("Speed = " .. velocity:len())
ItemTypes
Functions that return an ItemType will return one of the following values:
ShipType
RobotType
BulletType
MineType
SpyBugType
RobotType
TeleportType (not yet fully implemented)
SpeedZoneType (not yet fully implemented)
AsteroidType
CoreType
TurretType
ForceFieldProjectorType
TestItemType
FlagType
SoccerBallItemType
ResourceItemType
Things that are not really items
Polygonal-like
BotNavMeshZoneType
NexusType
GoalZoneType
LoadoutZoneType
Wall-like
BarrierType
ForceFieldType
Helper functions
- item findClosest((list of items [, teamIndx])