luarobloxluauroblox-studio

All ModuleScript variables == nil


For some reason, my local variables in the module script all seem to be nil, with no exact explanation for it, or solution. Local Script (Stamina bar Script):

local ms = require(game.ReplicatedStorage.ModuleScript)
if not ms then
    
    local ms = require(game.ReplicatedStorage:WaitForChild("ModuleScript"))
    
end

local TW = game:GetService("TweenService")--Get Tween Service

local Staminabar = script.Parent -- Get The Stamina bar

local function UpdateStaminabar() --Stamina Bar Size Change Function
    local stamina = math.clamp(ms.stamina / ms.maxstamina, 0, 1) --Maths
    local info = TweenInfo.new(ms.stamina / ms.maxstamina,Enum.EasingStyle.Linear,Enum.EasingDirection.InOut,0,false,0) --Tween Info
    TW:Create(script.Parent,info,{Size = UDim2.fromScale(ms.stamina, 1)}):Play() -- Create The Tween Then Play It
end

UpdateStaminabar()--Update The Health Bar

ms.stamina:GetPropertyChangedSignal("Value"):Connect(UpdateStaminabar) --Update The Health Bar When The Health Change
ms.maxstamina:GetPropertyChangedSignal("Value"):Connect(UpdateStaminabar) --Update The Health Bar Wheb The MaxHealth Change

LocalScript (Combat Script):

local ms = require(game.ReplicatedStorage.ModuleScript)
if not ms then
    
    local ms = require(game.ReplicatedStorage:WaitForChild("ModuleScript"))
    
end 
local uis = game:GetService("UserInputService")
local cas = game:GetService("ContextActionService")
local rs = game:GetService("ReplicatedStorage")

local events = rs:WaitForChild("Events")
local hitbox = events:WaitForChild("Hitbox")

local plr = game.Players.LocalPlayer
local character = plr.Character
if not character then
    
    plr:WaitForChild("Character")
    
end
local humanoid = character.Humanoid
local animator = humanoid:WaitForChild("Animator")

local idle = animator:LoadAnimation(script:WaitForChild("idle"))
local jab = animator:LoadAnimation(script:WaitForChild("jab"))
local rightcross = animator:LoadAnimation(script:WaitForChild("rightstraight"))
local lefthook = animator:LoadAnimation(script:WaitForChild("lefthook"))
local righthook = animator:LoadAnimation(script:WaitForChild("righthook"))
local swingsfx = script:WaitForChild("Air swing")

local currentPunch = 0
local currentPunch2 = 0
local debounce1 = false
local debounce2 = false

local function onInputBegan(input)
    
    if debounce2 == true then return end
    if ms.stamina <= 0 then return end
    
    
    if input.KeyCode == Enum.KeyCode.Q then
        
        ms.stamina -= 20
        debounce2 = true
        humanoid.WalkSpeed = 0.5
        lefthook:Play()
        swingsfx:Play()
        hitbox:FireServer(Vector3.new(4, 5, 3), Vector3.new(4.5, 1), 7.5, 0.15)
        task.wait(0.5)
        humanoid.WalkSpeed = 10
        lefthook:Stop()
        task.wait(6)
        debounce2 = false
        
    end 
    
    if input.KeyCode == Enum.KeyCode.E then

        ms.stamina -= 20
        debounce2 = true
        humanoid.WalkSpeed = 0.5
        righthook:Play()
        swingsfx:Play()
        hitbox:FireServer(Vector3.new(4, 5, 3), Vector3.new(4.5, 1), 7.5, 0.15)
        task.wait(0.5)
        humanoid.WalkSpeed = 10
        righthook:Stop()
        task.wait(6)
        debounce2 = false

    end 
end

local function punch()
    
    if debounce1 then return end
    
    debounce1 = true
    if currentPunch == 0 then
        
        ms.stamina -= 10
        humanoid.WalkSpeed = 0.6
        jab:Play()
        swingsfx:Play()
        hitbox:FireServer(Vector3.new(4, 5, 3), Vector3.new(5.7, 1), 2.5, 0.15)
        task.wait(0.5)
        humanoid.WalkSpeed = 10
        jab:Stop()
        debounce1 = false
        
    elseif currentPunch == 1 then
        
        ms.stamina -= 10
        humanoid.WalkSpeed = 0.6
        rightcross:Play()
        swingsfx:Play()
        hitbox:FireServer(Vector3.new(4, 5, 3), Vector3.new(5.7, 1), 2.5, 0.15)
        task.wait(0.5)
        humanoid.WalkSpeed = 10
        rightcross:Stop()
        debounce1 = false
        
    elseif currentPunch == 2 then
        
        ms.stamina -= 10
        humanoid.WalkSpeed = 0.6
        jab:Play()
        swingsfx:Play()
        hitbox:FireServer(Vector3.new(4, 5, 3), Vector3.new(5.7, 1), 2.5, 0.15)
        task.wait(0.5)
        humanoid.WalkSpeed = 10
        jab:Stop()
        debounce1 = false
        
    elseif currentPunch == 3 then
        
        ms.stamina -= 10
        debounce2 = true
        humanoid.WalkSpeed = 0.6
        rightcross:Play()
        swingsfx:Play()
        hitbox:FireServer(Vector3.new(4, 5, 3), Vector3.new(5.7, 1), 5, 0.15)
        task.wait(0.5)
        humanoid.WalkSpeed = 10
        rightcross:Stop()
        debounce1 = false
        debounce2 = false
        
    end

    if currentPunch == 3  then
        
        currentPunch = 0
        debounce1 = true
        wait(2)
        debounce1 = false
        
    else
        
        currentPunch += 1
        
    end
    
end

cas:BindAction("Punch", punch, true, Enum.UserInputType.MouseButton1)
uis.InputBegan:Connect(onInputBegan)

ModuleScript:

local info = {}

    local stamina = 100
    local maxstamina = 100
    
return info

I was trying to make a stamina system, together with a stamina bar, but they just refuse to use the locals, and instead print out errors like:

15:00:30.915 Players.Morelval1.PlayerGui.ScreenGui.StaminaBar.Frame.StaminaBar Script:12: attempt to perform arithmetic (div) on nil - Client - StaminaBar Script:12 15:00:32.505 Players.Morelval1.PlayerGui.Main.PunchScript:39: attempt to compare nil <= number - Client - PunchScript:39

I was expecting for the variables to be interacted with, and be used.


Solution

  • local ms = require(game.ReplicatedStorage.ModuleScript)
    if not ms then
        
        local ms = require(game.ReplicatedStorage:WaitForChild("ModuleScript"))    
    end
    

    The second ms is local to the if statement. It shadows the first ms. So in case the first require failed you'll store the return value of the second require into the wrong variable.

    Remove the local keyword.

    local ms = require(game.ReplicatedStorage.ModuleScript)
    if not ms then
        
        ms = require(game.ReplicatedStorage:WaitForChild("ModuleScript"))    
    end
    

    Or simply

    local ms = require(game.ReplicatedStorage.ModuleScript)
             or require(game.ReplicatedStorage:WaitForChild("ModuleScript"))    
    

    Of course you should still check if the second require attempt succeeded befor you proceed.

    No to your actual problem.

    local info = {}
    
        local stamina = 100
        local maxstamina = 100
        
    return info
    

    You return an empty table here. So any index operation on ms will result in nil.

    You want to do this:

    local info = {
    
        stamina = 100,
        maxstamina = 100,
    }
        
    return info
    

    or

    local info = {}
    
    info.stamina = 100
    info.maxstamina = 100
        
    return info
    

    As stamina and maxstamina need to be fields of the table info, not local variables to your script.

    Then the result of your require statement will be the table { maxstamina = 100, stamina = 100 } instead of { }