require("string") function load_level(file) local f = file_read { file = file } local result = { classes = { void = { }, }, glossary = { [" "] = "void", }, grid = {}, map = {}, size = { x = 0, y = 0 }, } -- iterate over lines local section, subsection = "none", "none" local from = 1 local start, limit = string.find(f, "\n", from) while start do local line = string.sub(f, from, start - 1) -- skip over if #line == 0 or line:find("^%-%-%s*") then goto skip -- start new section elseif line:find("^@%g+") then section = line:sub(2); subsection = "none" -- decode map one line at a time elseif section == "map" then local l = #result.map + 1 if result.size.x < #line then result.size.x = #line end result.map[l] = {} for i = 1, #line do result.map[l][i] = line:sub(i,i) end -- templates to expand elseif section == "classes" then -- properties if line:find("^ %g+") then local _, _, property, value = line:find("^ (%g+)%s?:%s?(.*)") result.classes[subsection][property] = value goto skip end local symbol, classname = line:sub(1,1), line:sub(3) result.classes[classname] = { symbol = symbol, } result.glossary[symbol] = classname subsection = classname elseif section ~= "none" then local _, _, property, value = line:find("^(%g+)%s?:%s?(.*)") if result[section] == nil then result[section] = {} end result[section][property] = value end ::skip:: from = limit + 1 start, limit = string.find(f, "\n", from) end -- post process for y = 1, #result.map do result.grid[y] = {} for x = 1, result.size.x do -- past defined for line local symbol if x > #result.map[y] then symbol = " " else symbol = result.map[y][x] end local class = result.classes[result.glossary[symbol]] if class["unique"] ~= nil then class.position = { x = x, y = y } end result.grid[y][x] = class ::continue:: end end result.size.y = #result.map print(result.meta.description) return result end function game_tick() if ctx.udata == nil then ctx.udata = { level = load_level("levels/00.lvl") } log_vec2 { value = ctx.udata.level.classes.player_spawn.position } end end