Lua Project: Text Adventure
A text adventure is a game played by typing short commands like go north or take key. Its rooms, exits, and items are tables, and a fixed list of commands drives the game instead of typed input.
A room is an object with a describe method
The Room table below acts as a class through its __index metamethod. A new room prints its name, its description, and its item count.
local Room = {}
Room.__index = Room
function Room.new(name, desc)
local room = {name = name, desc = desc, exits = {}, items = {}}
setmetatable(room, Room)
return room
end
function Room:describe()
print(self.name)
print(self.desc)
print(#self.items)
end
local hall = Room.new("Hall", "A quiet hall.")
hall.items[1] = "key"
hall:describe()An exit moves the player to another room
An exit is a table slot that maps a direction word to a room. Looking the direction up moves the player to that room.
local Room = {}
Room.__index = Room
function Room.new(name, desc)
local room = {name = name, desc = desc, exits = {}, items = {}}
setmetatable(room, Room)
return room
end
local hall = Room.new("Hall", "A quiet hall.")
local garden = Room.new("Garden", "A sunny garden.")
hall.exits.north = garden
local current = hall
current = current.exits.north
print(current.name)Taking moves an item to the inventory
Taking finds the named item in the room list, removes it there, and appends it to the inventory. Both list lengths prove the move.
local hallItems = {"key"}
local inventory = {}
for i = 1, #hallItems do
if hallItems[i] == "key" then
inventory[1] = hallItems[i]
table.remove(hallItems, i)
break
end
end
print(#inventory)
print(inventory[1])
print(#hallItems)Example
local Room = {}
Room.__index = Room
function Room.new(name, desc)
local room = {name = name, desc = desc, exits = {}, items = {}}
setmetatable(room, Room)
return room
end
local Item = {}
Item.__index = Item
function Item.new(name)
local item = {name = name}
setmetatable(item, Item)
return item
end
local entrance = Room.new("Entrance", "You stand in a dusty entrance.")
local garden = Room.new("Garden", "A garden with a locked vault to the east.")
local vault = Room.new("Vault", "A small vault.")
entrance.items[1] = Item.new("key")
entrance.exits.north = garden
garden.exits.south = entrance
garden.exits.east = vault
vault.exits.west = garden
vault.items[1] = Item.new("treasure")
local current = entrance
local inventory = {}
local function hasItem(name)
for i = 1, #inventory do
if inventory[i].name == name then
return true
end
end
return false
end
local function describe()
print(current.name)
print(current.desc)
if #current.items == 0 then
print("Items: none")
else
local names = {}
for i = 1, #current.items do
names[i] = current.items[i].name
end
print("Items: " .. table.concat(names, ", "))
end
end
local function showInventory()
if #inventory == 0 then
print("Inventory: none")
else
local names = {}
for i = 1, #inventory do
names[i] = inventory[i].name
end
print("Inventory: " .. table.concat(names, ", "))
end
end
local script = {"look", "go north", "go east", "go south", "take key", "go north", "go east", "take treasure", "inventory"}
for i = 1, #script do
local cmd = script[i]
print("> " .. cmd)
local dir = cmd:match("^go%s+(%w+)$")
local wanted = cmd:match("^take%s+(%w+)$")
if cmd == "look" then
describe()
elseif cmd == "inventory" then
showInventory()
elseif dir ~= nil then
local nextRoom = current.exits[dir]
if nextRoom == nil then
print("You cannot go that way.")
elseif dir == "east" and current.name == "Garden" and not hasItem("key") then
print("The vault door is locked. You need the key.")
else
current = nextRoom
print("You go " .. dir .. ".")
describe()
end
elseif wanted ~= nil then
local found = nil
local foundAt = 0
for j = 1, #current.items do
if current.items[j].name == wanted then
found = current.items[j]
foundAt = j
break
end
end
if found == nil then
print("There is no " .. wanted .. " here.")
else
table.remove(current.items, foundAt)
inventory[#inventory + 1] = found
print("You take the " .. wanted .. ".")
end
else
print("I do not understand that.")
end
end
if hasItem("treasure") then
print("You win!")
else
print("The treasure is still out there.")
endKey points
- Room: a room is a table holding a name, a description, exits, and items.
- Exit: an exit maps a direction word to another room table.
- Item: an item is a small object with a name, kept in a room list or in the inventory list.
- Command: a command is a string that the parser splits into a verb and a word with a pattern.
- Loop: the game loop walks the fixed command list in order and prints what happens for each command.
- Win: the game is won when the treasure item reaches the inventory list.
In this example, Room and Item are small classes built with metatables, and the three rooms link to each other through exit slots. The loop walks a fixed command list, parses each command with a pattern, and prints the result, including the locked vault door before the key is taken. Taking the key unlocks the east exit, taking the treasure fills the inventory, and the final check prints the win line.
Note
the command list is fixed in the code, so the same walkthrough prints the same story on every run.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
The adventure runs a fixed list of commands instead of reading typed input. What does that guarantee?