FAQ  •  Register  •  Login

S_bot2

<<

Fordcars

User avatar

Posts: 1016

Joined: Fri Apr 20, 2012 3:51 pm

Location: Some city, somewhere

Post Sun Mar 24, 2013 1:29 am

S_bot2

I done it! I just made s_bot a whole lot better.


- Bots now return flags in Capture the flag when they are close to it!
- Bots don't use sheild when team players shoot them!
- Bots don't shoot team or neutral spy bugs!
- Bot code is allot clearer now!

  Code:
--- from quickBot v2, modified by sam686 and fordcars
--- works on all game modes, except this bot don't work on non-pickup soccer

goalPt = point.new(0,0)

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()
    botRadius = bot:getRad()
    pathTimerMax = 250
    pathTimer = pathTimerMax
    dirToGo = 0
    game = GameInfo()

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

    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)))
            local bulletfromteam = false
            --logprint(angleDiff)
            if (game:isTeamGame() == true) and (bullet:getTeamIndx() == bot:getTeamIndx()) then -- If bullet is from team
                bulletfromteam = true                               -- bullet from team is true
            else                                                    -- If it is not a team game or if bullet is not from team
                bulletfromteam = false                              -- bullet from team is false
            end
            if (bulletfromteam ~= true) 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
     if(obj:getHealth() < .1) then
         --logprint("He's dead, Jim.")
         return(false)
        end
    end
   
    if(classId == ObjType.Ship    or   classId == ObjType.Robot   or   classId == ObjType.ForceFieldProjector   or
       classId == ObjType.Turret  or   classId == ObjType.SpyBug  or   classId == ObjType.Core) then
           if obj:getTeamIndx() == bot:getTeamIndx() and game:isTeamGame() or obj:getTeamIndx() == Team.Neutral then
                --logprint("It's an ally.")
                return(false)
           end
   end

   
    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_Bot2")
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
        -- 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 gotoPosition(otherFlag:getLoc()) end
        -- logprint(bot:getFlagCount())  -- always 1
        if bot:getFlagCount() > 3 and (game:isNexusOpen() or game:getNexusTimeLeft() < 10000) 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
    elseif(gameType == GameType.Rabbit) 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
    elseif(gameType == GameType.HTF or gameType == GameType.Retrieve) 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
    elseif(gameType == GameType.CTF) 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
                if not myFlag:isInInitLoc() then                                 -- If my flag is not in its initial location
                    if not myFlag:isOnShip() then                                -- If my flag is not on a ship
                        if point.distanceTo(myFlag:getLoc(), bot:getLoc()) <= 2000000 then
                            gotoPosition(myFlag:getLoc())                        -- Go to my flag
                        end
                    end
                end
            end
            if otherFlag ~= nil and not bot:hasFlag() then                           -- If there is an enemy flag and bot doesn't have a flag
                if myFlag:isInInitLoc() or point.distanceTo(myFlag:getLoc(), bot:getLoc()) > 2000000 then
                    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
        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
    elseif(gameType == GameType.Soccer) 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
    elseif(gameType == GameType.ZC) 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

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

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

function goInDirection()
    bot:setThrust(speed, dirToGo)
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

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

    if(pathTimer < 0) then
        pathTimer = pathTimerMax + math.random(0, pathTimerMax)
    end
end


Edit to add, by raptor:

These improvements have been merged into S_Bot for the next release. To get the latest S_Bot, go here:
https://bitfighter.googlecode.com/hg/re ... /s_bot.bot
skybax: Why is this health pack following me?
bobdaduck: uh, it likes you.
<<

raptor

Posts: 1046

Joined: Mon Oct 11, 2010 9:03 pm

Post Sun Mar 24, 2013 9:08 am

Re: S_bot2

Fordcars,

I'm in the process of merging some of your changes into the main code for s_bot. I do have a question about some of the logic:
- Why did you do a distance check of '2000000' in two of the control statements?

Your team bullet logic is very good. Also you almost exactly duplicated my change for not shooting team spybugs/mines that's already in the repo.

And good job with documentation. That helps a lot with future maintainability.

All-in-all, great job Fordcars!
<<

Fordcars

User avatar

Posts: 1016

Joined: Fri Apr 20, 2012 3:51 pm

Location: Some city, somewhere

Post Sun Mar 24, 2013 9:16 am

Re: S_bot2

I did that twice other wise the bot would try to get the enemy flag and return his team flag at the same time, which was kind of a problem ;)

if myFlag:isInInitLoc() or point.distanceTo(myFlag:getLoc(), bot:getLoc()) > 2000000 then
-- Go to enemy flag

------- This says that if the team flag is in it's initial location, continue to go to enemy flag or if the bot is more than 2000000 from team flag, continue to enemy flag. Like that, the ship will not go to enemy flag if it is 2000000 from the team flag or less and if the team flag is not in its initial location.
Last edited by Fordcars on Sun Mar 24, 2013 9:36 am, edited 1 time in total.
skybax: Why is this health pack following me?
bobdaduck: uh, it likes you.
<<

Fordcars

User avatar

Posts: 1016

Joined: Fri Apr 20, 2012 3:51 pm

Location: Some city, somewhere

Post Sun Mar 24, 2013 9:19 am

Re: S_bot2

raptor wrote:Fordcars,

I'm in the process of merging some of your changes into the main code for s_bot. I do have a question about some of the logic:
- Why did you do a distance check of '2000000' in two of the control statements?

Your team bullet logic is very good. Also you almost exactly duplicated my change for not shooting team spybugs/mines that's already in the repo.

And good job with documentation. That helps a lot with future maintainability.

All-in-all, great job Fordcars!


Thanks!

I am starting to get this whole lua bot thing
skybax: Why is this health pack following me?
bobdaduck: uh, it likes you.
<<

raptor

Posts: 1046

Joined: Mon Oct 11, 2010 9:03 pm

Post Sun Mar 24, 2013 10:30 am

Re: S_bot2

Fordcars, these Improvements have been merged into S_Bot for next release. I updated your first post to reflect this.

To see the changes:
https://code.google.com/p/bitfighter/so ... 810b51bded

Here is the link to the current and always latest S_Bot code from the repo:
https://bitfighter.googlecode.com/hg/re ... /s_bot.bot
<<

Fordcars

User avatar

Posts: 1016

Joined: Fri Apr 20, 2012 3:51 pm

Location: Some city, somewhere

Post Sun Mar 24, 2013 2:33 pm

Re: S_bot2

Thanks!
skybax: Why is this health pack following me?
bobdaduck: uh, it likes you.
<<

karamazovapy

Posts: 1567

Joined: Tue Feb 23, 2010 7:52 pm

Post Sat Mar 30, 2013 1:52 pm

Re: S_bot2

Nice work!
<<

Fordcars

User avatar

Posts: 1016

Joined: Fri Apr 20, 2012 3:51 pm

Location: Some city, somewhere

Post Mon Apr 01, 2013 2:41 pm

Re: S_bot2

Awesome!
skybax: Why is this health pack following me?
bobdaduck: uh, it likes you.

Return to Bots

Who is online

Users browsing this forum: No registered users and 3 guests

cron