local raypart = script.Parent.Parent.Turret 
local model = script.Parent.Parent
local numRays = 100
local searchDistance = 50 -- studs
local debounce = false
local peacelist = {}
local partlist

local mode = false --false = exploring, true = attacking
local debounce1 = false
local debounce2 = false
local debounce3 = false




function randomwarp()
	spawn(function()
	if mode == false and not debounce1 then
		debounce1 = true
		script.Parent.GoTo.Value = script.Parent.Parent.HumanoidRootPart.Position
	math.randomseed(tick()%1*1e6)
    local choose = math.random(1,4)
if choose == 1 then
	script.Parent.Warp.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(500,0,0)
elseif choose == 2 then
	script.Parent.Warp.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(-500,0,0)
elseif choose == 3 then
	script.Parent.Warp.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(0,0,500)
elseif choose == 4 then
	script.Parent.Warp.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(0,0,-500)
end
	end
	end)
	wait(50)
	debounce1 = false
end






function randommove()
	spawn(function()
	if mode == false and not debounce3 then
		debounce3 = true
	math.randomseed(tick()%1*1e6)
    local choose = math.random(1,4)
if choose == 1 then
	script.Parent.GoTo.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(500,0,0)
elseif choose == 2 then
	script.Parent.GoTo.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(-500,0,0)
elseif choose == 3 then
	script.Parent.GoTo.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(0,0,500)
elseif choose == 4 then
	script.Parent.GoTo.Value = script.Parent.Parent.HumanoidRootPart.Position + Vector3.new(0,0,-500)
end
	end
	end)
	wait(15)
	debounce3 = false
end










function getRayAtAngle( part, degrees, distance )--process rays
    local ray = Ray.new( part.CFrame.p, ( part.CFrame * CFrame.Angles( 0, math.rad( degrees ), 0 ) ).lookVector * distance )
    return ray
end




function startscan()--scan for a target
	spawn(function()
		if not debounce2 then
			debounce2 = true
	partlist = {}
local frac = 360 / numRays
for angle = frac, 360, frac do
    local ray = getRayAtAngle(raypart,angle,searchDistance)
    local part = game.Workspace:FindPartOnRay(ray,model)
table.insert(partlist,part)
end
compareradiustable()
wait(0.1)
debounce2 = false
end
end)
end





function compareradiustable()
for _, p in next, partlist do
		if p and p.Parent and p.Parent:FindFirstChild("Humanoid") then
			if p:IsA("BasePart") and p.Parent:FindFirstChild("Core") and p.Parent.Core.Owner.Value ~= script.Parent.Parent.Core.Owner.Value and
				p.Parent.Core.Owner.Value ~= "none" then
				gototarget(p)
				mode = true
			return
			end	
end
end
wait(0.2)
mode = false
end






function gototarget(p)
	if mode == true then
	script.Parent.GoTo.Value = p.Position + p.CFrame.LookVector * 10
	end
end





while true do
	wait()
	startscan()
	randommove()
	randomwarp()
	end

here I have an npc script, but Im always having trouble having them all fire properly. I tried using spawn() so that the while loop wont wait for functions but it seems that this does not work. I want some functions to wait different amount of times so I added some debounces but it looks like a mess.

can I get some tips and corrections on how I should handle functions in this situation?