-- Game control module for Lunatic. local require = require local ffi = require("ffi") local ffiC = ffi.C local jit = require("jit") -- Lua C API functions, this comes from El_PushCFunctions() in lunatic_game.c. local CF = CF local bit = require("bit") local io = require("io") local math = require("math") local table = require("table") local geom = require("geom") local bcheck = require("bcheck") local con_lang = require("con_lang") local byte = require("string").byte local setmetatable = setmetatable local assert = assert local error = error local ipairs = ipairs local pairs = pairs local print = print local rawget = rawget local rawset = rawset local tostring = tostring local type = type local unpack = unpack local format = require("string").format local actor, player = assert(actor), assert(player) local dc = require("defs_common") local cansee, hitscan, neartag = dc.cansee, dc.hitscan, dc.neartag local inside = dc.inside local sector, wall, sprite = dc.sector, dc.wall, dc.sprite local wallsofsect = dc.wallsofsect local spritesofsect, spritesofstat = dc.spritesofsect, dc.spritesofstat local OUR_NAME = "_con" local OUR_REQUIRE_STRING = "local "..OUR_NAME.."=require'con'" module(...) local lastid = { action=0, move=0, ai=0 } local def = { action = { NO=ffi.new("con_action_t") }, move = { NO=ffi.new("con_move_t") }, ai = { NO=ffi.new("con_ai_t") }, } local function forbidden() error("newindex forbidden", 2) end AC = setmetatable({}, { __index=def.action, __newindex=forbidden }) MV = setmetatable({}, { __index=def.move, __newindex=forbidden }) AI = setmetatable({}, { __index=def.ai, __newindex=forbidden }) local function check_name(name, what, errlev) if (type(name)~="string" or #name > 63) then error("bad argument #1 to "..what..": must be a string of length <= 63", errlev+1) end end local function action_or_move(what, numargs, tab, name, ...) if (lastid[what] <= -(2^31)) then error("Too many "..what.."s defined", 3); end check_name(name, what, 3) local args = {...} if (#args > numargs) then error("Too many arguments passed to "..what, 3) end for i=1,#args do local n = args[i] if (type(n)~="number" or not (n >= -32768 and n <= 32767)) then error("bad argument #".. i+1 .." to "..what.. ": must be numbers in [-32768..32767]", 3) end end -- missing fields are initialized to 0 by ffi.new -- Named actions or moves have negative ids so that non-negative ones -- can be used as (different) placeholders for all-zero ones. lastid[what] = lastid[what]-1 -- ffi.new takes either for initialization: varargs, a table with numeric -- indices, or a table with key-value pairs -- See http://luajit.org/ext_ffi_semantics.html#init_table tab[name] = ffi.new("const con_"..what.."_t", lastid[what], args) end ---=== ACTION / MOVE / AI ===--- function action(name, ...) bcheck.top_level("action") action_or_move("action", 5, def.action, name, ...) end function move(name, ...) bcheck.top_level("move") action_or_move("move", 2, def.move, name, ...) end -- Get action or move for an 'ai' definition. local function get_action_or_move(what, val, argi) if (val == nil) then return {} -- ffi.new will init the struct to all zeros elseif (type(val)=="string") then local am = def[what][val] if (am==nil) then error("no "..what.." '"..val.."' defined", 3) end return am elseif (ffi.istype("con_"..what.."_t", val)) then return val elseif (type(val)=="number") then if (val==0 or val==1) then -- Create an action or move with an ID of 0 or 1 but all other -- fields cleared. return ffi.new("con_"..what.."_t", val) end end error("bad argument #"..argi.." to ai: must be string or (literal) "..what, 3) end function ai(name, action, move, flags) bcheck.top_level("ai") if (lastid.ai <= -(2^31)) then error("Too many AIs defined", 2); end check_name(name, "ai", 2) lastid.ai = lastid.ai-1 local act = get_action_or_move("action", action, 2) local mov = get_action_or_move("move", move, 3) if (flags~=nil) then if (type(flags)~="number" or not (flags>=0 and flags<=32767)) then error("bad argument #4 to ai: must be a number in [0..32767]", 2) end else flags = 0 end def.ai[name] = ffi.new("const con_ai_t", lastid.ai, act, mov, flags) end ---=== RUNTIME CON FUNCTIONS ===--- local check_sector_idx = bcheck.sector_idx local check_tile_idx = bcheck.tile_idx local check_sprite_idx = bcheck.sprite_idx local check_player_idx = bcheck.player_idx local check_sound_idx = bcheck.sound_idx local check_type = bcheck.type -- Will contain [