Interactive fiction in Lua – Part 03

 Third part – Object IDs and object properties

For my interactive fiction game I want to access my objects via ID codes. The benefit of this approach is that you don’t need to move around a lot of data when moving the objects in the game. While you could compress the object IDs to hexadecimal format or using bits and bytes, I prefer having the IDs clearly readable for code debugging reasons.

    object 1 = ‘ID000001’
    object 2 = ‘ID000002’
    object 3 = ‘ID000003’

Below is a simple function I wrote that transforms numbers into an ID code format like the above example.

function get_ID_format(id_short) -- Returns a long ID
    local maxlength = 6
    local num = tostring(id_short)
    local zeros = string.rep("0", maxlength - #num)
    return "ID" .. zeros .. num

local id_long = get_ID_format(1)

Above, tostring(id_short) transforms the value of id_short into a string.

string.rep replicates the first argument “0” as many times as needed; maxlength – #num.

#num returns the length of the number string, similarly like writing string.len(num).

Finally the function returns the ID. The string is comprised of “ID” + the number of zero’s + the short id number in string form. The double periods “..” concatenates the strings together as a single string. Print result: ID000001.

With the object ID approach, moving objects from a room to the player inventory, or vice versa, is relatively simple and mainly involves moving the object IDs around, combined with changing a few properties.

 Object properties

At this point I would like to store object properties in a global table, which we could call g_objData.

g_objData = {} -- initializes 'g_objData'

In Lua it is useful to store data not only in numbered dimensions but also by using keys (strings).

Let’s say that I want to set up my object properties like this;
two functions are listed below, with the main code that calls the functions placed last:

function add_obj(room, name, liftable, held, visible, child_of, contain)
    local id_short = g_nextObjectID
    local id_long = get_ID_format(id_short)
    g_objData[id_long] = {
        room = room,
        name = name,
        child = child_of,
        carry = liftable,
        held = held,
        visible = visible,
        container = contain
    g_nextObjectID += 1 -- increase ID for next object

function get_ID_format(id_short) -- Returns a long string ID
    local maxlength = 6
    local num = tostring(id_short)
    local zeros = string.rep("0", maxlength - #num)
    return "ID" .. zeros .. num

g_objData = {} -- initializes 'g_objData'
g_nextObjectID = 1 -- assigns ID 1 to the first object

add_obj(1, "box", 1, 0, 1, "", 10)

local id_long = "ID000001"

Above, the function add_obj() is called with a few parameters that can be used for creating a simple box object. It has a property that tells us it can be carried, though the object is not yet held by anyone. It is visible and have a container property of 10, which could be used to define weight capacity, volume or a certain number of items.

Every time the add_obj() function finishes, it increments the global variable g_nextObjectID with one so that whenever the function is called, the next object will have a unique ID.

After the function add_obj() is called, the global object property table g_objData will be filled like this: = 1 -- Object room location = "box" -- Object name
g_objData.ID000001.child = "" -- Child of another object
g_objData.ID000001.carry = 1 -- The object can be carried
g_objData.ID000001.held = 0 -- Player holding the object
g_objData.ID000001.visible = 1 -- Object visibility
g_objData.ID000001.container = 10 -- Container capacity

This table could also be shown as such:

local id_long = "ID000001"

g_objData[id_long]["room"] = 1
g_objData[id_long]["name"] = "box"
g_objData[id_long]["child"] = ""
g_objData[id_long]["carry"] = 1
g_objData[id_long]["held"] = 0
g_objData[id_long]["visible"] = 1
g_objData[id_long]["container"] = 10


The last line in the above example would print out “box” in the console window, provided that the table g_objData[id_long] has been filled using the above function add_obj(), or a similar function.

Next, I would like to access the object data in the game through at least two functions;

        1. reading the data
        2. setting the data

Let’s create two functions for that:


Below is an example of a function returning the object property data:

function get_obj_property(id_long, type)
    local data = g_objData -- 'data' points to table g_objData
    if id_long and type and data then
        if id_long == "" then
            return 0
            local data_id = data[id_long]
            if type == "name" then
            elseif type == "room" then
            elseif type == "held" or type == "carried" then
                return data_id.held
            elseif type == "liftable" then
                return data_id.carry
            elseif type == "visible" then
                return data_id.visible
            elseif type == "container" then
                return data_id.container
            elseif type == "child" then
                return data_id.child
                print("Error. No '"..type.."' in '"..id_long.."'.")
                return 0
        return 0

print(get_obj_property(id_long, "name"))

The function above is called with two arguments; first the long ID string, then the string type, here providing the object property key that have already been defined in function add_obj().

First the function checks to make sure that three variables are not nil; id_long, type and data, since variables that hold a nil property will throw an error when they are accessed. If any of them are nil then a zero value will be returned. The main part of the function returns the object properties of g_objData[id_long][type] by using the local pointers.

Notice that there is only one reference to the table g_objData at the start; the rest of the function uses local pointers. The local table data points to the global table g_objData and local variable data_id points to g_objData[id_long]

Using a few central functions gives more flexibility than asking for


from numerous other functions or places in the code. Instead, you just call your designated function/s and let it handle the method of accessing the data you need, without burdening the rest of the program to bother about the exact details involved or which table is used to achieve the result.

 A few thoughts

I created the “child” property in order to place objects inside or upon other objects. The child property is intended to hold the ID of the object which it is a child of, i.e. parented to.

When I designed my room descriptions I decided to not mention objects that are on top of, or inside, other objects; I want the player to look at objects in order to find out what they contain.

If the player wants to see objects on a desk for example, they will have to examine the desk first. When the player inspects an object, a function checks which objects in the room have a child property matching the ID of the object the player is looking at. Those object names are then listed in a string after which another function is called for grammar correction before the description is shown to the player.


In later posts I will talk about room arrays, inventory handling, room layout, portals between rooms, player input and analysis, functions for grammar correction, placing room prefabs and adding new regions that can be traversed between.

Each new region will come with its own region-specific tables of data for rooms, portals, objects, room descriptions, illustrations, and so on. By changing pointers at a later stage, the data from one region can easily be swapped out by pointing to the data set of another region.

Leave a Reply