Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Why is my capture flag mechanic not working?

Whats up guys, so i got this problem while doing my capturing flag mechanic, and its that, or my script isnt detecting the StringValue that is in the character of every player with its value of the player team or i am doing something wrong with my if statements, can you help me out? Like the mechanic is basically checks if the current flag point is captured or not, and checks if there is a player who is not from the same team as the Current flag, and also checks for defenders who stop the capturing process until the players who are not from the current flag team and viceversa. The issue here is that the capturing process stills goes on having a player which team is not the same as the other one, so how can this be fixed? i share to you my scripts and some evidence.

See, when a opposite team player enters the zone it stills capturing and i dont want that, i want it to stop until, either a Allies or a Axis team leaves the zone and then continue capture. Here you have a **video **of what i am meaning. https://imgur.com/a/Dv3vadR My server Script.

local max_radius_size = 20
local part = game.Workspace.Part
local CurrentTeam 
local capturing = game.ReplicatedStorage.Capturing
local ileft = game.ReplicatedStorage.ILeft
local CanCapture = game.ReplicatedStorage.CapturingInside.Value
local capturers = 0 
local captureProgressValue = game.ReplicatedStorage.CaptureProgress.Value
local defenders = 0
local max_value = 1

while true do
	
	
	wait()
	for i, playersCircle in pairs(game.Players:GetPlayers()) do
		local char = playersCircle.Character or playersCircle.CharacterAdded:Wait()
		local PlayerTeam = char:WaitForChild("TeamValue").Value
		local distance = (char.HumanoidRootPart.Position - part.Position).Magnitude
		if distance < max_radius_size then -- CHECKS IF PLAYERS IS WITHIN CAPTURE RADIUS
			CanCapture = true -- MAKE THIS VARIABLE TRUE TO MAKE PLAYER ABLE TO CAP
			capturing:FireClient( playersCircle,CurrentTeam, captureProgressValue)
			if CurrentTeam == nil and CanCapture then -- WE SEE IF THE FLAG HAS NO OWNER
				if PlayerTeam ~= PlayerTeam then
						CanCapture = false
					elseif PlayerTeam == PlayerTeam then
						CanCapture = true
					end
					if CanCapture then
				captureProgressValue = math.clamp(captureProgressValue + 0.05, 0,1)
					wait(1)
					print("contrarios")
			if captureProgressValue == max_value then
						CurrentTeam = PlayerTeam
					end
				end
			end
		else
			CanCapture = false
		end -- first If statement				 
	end -- for i, v in pairs() loop 
end -- while true do line 

Thanks in advance!!!

1 answer

Notes:

  • Don't wait for a player's character if it doesn't exist when you're iterating over a bunch of players - if someone's character takes a few seconds to load up, capturing would stop working during that time!
  • Similarly, we use FindFirstChild rather than WaitForChild since we don't want to wait. This means that the script has to handle the possibility that the variables are nil, so we use and -- the way Lua works, if the value on the left of the and is nil or false, the stuff on the right hand side of the and won't be evaluated. This prevents the attempt to index nil error that would otherwise happen.
  • Next problem: you're iterating over each player and you assume you can capture after the first valid player you find. In what you described, you want custom behaviour if there are multiple players in the area, so you can't act until after you've finished your for loop. During the loop, we want to know how which players are involved from each team (I would normally say "the number of players from each team", but it looks like you have some remotes that you send to each capturing player, so we'll keep track of them)

Resulting script:

local max_radius_size = 20
local part = game.Workspace.Part
local CurrentTeam 
local capturing = game.ReplicatedStorage.Capturing
local ileft = game.ReplicatedStorage.ILeft
local CanCapture = game.ReplicatedStorage.CapturingInside.Value
local capturers = 0 
local captureProgressValue = game.ReplicatedStorage.CaptureProgress.Value
local defenders = 0
local max_value = 1
local capturingTeam
while true do
	wait()
	local teamToPlayersInCircle = {} --[teamValue] = list of players from that team that are in the circle
	local numTeams = 0
	local function addPlayer(team, player)
		local list = teamToPlayersInCircle[team]
		if not list then
			list = {}
			teamToPlayersInCircle[team] = list
			numTeams += 1
		end
		table.insert(list, player)
	end
	for i, player in ipairs(game.Players:GetPlayers()) do
		local char = player.Character
		local root = char and char:FindFirstChild("HumanoidRootPart")
		local TeamValue = char and char:FindFirstChild("TeamValue")
		if not root or not TeamValue then
			continue
		end
		local PlayerTeam = TeamValue.Value
		local distance = (root.Position - part.Position).Magnitude
		if distance < max_radius_size then -- CHECKS IF PLAYERS IS WITHIN CAPTURE RADIUS
			addPlayer(PlayerTeam, player)
			if numTeams > 1 then -- Get rid of this 'if' if you want to send out a remote to all players in the circle even if there are 2+ competing teams
				break
			end
		end
	end
	-- Now we know how many teams are involved
	if numTeams == 1 then -- Only one team, so they can capture
		local team, players = next(teamToPlayersInCircle) -- 'next' makes sense here since there is only one key-value pair in the table for 'next' to return
		local progress = #players * .05
		-- TODO Perform capturing logic here. You might want more variables to keep track of previous owners or to simulate the ability for enemy teams to undo capture progress. Simple example:
		if capturingTeam and capturingTeam ~= team then -- we have to undo progress
			captureProgressValue = math.clamp(captureProgressValue - progress, 0, max_value)
			if captureProgressValue == 0 then -- In the future this team can start making progress towards owning it now
				capturingTeam = team
			end
		elseif captureProgressValue < max_value then
			capturingTeam = team
			captureProgressValue = math.clamp(captureProgressValue + progress, 0, max_value)
			if captureProgressValue == max_value then
				-- todo they've successfully captured it
			end
		end
		for _, player in ipairs(players) do
			capturing:FireClient(player, capturingTeam, captureProgressValue) -- are you sure you don't want to notify all clients? (In which case, instead of this for loop, use FireAllClients)
		end
	end -- else there aren't any teams or there are 2+
end

[In response to comment] Further explanation

First we start with local teamToPlayersInCircle = {} --[teamValue] = list of players from that team that are in the circle. I use the comment to explain that teamToPlayersInCircle[teamValue] will equal the list of players (who are on the the teamValue team) in the capture zone. I recommend making sure you understand tables: http://lua-users.org/wiki/TablesTutorial - try experimenting with the syntax of tables in the command bar in Roblox Studio.

The next interesting line is local function addPlayer(team, player). (If you don't know much about functions, read over http://lua-users.org/wiki/FunctionsTutorial). I place the function definition where it is so that it can use the local variables declared above it (most importantly, teamToPlayersInCircle and numTeams). This function could be declared outside the while loop, but then we'd have to pass in teamToPlayersInCircle and numTeams every time (which is more to type). Here are some comments about each line of the function:

    local function addPlayer(team, player)
        local list = teamToPlayersInCircle[team] -- We are looking up the value associated with the team key in the teamToPlayersInCircle table. At first this will be nil because we haven't put anything in that table yet.
        if not list then -- If there is nothing in the table for that team yet, that means that this player is the first of their team in the capture zone
            list = {} -- so we create a new list to hold this player
            teamToPlayersInCircle[team] = list -- we associate their team with this new list we created
            numTeams += 1 -- we record that we have found a new team that's in the capture zone
        end
        -- At this point we are sure that 'list' either already existed or else we just created it
        table.insert(list, player) -- so we add the player to that list
    end
-- ...
            addPlayer(PlayerTeam, player) -- this calls the function addPlayer defined above. The 'team' parameter above will receive the value 'PlayerTeam' (just like if we said "team = PlayerTeam") and same thing for the two "player" variables.

2 comments

0

Hey man thanks!!!!!!!! I was struggling so bad with this for days literally. Also i dont know what some lines mean, what does the function AddPlayers? Why do you do like list = teamtoplayerinthecircle[team] are you trying to get the team and then do a dictionary??? Thanks in advance man.

0

No problem. I've added another section at the bottom to explain (starting with "[In response to comment]"); let me know if you have any further questions.

This discussion is preserved as it was. New answers, comments, and votes are closed.