Post Sun May 05, 2013 8:14 am

Sentinel2

Now introducing........... Sentinel2!
This bot does pretty much the same as SentinelBot, but better ;)

This bot will be kind of a servant to the specified player. You can assign a bot to a player (or yourself), and that bot will listen only to that player. But to add a bot, you have to enter a password, so, you can give a bot to a player, but only you know the password so only you can add Sentinel2 bots.

Oh, and also, the Bot will behave like a normal s_bot. When the player who owns the bot says the name of a player, all the Sentinel2 bots will orbit that player, or kill it (depending on the team it is in). To make Sentinel2 bots behave like normal s_bots again, the player who has bots assigned must say "Bots, stop" and the assigned bots will return to normal.

NOTE: Remeber to change the "PASSWORDHERE" to your custom password around the top of the bot code.

Adding bot: /addbot Sentinel2 <team> <password> <playerNameToListen>

Example: /addbot Sentinel2 0 holaDude Fordcars

So, in summary:
"Bots, stop" -- make bots return to normal
A player's name -- Orbit that player

To install, put the bot code in a file and name it Sentinel2. Then, put that file in the Bots folder located with bitfighter.ini.

  Code:
-- MODIFICATION OF S_BOT (QuickBotv2)
-- S_BOT by sam686
-- Sentinel2 by fordcars


goalPt = point.new(0,0)

itemsla = { }

prevtarget = nil

gotoPositionWasNil = true
 
o = point.new(0,0)
 
botLoc = nil        -- Bot's location, will be updated when onTick() is run

-- This function gets run once during setup.  It is the only time we can declare variables
-- and have them be defined as globals.
function main()
    subscribe(Event.MsgReceived)
    botRadius = bot:getRad()
    pathTimerMax = 250
    pathTimer = pathTimerMax
    dirToGo = 0
    game = GameInfo()

    difficulty         = tonumber(arg[3]) or .5
    agression          = tonumber(arg[4]) or 0.5
    defense            = tonumber(arg[5]) or 0
    speed              = tonumber(arg[6]) or 1
    directionThreshold = tonumber(arg[7]) or .25
    passwordla         = arg[1] or nil
    listenplayerarg    = arg[2] or nil

    listenplayergame   = nil
    playerattackinfo   = nil
    playerattack       = nil

    if (passwordla ~= nil) then
        if (listenplayerarg ~= nil) then
            if (passwordla == "PASSWORDHERE") then
                listenplayergame = listenplayerarg -- Set variable as master player (listen player game)
            end
        end
    end

    gameType = game:getGameType()
   
    averageIndex = 1
    averageMax = 20

    averageArray = { }
    for i = 1, averageMax do
        averageArray[i] = false
    end

    myOrbitalDirection = 1
    myObjective = math.random(0, 10)

end
 

items = { }     -- Global variable, reusable container for findGlobalObjects.  Reusing this table avoids costs of
                -- constructing and destructing it every time we call findGlobalObjects().  Be sure to clear the
                -- table before reusing it!
function shieldSelf()
    table.clear(items)
    findObjects(items, ObjType.Bullet, ObjType.Seeker, ObjType.Asteroid, ObjType.Mine)

    local distToShieldAt = botRadius * 2 + (1 - difficulty) * 100
    if (items ~= nil) then
        for i,bullet in ipairs(items) do
            local bulletLoc = bullet:getLoc()
            local bulletVel = bullet:getVel()
            local angleDiff = math.abs(angleDifference(point.angleTo(o, bulletVel), point.angleTo(bulletLoc, botLoc)))
            --logprint(angleDiff)

            local bulletFromTeam = false
            if (game:isTeamGame() == true) and (bullet:getTeamIndx() == bot:getTeamIndx()) then -- If bullet is from team
                bulletFromTeam = true                               -- bullet from team is true
            end

            if (bulletFromTeam == false) and (point.distanceTo(bulletLoc, botLoc) < distToShieldAt + bullet:getRad() + point.distanceTo(o, bulletVel) * 50 and angleDiff < math.pi / 4) then
                bot:activateModule(Module.Shield)
                return(true)
            end
        end
    end
end

function angleDifference(angleA, angleB)
    return (math.mod(math.mod(angleA - angleB, math.pi * 2) + math.pi * 3, math.pi * 2) - math.pi)
end

function fireAtObjects()
    table.clear(items)
    findObjects(items, ObjType.Robot,               ObjType.Turret, ObjType.Ship, ObjType.Asteroid,
                       ObjType.ForceFieldProjector, ObjType.SpyBug, ObjType.Core)

    -- Cycle through list of potential items until we find one that we can attack
    for index, enemy in ipairs(items) do
        if(fireAtObject(enemy, Weapon.Phaser)) then
            break
        end
    end
end
 
 
-- Fires at the specified object with the specified weapon if the obj is a good target.
-- Does not fire if object is on the same team or if there is something in the way.
-- Returns whether it fired or not.
function fireAtObject(obj, weapon)
    local classId = obj:getClassId()

    if(classId == ObjType.Turret or classId == ObjType.ForceFieldProjector) then
        -- Ignore all same-team engineered objects...  even in single-team games
        if obj:getTeamIndx() == bot:getTeamIndx() then
            return false                                 -- Cancel fireAtObject function
        end

        if obj:getHealth() < .1  then                                             -- If item is essentially dead
            return false                                                          
        end
    end
   
   
    -- No shooting various team related objects
    if (obj:getTeamIndx() == bot:getTeamIndx() and game:isTeamGame()) or  -- Same team
        obj:getTeamIndx() == Team.Neutral then                            -- Neutral team
        if (classId == ObjType.Ship    or   classId == ObjType.Robot   or    -- Turrets and FFs handled above
            classId == ObjType.Core    or   classId == ObjType.SpyBug) then
            return false
        end
    end
   
    -- No shooting non-flag carriers in single player rabbit
    if gameType == GameType.Rabbit and not game:isTeamGame() and
        (classId == ObjType.Ship or classId == ObjType.Robot) and
        not bot:hasFlag() and not obj:hasFlag() then
        return false
    end

    -- We made it here!  We have a valid target..
    local angle = getFiringSolution(obj)
    if angle ~= nil and bot:hasWeapon(weapon) then
        bot:setAngle(angle + math.rad((math.random()-0.5)*20*(1-difficulty)))
        bot:setWeapon(weapon)
        bot:fire()
        --logprint("bot:fire() called!");
        return(true)
    end
    --logprint("Firing solution not found.");
    return(false)
end
 
 
function getName()
     return("S_Bot")
end


function shield()
    averageArray[averageIndex] = shieldSelf()
    averageIndex = math.mod(averageIndex,averageMax) + 1

    local shieldPercent = 0

    for i = 1, averageMax do
        if(averageArray[averageIndex]) then
            shieldPercent = shieldPercent + 1
        end
    end

    shieldPercent = shieldPercent / averageMax

    if(shieldPercent > directionThreshold) then
        myOrbitalDirection = -myOrbitalDirection
        for i = 1, averageMax do
            averageArray[i] = false
        end
    end
end
 
function orbitPoint(pt, dir, inputDist, inputStrictness)
    local distAway = botRadius * 7
    local strictness = 2
    local direction = 1

    if(dir ~= nil) then
        direction = dir
    end


    if(inputDist ~= nil) then
        distAway = inputDist
    end

    if(inputStrictness ~= nil) then
        strictness = inputStrictness
    end

    if(pt ~= nil) then
        local dist = point.distanceTo(pt, botLoc)
        local deltaDistance = (dist - distAway) * strictness / distAway
        local sign = 1
        if(deltaDistance > 0) then
            sign = 1
        elseif(deltaDistance < 0) then
            sign = -1
        end

        local changeInAngle = (math.abs(deltaDistance)/(deltaDistance + sign)) * math.pi/2
        local angleToPoint = point.angleTo(pt, bot:getLoc())
        dirToGo = angleToPoint + (math.pi/2 + changeInAngle)*direction
        --bot:setThrust(speed, dirToGo)
    end
end

function gotoPosition(pt)
    if pt ~= nil then
        gotoPositionWasNil = false
        if pathTimer < .01 then
            goalPt = bot:getWaypoint(pt)
            if(goalPt ~= nil) then
                dirToGo = point.angleTo(botLoc, goalPt)
            end
        end
    end
end

function gotoAndOrbitPosition(pt)
    if pt ~= nil then
        gotoPositionWasNil = false
        if not bot:hasLosPt(pt) then
            gotoPositionWasNil = false
            gotoPosition(pt)
        else
            gotoPositionWasNil = false
            orbitPoint(pt, myOrbitalDirection, botRadius * 5, 2)
        end
    end
end
 
-- Returns true if it found an enemy to fight
function attackNearbyEnemies(target, agressionLevel)
    if target ~= nil then
        local targetLoc = target:getLoc()
     
        -- local dist    = point.distanceTo(botLoc, targetLoc)
        local myPow   = bot:getEnergy() + bot:getHealth()

        table.clear(items)
        findObjects(items, ObjType.Ship, ObjType.Robot)
     
        local otherPow = target:getEnergy() + target:getHealth() * #items
     
        --advantage is between -1 and 1, -1 meaning an extreme disadvantage and 1 meaning an extreme advantage
        local advantage = (myPow - otherPow) / math.max(myPow, otherPow)
        if(advantage  / 2 + .5  >agressionLevel) then
            --orbitPoint(targetLoc, myOrbitalDirection, botRadius * 9, 2)
            prevtarget = targetLoc
            return(false)      -- was true
        else
        end
    end
    return(false)
end


-- Returns the objective for the bot, in the form of an object the bot can navigate towards.  This makes bots choose different defending locations.
-- If onTeam is true, will only return items on specified team.  If onTeam is false, will return items *not* on
-- specified team.  If called with fewer than three args, will ignore team altogether.
function getObjective(objType, team, onTeam)

    table.clear(items)
    bot:findGlobalObjects(items, objType)       -- Returns a list of all items of type objType in the game

    local itemsOnMyTeam = {}
    local currentIndex = 1

    for index, item in ipairs(items) do         -- Iterate through all found items
        local itemTeamIndex = item:getTeamIndx()

        if (objType == ObjType.Flag) and (gameType == GameType.Nexus) then
            if not item:isOnShip() then
                itemsOnMyTeam[currentIndex] = item
                currentIndex = currentIndex + 1
            end
        elseif (objType == ObjType.Flag) and
               ((gameType == GameType.HTF) or (gameType == GameType.Retrieve)) and
               item:isInCaptureZone() then
                --logprint(item:getCaptureZone():getTeamIndx());
            if item:getCaptureZone():getTeamIndx() ~= bot:getTeamIndx() then
                itemsOnMyTeam[currentIndex] = item
                currentIndex = currentIndex + 1
            end
        elseif (objType == ObjType.GoalZone) and (gameType == GameType.HTF or gameType == GameType.Retrieve) then
            if onTeam == nil or ((itemTeamIndex == team) == onTeam) then
                if not item:hasFlag() then
                    itemsOnMyTeam[currentIndex] = item
                    currentIndex = currentIndex + 1
                end
            end
        else
            if (itemTeamIndex == Team.Neutral ) and (objType ~= ObjType.GoalZone or gameType ~= GameType.ZC) then
                itemTeamIndex = team   -- anything Neutral is on our team (except zone control neutral goal zone)
            end
            if onTeam == nil or ((itemTeamIndex == team) == onTeam) then
                itemsOnMyTeam[currentIndex] = item
                currentIndex = currentIndex + 1
            end
        end
    end
    local listMax = 0
    --find max
    if itemsOnMyTeam[1] ~= nil then
        for index,item in ipairs(itemsOnMyTeam) do
            if(item ~= nil) then
                listMax = listMax + 1
            end
        end
        local targetNum = math.mod(myObjective, listMax) + 1
        return(itemsOnMyTeam[targetNum])
    else
        return(nil)
    end

--  local closestitem = 0 --itemsOnMyTeam[1]
--  local cur = 1
--  local closestdist = 99999999
--  while itemsOnMyTeam[cur] ~= nil do
--      local item1 = itemsOnMyTeam[cur]
--      if item1 ~= nil then
--          local loc = item1.getLoc()
--          if loc ~= nil then
--              local dist = point.distanceTo(botLoc, loc)
--              if dist < closestdist then
--                  closestdist = dist
--                  closesetitem = item1
--              end
--          end
--      end
--      cur=cur+1
--  end
--  return(closestitem)
end


function doObjective(closestEnemy)
    gotoPositionWasNil = true
    if(gameType == GameType.Bitmatch) then
        --Nothing to do here.          
    elseif(gameType == GameType.Nexus) then
        if playerattackinfo == nil then
        -- Grab any flags that are found, and go to nexus when it opens
        local otherFlag = getObjective(ObjType.Flag)            -- Find any flags
        if otherFlag ~= nil then                                -- If there is a flag avalible
            gotoPosition(otherFlag:getLoc())
        end

        --  If bot has more than 4 flags and the nexus is open or we're within 10 seconds of opening
        if bot:getFlagCount() > 4 and (game:isNexusOpen() or game:getNexusTimeLeft() < 10) then  --  Need to know if nexus is open
            local nexusOrFlag = getObjective(ObjType.Nexus)  -- unimplemented push function error.
            if nexusOrFlag ~= nil then
                gotoPosition(nexusOrFlag:getLoc())
            end
        end
        end
    elseif(gameType == GameType.Rabbit) then
        if playerattackinfo == nil then
        --Grab a flag, or go after the flag.            
        if not bot:hasFlag() then
            local otherFlag = getObjective(ObjType.Flag, bot:getTeamIndx(), true)       -- Find flags on our team
            gotoPosition(otherFlag:getLoc())
        end
        end
    elseif(gameType == GameType.HTF or gameType == GameType.Retrieve) then
        if playerattackinfo == nil then
        -- Grab the flag and put it into goal zones
        -- Robot keeps trying to pick up the flags that is already in the goalZones
        if bot:hasFlag() then                                                           -- If the bot has the flag
            local otherFlag = getObjective(ObjType.GoalZone, bot:getTeamIndx(), true)   -- Find an avalible GoalZone on our team
            if otherFlag ~= nil then                                                    -- If there is an avalible GoalZone
                gotoPosition(otherFlag:getLoc())                                        -- Go to it
            end
        else                                                                            -- If the bot doesn't have the flag
            local otherFlag = getObjective(ObjType.Flag, bot:getTeamIndx(), true)       -- Find flags on our team
            if otherFlag ~= nil then                                                    -- If there is a flag avalible
                gotoPosition(otherFlag:getLoc())                                        -- Go to it
            end
        end
        end
    elseif(gameType == GameType.CTF) then
        if playerattackinfo == nil then
        --defend the flag
        local myFlag    = getObjective(ObjType.Flag, bot:getTeamIndx(), true)    -- Find flags on our team
        local otherFlag = getObjective(ObjType.Flag, bot:getTeamIndx(), false)   -- Find flags not on our team

        if(defense < .5) then                                                    -- If bot doesn't defend allot (default is 0)
            if bot:hasFlag() then                                                -- If the bot has a flag
                if not myFlag:isOnShip() then                                    -- If my flag is not on a ship
                    gotoPosition(myFlag:getLoc())                                -- Go to position of my flag
                else
                    gotoAndOrbitPosition(myFlag:getLoc())                        -- Otherwise, go and orbit the flag on enemy
                end
                --gotoPosition(myFlag:getLoc())
            else                                                                 -- If the bot doesn't have the flag
                local retrievingFlag = false
                if myFlag ~= nil then
                    if not myFlag:isInInitLoc() and not myFlag:isOnShip() and                     -- If my flag is not in its initial location and my flag is not on a ship
                            point.distSquared(myFlag:getLoc(), bot:getLoc()) <= 2000 * 2000 then  -- .. and we're within some sane range of the flag
                        gotoPosition(myFlag:getLoc())                                             -- Go to and return my flag
                        retrievingFlag = true
                    end
                end

                if otherFlag ~= nil then                                         -- If there is an enemy flag
                    if not retrievingFlag then                                   -- .. and this bot isn't already retrieving a flag
                        if myFlag:isOnShip() then                                -- If my flag is on a ship
                            gotoPosition(myFlag:getLoc())                        -- Go to position of my flag
                        elseif not otherFlag:isOnShip() then                     -- If enemy flag is not on a ship
                            gotoPosition(otherFlag:getLoc())                     -- Go to that flag
                        else
                            gotoAndOrbitPosition(otherFlag:getLoc())             -- Go and orbit our team flag's carrier
                        end
                    end
                end
            end
        else
            if bot:hasFlag() then                                                -- If the bot has a flag and has more than .5 defense
                gotoPosition(myFlag:getLoc())                                    -- Go to team flag
            elseif myFlag:isInInitLoc() then                                     -- If the bot doesn't have a flag and the team flag is in intial location
                gotoAndOrbitPosition(myFlag:getLoc())                            -- Go and orbit team flag
            else
                if myFlag:isOnShip() then                                        -- If team flag is on a ship
                    gotoAndOrbitPosition(myFlag:getLoc())                        -- Go and orbit team flag
                else
                    gotoPosition(myFlag:getLoc())                                -- If team flag is not on a ship, go to team flag
                end
            end
        end
        end
    elseif(gameType == GameType.Soccer) then
        if playerattackinfo == nil then
        --grab soccer and put into enemy goal
        -- How do we know if we are holding soccer ? (not supported when cannot pickup soccer (016)
        if bot:getMountedItems(ObjType.SoccerBallItem)[1] ~= nil then
            local otherFlag = getObjective(ObjType.GoalZone, bot:getTeamIndx(), false)   -- Find GoalZones not on our team
            if otherFlag ~= nil then
                gotoPosition(otherFlag:getLoc())
            end          
        else
            local otherFlag = getObjective(ObjType.SoccerBallItem)                        -- Find SoccerBall
            if otherFlag ~= nil then
                gotoPosition(otherFlag:getLoc())
            end
        end
        end
    elseif(gameType == GameType.ZC) then
        if playerattackinfo == nil then
        -- Grab flag, then go after zones that is not ours.
        if not bot:hasFlag() then
            local otherFlag = getObjective(ObjType.Flag, bot:getTeamIndx(), true)           -- Find flags on our team
            if otherFlag ~= nil then
                if otherFlag:isOnShip() then
                    gotoAndOrbitPosition(otherFlag:getLoc())
                else
                    gotoPosition(otherFlag:getLoc())
                end
            end
        else
            local otherFlag = getObjective(ObjType.GoalZone, bot:getTeamIndx(), false)      -- Find GoalZones on our team
            if otherFlag then
                gotoPosition(otherFlag:getLoc())
            end
        end
        end

    elseif(gameType == GameType.Core) then
        if playerattackinfo == nil then
        local obj = getObjective(ObjType.Core, bot:getTeamIndx(), false)                    -- Find enemy Core
        if obj ~= nil then
            gotoAndOrbitPosition(obj:getLoc())
        end
        end
    end

    -- If we have no where to go, go to nearest enemy.
    if gotoPositionWasNil then
    if playerattackinfo == nil then
        if(closestEnemy ~= nil) then
            prevtarget = closestEnemy:getLoc()
        end
        if(prevtarget ~= nil) then
            gotoAndOrbitPosition(prevtarget)
        end
    end
    end
end
 

function goInDirection()
    bot:setThrust(speed, dirToGo)
end



function onMsgReceived(message, senderPlayerInfo)
    if senderPlayerInfo:getName() ~= nil then
        if senderPlayerInfo:getName() == listenplayergame then
            playerattack = message
        end
    end
end


-- This function gets called every game tick; deltaTime is the time that has elapsed since it was last called
function onTick(deltaTime)
    botLoc = bot:getLoc()
    pathTimer = pathTimer - deltaTime
    assert(bot:getLoc() ~= nil)

    local closestEnemy = bot:findClosestEnemy()
   
    -- attackNearbyEnemies returns true if there is an enemy to fight, false if the bot can do something else
    attackNearbyEnemies(closestEnemy, 1 - agression)
    doObjective(closestEnemy)   -- Set bot's objective
-- -------------------------------------------------------------Up is shooting enemies and variables
    if playerattack ~= nil then -- If there is a player to attack
            if playerattack == "Bots, stop" then
                playerattackinfo = nil
            end

            table.clear(itemsla)
            bot:findGlobalObjects(itemsla, ObjType.Ship, ObjType.Robot)

            for index, item in ipairs(itemsla) do
                if item:getPlayerInfo() ~= nil then
                    if item:getPlayerInfo():getName() == playerattack then
                        playerattackinfo = item:getLoc()
                        break
                    end
                end
            end
            if playerattackinfo ~= nil then
                gotoAndOrbitPosition(playerattackinfo)
            end
    end

    goInDirection()             -- Move the ship
    fireAtObjects()             -- Fire weapons
    shield()                    -- Apply shield

    if(pathTimer < 0) then
        pathTimer = pathTimerMax + math.random(0, pathTimerMax)
    end
end
 
skybax: Why is this health pack following me?
bobdaduck: uh, it likes you.