Search code examples
luascopelua-tablemoonsharp

Lua: Concise expression of table scope


I'm working on a game where a bunch of characters will be generated on the fly, based on some constraints defined either in the project or externally via mod files. I am using MoonSharp Lua (5.2) interpreter for interfacing with my C# code, and Lua tables to store the constraint presets. As an example:

require "Defaults"
AgePresets = {}

-- Single value
AgePresets.Newborn = 0

-- Simple ranges
AgePresets.Default = defaultAgeRange --referring to the Defaults require
AgePresets.Child = {1, 12} 
AgePresets.Teenager = {13, 19}
AgePresets.YoungAdult = {20, 29}
AgePresets.Adult = {30, 40}
AgePresets.MiddleAge = {40, 60} 
AgePresets.Senior = {61, 80}
AgePresets.Elder = {81, 99}
AgePresets.Methuselah = {100, 150}  
AgePresets.Methuselah2 = {150, 200}

-- Weighted ranges // again referring to previously defined elements to keep things concise
AgePresets.Tween = {
            {weight = 1, minmax = AgePresets.Teenager },
            {weight = 1, minmax = AgePresets.YoungAdult }
         } 

This works fine, but from an end-user point of view, there's a lot of unnecessary typing involved. We are clearly working on AgePresets here but it is still mentioned as a prefix before every member name.

I could of course define AgePresets as an array, like AgePresets = { Child = {}, Teenager = {} } but the problem with that is then I cannot refer to previously defined elements in the array.

This doesn't work:

AgePresets = {
    Child = {1,12},
    RefToChild = Child, //attempt to index a nil value exception
    Teen = {13,19}
}

What I ideally want to achieve is a clean, concise way for users to enter this data in, like in the first example but without having to put AgePresets. prefix before everything. How do I go about declaring a scope in a file such that all succeeding members defined in the file will be within that scope, while maintaining the ability to refer to other members defined previously in the scope?


Solution

  • AgePresets = setmetatable({}, {__index = _G})
    
    do
       local _ENV = AgePresets
       Newborn = 0
       Child = {1,12}
       RefToChild = Child -- this ref is Ok
       Teen = {13,19}
       YoungAdult = {20,29}
       Tween = {
          {weight = 1, minmax = Teen },
          {weight = 1, minmax = YoungAdult }
       }
       rnd = math.random(10)   -- global functions are available here
    end
    
    setmetatable(AgePresets, nil)