Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How can I use pairs with the until argument?

Asked by
Seyfert 90
8 years ago

My code looks like this, and I am assuming it is wrong as ROBLOX tells me v is a nil value.

while true do 
    wait()
    repeat
    for i, v in pairs(game.Players:GetPlayers()) do
    if v.TeamColor == BrickColor.new("Bright red") then
    if v.Character.Humanoid.Health == "100" then 
    wait()
    end
    end
    end
    until v.Character.Humanoid.Health == "0" 

If you can't tell, I want the script to look for the players on Bright red team and then to check if health is 100, if it is, it is just going to wait() / repeat those lines. I want it to stop repeating when the player (or v.Character) has a health of 0. Could I add another for i, v in pairs after the until? ROBLOX still shows red lines on it so I am assuming I can't. How else can I get around this?

0
Please edit your answer, press the lua button, and place your code inside the two lines. Sublimus 992 — 8y
0
You should really use a code block. User#11440 120 — 8y
0
Yeah I apologize sincerely, I forgot to put it. I have fixed it though, sorry Seyfert 90 — 8y
0
I don't think you should be using a repeat loop. Also, you're checking if the health value is a string instead of a number value, or an int value. This means that if you do manage to get the repeat to work, it could crash your studio, but it would probably just error. User#11440 120 — 8y

1 answer

Log in to vote
0
Answered by
Link150 1355 Badge of Merit Moderation Voter
8 years ago

Roblox errors "attempt to index a nil value" because your v variable is out of scope. "attempt to index a nil value" means you are trying to access a variable's member through the '.' or ':' operators but that variable is nil; it has no value.

About a variable's scope:

When we say a variable is out of scope, we mean the variable's lifetime is over; It does not exist anymore. In this particular example, this is due to the fact that the variables i and v are local to your for loop. In other words, the variables are deleted after the for loop is done executing; at the end of the loop.

There are two kinds of variables in Lua (not to be confused with a variable's type): Global variables and local variables.

A global variable's scope is that of the whole script. It exists throughout the entire "file".

A local variable's scope is the level of the block in which it is declared in (starting at the line following the one it was declared on). They are introduced by prefixing them with the local keyword.

E.g:

-- 'a' is global variable. It exists and can be used through the whole script.
a = 2


if a == 2 then
    local b = "test"
    -- 'b' is a local variable. Its scope (and so its lifetime) is limited
    -- to the block following this 'if' statement and all the blocks
    -- "under", or "inside", it. Functions; 'while', 'for' and 'repeat ...
    -- until' loops; as well as 'do ... end' statements are also blocks.
    -- A block, and by extension its scope level, ends whenever an
    -- 'else', 'elseif' or 'end' keyword is encountered by Lua.

    if b == "test" then
        -- 'b' still exists here.

        local c
        -- You don't need to assign them a value by the way.
        -- A local variable declared with no value will by default
        -- have the value 'nil'.
        -- 
        -- For global variables, this is redundant and thus will
        -- throw an error saying "'=' expected near '<eof>'".
    end
end
-- 'b' ceases to exist here; It is now out of scope.
-- Any reference to 'b' will return nil, and so any
-- attempt to access a member of that nil value
-- will error out "attempt to access a nil value"

-- 'd' is a variable local to the global scope. There is
-- a minor subtlety with a global variable. 'd's scope
-- starts here and persists until the end of the file...
local d = 4


function setValueOfE(value)
    e = value
end

-- ...whereas 'e's scope still starts at the top of the file.
-- The difference is that 'e' can be used anywhere,
-- EVEN ABOVE these lines and will still refer to the same
-- global variable 'e' (although it's value will be nil until
-- it is first assigned a value).
setValueOfE(2)
print(e)        -- prints "2"

e = 1
print(e)        -- prints "1"


do
    -- Just like local variables, local functions can only
    -- be called in the block they have been declared
    -- in (starting at the line following the declaration).
    -- Just like local variables, they can also be local to
    -- the global scope (Although I won't demonstrate
    -- this here, I figure you get the point).

    -- 'f' doesn't exist yet.
    f() -- "attempt to call global 'f', a nil value"

    -- 'f's scope starts here.
    local function f()
        print("Hello, World!")
    end

    f() -- prints "Hello, World!".

    -- A local function, like a global function can
    -- also call itself without problem.
    local function factorial(n)
        if n < 0 then
            error("n is negative", n)
        elseif n < 2 then
            return 1
        else
            return n - factorial(n - 1)
        end
    end
end

-- 'f' and 'g' are now out of scope.
f() -- "attempt to call global 'f' (a nil value)"
g() -- "attempt to call global 'g' (a nil value)"


-- a local or global function declaration is really
-- just the same as variable assigned a "function value"
-- (also known as anonymous function):
local myFunction1 = function()
    print("Hello!")
end

local myFunction2 = function()
    print("World!")
end

-- Since in essence they are just variables, you could also
-- pass them as a parameter to another function:
local function execute(someFunction)
    -- receives 'someFunction' as a parameter
    -- and calls it.
    someFunction()
end

local function printHelloWorld()
    print("Hello, World!")
end

execute(printHelloWorld)
execute(function() print("This works too!") end)

Alright, that's it for the theory. Let's jump to your problem.

There are two solutions to your problem:

Solution #1: Use a global variable This is -- and any good Lua scripter will agree with me -- the easiest (as in, you won't have to change your script too much) but also ugliest way to solve this problem. While you won't have to rethink your script much, it is considered bad practice. Very bad. Unless you have a really good reason not to, you should always stick to local variables. True, global variables and functions are convenient. Simply by typing a = 5 or using the _G table (_G.a = 5, which is the exact same thing), you can create a variable that’s accessible from anywhere in your code. But there are also multiple reasons why this is bad. First of all, Lua is much more efficient and faster when working with local variables than global variables. Secondly, say I were to write something like this: string = "myString"; In this case I would have completely trashed the string library just because I wanted a variable named 'string'! Whereas if I used a local variable, the string library (which is really just a global table filled with functions) would never have been modified. There are other cons to using global variables or the global table, but I won't discuss them all here. Let's just say they are out of scope of this answer. :)

Solution #2: Subscribing to the Died event Instead of Wait()ing for a player to die, you could instead subscribe to the Died event of the player characters' Humanoid, here's an example:

function onDeath(character)
    print("Someone died")
end


function onPlayerAdded(player)
    -- For each player who joins the game, we...

    -- check their TeamColor. If they are in the bright red team then...
    if v.TeamColor == BrickColor.new("Bright red") then
        -- we obtain their character model through their Player instance...
        local character = v.Character

        -- we check if it exists, just to be sure.
        if character then
            -- If it exists then we look for an Humanoid object
            -- inside their character model...
            local humanoid = v:FindFirstChild("Humanoid")

            -- again, we check if it exists.
            if humanoid then
                -- If it exists then we "subscribe" (we also say "listen"
                -- or "connect") to it's Died event. By this, I really just
                -- mean passing it a function that will be called back
                -- when the event triggers. Such a function is known as
                -- a "Callback". That's a very original name, isn't?

                humanoid.Died:connect(onDeath)
                -- Our "onDeath" function will now always be called
                -- whenever someone on the bright red team dies.
                -- 
                -- Note that players who already died once won't be
                -- affected. For this, you'd need to subscribe to the
                -- player's CharacterAdded event -- which is fired every-
                -- time a player's character respawns -- and connect
                -- your onDeath function callback each time the callback
                -- passed to CharacterAdded is called. I'll leave this to you
                -- as an excercise.
            end
        end
    end
end


-- We subscribe to the PlayerAdded event, which is fired whenever
-- a player joins the game.
game.Players.PlayerAdded:connect(onPlayerAdded)

Alright. That was a particularly long read but I hope it helped you and that maybe you've learned a few things. Please be sure to upvote and mark my answer as accepted if it did. If you still need help with this, feel free to leave me a message.

0
Hi, thank you for helping me, I tried following the second solution as I liked it a lot, but I added a while true do for the for i, v in pairs as I want this to always be checking. However, it does not seem to be calling the function onDeath. I know that the loop is working because I put a print("Loop is working" at the start of the while true do and that gets constantly spammed in the output wind Seyfert 90 — 8y
0
Yeah, I just noticed a flaw in my script so I updated it. Note that you don't need an infinite loop to do this. Link150 1355 — 8y
Ad

Answer this question