-- 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 bcheck = require("bcheck") local con_lang = require("con_lang") local byte = require("string").byte local setmetatable = setmetatable local band, bor = bit.band, bit.bor local rshift = bit.rshift local tobit = bit.tobit local assert = assert local error = error local ipairs = ipairs local pairs = pairs local print = print local rawget = rawget local rawset = rawset local select = select 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 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_number = bcheck.number local check_type = bcheck.type local lprivate = require("lprivate") local GET, WEAPON = lprivate.GET, lprivate.WEAPON ffi.cdef[[ size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, void * restrict stream); ]] local OUR_REQUIRE_STRING = [[ local _con=require'con' local _ga,_av,_pv=_con._gamearray,_con.actorvar,_con.playervar ]] local function our_get_require() return OUR_REQUIRE_STRING end module(...) ---=== ACTION/MOVE/AI HELPERS ===--- local lastid = { action=0, move=0, ai=0 } local con_action_ct = ffi.typeof("const con_action_t") local con_move_ct = ffi.typeof("const con_move_t") local con_ai_ct = ffi.typeof("const con_ai_t") -- All-zero action and move with IDs. Mostly for CON support. local literal_act = { [0]=con_action_ct(0), [1]=con_action_ct(1) } local literal_mov = { [0]=con_move_ct(0), [1]=con_move_ct(1) } local literal_am = { action=literal_act, move=literal_mov } -- Const-qualified 'full' action and move (with ID): local am_ctype_full_const = { action=con_action_ct, move=con_move_ct } -- Non-const-qualified 'bare' action and move (without ID): local am_ctype_bare = { action=ffi.typeof("struct action"), move=ffi.typeof("struct move") } -- CODEDUP lunacon.lua local function truetab(tab) local ttab = {} for i=1,#tab do ttab[tab[i]] = true end return ttab end -- CODEDUP lunacon.lua local ALLOWED_VIEWTYPE = truetab { 0, 1, 3,4, 5, 7, 8, -5, -7 } local function def_action_or_move(what, tab) if (lastid[what] <= -(2^31)) then error("Too many "..what.."s defined", 3); end bcheck.top_level(what, 4) -- NOTE: tab[0]~=nil check for "Special default values" below. if (type(tab) ~= "table" or tab[0]~=nil) then error("invalid argument to con."..what..": must be a table", 3) end -- Pass args table to ffi.new, which can take either: a table with numeric -- indices, or a table with key-value pairs, *but not in combination*. -- See http://luajit.org/ext_ffi_semantics.html#init_table local am = am_ctype_bare[what](tab) -- Now, set all string keys as they have been ignored if tab[1] was -- non-nil. for key, val in pairs(tab) do if (type(key)=="string") then am[key] = val end end if (what=="action") then -- Special default values or checking of actor members. -- KEEPINSYNC with ACTOR_CHECK in lunacon.lua for consistency. local numframes = tab[2] or tab.numframes local viewtype = tab[3] or tab.viewtype local incval = tab[4] or tab.incval if (numframes==nil) then am.numframes = 1 else check_number(numframes, 4) if (numframes < 0) then error("action has negative number of frames", 3) end end if (viewtype==nil) then am.viewtype = 1 else check_number(viewtype, 4) if (ALLOWED_VIEWTYPE[viewtype] == nil) then error("action has disallowed viewtype "..viewtype, 3) end end if (incval==nil) then am.incval = 1 end end -- 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 return am_ctype_full_const[what](lastid[what], am) end ---=== ACTION/MOVE/AI FUNCTIONS ===--- function action(tab) return def_action_or_move("action", tab) end function move(tab) return def_action_or_move("move", tab) end -- Get action or move for an 'ai' definition. local function get_action_or_move(what, val, argi) if (val == nil) then return literal_am[what][0] elseif (ffi.istype(am_ctype_full_const[what], val)) then return val elseif (type(val)=="number") then if (val==0 or val==1) then return literal_am[what][val] end end error("bad argument #"..argi.." to ai: must be nil/nothing, 0, 1, or "..what, 3) end function ai(action, move, flags) bcheck.top_level("ai") if (lastid.ai <= -(2^31)) then error("Too many AIs defined", 2); end 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 lastid.ai = lastid.ai-1 return con_ai_ct(lastid.ai, act, mov, flags) end ---=== RUNTIME CON FUNCTIONS ===--- -- Will contain [