For Loop doesn't loop, but only when a round starts?

So, I’ve been working on a shotgun for my game. The way it currently works is that it gets 8 “destinations” for each pellet, then loops through the Raycast calculations 8 times, each time with a different “destination”. This code works… except when a round starts.

When the round starts, the game loads in the map from serverStorage, sets up the location of certain objects, then kills every player and begins the round. During the round, the shotgun only repeats the Raycast loop once, instead of 8 times.

However, when the round ends and everything despawns, it starts working again! I’m not even getting any error messages; what gives?

Shotgun Server Script

-- Game Services
local players = game:GetService("Players")
local debris = game:GetService("Debris")
local souSe = game:GetService("SoundService")
local colSe = game:GetService("CollectionService")
local gunModule = require(game.ServerScriptService.serverGunModule)

-- Setup Variables
local tool = script.Parent
local barrel = tool.Handle.Barrel
local att0 = barrel.att0
local att1 = barrel.att1
local tracer = barrel.tracer
local bulletLocation = 0
local assistTable = {}
local headshot = false

local gunFireSFX = tool.shotgunSounds["Gun Fire"]:Clone()
gunFireSFX.Parent = tool.Handle.Barrel

-- Gameplay Variables
local DMG = 5
local spread = 3 -- in Degrees
local pellets = 8

-- On Shoot Event
tool.shotgunShoot.OnServerEvent:Connect(function(player, mousePosition)
	print("Received Server Event")
	local currentPellet = 0
	local spreadValues = {} -- saves all the positions of the barrelLooks so it isn't constantly making 8 parts each time.
	
	-- barrelLook: Basically, it recreates mousePosition - tool.Handle.Barrel.Position BUT with an actual rotation value I can edit
	local barrelLook = Instance.new("Part")
	barrelLook.Name = "barrelLook"
	barrelLook.Size = Vector3.new(0.125, 0.125, 0.125)
	barrelLook.CanCollide = false
	barrelLook.CanTouch = false
	barrelLook.CanQuery = false
	barrelLook.Color = Color3.new(1, 0, 0)
	
	-- First, the CFrame is changed to be the barrel's position, looking at the mouse. Then, if there is spread on the gun, adds an angle based on the spread to the rotation.
	repeat
		for i = 1, pellets do
			barrelLook.CFrame = CFrame.lookAt(barrel.CFrame.Position, mousePosition) * CFrame.Angles(math.rad(math.random(-spread, spread)), math.rad(math.random(-spread, spread)), 0)
			if table.find(spreadValues, barrelLook.CFrame.LookVector) == true then
				print("Found Duplicate")
				return
			else
				table.insert(spreadValues, barrelLook.CFrame.LookVector)
				print("Added Value to Table")
			end
		end
	until #spreadValues >= 8
	barrelLook.Parent = tool.Handle
	
	local barrelLookWeld = Instance.new("WeldConstraint")
	barrelLookWeld.Part0 = tool.Handle
	barrelLookWeld.Part1 = barrelLook
	barrelLookWeld.Parent = tool.Handle

	if tool.Handle:FindFirstChild("barrelLook") == false then
		return
	end

	debris:AddItem(barrelLook, 0)
	debris:AddItem(barrelLookWeld, 0)

	-- Raycast Paramaters
	local raycastParams = RaycastParams.new() -- colSe:GetTagged("leaves")
	raycastParams.FilterDescendantsInstances = {player.Character, colSe:GetTagged("water"), colSe:GetTagged("mapBorder"),} --  Add all targets bullet should pass through here
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	
	-- Raycast Calculations
	
	for i = 1, pellets do
		currentPellet += 1
		print(currentPellet)
		print(spreadValues)
		
		local chosenSpreadValue = spreadValues[math.random(1, #spreadValues)]
		local cSVIndex = table.find(spreadValues, chosenSpreadValue)
		print(cSVIndex, chosenSpreadValue)
		
		local raycastResult = workspace:Raycast(tool.Handle.Barrel.Position, chosenSpreadValue * 300, raycastParams)

		if raycastResult == nil then
			bulletLocation = tool.Handle.Barrel.Position + chosenSpreadValue * 300
		else
			bulletLocation = raycastResult.Position
		end

		gunModule.makeTracer(bulletLocation, att0, att1, tracer, tool.Handle.Barrel.Position)
		gunModule.makeMuzzleFlash(barrel)
		print(bulletLocation)
		gunFireSFX:Play()

		if raycastResult then
			local raycastInstance = raycastResult.Instance
			local model = raycastInstance:FindFirstAncestorOfClass("Model")	

			if model then
				local humanoid = model:FindFirstChild("Humanoid")
				if humanoid == nil then
					print("Humanoid not Found")
					gunModule.bulletHoleSFX(raycastResult)
					gunModule.makebulletHole(bulletLocation, raycastResult)
					return
				end

				local humPlayer = players:GetPlayerFromCharacter(humanoid.Parent)
				if humPlayer ~= nil and player.Team == humPlayer.Team then -- Or: if there IS a Player for the model AND that Player's team is equal to yours, return.
					print("Hit Teammate!")
					return
						-- This makes it so NPCs can be damaged (they return "nil" for humPlayer, so cannot complete the if statement)

				elseif raycastInstance.Name == "Head" then
					gunModule.untagHumanoid(humanoid, assistTable)
					gunModule.tagHumanoid(humanoid, player, assistTable)
					humanoid:takeDamage(DMG*2)
					print("Critical Hit!")
					headshot = true
					local humHP = humanoid.Health
					tool.shotgunHitMarkers:FireClient(player, headshot, humHP)
				else
					gunModule.untagHumanoid(humanoid, assistTable)
					gunModule.tagHumanoid(humanoid, player, assistTable) -- Extremely imporant to note: untagHumanoid and tagHumanoid NEED to pass through humanoid and player
					humanoid:takeDamage(DMG)
					print("Hit!")
					headshot = false
					local humHP = humanoid.Health
					tool.shotgunHitMarkers:FireClient(player, headshot, humHP)
				end			

			else
				gunModule.bulletHoleSFX(raycastResult)
				print(bulletLocation)
				print(raycastResult)
				gunModule.makebulletHole(bulletLocation, raycastResult)
			end
		end
		
		table.remove(spreadValues, cSVIndex)
		print("Loop Completed")
	end

print("Finished Calculations")
end)

Map Loading/Unloading Script

local function loadMap()
	for i,v in serverStorage.GSG_Map1:GetChildren() do
		
		if v:IsA("Folder") then
			for i2,v2 in v:GetChildren() do	
				local vC2 = v2:Clone() 
				vC2.Parent = workspace.currentMap
				task.wait()
			end
		end
				
		if v:IsA("Model") or v:IsA("UnionOperation") or v:IsA("Part") then
			local vC = v:Clone() 
			vC.Parent = workspace.currentMap
			task.wait()
		end
		
	end
	
	for i,v in serverStorage.locations:GetChildren() do
			
		local YCoord = 0.5

		local vC = v:Clone()  -- location
		vC.Parent = workspace.currentLocations -- load it into the workspace
		
		vC:PivotTo(CFrame.new(
			locationCoordsX[math.random(1, #locationCoordsX)], -- choose one of the 4 quadrants
			YCoord,
			locationCoordsZ[math.random(1, #locationCoordsX)]
			)
		)

		while table.find(locationNewPositions, vC:GetPivot()) do -- check if there's a building there, if there is, reroll the location
			vC:PivotTo(CFrame.new(
				locationCoordsX[math.random(1, #locationCoordsX)],
				YCoord,
				locationCoordsZ[math.random(1, #locationCoordsX)]
				)
			)
			print("Re-Rolled")
			task.wait()
		end
		
		table.insert(locationNewPositions, 1, vC:GetPivot()) -- add the location to list of places another location cannot spawn

		print(vC:GetPivot())
		print(locationNewPositions)
		task.wait()
	
	end
	
	if game.Workspace.currentLocations:FindFirstChild("location_House") then
		local house = game.Workspace.currentLocations:FindFirstChild("location_House")
		house:PivotTo(CFrame.new(house:GetPivot().X, 0.375, house:GetPivot().Z))
	end
	
	for _, v in game.Workspace:GetDescendants() do
		if v.Name == "leaves" then
			collectionService:AddTag(v, "leaves")
		end
	end
	
end

local function intermission()
	print("intermission")
	for i, v in pairs(players:GetPlayers()) do
		v.leaderstats.Kills.Value = 0
		v.leaderstats.Assists.Value = 0
		v.leaderstats.Deaths.Value = 0 
	end
	
	if gameStarted == false then
		currentTime = intermissionTime
		repeat 
			currentTime -= 1
			task.wait(1)
			updateTimer:FireAllClients(currentTime)
			print(currentTime)
		until currentTime <= 0
	end
end

local function gameRound()
	print("gameRound")
	
	loadMap()
		
	for i, v in pairs(players:GetPlayers()) do
		v.leaderstats.Kills.Value = 0
		v.leaderstats.Assists.Value = 0
		v.leaderstats.Deaths.Value = 0
		v.Character:FindFirstChild("Humanoid").Health = 0
		if v.Backpack:FindFirstChild("Pistol") == false then
			local newPistol = game:GetService("StarterPack").Pistol:Clone()
			newPistol.Parent = v.Backpack
		end
	end
	task.wait(players.RespawnTime + 1)
	
	gameStarted = true
	if gameStarted == true then
		currentTime = roundTime
		repeat
			currentTime -=1
			task.wait(1)
			updateTimer:FireAllClients(currentTime)
			print(currentTime)
		until currentTime <= 0
		gameStarted = false
	end
end

local function determineWinner()
	print("determineWinner")
	local redKills = 0
	local blueKills = 0
	local Victory = ""

	for _, v in pairs(redTeam:GetPlayers()) do
		local killstatRed = v.leaderstats.Kills
		redKills += killstatRed.Value
	end

	for _, v in pairs(blueTeam:GetPlayers()) do
		local killstatBlue = v.leaderstats.Kills
		blueKills += killstatBlue.Value
	end
	
	if redKills > blueKills then
		for _, v in pairs(redTeam:GetPlayers()) do
			v.leaderstats.Wins += 1
			Victory = "red"
			declareVictory:FireAllClients(Victory)
		end
		
	elseif  blueKills > redKills then
		for _, v in pairs(blueTeam:GetPlayers()) do
			v.leaderstats.Wins.Value += 1
			Victory = "blue"
			declareVictory:FireAllClients(Victory)
		end
	else
		Victory = ""
		declareVictory:FireAllClients(Victory)
	end
	
	redKills = 0
	blueKills = 0
	
	task.wait(5)
	
	table.clear(locationNewPositions)
	for _, v in game.Workspace.currentMap:GetChildren() do
		v:Destroy()
	end
	for _, v in game.Workspace.currentLocations:GetChildren() do
		v:Destroy()
	end
	
	for i, v in pairs(players:GetPlayers()) do
		v.Character:FindFirstChild("Humanoid").Health = 0
	end
	
end


local function roundLoop()
	while true do
		intermission()
		gameRound()
		determineWinner()
	end
end

Video of what’s going on:

Can you try replacing

if table.find(spreadValues, barrelLook.CFrame.LookVector) == true then

with

if table.find(spreadValues, barrelLook.CFrame.LookVector) then

in the shotgun server script?

Tried it, seems to return way more often now, meaning that quite a few shots don’t fire. Didn’t seem to fix anything about the round bug, either.

Looking more carefully, it seems that when the bug occurs, the code never prints the “Loop completed” statement at the end, while it does when it, well, works. Really weird…

Hi future confused developers
I was just stupid
since the code checks every model for a humanoid, then returns if it can’t find one, it was returning when shooting any piece of map geometry, and thus cancelling the loop since it returned.
All I did was switch out return for continue, which basically is return, but it doesn’t break the loop.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.