I have figured out how to pass functions around in Lua, and I am using the technique of inserting functions into tables in order to dynamically assign functions to the cards in a trading card game. The functions are assigned when the Card is first created, but more could easily be added later. I am still new to Lua so I would love to hear about any syntax errors I am making, or if the way I am doing anything might be dangerous in the future or violates Lua best practices.The basic idea is that each Card has a unique ID, and each ID has a table of strings associated with it.  The Card first gets this table of strings from the CardFunctionsList script, then passes them to the FunctionsList script which returns a table of the functions themselves.  Then the card can run any function that has been loaded in this way, and could pass the function along to another card if need be.  When called, the card passes itself into the function, and the function modifies it.There are some problems with this approach.  I do not like having to use tables full of strings in CardFunctionsList.lua, but I do not see a better way to do it.  I originally just used numbers, but the readability was worse compared to this version.  But if there are any typos the functions will not be loaded.  Also, I think it might be better to have just one script instead of two to return the functions table, but it seems cleaner to have it separated this way.  I am not sure about this.  Finally, I am struggling with the names CardFunctionsList and FunctionsList, but I can't think of anything better that makes sense.Card.lualocal Card = {}function Card:new(cardSuit, cardType, cardId)    local instance = setmetatable({}, { __index = self })    instance.suit = cardSuit    instance.id = cardId    instance.type = cardType    --these will be assigned by a script that is not yet complete    instance.health = 0    instance.strength = 0    --these are the functions of the card    instance.abilityList = {}    instance:loadAbilityList(cardId)    --this will contain things like Taunt or Charge    instance.statusList = {}    --diagnostic method for the prototype    instance:doTestAbilitiesAndPrint()    return instanceendfunction Card:loadAbilityList(cardId)    local cardFunctionsList = require CardFunctionsList    local functionsList = require FunctionsList    local functionNames = cardFunctionsList:functionNamesForId(cardId)    self.abilityList = functionsList:new(functionNames)end--if the card does not have the ability, nothing will happenfunction Card:doAbility(abilityName)    for key,functionTable in ipairs(self.abilityList) do        for name,func in pairs(functionTable) do            if name == abilityName then                amountToIncrease = 1                func(self,amountToIncrease) --self because the card passes itself into the function            end        end    endendfunction Card:doTestAbilitiesAndPrint()    self:doAbility(addTaunt)    self:doAbility(addCharge)    for key,value in ipairs(self.statusList) do        print(value)    endendreturn CardCardFunctionsList.lualocal CardFunctionsList = {}--For each card ID, the names must be manually entered as a table--they must match values in the FunctionsList scriptfunction CardFunctionsList:functionNamesForId(id)    if       id == 1 then return {increaseHealth}      elseif id == 2 then return {increaseStrength}      elseif id == 3 then return {addTaunt}      elseif id == 4 then return {increaseHealth, addTaunt}      elseif id == 5 then return {increaseStrength, addTaunt, addCharge}      elseif id == 6 then return {increaseHealth, increaseStrength, addTaunt, addCharge}      elseif id == 7 then return {increaseHealth, increaseStrength}      else return {} --if the id does not match anything, nothing bad will happen    endendreturn CardFunctionsListFunctionsList.lualocal FunctionsList = {}--The inputted functionNames are a table created by the CardFunctionsListfunction FunctionsList:new(functionNames)    local instance = setmetatable({}, { __index = self })    instance.functions = {}    instance:loadFunctionsToReturn(functionNames)    return instance.functionsendfunction FunctionsList:loadFunctionsToReturn(functionNames)    for key,name in ipairs(functionNames) do        table.insert(self.functions, self:functionForName(name))    endendfunction FunctionsList:functionForName(name)    --even though the table key looks like plain text, it will accept a string to access it    if       name == increaseHealth then return {increaseHealth = increaseHealth}      elseif name == increaseStrength then return {increaseStrength = increaseStrength}      elseif name == addTaunt then return {addTaunt = addTaunt}      elseif name == addCharge then return {addCharge = addCharge}    endend--Here is the list of all functionsfunction increaseHealth(card, amount)    card.health = card.health + amountendfunction increaseStrength(card, amount)    card.strength = card.strength + amountendfunction addTaunt(card)    table.insert(card.statusList, Taunt)endfunction addCharge(card)    table.insert(card.statusList, Charge)endreturn FunctionsListFrom here in order to add new gameplay to the game, a card ID entry must be created in CardFunctionsList.lua that returns a table of strings.  Then entries must be made for those strings in the else-if in FunctionsList.lua, and the actual functions added to that script.  One goal is for a person with possibly very little coding knowledge to be able to create new cards for the game by editing the scripts directly, so that is something that should be considered as far as the structure and readability of the code.
Adding Abilities to Cards Dynamically in a Trading Card Game
game;lua
This part of your code:for name,func in pairs(functionTable) do    if name == abilityName then        amountToIncrease = 1        func(self,amountToIncrease) --self because the card passes itself into the function    endendCan be greatly simplified simply by checking if the index you are looking for exists or not:local ability = functionTable[abilityName]if ability then    amountToIncrease = 1    ability(self,amountToIncrease) --self because the card passes itself into the functionendEven though the code for assigning strength and health to a card is not complete, it seems like you are assigning functions/abilities on one place, assigning strength/health at another place... And I'm not so sure about the methods to assign a card some abilities that you add when you create the card. It seems to me like it would be better to not call the addTaunt method but instead to assign the card taunt through the constructor. You seem to be grouping properties together instead of cards. You're defining all functions for all cards at one place, will you then define all strengths and healths for all cards at another place? It would be better to group by card.Right now you are mapping cardId --> function name in CardFunctionsList:functionNamesForId(id) and then you are mapping functionName --> Actual function. When I started refactoring this to skip the name I realized that you really need it that way, because of the doAbility function. A comment about that would be helpful so that I don't try refactoring it again :)One thing I noted about the functions/abilities thingy though is that your FunctionsList only contains one thing: instance.functions. Why not simply use the instance directly?FunctionsList:functionForName always returns a table. I don't see the usefulness of this. You can make it return a single function and viol, it will have reduces table nesting.I managed to re-write your FunctionsList code to this:function FunctionsList:new(functionNames)    local instance = {}    self:loadFunctionsToReturn(instance, functionNames)    return instanceendfunction FunctionsList:loadFunctionsToReturn(tabl, functionNames)    for key,name in ipairs(functionNames) do        tabl[name] = self:functionForName(name)    endendfunction FunctionsList:functionForName(name)    --even though the table key looks like plain text, it will accept a string to access it    if       name == increaseHealth then return increaseHealth      elseif name == increaseStrength then return increaseStrength      elseif name == addTaunt then return addTaunt      elseif name == addCharge then return addCharge    endendAnd then you of course have to make the related changes in Card.lua, primarily the doAbility function which I wrote like this:function Card:doAbility(abilityName)    local ability = self.abilityList[abilityName]    if ability then        amountToIncrease = 1        ability(self,amountToIncrease) --self because the card passes itself into the function    endendA bit related to your question is this:The basic idea is that each Card has a unique ID, and each ID has a table of strings associated with it.When I read that I instantly thought entity-component-system, which works a little like this. Your code isn't really ECS though, but I just wanted to throw this out there.