arrayslualua-table

Creating separate lua tables for each object in an array


So I have an array of creatures from a game, each one is just the name as a string. I want to iterate over each one and create a table for each one that contains all of the creatures stats, hp, damage, etc. But I can't find a way to create new Lua tables, as assigning a new variable to a table doesn't copy it.

I really haven't tried much, as I'm pretty new to coding and have found near to no information online that deals with my specific issue.


Solution

  • Let's say your array looks like this (and keep in mind that lua arrays are tables with numeric indexes):

    monsters = {[1] = "orc", [2] = "troll", [3] = "ogre"}
    

    yeah, you'll get into trouble if you try to create a single "stats" table template and assign it to each monster name in the array:

    stats = {["strength"] = 15, ["health"] = 10}
    
    monster_stats = {} -- initialize new table for stats
    
    for k,v in ipairs(monsters) do
            monster_stats[v] = stats
    end
    
    monster_stats["orc"].strength = 10 -- change strength
    
    print(monster_stats["orc"].strength)
    
    print(monster_stats["troll"].strength)
    

    output:

    10
    10
    

    We want to only change the orc's strength, but we end up changing everyone's strength. That's because both monster_stats["orc"] and monster_stats["troll"] point at the same table in memory. What you want is a way to clone a table -- and there is an example at lua.org[0].

    Add that function to the top of your script, and now you can call clone() during the assignment. Things work out as intended this time, because each monster's "stats" variable points to a different table in memory.

    function clone (t)           -- t is a table
      local new_t = {}           -- create a new table
      local i, v = next(t, nil)  -- i is an index of t, v = t[i]
      while i do
        new_t[i] = v
        i, v = next(t, i)        -- get next index
      end
      return new_t
    end
        
    monsters = {[1] = "orc", [2] = "troll", [3] = "ogre"}
    
    stats = {["strength"] = 15, ["health"] = 10}
    
    monster_stats = {} -- initialize new table for stats
    
    for k,v in ipairs(monsters) do
            monster_stats[v] = clone(stats)
    end
    
    monster_stats["orc"].strength = 10 -- change strength
    
    print(monster_stats["orc"].strength)
    
    print(monster_stats["troll"].strength)
    

    output:

    10
    15
    

    You can see that the tables are now all separate by printing out the values of the tables themselves:

    print(monster_stats["orc"])
    print(monster_stats["troll"])
    print(monster_stats["ogre"])
    

    output:

    table: 0x55be070536b0
    table: 0x55be07053bc0
    table: 0x55be07053c80
    

    References:

    [0] https://www.lua.org/manual/2.4/node31.html