Example Game - The Haunted Tower
This complete game demonstrates all major features of the Booktasy engine.
Code
-- Booktasy Tutorial Game: The Haunted Tower
-- ==========================================
-- 1. GLOBAL VARIABLES
-- ==========================================
-- These track game progress.
HAS_KEY = false
HAS_TORCH = false
BOSS_DEFEATED = false
TURN_COUNT = 0
-- Register globals for saving
Booktasy.save("HAS_KEY")
Booktasy.save("HAS_TORCH")
Booktasy.save("BOSS_DEFEATED")
Booktasy.save("TURN_COUNT")
Booktasy.MAX_TURNS = 50
-- ==========================================
-- 2. FACTORY FUNCTIONS
-- ==========================================
-- We define functions to create complex objects so we can call them in init().
function create_shadow_beast()
local beast = Booktasy.Entity("Shadow Beast", "A shifting mass of darkness with glowing red eyes.", { })
beast.hp = 10
beast.max_hp = 10
beast.damage = 3
beast.is_enemy = true
return beast
end
function create_wizard()
return Booktasy.Entity("Old Wizard", "A frail man in blue robes.", {
dialogue = {
"Wizard: 'Greetings, traveler.'",
"Wizard: 'Beware the upper floors. A Shadow Beast lurks there.'",
"Wizard: 'It hates the light. Remember that.'"
}
})
end
-- ==========================================
-- 3. CUSTOM COMMANDS
-- ==========================================
function get_room() return Booktasy.GAME_WORLD.current_room end
function command_use(target)
if not target then print("Use what?"); return end
local item = Booktasy.find_item_in_inventory(target)
if not item then print("You don't have that."); return end
if item.name == "Torch" then
if not HAS_TORCH then
HAS_TORCH = true
print("You light the torch. It burns brightly.")
item.description = "A burning torch. It provides light."
else
print("The torch is already lit.")
end
elseif item.name == "Health Potion" then
print("You drink the potion. You feel revitalized!")
local _, idx = Booktasy.find_item_in_inventory("Health Potion")
table.remove(Booktasy.INVENTORY, idx)
elseif item.name == "Iron Key" then
print("It's a key. You need to find a locked door to use it on.")
else
print("You can't use that.")
end
end
function custom_go(dir)
local room = get_room()
-- Darkness Logic
if room.name == "Tower Entrance" and dir == "north" and not HAS_TORCH then
print("#[R]{It's too dark in the hallway! You need a light source.}")
return
end
-- Locked Door Logic
if room.name == "Dark Hallway" and dir == "up" then
if HAS_KEY then
print("You unlock the heavy door with the Iron Key and proceed up.")
Booktasy.core_go("up")
return
else
print("#[D]{The door to the upper level is locked.}")
return
end
end
-- Default Movement
Booktasy.core_go(dir)
end
function command_search(target)
if not target then print("Search what?"); return end
local entity = Booktasy.find_entity_in_room(get_room(), target)
if not entity then print("You don't see that here."); return end
if #entity.inventory > 0 then
print("You search the " .. entity.name .. " and find:")
for i, item in ipairs(entity.inventory) do
print("- #[I]{" .. item.name .. "}")
table.insert(Booktasy.INVENTORY, item)
end
entity.inventory = {}
print("You take everything.")
if Booktasy.find_item_in_inventory("Iron Key") then HAS_KEY = true end
else
print("You find nothing in the " .. entity.name .. ".")
end
end
function command_attack(target)
local entity = Booktasy.find_entity_in_room(get_room(), target)
if not entity or not entity.is_enemy then print("You can't attack that."); return end
local damage = 1
local weapon = Booktasy.find_item_in_inventory("Rusty Sword")
if weapon then damage = weapon.damage end
print("You swing at the " .. entity.name .. "!")
local roll = Booktasy.rnd(1, 6)
if roll > 2 then
print("#[S]{HIT!} You deal " .. damage .. " damage.")
entity.hp = entity.hp - damage
if entity.hp <= 0 then
print("The " .. entity.name .. " creates a terrible shriek and dissolves into smoke!")
local r = get_room()
for i, e in ipairs(r.entities) do
if e == entity then table.remove(r.entities, i); break end
end
if entity.name == "Shadow Beast" then
BOSS_DEFEATED = true
Booktasy.check_events()
end
else
print("The beast has " .. entity.hp .. " HP left.")
end
else
print("#[D]{MISS!} The beast dodges your attack.")
end
end
-- Register Commands
Booktasy.commands.use = command_use
Booktasy.commands.search = command_search
Booktasy.commands.attack = command_attack
Booktasy.commands.go = custom_go
Booktasy.commands.n = function() custom_go("north") end
Booktasy.commands.s = function() custom_go("south") end
Booktasy.commands.e = function() custom_go("east") end
Booktasy.commands.w = function() custom_go("west") end
Booktasy.commands.u = function() custom_go("up") end
Booktasy.commands.d = function() custom_go("down") end
-- ==========================================
-- 4. INITIALIZATION (RESTART SAFE)
-- ==========================================
function Booktasy.init()
-- 1. Reset Global Flags
HAS_KEY = false
HAS_TORCH = false
BOSS_DEFEATED = false
TURN_COUNT = 0
Booktasy.GAME_OVER = false
Booktasy.GAME_OVER_MESSAGE = ""
Booktasy.INVENTORY = {} -- Clear old inventory
Booktasy.GAME_WORLD.rooms = {} -- Clear old rooms
Booktasy.EVENTS = {}
Booktasy.TIMERS = {}
-- 2. REBUILD THE WORLD (Fresh Objects)
-- Items
local iron_key = Booktasy.Item("Iron Key", "A heavy, rusted iron key.", { usable = true })
local torch = Booktasy.Item("Torch", "A wooden torch.", { usable = false, lit = false })
local rusty_sword = Booktasy.Item("Rusty Sword", "An old blade.", { usable = false })
rusty_sword.damage = 2
local potion = Booktasy.Item("Health Potion", "A red bubbly liquid.", { usable = true })
potion.heal_amount = 5
-- Rooms
local entrance = Booktasy.Room("Tower Entrance", "You stand before a large stone tower. The door is open.")
table.insert(entrance.entities, create_wizard())
table.insert(entrance.items, torch)
local hallway = Booktasy.Room("Dark Hallway", "A long, dark corridor. It's hard to see.")
local armory = Booktasy.Room("Armory", "Racks of old weapons line the walls.")
table.insert(armory.items, rusty_sword)
local lab = Booktasy.Room("Laboratory", "Beakers and books are scattered everywhere.")
table.insert(lab.items, potion)
local desk = Booktasy.Entity("Desk", "A cluttered wooden desk.", { inventory = { iron_key } })
table.insert(lab.entities, desk)
local boss_room = Booktasy.Room("Throne Room", "A cold room at the top of the tower.")
local boss = create_shadow_beast()
table.insert(boss_room.entities, boss)
-- Register Rooms
Booktasy.add_room(entrance)
Booktasy.add_room(hallway)
Booktasy.add_room(armory)
Booktasy.add_room(lab)
Booktasy.add_room(boss_room)
-- Connect Rooms
Booktasy.connect_rooms("Tower Entrance", "north", "Dark Hallway")
Booktasy.connect_rooms("Dark Hallway", "west", "Armory")
Booktasy.connect_rooms("Dark Hallway", "east", "Laboratory")
boss_room.exits["down"] = "Dark Hallway"
-- Manually set the 'up' exit for logic mapping, though locked logic handles access
hallway.exits["up"] = "Throne Room"
-- 3. Register Events
Booktasy.add_event(Booktasy.Event("MonsterAttack",
function()
local r = get_room(); if not r then return false end
for _, e in ipairs(r.entities) do if e.is_enemy then return true end end
return false
end,
function()
local r = get_room()
for _, e in ipairs(r.entities) do
if e.is_enemy then
print("#[R]{The " .. e.name .. " lashes out at you!}")
print("You take " .. e.damage .. " damage!")
end
end
end,
false
))
Booktasy.add_event(Booktasy.Event("GameWon",
function() return BOSS_DEFEATED end,
function() Booktasy.end_game("You have cleansed the tower! VICTORY!") end,
true
))
Booktasy.add_event(Booktasy.Event("StartTorchTimer",
function() return HAS_TORCH and not Booktasy.has_timer("TorchTimer") end,
function()
print("#[D]{(Your torch begins to burn... it will last 20 turns)}")
Booktasy.add_timer("TorchTimer", 20, function()
HAS_TORCH = false
print("#[R]{Your torch flickers and dies!}")
local item = Booktasy.find_item_in_inventory("Torch")
if item then item.description = "A burnt out wooden stick." end
end, false)
end,
false
))
-- 4. Start Game
print("#[S]{Welcome to The Haunted Tower}")
print("Find the key, light your way, and defeat the evil within.")
print("---------------------------------------------------")
Booktasy.GAME_WORLD.current_room = entrance
entrance:describe()
-- 5. Snapshot for Restart
-- We save this clean state immediately
if not Booktasy._INITIAL_STATE then
Booktasy.save_initial_state()
end
end
function Booktasy.turn_limit_reached()
print("#[R]{The moon has set. The tower's magic seals forever.}")
Booktasy.end_game("Time Out")
end