local function F()return maid.humanoid.Health>0 and maid.humanoid:GetState()~=Enum.HumanoidStateType.Dead end local function H()maid:destroy()end local function T()while F()do if not attacking then local F=getRandomPointInCircle(startPosition,PATROL_RADIUS)maid.humanoid.WalkSpeed=PATROL_WALKSPEED maid.humanoid:MoveTo(F)end wait(random:NextInteger(MIN_REPOSITION_TIME,MAX_REPOSITION_TIME))end end local function C(F)local H=false local T=F and(F.Parent and F.Parent:FindFirstChild("\072\117\109\097\110\111\105\100"))if not T then return false end local C=false if ATTACK_MODE==1 then if CollectionService:HasTag(F.Parent,"\083\111\108\100\105\101\114\069\110\101\109\121")and not CollectionService:HasTag(F.Parent,"\083\111\108\100\105\101\114\070\114\105\101\110\100")then C=true end elseif ATTACK_MODE==2 then if not CollectionService:HasTag(F.Parent,"\083\111\108\100\105\101\114\070\114\105\101\110\100")then C=true end elseif ATTACK_MODE==3 then C=true end if C then local C=(maid.humanoidRootPart.Position-F.Position).Magnitude if C<=ATTACK_RADIUS then local b=Ray.new(maid.humanoidRootPart.Position,(F.Parent.HumanoidRootPart.Position-maid.humanoidRootPart.Position).Unit*C)local A=Workspace:FindPartOnRayWithIgnoreList(b,{F.Parent,maid.instance},false,true)if F~=maid.instance and(F:IsDescendantOf(Workspace)and(T.Health>0 and(T:GetState()~=Enum.HumanoidStateType.Dead and not A)))then H=true end end end return H end local function b()local F=target.Parent:FindFirstChild("\072\117\109\097\110\111\105\100")F:TakeDamage(ATTACK_DAMAGE)maid.attackAnimation:Play()maid.gunFireSound:Play()local H=maid.instance.Weapon.Handle.FiringPositionAttachment H.FireEffect:Emit(10)H.PointLight.Enabled=true wait(.1)H.PointLight.Enabled=false end local function A()if not searchingForTargets and tick()-timeSearchEnded>=SEARCH_DELAY then searchingForTargets=true local F=maid.humanoidRootPart.Position local H=F+Vector3.new(ATTACK_RADIUS,ATTACK_RADIUS,ATTACK_RADIUS)local T=F+Vector3.new(-ATTACK_RADIUS,-ATTACK_RADIUS,-ATTACK_RADIUS)searchRegion=Region3.new(T,H)searchParts=Workspace:FindPartsInRegion3(searchRegion,maid.instance,math.huge)newTarget=nil newTargetDistance=nil searchIndex=1 end if searchingForTargets then local F=0 while searchingForTargets and(searchIndex<=#searchParts and F<MAX_PARTS_PER_HEARTBEAT)do local H=searchParts[searchIndex]if H and C(H)then local F=H.Parent local T=(F.HumanoidRootPart.Position-maid.humanoidRootPart.Position).magnitude if not newTargetDistance or T<newTargetDistance then newTarget=F.HumanoidRootPart newTargetDistance=T end end searchIndex=searchIndex+1 F=F+1 end if searchIndex>=#searchParts then target=newTarget searchingForTargets=false timeSearchEnded=tick()end end end local function E()attacking=true local H=maid.humanoid.WalkSpeed maid.humanoid.WalkSpeed=0 maid.attackIdleAnimation:Play()local T=0 while attacking and(C(target)and F())do b()T=(T+1)%CLIP_CAPACITY if T==CLIP_CAPACITY-1 then wait(RELOAD_DELAY)else wait(ATTACK_DELAY)end end maid.humanoid.WalkSpeed=H maid.attackIdleAnimation:Stop()attacking=false end
--[[
	Implementation
]]

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

local function destroy()
	maid:destroy()
end

local function patrol()
	while isAlive() do
		if not attacking then
			local position = getRandomPointInCircle(startPosition, PATROL_RADIUS)
			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 isAttackable = false

	local targetHumanoid = targetInstance and targetInstance.Parent and targetInstance.Parent:FindFirstChild("Humanoid")
	if not targetHumanoid then
		return false
	end

	-- Determine if they are attackable, depening on the attack mode
	local isEnemy = false
	if ATTACK_MODE == 1 then
		-- Attack characters with the SoldierEnemy tag
		if
			CollectionService:HasTag(targetInstance.Parent, "SoldierEnemy")
			and not CollectionService:HasTag(targetInstance.Parent, "SoldierFriend")
		then
			isEnemy = true
		end
	elseif ATTACK_MODE == 2 then
		-- Attack all humanoids without the SoldierFriend tag
		if not CollectionService:HasTag(targetInstance.Parent, "SoldierFriend") then
			isEnemy = true
		end
	elseif ATTACK_MODE == 3 then
		-- Attack all humanoids
		isEnemy = true
	end

	if isEnemy then
		local distance = (maid.humanoidRootPart.Position - targetInstance.Position).Magnitude

		if distance <= ATTACK_RADIUS then
			local ray = Ray.new(
				maid.humanoidRootPart.Position,
				(targetInstance.Parent.HumanoidRootPart.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 part
			then
				isAttackable = true
			end
		end
	end

	return isAttackable
end

local function fireGun()
	-- Do damage to the target
	local targetHunanoid = target.Parent:FindFirstChild("Humanoid")
	targetHunanoid:TakeDamage(ATTACK_DAMAGE)

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

	-- Play the firing sound effect
	maid.gunFireSound:Play()

	-- Muzzle flash
	local firingPositionAttachment = maid.instance.Weapon.Handle.FiringPositionAttachment
	firingPositionAttachment.FireEffect:Emit(10)
	firingPositionAttachment.PointLight.Enabled = true

	wait(0.1)

	firingPositionAttachment.PointLight.Enabled = false
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 attack()
	attacking = true

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

	maid.attackIdleAnimation:Play()

	local shotsFired = 0
	while attacking and isInstaceAttackable(target) and isAlive() do
		fireGun()

		shotsFired = (shotsFired + 1) % CLIP_CAPACITY

		if shotsFired == CLIP_CAPACITY - 1 then
			wait(RELOAD_DELAY)
		else
			wait(ATTACK_DELAY)
		end
	end

	maid.humanoid.WalkSpeed = originalWalkSpeed

	maid.attackIdleAnimation:Stop()

	attacking = false
end
