How to make a AI that can detect player like entry point

So I am making a AI that can detect a player within a range and if the player is in the AI’s range long enough it detects it and something happens like prints "PLAYER TOO LONG IN RANGE INITIATING NUCLEAR WARHEAD PROCEDURE" lol you get the idea right?

local character = script.Parent
local head = character:WaitForChild("Head")
local WaypointsFolder = workspace.CivWaypoints
local Waypoints = WaypointsFolder:GetChildren()
local inround = false
table.sort(Waypoints,function(a,b)
	return a.Name < b.Name
end)
local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({	
	AgentRadius = 2,
	AgentHeight = 7,
	AgentCanJump = true,
	AgentCanClimb = true,
})
local humanoid = character:WaitForChild("Humanoid")

local waypoints

character.PrimaryPart:SetNetworkOwner(nil)

local function followPath(destination)
	-- Compute the path
	local success, errorMessage = pcall(function()
		path:ComputeAsync(character.PrimaryPart.Position, destination)
	end)

	if success and path.Status == Enum.PathStatus.Success then
		waypoints = path:GetWaypoints()
		for i,v in pairs(waypoints) do
			humanoid:MoveTo(v.Position)
			if v.Action == Enum.PathWaypointAction.Jump then
				humanoid.Jump = true
			end
			humanoid.MoveToFinished:Wait()
		end
	end
end

local angle = 45
local dist = 35

while true do
	for idx = -angle,angle,5 do
		local Origin = head.Position
		local Destination = head.CFrame*CFrame.Angles(0,math.rad(idx),0)*CFrame.new(0,0,-dist)
		local Direction = Destination.Position-Origin
		local DetectionRay = Ray.new(Origin,Direction)
		local Part,Pos = workspace:FindPartOnRay(DetectionRay,head.Parent,false,false)
		if Part ~= nil then
			if Part.Parent:FindFirstChild("Humanoid") or Part.Parent.Parent:FindFirstChild("Humanoid") then
				local player = game.Players:GetPlayerFromCharacter(Part.Parent or Part.Parent.Parent)
				if player ~= nil and player:IsA("Player") then
					humanoid.WalkSpeed = 0
					game.ReplicatedStorage.Detection:FireClient(player,script.Parent.HumanoidRootPart,dist)
				end
			else
				humanoid.WalkSpeed = 16
			end
		end
	end
	coroutine.resume(coroutine.create(function()
		if inround then return end
		inround = true
		for Idx,Obj in pairs(Waypoints) do
			followPath(Obj.Position)
			local div = humanoid.WalkSpeed/2
			wait((Obj.Position-character.PrimaryPart.Position).Magnitude/div)
		end
		inround = false
	end))
	wait()
end

this is my code and its not good it detects the player and stops the bot but its not that good like when its detecting the player it stops and when it stops detecting the player its just standing. Doesn’t move again.

First of all: AI is different than the ep one. Ep does not have any sort of AI. AI learns things, the bots you can see killing players aren’t learning anything, they just run different part of codes and do something. It’s just made well that you can imagine they are humans, but ep does not have AI.

So first of all, I made an npc in the close-past with 400 lines of code that:

  1. Detects the player
  2. Calculates the route there and call a pathfinding upon that
  3. Throw a raycast out of the head (the head is moving towards the closest player), and if the raycast hits a player, a bullet goes out and damages the player
  4. When the npc fires (it will only fire if it sees a player or window or etc) the ammo variable goes down by one, and if it’s zero, the npc will reload
  5. Anims are scripted to the npc

That was 400 lines of code (if I wanna make this so clean), but you need to make this for an assault npc. I used runService and a variable to make the functions smooth but in-time.
If you have any questions about each part, contact me on devforum with a message.

i am talking about the civilian npcs in ep like if ur doing something sus they start detecting you and after some time your whole run is gone.

Check if the walking speed isn’t 0, or call a pathfinding. In that function, you may make sure the walkingspeed will be not 0, or make a variable for that if it is then the walking speed can go on.

I made a pre-guard, that has a value, and if the raycast his head made hits a player, the vaule will count down, and if it hits a level, it will alarm.

But after some time, it will reset, so the npc can set back its status to default.

hmm ok I think I have a plan up my sleeves thank you for the help

one more thing that uhh I made a code to change the theme of my uis but FOR SOME REASON

local Themes = {
    Girl = {
        ["P"] = Color3.fromRGB(232, 65, 24),
        ["S"] = Color3.fromRGB(194, 54, 22),
        ["T"] = Color3.fromRGB(131, 149, 167)
    },
    Boy = {
        ["P"] = Color3.fromRGB(39, 60, 117),
        ["S"] = Color3.fromRGB(25, 42, 86),
        ["T"] = Color3.fromRGB(131, 149, 167)
    },
}

local function ChangeTheme(Theme)
    for i,v in pairs(game.Players.LocalPlayer.PlayerGui:GetDescendants()) do
        if v:IsA("StringValue") then
            if v.Name == "P" then
                v.Parent.BackgroundColor3 = Theme["P"]
            elseif v.Name == "S" then
                v.Parent.BackgroundColor3 = Theme["S"]
            elseif v.Name  ==  "Tri" then
                v.Parent.BackgroundColor3 = Theme["T"]
            end
        end
    end
end

while true do
ChangeTheme(Themes.Boy)
wait(1)
ChangeTheme(Themes.Girl)
wait(1)
end

THIS WORKS

local Themes = {
    Girl = {
        ["P"] = Color3.fromRGB(232, 65, 24),
        ["S"] = Color3.fromRGB(194, 54, 22),
        ["T"] = Color3.fromRGB(131, 149, 167)
    },
    Boy = {
        ["P"] = Color3.fromRGB(39, 60, 117),
        ["S"] = Color3.fromRGB(25, 42, 86),
        ["T"] = Color3.fromRGB(131, 149, 167)
    },
}

local function ChangeTheme(Theme)
    for i,v in pairs(game.Players.LocalPlayer.PlayerGui:GetDescendants()) do
        if v:IsA("StringValue") then
            if v.Name == "P" then
                v.Parent.BackgroundColor3 = Theme["P"]
            elseif v.Name == "S" then
                v.Parent.BackgroundColor3 = Theme["S"]
            elseif v.Name  ==  "Tri" then
                v.Parent.BackgroundColor3 = Theme["T"]
            end
        end
    end
end

script.Parent.Menu.Back.Gender.Male.MouseButton1Click:Connect(function()
    ChangeTheme(Themes.Boy)
    print("why? why? WHY??")
end)
script.Parent.Menu.Back.Gender.Female.MouseButton1Click:Connect(function()
    ChangeTheme(Themes.Girl)
    print("WHY OH WHY?")
end)

BUT THIS DOESNT!

Its like the script doesnt change it if its in a function but if its not in a function it changes it!

Probably because in the first script it runs by the server’s type - Under this I mean if it’s a normal script, it will run on the server, if it’s a localscript, it will run on the client -. Whoever clickdetectors can’t detect a click that is wrote on a localscript, so if you wrote the 2nd script into a localscript, that’s the issue, because it just won’t detect it.

I assume that the 2 scripts’ lines are the same, so it’s the type of script only, because with the while loop it ran, but with the clickdetectorEvent it didn’t.

it does print “WHY WHY WHY” so that means it ran also side note haha when I add a print to see if it actually changed the backgroundcolor IT DID BUT IT WONT SHOW! and no there is no other script changing them.

also the script is in StarterGUi and yes its a localscript

The 2nd script is probably in a localscript beacuse it doesn’t print out “why why why”, and beacuse there is no variable that has to be to make the script run, it must be the type of the script - change the script type to normal (server) script instead of a localscript. Either if changetheme(themes.boy) wouldn’t run, the print should go on, so it is either a localscript or I must go check it out better.

If it’s in startergui, be more careful, because if you see the gui from your own monitor, the gui will be set by how the localscript sets it, so if you use normal script to set something on the gui, use another normal script to set it back or it will be chaos.

For example if I make a script that will change something in my gui, and I set it to sg else with a localscript in startergui, it will look like that, because the localscript’s lines overwrite the normal script’s lines in this chase because of the unique-player gui

can you explain in a way that my pee brain can understand? explain it in a script way.

You put down a part and a clickdetector inside of it (in the workspace of course). You make a gui too in the playergui.
Add a line to your clickdetector script that will say:

script.Parent.MouseClick:Connect(function(playerWhoClicked))
      local playerGui = playerWhoClicked.PlayerGui
      playerGui.Frame.Color = Color3.fromRGB(255, 0, 0) --this will change your gui called frame for the color red
end)

now go add a textbutton, add a localscript inside of it and say:

script.Parent.MouseButton1Up:Connect(function()
      script.Parent.Parent.Frame.Color = Color3.fromRGB(0, 255, 0) --It will change the frame to the color green
end)

As we assume, the clickdetector will always change the frame to red, the textbutton to green, right? No
Because the clickdetector’s script is a SERVERSCRIPT, and the textbutton’s script is a LOCALSCRIPT, it will outplay each other’s command and the local script will win because it’s handled on the local (player’s) side.

So once we clicked on the textbutton, the gui will be green, doesn’t matter how long we click the clickdetector,

To avoid it, use the same types of scripts for 1 type of job. Par example: if you use serverscript, use serverscript for another command, same with localscript, so the same-level commands can 0 them.

ok ok ok so your saying that I stop using a server script and result to a local script. Now I am using a local script. I am so sorry if I dont understand my mind is melted into liquid right now.