RepairBot
I present to you: RepairBot!
Usage:
/addbot repair
Behavior:
- Finds any friendly or neutral turret or forcefield projector and repairs the closest one. It will proceed until all possible are repaired
- Shoots nearby targets (is slightly more accurate than s_bot)
- Does not shield - this took too much energy away from its primary goal
Enjoy!
- Code:
- -------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--
-- RepairBot: finally delegating base repair to a computer
--
-- RepairBot is a robot that will find any neutral or friendly turrets and
-- and forcefield projectors on the map and will proceed to repair them
--
-- RepairBot will also shoot nearby enemies if they come within range
--
-- Author:
-- - raptor
--
-- Version history
--
-- 0.1 Initial release (for 017?)
-- 0.2 Fix some crashes, remove ability to heal engineered items
-- 0.3 Port to 018a, add optimizations, fixes
-- 0.4 Only target a repairable you can actually navigate to
-- 0.5 Don't use stupid waypoint finding, add back healing of engineered items
-- 0.6 Update to 019 API
--
function getName()
return( "RepairBot" )
end
function fireAtObject(obj, weapon)
if(obj:getObjType() == ObjType.Turret or obj:getObjType() == ObjType.ForceFieldProjector) then
if(obj:getHealth() < .1) then
return(false)
end
end
if(obj:getObjType() == ObjType.Ship or
obj:getObjType() == ObjType.Robot or
obj:getObjType() == ObjType.Turret or
obj:getObjType() == ObjType.ForceFieldProjector or
obj:getObjType() == ObjType.Core) then
if obj:getTeamIndex() == bot:getTeamIndex() and game:isTeamGame() or obj:getTeamIndex() == Team.Neutral then
return(false)
end
end
local angle = getFiringSolution(obj)
if angle ~= nil and bot:hasWeapon(weapon) then
bot:setAngle(angle)
bot:fireWeapon(Weapon.Phaser)
return(true)
end
return(false)
end
function fireAtObjects()
table.clear(items)
bot:findVisibleObjects(items, ObjType.Robot, ObjType.Turret, ObjType.Ship, ObjType.Asteroid, ObjType.ForceFieldProjector, ObjType.SpyBug, ObjType.Core)
for index,enemy in ipairs(items) do
if(fireAtObject(enemy, Weapon.Phaser)) then
break
end
end
end
-- Helper function to return the closest friendly or neutral item to the bot
-- Returns the closest item
function findClosestFriendly(items)
if #items == 0 then
return nil
end
local closestItem = nil
local smallestDist = signedIntMax
local distance
for index, item in ipairs(items) do
if (item:getTeamIndex() == bot:getTeamIndex() or item:getTeamIndex() == Team.Neutral) then
distance = point.distSquared(bot:getPos(), item:getPos())
if( distance < smallestDist ) then
closestItem = item
smallestDist = distance
end
end
end
return closestItem
end
function findClosestLoadoutZone()
return findClosestFriendly(possibleLoadoutZones)
end
function findClosestRepairTarget()
if #possibleRepairTargets == 0 then
return nil
end
local closestRepairTarget = nil
local smallestDist = signedIntMax
local distance
for index, repairTarget in ipairs(possibleRepairTargets) do
-- Must be able to repair it for the bot's team
if (repairTarget:getTeamIndex() == bot:getTeamIndex() or repairTarget:getTeamIndex() == Team.Neutral) and
-- Must need health
repairTarget:getHealth() < repairHealthThreshold and
-- Must be a path to get there
bot:getWaypoint(adjustRepairTargetPoint(repairTarget)) ~= nil then
distance = point.distSquared(bot:getPos(), repairTarget:getPos())
if( distance < smallestDist ) then
closestRepairTarget = repairTarget
smallestDist = distance
end
end
end
return closestRepairTarget
end
function findAllRepairTargets()
-- Find all repairables
table.clear(possibleRepairTargets)
bf:findAllObjects(possibleRepairTargets, ObjType.ForceFieldProjector)
table.clear(items)
bf:findAllObjects(items, ObjType.Turret)
-- Combine the tables into one
for key, value in ipairs(items) do
table.insert(possibleRepairTargets, items[key])
end
end
-- We need to adjust the repair target point because sometimes the bot waypoint
-- search can't find it because it is against a wall; we offset only 10
function adjustRepairTargetPoint(repairTarget)
return repairTarget:getPos() +
point.new(10 * math.cos(repairTarget:getMountAngle()), 10 * math.sin(repairTarget:getMountAngle()))
end
function gotoClosestLoadoutZone()
local zone = findClosestLoadoutZone()
-- Go to nearest loadout zone to change
if zone ~= nil then
-- If we're close enough, just sit instead of fighting other bots for
-- the zone center point
if point.distSquared(zone:getPos(), bot:getPos()) > 1225 then -- (35^2)
bot:setThrustToPt(zone:getPos())
end
end
end
function hasRepairLoadout()
return bot:hasModule(Module.Repair)
end
-- This function does most the logic for repair
function doObjective()
-- This objective must be completed first at all costs (we need repair module)
if needsRepairLoadout then
gotoClosestLoadoutZone()
-- See if we have repair
if hasRepairLoadout() then
needsRepairLoadout = false
end
return
end
-- Check some things with the timer
if delayTimer < 0.01 then
-- If no repair targets, search for them again
if #possibleRepairTargets == 0 then
findAllRepairTargets()
return
end
-- Check our loadout in case we've been blowed up (loadout doesn't stick upon bots respawning??)
if not hasRepairLoadout() then
needsRepairLoadout = true
end
end
-- Control logic based on current energy
if (currentBotEnergy < 0.03) then
onRepairTask = false
elseif currentBotEnergy > 0.8 and not onRepairTask then
onRepairTask = true
end
-- On repair duty!
if onRepairTask then
-- Do some tasks like pathfinding or target refreshing only every once in a while...
if delayTimer < 0.01 then
-- Find closest repair targets
if currentRepairTarget == nil or currentRepairTarget:getHealth() >= repairHealthThreshold then
currentRepairTarget = findClosestRepairTarget()
end
if currentRepairTarget ~= nil then
goalPoint = bot:getWaypoint(adjustRepairTargetPoint(currentRepairTarget))
-- Let's look for everything again if we still can't find a target. This should find engineered
-- items, too
else
findAllRepairTargets()
end
end
-- No waypoint or repair target (probably everything has been repaired)
if goalPoint == nil or currentRepairTarget == nil or currentRepairTarget:getPos() == nil then
-- The :getPos() nil test here is to protect against engineered items disappearing
if currentRepairTarget ~= nil and currentRepairTarget:getPos() == nil then
currentRepairTarget = nil
end
return
end
-- Now go the repair target and heal it
if point.distSquared(currentBotLocation, currentRepairTarget:getPos()) > 4900 then
bot:setThrustToPt(goalPoint)
else
bot:fireModule(Module.Repair)
end
end
end
function onTick(deltaTime)
currentBotLocation = bot:getPos()
currentBotEnergy = bot:getEnergy()
delayTimer = delayTimer - deltaTime
-- Do something!
doObjective()
-- Fire!
fireAtObjects()
-- Now reset timer if needed
if delayTimer < 0 then
delayTimer = delayTime
end
end
function main()
-- General variables
game = bf:getGameInfo()
signedIntMax = 2147483647
-- Current bot data
currentBotLocation = nil
currentBotEnergy = nil
-- This timer slows some of the more CPU intesive actions like pathfinding
delayTime = 500
delayTimer = delayTime
goalPoint = nil
-- Table for various global searches
items = {}
-- Repair specific variables
possibleRepairTargets = {}
possibleLoadoutZones = {}
bf:findAllObjects(possibleLoadoutZones, ObjType.LoadoutZone)
onRepairTask = false
currentRepairTarget = nil
repairHealthThreshold = 0.99
-- Do some starting tasks
needsRepairLoadout = true
-- Set up the loadout we want
local loadout = {Weapon.Phaser, Weapon.Bouncer, Weapon.Triple, Module.Shield, Module.Repair}
-- Set the loadout, will become active when bot hits loadout zone
-- or spawns, depending on game
bot:setLoadout(loadout)
findAllRepairTargets()
end
Update: RepairBot optimizations and minor tweaks. Also fix a possible crash by disabling repair of engineered items - sorry
Update 2: Posted code here directly - still needs to be 018afied
Update 3: RepairBot has been updated for 018a; also with some more optimizations and AI improvements
Update 4: Slightly less dumb at finding a repair target
Update 5: Fix stupidness with waypoint finding and add back in ability to fix engineered items
Update 6: Update to 019 API