local function M()return maid.humanoid.Health>0 and maid.humanoid:GetState()~=Enum.HumanoidStateType.Dead end local function D()maid:destroy()end local function e()local M=workspace.SearchParts:GetChildren()local D=M[math.random(1,#M)].Position return D end local function k()while M()do if not attacking then local M=e()maid.humanoid.WalkSpeed=PATROL_WALKSPEED maid.humanoid:MoveTo(M)end wait(random:NextInteger(MIN_REPOSITION_TIME,MAX_REPOSITION_TIME))end end local function n(M)local D=M and M.Parent local e=D and D:FindFirstChild("\072\117\109\097\110\111\105\100")local k=D and D:FindFirstChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")if not e or not k then return false end local n=false local i=(maid.humanoidRootPart.Position-k.Position).Magnitude if i<=ATTACK_RADIUS then local D=Ray.new(maid.humanoidRootPart.Position,(k.Position-maid.humanoidRootPart.Position).Unit*i)local X=Workspace:FindPartOnRayWithIgnoreList(D,{M.Parent;maid.instance},false,true)if M~=maid.instance and(M:IsDescendantOf(Workspace)and(e.Health>0 and(e:GetState()~=Enum.HumanoidStateType.Dead and(not CollectionService:HasTag(M.Parent,"\090\111\109\098\105\101\070\114\105\101\110\100")and not X))))then n=true end end return n end local function i()if not searchingForTargets and tick()-timeSearchEnded>=SEARCH_DELAY then searchingForTargets=true local M=maid.humanoidRootPart.Position local D=M+Vector3.new(ATTACK_RADIUS,ATTACK_RADIUS,ATTACK_RADIUS)local e=M+Vector3.new(-ATTACK_RADIUS,-ATTACK_RADIUS,-ATTACK_RADIUS)searchRegion=Region3.new(e,D)searchParts=Workspace:FindPartsInRegion3(searchRegion,maid.instance,math.huge)newTarget=nil newTargetDistance=nil searchIndex=1 end if searchingForTargets then local M=0 while searchingForTargets and(searchIndex<=#searchParts and M<MAX_PARTS_PER_HEARTBEAT)do local D=searchParts[searchIndex]if D and n(D)then local M=D.Parent local e=(M.HumanoidRootPart.Position-maid.humanoidRootPart.Position).magnitude if not newTargetDistance or e<newTargetDistance then newTarget=M.HumanoidRootPart newTargetDistance=e end end searchIndex=searchIndex+1 M=M+1 end if searchIndex>=#searchParts then target=newTarget searchingForTargets=false timeSearchEnded=tick()end end end local function X()local M=(maid.humanoidRootPart.Position-target.Position).Unit*ATTACK_RANGE+target.Position maid.humanoid:MoveTo(M)if not movingToAttack then maid.humanoid.WalkSpeed=random:NextInteger(ATTACK_MIN_WALKSPEED,ATTACK_MAX_WALKSPEED)end movingToAttack=true maid.attackAnimation:Stop()end local function x()attacking=true lastAttackTime=tick()local M=maid.humanoid.WalkSpeed maid.humanoid.WalkSpeed=0 maid.attackAnimation:Play()local D=Instance.new("\080\097\114\116")D.Size=HITBOX_SIZE D.Transparency=1 D.CanCollide=true D.Anchored=true D.CFrame=maid.humanoidRootPart.CFrame*CFrame.new(0,-1,-3)D.Parent=Workspace local e=D:GetTouchingParts()D:Destroy()local k={}for M,D in pairs(e)do local e=D:FindFirstAncestorOfClass("\077\111\100\101\108")if n(D)and not k[e]then k[e.Humanoid]=true end end for M in pairs(k)do M:TakeDamage(ATTACK_DAMAGE)end startPosition=maid.instance.PrimaryPart.Position wait(ATTACK_STAND_TIME)maid.humanoid.WalkSpeed=M maid.attackAnimation:Stop()attacking=false end


local function isAlive()
	return maid.humanoid.Health > 0 and maid.humanoid:GetState() ~= Enum.HumanoidStateType.Dead
end

local function destroy()
	maid:destroy()
end

local function getposition()
	local searchParts = workspace.SearchParts:GetChildren()
	local position = searchParts[math.random(1, #searchParts)].Position
	return position
end

local function patrol()
	while isAlive() do
		if not attacking then
			local position = getposition()
			maid.humanoid.WalkSpeed = PATROL_WALKSPEED
			maid.humanoid:MoveTo(position)
		end

		wait(random:NextInteger(MIN_REPOSITION_TIME, MAX_REPOSITION_TIME))
	end
end

local function isInstaceAttackable(targetInstance)
	local targetParent = targetInstance and targetInstance.Parent
	local targetHumanoid = targetParent and targetParent:FindFirstChild("Humanoid")
	local targetHumanoidRootPart = targetParent and targetParent:FindFirstChild("HumanoidRootPart")

	if not targetHumanoid or not targetHumanoidRootPart then
		return false
	end

	local isAttackable = false
	local distance = (maid.humanoidRootPart.Position - targetHumanoidRootPart.Position).Magnitude

	if distance <= ATTACK_RADIUS then
		local ray = Ray.new(
			maid.humanoidRootPart.Position,
			(targetHumanoidRootPart.Position - maid.humanoidRootPart.Position).Unit * distance
		)

		local part = Workspace:FindPartOnRayWithIgnoreList(ray, {
			targetInstance.Parent, maid.instance,
		}, false, true)

		if
			targetInstance ~= maid.instance and
			targetInstance:IsDescendantOf(Workspace) and
			targetHumanoid.Health > 0 and
			targetHumanoid:GetState() ~= Enum.HumanoidStateType.Dead and
			not CollectionService:HasTag(targetInstance.Parent, "ZombieFriend") and
			not part
		then
			isAttackable = true
		end
	end

	return isAttackable
end

local function findTargets()
	-- Do a new search region if we are not already searching through an existing search region
	if not searchingForTargets and tick() - timeSearchEnded >= SEARCH_DELAY then
		searchingForTargets = true

		-- Create a new region
		local centerPosition = maid.humanoidRootPart.Position
		local topCornerPosition = centerPosition + Vector3.new(ATTACK_RADIUS, ATTACK_RADIUS, ATTACK_RADIUS)
		local bottomCornerPosition = centerPosition + Vector3.new(-ATTACK_RADIUS, -ATTACK_RADIUS, -ATTACK_RADIUS)

		searchRegion = Region3.new(bottomCornerPosition, topCornerPosition)
		searchParts = Workspace:FindPartsInRegion3(searchRegion, maid.instance, math.huge)

		newTarget = nil
		newTargetDistance = nil

		-- Reset to defaults
		searchIndex = 1
	end

	if searchingForTargets then
		-- Search through our list of parts and find attackable humanoids
		local checkedParts = 0
		while searchingForTargets and searchIndex <= #searchParts and checkedParts < MAX_PARTS_PER_HEARTBEAT do
			local currentPart = searchParts[searchIndex]
			if currentPart and isInstaceAttackable(currentPart) then
				local character = currentPart.Parent
				local distance = (character.HumanoidRootPart.Position - maid.humanoidRootPart.Position).magnitude

				-- Determine if the charater is the closest
				if not newTargetDistance or distance < newTargetDistance then
					newTarget = character.HumanoidRootPart
					newTargetDistance = distance
				end
			end

			searchIndex = searchIndex + 1

			checkedParts = checkedParts + 1
		end

		if searchIndex >= #searchParts then
			target = newTarget
			searchingForTargets = false
			timeSearchEnded = tick()
		end
	end
end

local function runToTarget()
	local targetPosition = (maid.humanoidRootPart.Position - target.Position).Unit * ATTACK_RANGE + target.Position

	maid.humanoid:MoveTo(targetPosition)

	if not movingToAttack then
		maid.humanoid.WalkSpeed = random:NextInteger(ATTACK_MIN_WALKSPEED, ATTACK_MAX_WALKSPEED)
	end

	movingToAttack = true

	-- Stop the attack animation
	maid.attackAnimation:Stop()
end

local function attack()
	attacking = true
	lastAttackTime = tick()

	local originalWalkSpeed = maid.humanoid.WalkSpeed
	maid.humanoid.WalkSpeed = 0

	-- Play the attack animation
	maid.attackAnimation:Play()

	-- Create a part and use it as a collider, to find humanoids in front of the zombie
	-- This is not ideal, but it is the simplest way to achieve a hitbox
	local hitPart = Instance.new("Part")
	hitPart.Size = HITBOX_SIZE
	hitPart.Transparency = 1
	hitPart.CanCollide = true
	hitPart.Anchored = true
	hitPart.CFrame = maid.humanoidRootPart.CFrame * CFrame.new(0, -1, -3)
	hitPart.Parent = Workspace

	local hitTouchingParts = hitPart:GetTouchingParts()

	-- Destroy the hitPart before it results in physics updates on touched parts
	hitPart:Destroy()

	-- Find humanoids to damage
	local attackedHumanoids	= {}
	for _, part in pairs(hitTouchingParts) do
		local parentModel = part:FindFirstAncestorOfClass("Model")
		if isInstaceAttackable(part) and not attackedHumanoids[parentModel]	then
			attackedHumanoids[parentModel.Humanoid] = true
		end
	end

	-- Damage the humanoids
	for humanoid in pairs(attackedHumanoids) do
		humanoid:TakeDamage(ATTACK_DAMAGE)
	end

	startPosition = maid.instance.PrimaryPart.Position

	wait(ATTACK_STAND_TIME)

	maid.humanoid.WalkSpeed = originalWalkSpeed

	maid.attackAnimation:Stop()

	attacking = false
end
