luarobloxlua-table

Attempt to call missing method of table


I'm trying to make my first Roblox studio game and I ran into this problem:

attempt to call missing method 'UpdateCharacter' of table

attempt to call missing method 'Equip' of table

Any function that is called from FistCombat even if it is declared. I attach the 3 scripts that I believe are the problem.

local RS = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")

local Player = game:GetService("Players").LocalPlayer
local Camera = workspace.CurrentCamera
local GUI = Player.PlayerGui:WaitForChild("CombatGui")
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid
local Backpack = Player.Backpack

local CharacterConnections = {

}


--ReplicateRemote
local ReplicateRemote = RS.Remotes.Replicate

--CameraShaker
local function ShakeCamera(ShakeCFrame)
    Camera.CFrame = Camera.CFrame * ShakeCFrame
end

local CameraShaker = require(RS.Modules.Auxillary.CameraShaker).new(Enum.RenderPriority.Camera.Value, ShakeCamera)
CameraShaker:Start()

--CooldownManager
local CooldownManager = require(RS.Modules.Auxillary.CooldownManager).new(Player, GUI)

--Status Manager
local StatusManager = Character:WaitForChild("StatusFolder")
local StatusManager = require(RS.Modules.Auxillary.StatusManager).new(Player)

local AuxObjects = {
    ["CameraShaker"] = CameraShaker,
    ["CooldownManager"] = CooldownManager,
    ["StatusManager"] = StatusManager,
}


--Default current weapon to fist
local BaseCombat = require(RS.Modules.Items.FistCombat).new(Player, AuxObjects)
local CurrentItem = BaseCombat
CurrentItem:Equip()

function HandleInputs(UserInput, GPE)
    if GPE then return end
    --Convert UserInput into a String for ease of use
    local InputName = UserInput.KeyCode.Name
    if  UserInput.UserInputType == Enum.UserInputType.MouseButton1 then
        InputName = "M1"
    elseif UserInput.UserInputType == Enum.UserInputType.MouseButton2 then
        InputName = "M2"
    end

    --Input Validation
    if CurrentItem.Keys[InputName] then
        if UserInput.UserInputState == Enum.UserInputState.Begin then
            CurrentItem[InputName](CurrentItem)
        elseif UserInput.UserInputState == Enum.UserInputState.End then
            CurrentItem[InputName.."End"](CurrentItem)
        end
    end
end

UIS.InputBegan:Connect(HandleInputs)
UIS.InputEnded:Connect(HandleInputs)

-- Super Simple Replicator
local Modules = {}
for i, Item in pairs(RS.Modules.Items:GetChildren()) do
    Modules[Item.Name] = require(Item)
end

ReplicateRemote.OnClientEvent:Connect(function(Args)
    Modules[Args.Module][Args.Action](Args)
end)

-------------------------------------
--Inventory System

--Connections
local BackpackConnections = {}
local BackpackCoreConnections = {}

function AddItem(Tool)
    if Tool:IsA("Tool") and not BackpackConnections[Tool] then
        BackpackConnections[Tool] = {}
        BackpackConnections[Tool].Module = require(RS.Modules.Items[Tool.Name]).new(Player, AuxObjects)
        BackpackConnections[Tool].Equipped = Tool.Equipped:Connect(function()
            Currentitem:Unequip()
            Currentitem = BackpackConnections[Tool].Module
            Currentitem:Equip()
        end)
        
        BackpackConnections[Tool].Unequipped = Tool.Unequipped:Connect(function()
            if Character:FindFirstChildWhichIsA("Tool") == nil then
                Currentitem:Unequip()
                Currentitem = BaseCombat
                Currentitem:Equip()
            end
        end)
    end
end

for i, OtherPlayer in pairs(game:GetService("Players"):GetPlayers()) do
    if OtherPlayer ~= Player then
        if OtherPlayer.Character:FindFirstChildWhichIsA("Tool") then
            Modules[OtherPlayer.Character:FindFirstChildWhichIsA("Tool").Name].CreateModel({Character = OtherPlayer.Character})
        end
    end
end

function LoadCharacter(Char)
    Character = Char
    Humanoid = Char:WaitForChild("Humanoid")
    Humanoid:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
    Humanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
    
    Backpack = Player.Backpack
    BackpackCoreConnections.childAdded = Backpack.ChildAdded:Connect(function(Tool)
        if Tool:IsA("Tool") then
            AddItem(Tool)
        end
    end)
    
    BackpackCoreConnections.ChildRemoved = Backpack.ChildRemoved:Connect(function(Tool)
        if Tool:IsA("Tool") then
            if Tool.Parent ~= Character then
                BackpackConnections[Tool].Equipped:Disconnect()
                BackpackConnections[Tool].Unequipped:Disconnect()
                BackpackConnections[Tool].Module:Destroy()
                BackpackConnections[Tool] = nil
            end
        end
    end)
    
    for i,Tool in pairs(Backpack:GetChildren()) do
        AddItem(Tool)
    end
    
    CurrentItem = BaseCombat
    CurrentItem:Equip()
    
    CharacterConnections["Died"] = Humanoid.Died:Connect(function()
        BackpackCoreConnections.childAdded:Disconnect()
        BackpackCoreConnections.ChildRemoved:Disconnect()
        --Make sure our Character inst attacking when dead
        CurrentItem:Lock()
    end)
    
    CurrentItem:UpdateCharacter()
    CurrentItem:Unlock()    
end

Player.CharacterAdded:Connect(LoadCharacter)
LoadCharacter(Character)
local FistCombat = {}
FistCombat._index = FistCombat

local RF = game:GetService("ReplicatedFirst")
local RS = game:GetService("ReplicatedStorage")
local TS = game:GetService("TweenService")

local ActionService = RS.Remotes.ActionService
local ReplicateRemote = RS.Remotes.Replicate

local Auxillary = require(RS.Modules.Auxillary.Auxillary)

local Assets = RF.Assets.FistCombat
local VFX = Assets.VFX
local Sound =  Assets.Sound
local Animations = Assets.Animations

local PunchTextures = {
    "rbxassetid://",
    "rbxassetid://",
    "rbxassetid://",
    "rbxassetid://",
    "rbxassetid://",
    "rbxassetid://",
}

local COMBOLENGTH = 5
local COMBORESETLENGTH = 1
local ITEMNAME =  "FistCombat"

function FistCombat.new(User, AuxObjects)
    local self = setmetatable({}, FistCombat)
    
    
    self.User = User
    self.Mouse = User:GetMouse()
    self.CooldownManager = AuxObjects.CooldownManager
    self.CameraShaker = AuxObjects.CameraShaker
    self.StatusManager = AuxObjects.StatusManager
    self.Character = User.Character
    
    self.Locked = false
    self.Equipped = false
    
    self.Status = {
        ["Combo"] = 1,
        ["LastCombo"] = 0,
        ["Blocking"] = false,
        ["Action"] = false,
    }
    
    self.Keys ={
        ["M1"] = {["Name"] = "Punch", ["LayoutOrder"] = 1 },
        ["M2"] = {["Name"] = "Heavy", ["LayoutOrder"] = 2 },
        ["F"] = {["Name"] = "Block", ["LayoutOrder"] = 3 },
    }
    
    self.Animations = {
        
    }
    
    self.CooldownManager:AddItem("FistCombat", self.Keys)
    
    return self
end

function FistCombat:Name()
    print("FistCombat") 
end

function FistCombat:Equip()
    --Equip the item and load cooldown ui
    self.CooldownManager:LoadItem("FistCombat")
    self.Equipped = true 
end

function FistCombat:M1()
    --CheckCooldown and other requirements
    if 
        not self.CooldownManager:onCooldown(ITEMNAME, "Punch")
        and self.Equipped
        and not self.Locked
        and not self.Status.Blocking
        and not self.Status.Action
        and not self.StatusManager:GetSatus().Stun
        and not self.CooldownManager.InAction
    then
        self.CooldownManager.SetAction(true)
        self.Status.Action = true
        
        if time() - self.Status.LastCombo > COMBORESETLENGTH then
            self.Status.LastCombo = 1
        end 
        
        self.Status.LastCombo = time()
        
        local Cooldown =.3
        if self.Status.Combo == 5 then
            Cooldown = 1
        end
        
        self.CoolDownManager:AddCooldown(ITEMNAME,"Punch", Cooldown)
        
        self.Character.Humanoid.walkSpeed = 4
        
        --Move the Player
        local BV = Instance.new("BodyVelocity")
        BV.MaxForce = Vector3.new(999999,0,999999)
        BV.Velocity = self.Character.HumanoidRootPart.CFrame.LookVector * 25
        BV.Parent = self.Character.HumanoidRootPart
        
        task.delay(.1,function()
            BV:Destroy()
        end)
        
        --Play the animation
        local Animation = self.Character.Humanoid.Animator:LoadAnimation(Animations["M"..self.Status.Combo])
        Animations:Play()
        
        --Create the effect
        local ReplicateArgs = {
            Module = "FistCombat",
            Action = "PunchEffect",
            Character = self.Character,
            Combo = self.Status.Combo,
        }
        FistCombat.PunchEffect(ReplicateArgs)
        ReplicateRemote:FireServer(ReplicateArgs)
        
        --Camera Shake
        self.CameraShaker:ShakeOnce(2,4,.2,.3)
        
        --Hitboxing
        local params = OverlapParams.new()
        params.FilterType = Enum.RaycastFilterType.Exclude
        params.FilerDescendantsInstances = {workspace.Map, workspace.FX, self.Character}
        
        local HitList = {}
        local HB = workspace.GetPartBundsInBox(self.character:GetPivot() * CFrame.new(0,0,-4), Vector3.new(4,4,6), params)
        
        for i, Part in pairs(HB) do
            if Part.Parent:FindFirstChild("Humanoid") and table.find(HitList, Part.Parent) == nil then
                table.insert(HitList, Part.Parent)
                
                local Highlght = Instance.new("Highlight", Part.Parent)
                Highlght.DepthMode = Enum.HighlightDepthMode.Occluded
                Highlght.FillColor = Color3.fromRGB(195,0,0)
                Highlght.FillTransparency = 0
                Highlght.OutlineTransparency = 1
                TS:Create(Highlght, TweenInfo.new(.4),{fillTransparency = 1}):Play()
                
                task.delay(.4, function()
                    Highlght:Destroy()
                end)
                
                local ReplicateArgs = {
                    Module = "FistCombat",
                    Action = "HitEffect",
                    Target = Part.Parent,
                    Combo = self.Status.Combo,
                }
                FistCombat.HitEffect(ReplicateArgs)
                ReplicateRemote:FireServer(ReplicateArgs)
                
                if self.Status.Combo == 5 then
                    local ReplicateArgs = {
                        Module = "FistCombat",
                        Action = "HeavyhitEffect",
                        Target = Part.Parent,
                        Character = self.Character,
                    }
                    FistCombat.HeavyHitEffect(ReplicateArgs)
                    ReplicateRemote:FireServer(ReplicateArgs)
                end
            end
        end
        
        local   ServerArgs = {
            ["Module"] = "FistCombat",
            ["Action"] = "hit",
            ["HitList"] = HitList,
            ["Knockback"] = self.Character.HumanoidRootPart.CFrame.LookVector *25,
            ["Combo"] = self.Status.Combo,
        }
        
        if self.Status.Combo == 5 then
            ServerArgs.Knockback *=3
        end
        
        ActionService:InvokeServer(ServerArgs)
        
        if self.Status.Combo == COMBOLENGTH then
            self.Status.Combo = 0
        end
        self.Status.Combo +=1
        
        task.wait(.3)
        self.Character.humanoid.WalkSpeed = 16
        self.Status.action = false
        self.CooldownManager:SetAction(false)
    end
end

function FistCombat.HitEffect(Args)
    local Target = Args.Target
    local Attachment = Instance.new("Attachment", Target.HumanoidRootPart)
    Attachment.Name = "HitEffect"
    
    if Target:GetAttribute("Blocking") then
        if Args.Combo == 5 then
            for i, ptc1 in pairs(VFX.BlockBreak:GetChildren()) do
                ptc1:Clone().Parent = Attachment
            end
        else
            for i, ptc1 in pairs(VFX.Block:GetChildren()) do
                ptc1:Clone().Parent = Attachment
            end
        end
    else
        for i, ptc1 in pairs(VFX.Hit:GetChildren()) do
            ptc1:Clone().Parent = Attachment
        end
    end
    
    Auxillary.Emit(Attachment)
    task.delay(1,function()
        Attachment:Destroy()
    end)
end

function FistCombat.HeavyHitEffect(Args)
    local Character = Args.Character
    local Target = Args.Target
    local Direction = Character.HumanoidRootPart.CFrame.LookVector
    
    local HeavyEffect = VFX.heavy:Clone()
    HeavyEffect.CFrame = CFrame.new(Target.HumanoidRootpart.Position, Character.HumanoidRootPart.Position) * CFrame.Angles(0,math.rad(180),0)
    HeavyEffect.Parent = workspace.FX
    Auxillary.Emit(HeavyEffect.Attachment)
    task.delay(2,function()
        HeavyEffect:Destroy()
    end)
    
    task.spawn(function()
        local Params = RaycastParams.new()
        Params.FilterType = Enum.RaycastFilterType.Include
        Params.FilterDescendantsInstances = {workspace.Map}
        for i = 1, 15 do
            local Result = workspace:Raycast(Target.HumanoidRootpart.Position, Vector3.new(0,-8,0), Params)
            if Result then
                local Dust = VFX.Dust:Clone()
                Dust.CFrame = CFrame.new(Target.HumanoidRootpart.Position, Direction)
                Dust.Position = Result.Position
                Dust.Dust.Enabled = true
                Dust.Parent = workspace.FX
                Dust.Dust.Color = ColorSequence.new{ColorSequenceKeypoint.new(0,Auxillary.GetColorFromRay(Result)), ColorSequenceKeypoint.new(1, Auxillary.GetColorFromRay(Result))}
                task.delay(.15, function()
                    Dust.Dust.Enabled = false
                    task.wait(4)
                    Dust:Destroy()
                end)                
            end
            task.wait(.03)
        end
    end)
end

function FistCombat.PunchEffect(Args)
    local Punch = VFX.Punch:Clone()
    local Weld = Auxillary.Weld(Args.Character.HumanoidRootPart, Punch, CFrame.new(), CFrame.new())
    local WeldC0 = CFrame.new()
    
    if Args.Combo == 1 then
        WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(190)) * CFrame.Angles(0,math.rad(100), 0)
    elseif Args.Combo == 2 then
        WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(-10)) * CFrame.Angles(0,math.rad(100), 0)
    elseif Args.Combo == 3 then
        WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(200)) * CFrame.Angles(0,math.rad(100), 0)
    elseif Args.Combo == 4 then
        WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(-15)) * CFrame.Angles(0,math.rad(100), 0)
    else
        for i, Particle in pairs(Punch.Trail:GetChildren()) do
            local ClonedParticle = Particle:Clone()
            ClonedParticle.Parent = Punch.Trail
            ClonedParticle.EmissionDirection = Enum.NormalId.Right
        end
    end
    
    Auxillary.Emit(Punch.Trail)
    Weld.C0 = WeldC0
    Punch.Parent = workspace.FX
    
    task.spawn(function()
        for i = 1, 6 do
            Punch.Mesh.TextureId = PunchTextures[i]
            wait()
        end
        Punch:Destroy()
    end)
    
    TS:Create(Weld, TweenInfo.new(.3, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out, 0, false,0),{C0 = Weld.C0 * CFrame.Angles(0,math.rad(-100),0)}):Play()
end

function FistCombat:M1End()
    
end

function FistCombat:M2()
    if 
        not self.CooldownManager:OnCooldown(ITEMNAME, "Heavy")
        and self.Equipped
        and not self.Locked
        and not self.Blocking
        and not self.Status.Action
        and not self.StatusManager:GetStatus().Stun
        and not self.CooldownManager.inAction
    then
        self.Status.Action = true
        self.CooldownManager:SetAction(true)
        self.CooldownManager:AddCooldown(ITEMNAME,"Heavy", 1.5)
        
        self.Character.Humanoid.WalkSpeed = 4
        
        --Move the Player
        local BV = Instance.new("BodyVelociy")
        BV.MaxForce = Vector3.new(999999,0,999999)
        BV.Velocity = self.Character.humanoidRootPart.CFrame.LookVector * 25
        BV.Parent = self.Character.HumanoidRootPart
        
        task.delay(.1, function()
            BV:Destroy()
        end)
        
        --Play the animation
        local Animation = self.Character.Humanoid.Animator:LoadAnimation(Animations["M5"])
        Animation:Play()
        
        --Create the Effect
        local ReplicateArgs = {
            Module = "FistCombat",
            Action = "Puncheffect",
            Character = self.Character,
            Combo = 5,
        }       
        FistCombat.PunchEffect(ReplicateArgs)
        ReplicateRemote:FireServer(ReplicateArgs)
        
        --Camera Shake
        self.CameraShaker:ShakeOnce(2,4,0.2,0.3)
        
        --Hitboxing
        local Params = OverlapParams.new()
        Params.FilterType = Enum.RaycastFilterType.Exclude
        Params.FilterDescendantsInstances = {workspace.Map, workspace.FX, self.Character}

        local HitList = {}
        local HB = workspace:GetPartBoundsInBox(self.Character:GetPivot() * CFrame.new(0,0,-4), Vector3.new(4,4,6), Params)
        for i, Part in pairs(HB) do
            if Part.Parent:FindFirstChild("Humanoid") and table.find(HitList, Part.Parent) == nil then
                table.insert(HitList, Part.Parent)
                
                local Highlight = Instance.new("Highlight", Part.Parent)
                Highlight.DepthMode = Enum.HighlightDepthMode.Occluded
                Highlight.FillColor = Color3.fromRGB(195,0,0)
                Highlight.FillTransparency = 1
                Highlight.OutlineTransparency = 1
                TS:Create(Highlight, TweenInfo.new(.4), {FillTransparency = 1}):Play()
                
                task.delay(.4, function()
                    Highlight:Destroy()
                end)
                
                local ReplicateArgs = {
                    Module = "FistCombat",
                    Action = "HitEffect",
                    Target = Part.Parent,
                    Combo = 5,
                }
                FistCombat.HitEffect(ReplicateArgs)
                ReplicateRemote:FireServer(ReplicateArgs)
                
                local ReplicateArgs = {
                    Module = "FistCombat",
                    Action = "HeavyEffect",
                    Target = Part.Parent,
                    Character = self.Character
                }
                FistCombat.HeavyHitEffect(ReplicateArgs)
                ReplicateRemote:FireServer(ReplicateArgs)
            end
        end
        
        --Fire to Server
        local ServerArgs = {
            ["Module"] = "FistCombat",
            ["Action"] = "hit",
            ["HitList"] = HitList,
            ["Knockback"] = self.Character.HumanoidRootPart.CFrame.LookVector *75,
            ["Combo"] = 5,
        }
        
        ActionService:InvokeServer(ServerArgs)
        
        
        task.wait(.3)
        self.Character.Humanoid.WalkSpeed = 16
        self.Status.Action = false
        self.CooldownManager:SetAction(false)
        
    end
end

function FistCombat:M2End()
    
end

function FistCombat:F()
    if 
        not self.Status.Blocking
        and not self.Status.Action
        and not self.Satusmanager:GetSatus().Stun
        and not self.CooldownManager.InAction
    then
        self.CooldownManager:SetAction(true)
        self.Character.humanoid.WalkSpeed = 4
        self.Status.Blocking = true
        self.Animations.Blocking = self.Character.Humanoid.Animator:LoadAnimation(Animations.Block)
        self.Animations.Blocking:Play()
        local ServerArgs = {
            ["Modules"] = "fistCombat",
            ["Action"] = "Block",
        }
        ActionService:InvokeServer(ServerArgs)
    end
end

function FistCombat:FEnd()
    local ServerArgs = {
        ["Modules"] = "fistCombat",
        ["Action"] = "Unblock",
    }
    ActionService:InvokeServer(ServerArgs)
    self.Character.humanoid.WalkSpeed = 16
    self.Status.Blocking = false
    self.Animations.Blocking:Stop()
    self.CooldownManager:SetAction(false)
end


function FistCombat:Unequip()
    self.Equipped = false
    self:FEnd()
end


function FistCombat:Lock()
    self.Locked = true
end

function FistCombat:Unlock()
    self.Locked = false
end

function FistCombat:UpdateCharacter()
    self.Character = self.User.Character
end

function FistCombat:Destryoy()
    setmetatable(self, nil)
    table.clear(self)
    table.freeze(self)
end

return table.freeze(FistCombat)
local CooldownManager = {}
CooldownManager.__index = CooldownManager

local RF = game:GetService("ReplicatedFirst")
local TS = game:GetService("TweenService")
local RS = game:GetService("RunService")

local Assets = RF.Assets.UI.Cooldown

function CooldownManager.new(User, GUI)
    local self = setmetatable({}, CooldownManager)
    self.GUI = GUI
    self.CooldownList = {}
    self.CurrentItem = nil
    self.InAction = false
    
    return self
end

function CooldownManager:AddCooldown(ItemName, Action, Length)
    local Cooldown = self.CooldownList[ItemName][Action]
    Cooldown.OnCooldown = true
    Cooldown.StartTime = time()
    Cooldown.Length = Length

    self.GUI.Main.Cooldowns[Action].BackgroundColor3 = Color3.fromRGB(144, 80, 80)
    TS:Create(self.GUI.Main.Cooldowns[Action], TweenInfo.new(Length, Enum.EasingStyle.Linear), { BackgroundColor3 = Color3.fromRGB(144, 144, 144) }):Play()
    Cooldown.Times += 1

    task.spawn(function()
        local StartTime = Cooldown.StartTime
        Cooldown.Con = RS.RenderStepped:Connect(function()
            if time() - StartTime >= Length then
                self.GUI.Main.Cooldowns[Action].Time.Text = "0" .. "s"              self.GUI.Main.Cooldowns[Action].Time.Text = ""
                Cooldown.Con:Disconnect()
                -- Update CurrentTimes within the loop
                Cooldown.Times = Cooldown.Times - 1
                if Cooldown.Times == 0 then
                    Cooldown.OnCooldown = false
                end
            else
                self.GUI.Main.Cooldowns[Action].Time.Text = "" .. (math.round((Length - (time() - StartTime)) * 10) / 10) .. "s"
            end
        end)
    end)
end

function CooldownManager:AddItem(ItemName, Actions)
    self.CooldownList[ItemName] = {}
    for i, v in pairs(Actions) do
        self.CooldownList[ItemName][v.Name] = {Times = 0, OnCooldown = false, Key = i}
    end
end

function CooldownManager:OnCooldown(ItemName, Action)
    return self.CooldownList[ItemName][Action].OnCooldown
end

function CooldownManager:LoadItem(ItemName)
    if self.CurrentItem ~= nil then
        for i, Cooldown in pairs(self.CooldownList[self.CurrentItem]) do
            if Cooldown.Con then
                Cooldown.Con:Disconnect()
            end
        end
    end
    
    for i, v in pairs(self.GUI.Main.Cooldowns:GetChildren()) do
        if v:IsA("GuiBase") then
            v:Destroy()
        end
    end

    for i, Cooldown in pairs(self.CooldownList[ItemName]) do
        local UI = Assets.CooldownHolder:Clone()
        UI.LayoutOrder = Cooldown.LayoutOrder
        UI.Key.Text = Cooldown.Key
        UI.Time.Text = ""
        UI.ActionName.Text = i
        UI.Name = i
        UI.Parent = self.GUI.Main.Cooldowns
        UI.BackgroundColor3 = Color3.fromRGB(144,144,144)
        
        if Cooldown.StartTime then
            if time() - Cooldown.StartTime < Cooldown.Length then
                self:AddCooldown(ItemName, i, Cooldown.Length - (time() - Cooldown.StartTime))
            else
                Cooldown.OnCooldown = false
            end
        end
        
    end
    self.CurrentItem = ItemName
end

function CooldownManager:SetAction(InAction)
    self.InAction = InAction
end


return CooldownManager

When it came out the first time I tried to comment on the code and I saw that it was not the only one, I checked the references but they are in the right place, I have been going through the code for many hours now, I am blind xD


Solution

  • When working with OOP in lua, there's 3 things to double check are all present and working properly :

    -- 1. The base table is defined
    local Thing = {}
    
    -- 2. The base table has a self referential __index meta method
    Thing.__index = Thing
    
    function Thing.new()
       -- 3. A call to setmetatable to link the new object to the base table
       return setmetatable({}, Thing)
    end
    
    

    And looking at your code...

    FistCombat._index = FistCombat
    

    It looks like you didn't set the __index metamethod properly. Notice that __index has two underscores at the front. When you defined it, it looks like you only used one.

    So change that line to this :

    FistCombat.__index = FistCombat
    

    And see if that helps