--Heavily modified version of build_ally_bot_old.lua by royal print("The bots now stop following when they hurt, or get hurt") -- we can't expect lua to do all the work - joshua graham -- local BOT_SETUP_VSCRIPT = "activator.SetDifficulty(3); activator.SetMaxVisionRangeOverride(0.1)" -- 16 -- disable dodge local activeBots = {} -- bots alive local activeBuiltBots = {} -- bot built by player local activeBuiltBotsOwner = {} local lingeringBuiltBots = {} local PlayersWithCallbacks = {} --kill bots, behead bots, judo throw bots into active volcanos function OnWaveInit() for _, bot in pairs(activeBuiltBots) do bot:Suicide() bot.m_iTeamNum = 1 end for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() == false and player.m_iTeamNum == 2 and player:IsAlive() == true then player:Suicide() player.m_iTeamNum = 1 end end activeBuiltBots = {} end function updateScrapCounterProxy(counter) local activator = counter.m_hMoveParent print(activator) for i=0,20,1 do if activator:IsPlayer() == true then break end activator = activator.m_hMoveParent print(activator) if IsValid(activator) == false then print("Reached end of hierarchy, no player found") break return end end print(counter) print(activator) --if activator:GetAttributeValue("cannot giftwrap", false) == nil then -- activator:SetAttributeValue("cannot giftwrap", 0) --end counter:AcceptInput("Display", nil, activator, activator) --counter.m_iszMessage = "Scrap " .. activator:GetAttributeValue("cannot giftwrap", false) end local function removeCallbacks(player, callbacks) if not IsValid(player) then return end for _, callbackId in pairs(callbacks) do player:RemoveCallback(callbackId) end end local function setupBot(bot, owner, handle) local callbacks = {} local botHandle = bot:GetHandleIndex() owner.BuiltBotHandle = tostring(botHandle) activeBots[botHandle] = true activeBuiltBots[handle] = bot lingeringBuiltBots[botHandle] = true activeBuiltBotsOwner[botHandle] = owner callbacks.died = bot:AddCallback(ON_DEATH, function() owner.BuiltBotHandle = false activeBots[botHandle] = nil activeBuiltBots[handle] = nil activeBuiltBotsOwner[botHandle] = nil removeCallbacks(bot, callbacks) end) return callbacks end function assignOwnerToBot(activator) local botSpawn = nil local owner = activator print(owner) local handle = owner:GetHandleIndex() print("Assigned to " .. activator.m_szNetname) local allPlayers = ents.GetAllPlayers() for _, player in pairs(allPlayers) do if player.m_iTeamNum == 2 and player:IsRealPlayer() == false and player:InCond(71) == true and player:IsAlive() == true then botSpawn = player botSpawn:RemoveCond(71) print("Unowned bot found") break end end if botSpawn == nil then print("No bots found, aborting") return end local callbacks = setupBot(botSpawn, owner, handle) timer.Simple(0, function() local spawnedCallback spawnedCallback = botSpawn:AddCallback(ON_SPAWN, function() lingeringBuiltBots[handle] = nil botSpawn:RemoveCallback(spawnedCallback) spawnedCallback = nil end) end) -- bot behavior -- default behavior is always following you local logicLoop logicLoop = timer.Create(0.2, function() if not botSpawn:IsAlive() or botSpawn.m_iTeamNum ~= 2 or botSpawn:InCond(71) == true then timer.Stop(logicLoop) print("Terminated timer") return end if owner:InCond(TF_COND_TAUNTING) then botSpawn:SetAttributeValue("cannot taunt", nil) botSpawn["$Taunt"](botSpawn) botSpawn:SetAttributeValue("cannot taunt", 1) end local pos = owner:GetAbsOrigin() local distance = pos:Distance(botSpawn:GetAbsOrigin()) if distance >= 400 then botSpawn:AddCond(TF_COND_SPEED_BOOST, 1) end local stringStart = "interrupt_action -switch_action Default" -- don't move if already close, or if you are told to not move if distance <= 150 then botSpawn:BotCommand(stringStart .. " -duration 0.1") return end local interruptAction = ("%s -pos %s %s %s -duration 0.1"):format(stringStart, pos[1], pos[2], pos[3]) if botSpawn:InCond(12) == false then botSpawn:BotCommand(interruptAction) end end, 0) end local function checkOnHit(parent, damageinfo) --print("Check on hit") local attacker = damageinfo.Attacker if not attacker then return end local handle = attacker:GetHandleIndex() local victimHandle = parent:GetHandleIndex() local owner = activeBuiltBotsOwner[handle] local victimOwner = activeBuiltBotsOwner[victimHandle] if owner ~= nil and parent ~= owner then attacker:AddCond(12, 5) damageinfo.Attacker = owner end if victimOwner ~= nil and attacker ~= victimOwner then parent:AddCond(12, 5) end return true end ents.AddCreateCallback("tank_boss", function(tank) tank:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageinfo) return checkOnHit(tank, damageinfo) end) end) -- convert damage dealt by bots to owner -- and nullify damage taken by built bot during prewave local function addGlobalCallbacks(player) player:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageinfo) return checkOnHit(player, damageinfo) end) -- failsafe for spawning bot in setup player:AddCallback(ON_SPAWN, function() --print("Spawn callback") if player:IsRealPlayer() then return end timer.Simple(0.1, function() if inWave then return end local owner = activeBuiltBots[player:GetHandleIndex()] if not owner then return end if player.m_iTeamNum == owner.m_iTeamNum then player:Suicide() end end) end) end AddEventCallback("player_spawn", function(eventTable) --print("Added callbacks") local spawnedPlayer = ents.GetPlayerByUserId(eventTable.userid) --print(spawnedPlayer) local revisedTable = {} local spawnedPlayerInTable = false for _, player in pairs(PlayersWithCallbacks) do if IsValid(player) then table.insert(revisedTable, player) end if player == spawnedPlayer then spawnedPlayerInTable = true end end if #revisedTable ~= #PlayersWithCallbacks then PlayersWithCallbacks = {} print("A player was invalid, rebuilding") for _, player in pairs(revisedTable) do table.insert(PlayersWithCallbacks, player) end end if spawnedPlayerInTable == false then print("Added spawning player to table and applied callbacks") addGlobalCallbacks(spawnedPlayer) table.insert(PlayersWithCallbacks, spawnedPlayer) end --timer.Simple(0.01, function() -- local allPlayers = ents.GetAllPlayers() -- for _, player in pairs(allPlayers) do -- if player.m_iTeamNum == 2 and player:IsRealPlayer() == true then -- assignOwnerToBot(player) -- print("Assignment complete") -- break -- end -- end --end) end)