local function is_point_behind_plane(point, plane_normal, plane_dist) local d = point:Dot(plane_normal) return d < -plane_dist end local function getEyeAngles(player) --from royal, gets accurate eye angles local pitch = player["m_angEyeAngles[0]"] local yaw = player["m_angEyeAngles[1]"] return Vector(pitch, yaw, 0) end local function chatMessage(message) local allPlayers = ents.GetAllPlayers() for _, player in pairs(allPlayers) do player:AcceptInput("$DisplayTextChat", message) end end function AngleTesterBotSpawn(status, activator) local bulletWeapons = { [1] = "TF_WEAPON_ROCKETLAUNCHER", -- [1] = "MARKER", [2] = "TF_WEAPON_ROCKETLAUNCHER" } local fireTime = { [1] = 9999, [2] = 9999 } local dronesDeadCount = 0 local dronePrefix = "drone" .. tostring(activator:GetHandleIndex()) local droneOffsets = {Vector(0, 0, 150)} local droneCountToSpawn = 1 for i = 1, droneCountToSpawn do local sentryModel = ents.CreateWithKeys("prop_dynamic", { model = "models/rcat/rcat_level2.mdl", ["$positiononly"] = 1, skin = 1, }, true, true) sentryModel:SetName(dronePrefix .. tostring(sentryModel:GetHandleIndex())) local weaponMimic = ents.CreateWithKeys("tf_point_weapon_mimic", { teamnum = activator.m_iTeamNum, ["$preventshootparent"] = 1, ["$weaponname"] = bulletWeapons[i], ["$firetime"] = fireTime[i], }) weaponMimic:SetName(dronePrefix .. "_weaponmimic_" .. tostring(sentryModel:GetHandleIndex())) weaponMimic["$SetOwner"](weaponMimic, activator) weaponMimic:SetParent(sentryModel) sentryModel["$fakeparentoffset"] = droneOffsets[i] sentryModel:SetFakeParent(activator) weaponMimic["$StartFiring"](weaponMimic, math.huge) local logic logic = timer.Create(0.1, function() if not IsValid(sentryModel) then timer.Stop(logic) return end local curOrigin = sentryModel:GetAbsOrigin() local closest = { nil, math.huge } for _, player in pairs(ents.GetAllPlayers()) do local valid = true if not player:IsAlive() then valid = false elseif player.m_iTeamNum == activator.m_iTeamNum then valid = false elseif player:InCond(TF_COND_DISGUISED) == 1 then valid = false elseif player:InCond(TF_COND_STEALTHED) == 1 then valid = false end if valid then local porigin = player:GetAbsOrigin() local distance = curOrigin:Distance(porigin) local vectorToPlayer = porigin - curOrigin local botToPlayerAngles = vectorToPlayer:ToAngles() local botEyeAngles = getEyeAngles(activator) chatMessage(is_point_behind_plane(porigin,botEyeAngles:GetForward(),curOrigin:Length())) if distance < closest[2] then closest = { player, distance } end end end if not closest[1] then return end sentryModel:FaceEntity(closest[1]) end, 0) -- go straight to phase 2 if both drones are destroyed prematurely -- drone:AddCallback(ON_REMOVE, function () -- dronesDeadCount = dronesDeadCount + 1 -- if dronesDeadCount >= 2 then -- ColDronemanEngaged(_, activator, true) -- end -- end) end end local function getDrones(activator) local dronePrefix = "drone" .. tostring(activator:GetHandleIndex()) .. "_weaponmimic_" return ents.FindAllByName(dronePrefix .. "*") end local function removeAllDrones(activator) for _, drone in pairs(ents.FindAllByName("drone" .. tostring(activator:GetHandleIndex()) .. "*")) do util.ParticleEffect("ExplosionCore_buildings", drone:GetAbsOrigin(), Vector(0, 0, 0)) drone:Remove() end end