Making a targeting system for bots

Hello. Something just crossed my mind. I’ve always wanted to make the player bots in Gmod(You know, the ones who have pretty crappy AI) actually work for a deathmatch-type gamemode. How would I create a targeting and fire-weapon-type system for them? I was thinking that to get one to work on bots I’d have to make an if function:


if ply:IsBot() then 
ply:SendLua(insert the targeting and weapon-firing script here)
end

Something like that. However, there was a youtube video where an excellent coder(Called BFG9000) created a code that basically did this. If he sees this, or if anyone can ask him, can I have a look at that code?

Video: http://www.youtube.com/watch?v=3-x4ZXtAhv8

I think you’d be better off using NextBots as you have more control over them

Well, my goal is to make them player bots, not nextbot NPCs.

I think you can do it using CUserCmd as far I know. But it may be very hard to do.
Anyways, here some codes that was from the WAYWO thread #?(I don’t remember). With this, you could have a idea on how to implement the aiming+weapon on the bot.
(Because it was used for NextBot Players. A nextbot things that act as a player(like bot) and not a NPC entity.)



 
local BOTS = {}
local botsName = {"Dakota",
"Bret",
"Marhta",
"Ayako",
"Kyle",
"Elena",
"Aurore",
"Zetta",
"Hannelore",
"Arron"}
 
concommand.Add("gz_create_bot",function(ply)
        local b = player.CreateNextBot(botsName[math.random(#botsName)])
        table.insert(BOTS,b)
        b.Owner = ply
end)
 
hook.Add("PlayerSay","Bots",function(ply,text)
        if(text == "!follow") then
                ply.State = 1
        end
        if(text == "!quiet") then
                ply.State = 0
        end
        if(text == "!attack") then
                ply.State = 2
        end
        if(text == "!defend") then
                ply.State = 3
        end
end)
 
hook.Add("EntityTakeDamage","Defend!",function(ent,dmg)
 
        if(ent:IsPlayer() && !ent:IsBot() && !dmg:GetAttacker():IsWorld()) then
                for k,v in pairs(player.GetBots()) do
                        if(v.Owner == ent) then
                                v.Target = dmg:GetAttacker()
                        end
                end
        end
        if(dmg:GetAttacker():IsPlayer() && !ent:IsWorld()) then
                MsgN(ent)
                for k,v in pairs(player.GetBots()) do
                        if(v.Owner == dmg:GetAttacker()) then
                                v.Target = ent
                        end
                end
        end
 
end)
 
hook.Add("StartCommand","MoveBots",function(ply,cmd)
        if(IsValid(ply.Owner)) then
 
                cmd:ClearMovement()
                cmd:ClearButtons()
 
                if(ply.Owner.State == nil) then
                        ply.Owner.State = 1
                end
 
                local ow = ply.Owner
                local ang = ((ply:EyePos() - Vector(0,0,10))-(ow:EyePos() - Vector(0,0,10))):Angle()
 
                local lClamp = ang + Angle(0,180,0)
 
                ply:SetEyeAngles(Angle(math.Clamp(lClamp.p,-180,180),lClamp.y,math.Clamp(lClamp.r,-180,180)))
                cmd:SetViewAngles(Angle(math.Clamp(lClamp.p,-180,180),lClamp.y,math.Clamp(lClamp.r,-180,180)))
 
                if(ow.State == 1 or ow.State == 3) then
                        if(ow:GetPos():Distance(ply:GetPos()) > 128) then
                                cmd:SetForwardMove(750)
                        end
                end
 
                if(ow.State == 2) then
                        if(ow:GetPos():Distance(ply:GetPos()) < 72 && ow:Alive() or (ply.Ranged or false)) then
                                if(ow:Alive()) then
                                        cmd:SetButtons(IN_ATTACK)
                                        if(ow:GetPos():Distance(ply:GetPos()) < 72) then
                                                ply:SelectWeapon("weapon_crowbar")
                                                ply.Ranged = false
                                        end
                                end
                        end
 
                        if(ow:GetPos():Distance(ply:GetPos()) > 256) then
                                if(ply:GetActiveWeapon():GetClass() != "weapon_ar2") then
                                        ply:SelectWeapon("weapon_ar2")
                                        ply.Ranged = true
                                end
                        end
 
                        if(ow:GetPos():Distance(ply:GetPos()) > 64) then
                                cmd:SetForwardMove(750)
                        end
 
                        cmd:SetSideMove(math.cos(RealTime())*400)
                end
 
                if(ow.State == 3) then
                        if(IsValid(ply.Target)) then
                                local ang = (ply:GetShootPos()-ply.Target:GetPos()):Angle()
                                if(ply.Owner:KeyDown(IN_ATTACK)) then
                                        ang = (ply:GetShootPos()-ply.Owner:GetEyeTrace().HitPos):Angle()
                                end
 
                                local lClamp = ang + Angle(90,180,0)
                                ply:SetEyeAngles(lClamp)
                                cmd:SetViewAngles(lClamp)
 
                                if(ply.Target:GetPos():Distance(ply:GetShootPos()) > 256) then
                                        if(ply:GetActiveWeapon():GetClass() != "weapon_ar2") then
                                                ply:SelectWeapon("weapon_ar2")
                                                ply.Ranged = true
                                        end
                                else
                                        ply:SelectWeapon("weapon_crowbar")
                                        if(ply.Target:GetPos():Distance(ply:GetPos()) > 64) then
                                                cmd:SetForwardMove(750)
                                        end
                                end
 
                                cmd:SetButtons(IN_ATTACK)
                        end
                end
 
        end
end)

If you want a way to manage the bots and name them using a name generator online:

[lua]

ServerFiller = {}
ServerFiller.Names = {}
ServerFiller.Bots = {}
ServerFiller.Config = {
maxplayers = game.MaxPlayers(),
maxbots = 4, – Maximum number of bots created.
namegenerator = “http://www.namegenerator.biz/application/p.php?type=1&id=wow_human_male_names&spaceflag=true”, – Must be CSV
printcolor = Color( 93, 212, 107), – Color of tag in the console messages
}

– Main functions

function ServerFiller.Initialize()
timer.Simple( 5, function()
ServerFiller.UpdateNameList()
ServerFiller.Print( “Starting up” )
end)

timer.Simple( 10, function()
	ServerFiller.Print( "Populating server" )
	for i=1, ServerFiller.Config.maxbots do
		ServerFiller.CreateBot( )
	end
end)

end

function ServerFiller.Print( Err )
MsgC( ServerFiller.Config.printcolor, "[ServerFiller] " , Color( 255,255,255), Err, "
" )
end

– Name functions

function ServerFiller.UpdateNameList()
http.Fetch( ServerFiller.Config.namegenerator, ServerFiller.ParseNames, function() ServerFiller.Print( “Failed to get names from name generator! HTTP problem” ) end )
end

function ServerFiller.ParseNames( csvnames, len, headers, code )
if ( len == 0 ) then
ServerFiller.Print( “Failed to get names from name generator! No names returned” )
end
ServerFiller.Names = string.Explode( “,”, csvnames )
table.remove( ServerFiller.Names, #ServerFiller.Names ) – Fix for name generator
end

function ServerFiller.GetRandomName()
if ( #ServerFiller.Names < 3 ) then – Get more names
ServerFiller.UpdateNameList()
end
local _randomindex = math.random( 1, #ServerFiller.Names )
return ServerFiller.Names[_randomindex], _randomindex
end

– Bot functions

function ServerFiller.CreateBot( )
local _name, _index = ServerFiller.GetRandomName()
if ( !game.SinglePlayer() && #player.GetAll() < ServerFiller.Config.maxplayers ) then
local _newbot = player.CreateNextBot( _name or “[ServerFiller] Error! No names returned!”)
if ( IsValid( _newbot ) ) then
table.insert( ServerFiller.Bots, _newbot )
table.remove( ServerFiller.Names, _index )
ServerFiller.Print( "Creating bot! Name is "… _name )
else
ServerFiller.Print( “Failed to create bot, unknown error!” )
end
else
print( !game.SinglePlayer() , ServerFiller.Config.maxplayers )
ServerFiller.Print( “Failed to create bot as server is full!” )
end
end

function ServerFiller.DestroyFirstBot( )
local _bot = ServerFiller.Bots[1]
if ( _bot ) then
if ( IsValid( _bot ) ) then
_bot:Kick( “[ServerFiller] Discarding bot” )
else
ServerFiller.Print( “Failed to destroy first bot as bot did not exist! Rectifying…” )
end
end
table.remove( ServerFiller.Bots, 1 )
end

function ServerFiller.GetBotCount()
return table.Count( ServerFiller.Bots )
end

function ServerFiller.PlayerAuthed()
if ( ServerFiller.GetBotCount() < ServerFiller.Config.maxbots ) then
ServerFiller.DestroyFirstBot( )
end
end

function ServerFiller.PlayerDisconnected()
if ( #player.GetAll() <= ServerFiller.Config.maxbots and ServerFiller.GetBotCount() < ServerFiller.Config.maxbots ) then
ServerFiller.CreateBot()
end
end

– Hooks

hook.Add( “PlayerAuthed”, “ServerFiller.KickBot”, ServerFiller.PlayerAuthed)
hook.Add( “PlayerDisconnected”, “ServerFiller.CreateBot”, ServerFiller.PlayerDisconnected)
hook.Add( “Initialize”, “ServerFiller.Initialize”, ServerFiller.Initialize )
[/lua]

The name generator URL is down since I made this but it’s fairly obvious what format it should be in.

Haha, well I’m flattered.
In truth, all I’m doing is getting all entities in a certain range of the bot, finding which ones are visible and are NPCs/players, and then calculating which ones are the closest to the bot. Then I make the bot aim at them and fire.
Actually, I don’t even do the firing part, that’s literally me just enabling bot_attack 1 or bot_flipout 1 in console. I haven’t worked on this system since, but I guess I can send you what I have so far.

I’m just posting this here in case anyone else is ever looking for it again, but I must warn you, that script was mostly a joke, and the code isn’t top notch, so try to use it as inspiration as opposed to a base that you work up from.