mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-10 23:02:03 +00:00
Lunatic: prototypical editor binding.
git-svn-id: https://svn.eduke32.com/eduke32@3056 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
fb5d920408
commit
851c6b081d
9 changed files with 592 additions and 403 deletions
|
@ -163,6 +163,8 @@ ifneq (0,$(LUNATIC))
|
|||
else
|
||||
LIBS+= -L/usr/local/lib -lluajit-5.1
|
||||
endif
|
||||
|
||||
EDITOROBJS+= $(OBJ)/lunatic_m32.$o
|
||||
GAMEOBJS+= $(OBJ)/lunatic.$o
|
||||
|
||||
GAMEOBJS+= $(OBJ)/../lpeg.$o # TEMP
|
||||
|
|
|
@ -49,6 +49,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "m32script.h"
|
||||
#include "m32def.h"
|
||||
|
||||
#ifdef LUNATIC
|
||||
# include "lunatic_m32.h"
|
||||
#endif
|
||||
|
||||
#include "rev.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -87,6 +91,10 @@ char **g_clipMapFiles = NULL;
|
|||
int32_t g_clipMapFilesNum = 0;
|
||||
#endif
|
||||
|
||||
#ifdef LUNATIC
|
||||
Em_State *g_EmState;
|
||||
#endif
|
||||
|
||||
#pragma pack(push,1)
|
||||
sound_t g_sounds[MAXSOUNDS];
|
||||
#pragma pack(pop)
|
||||
|
@ -10492,6 +10500,21 @@ int32_t ExtInit(void)
|
|||
|
||||
MultiPskyInit();
|
||||
|
||||
#ifdef LUNATIC
|
||||
g_EmState = Em_CreateState();
|
||||
|
||||
if (g_EmState)
|
||||
{
|
||||
i = Em_RunOnce(g_EmState, "defs_m32.ilua");
|
||||
if (i)
|
||||
{
|
||||
initprintf("Lunatic: Error preparing global Lua state (code %d)\n", i);
|
||||
Em_DestroyState(g_EmState);
|
||||
g_EmState = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
signal(SIGINT, m32script_interrupt_handler);
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -6,95 +6,25 @@ _EDUKE32_LUNATIC = true
|
|||
local ffi = require("ffi")
|
||||
local ffiC = ffi.C
|
||||
|
||||
---=== Duke3D engine and game definitions ===---
|
||||
ffi.cdef[[
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
const int16_t wallptr, wallnum;
|
||||
int32_t ceilingz, floorz;
|
||||
int16_t ceilingstat, floorstat;
|
||||
int16_t ceilingpicnum, ceilingheinum;
|
||||
int8_t ceilingshade;
|
||||
uint8_t ceilingpal, ceilingxpanning, ceilingypanning;
|
||||
int16_t floorpicnum, floorheinum;
|
||||
int8_t floorshade;
|
||||
uint8_t floorpal, floorxpanning, floorypanning;
|
||||
uint8_t visibility, filler;
|
||||
int16_t lotag, hitag, extra;
|
||||
} sectortype;
|
||||
local string = string
|
||||
local table = table
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t x, y;
|
||||
const int16_t point2, nextwall, nextsector;
|
||||
int16_t cstat;
|
||||
int16_t picnum, overpicnum;
|
||||
int8_t shade;
|
||||
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
|
||||
int16_t lotag, hitag, extra;
|
||||
} walltype;
|
||||
--== First, load the definitions common to the game's and editor's Lua interface.
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t x, y, z;
|
||||
int16_t cstat, picnum;
|
||||
int8_t shade;
|
||||
uint8_t pal, clipdist, filler;
|
||||
uint8_t xrepeat, yrepeat;
|
||||
int8_t xoffset, yoffset;
|
||||
const int16_t sectnum, statnum;
|
||||
int16_t ang, owner, xvel, yvel, zvel;
|
||||
int16_t lotag, hitag, extra;
|
||||
} spritetype;
|
||||
|
||||
typedef struct {
|
||||
const uint32_t mdanimtims;
|
||||
const int16_t mdanimcur;
|
||||
int16_t angoff, pitch, roll;
|
||||
int32_t xoff, yoff, zoff;
|
||||
uint8_t flags;
|
||||
uint8_t xpanning, ypanning;
|
||||
const uint8_t filler;
|
||||
float alpha;
|
||||
const int32_t _do_not_use1;
|
||||
const int32_t _do_not_use2;
|
||||
} spriteext_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t x, y, z;
|
||||
} vec3_t;
|
||||
|
||||
typedef struct {
|
||||
vec3_t pos;
|
||||
int16_t sprite, wall, sect;
|
||||
} hitdata_t;
|
||||
|
||||
typedef struct {
|
||||
char r,g,b,f;
|
||||
} palette_t;
|
||||
#pragma pack(pop)
|
||||
]]
|
||||
|
||||
local vec3_ct = ffi.typeof("vec3_t")
|
||||
local hitdata_ct = ffi.typeof("hitdata_t")
|
||||
|
||||
---- engine data and functions ----
|
||||
|
||||
-- GLOBAL gv: provides access to C global *scalars* and safe functions
|
||||
-- XXX: still exposes C library functions etc. contained in ffi.C.
|
||||
-- Is this a problem?
|
||||
-- The "gv" global will provide access to C global *scalars* and safe functions.
|
||||
-- XXX: still exposes C library functions etc. contained in ffi.C, problem?
|
||||
local gv_ = {
|
||||
-- all non-scalars need to be explicitly listed here and access to them is
|
||||
-- All non-scalars need to be explicitly listed here and access to them is
|
||||
-- redirected to the dummy empty table...
|
||||
}
|
||||
|
||||
local dummy_empty_table = {}
|
||||
|
||||
-- This is for declarations of arrays or pointers which should not be
|
||||
-- accessible through the gv global.
|
||||
-- accessible through the "gv" global. The "defs_common" module require will
|
||||
-- use this function.
|
||||
-- NOTE: don't declare multiple pointers on one line (like int32_t *a, *b;)!
|
||||
local function decl(str)
|
||||
function decl(str)
|
||||
for varname in string.gmatch(str, "([%a_][%w_]*)[[(;]") do
|
||||
-- print("protect "..varname)
|
||||
gv_[varname] = dummy_empty_table
|
||||
|
@ -103,86 +33,11 @@ local function decl(str)
|
|||
ffi.cdef(str)
|
||||
end
|
||||
|
||||
ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]]
|
||||
-- load them!
|
||||
local defs_c = require("defs_common")
|
||||
|
||||
-- NOTE TO SELF: This is not C, never EVER write
|
||||
-- if (x)
|
||||
-- when checking a C variable x for 'thuthiness'
|
||||
if (ffiC.engine_main_arrays_are_static ~= 0) then
|
||||
decl[[
|
||||
sectortype sector[];
|
||||
walltype wall[];
|
||||
spritetype sprite[];
|
||||
spriteext_t spriteext[];
|
||||
]]
|
||||
else
|
||||
decl[[
|
||||
sectortype *sector;
|
||||
walltype *wall;
|
||||
spritetype *sprite;
|
||||
spriteext_t *spriteext;
|
||||
]]
|
||||
end
|
||||
|
||||
if (ffiC.engine_v8 == 0) then
|
||||
-- V7
|
||||
ffi.cdef[[
|
||||
enum
|
||||
{
|
||||
MAXSECTORS = 1024,
|
||||
MAXWALLS = 8192,
|
||||
MAXSPRITES = 4096,
|
||||
}
|
||||
]]
|
||||
else
|
||||
-- V8
|
||||
ffi.cdef[[
|
||||
enum
|
||||
{
|
||||
MAXSECTORS = 4096,
|
||||
MAXWALLS = 16384,
|
||||
MAXSPRITES = 16384,
|
||||
}
|
||||
]]
|
||||
end
|
||||
|
||||
ffi.cdef[[
|
||||
enum {
|
||||
MAXSTATUS = 1024,
|
||||
MAXTILES = 30720,
|
||||
|
||||
MAXBUNCHES = 256,
|
||||
CEILING = 0,
|
||||
FLOOR = 1,
|
||||
|
||||
CLIPMASK0 = (1<<16)+1, // blocking
|
||||
CLIPMASK1 = (256<<16)+64, // hittable
|
||||
};
|
||||
]]
|
||||
|
||||
ffi.cdef[[
|
||||
const int16_t numsectors, numwalls;
|
||||
const int32_t numyaxbunches;
|
||||
const int32_t totalclock;
|
||||
const int32_t xdim, ydim;
|
||||
]]
|
||||
|
||||
decl[[
|
||||
const int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
|
||||
const int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
|
||||
const int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
|
||||
|
||||
const int16_t headsectbunch[2][MAXBUNCHES], nextsectbunch[2][MAXSECTORS];
|
||||
|
||||
int16_t yax_getbunch(int16_t i, int16_t cf);
|
||||
|
||||
int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
|
||||
hitdata_t *hitinfo, uint32_t cliptype);
|
||||
|
||||
void rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
|
||||
int8_t dashade, char dapalnum, int32_t dastat,
|
||||
int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2);
|
||||
]]
|
||||
---=== EDuke32 game definitions ===---
|
||||
|
||||
-- array -> element flattening inside structs,
|
||||
-- e.g. int32_t a[4] --> int32_t _a0, _a1, _a2, _a3;
|
||||
|
@ -546,12 +401,7 @@ double rand_jkiss_dbl(rng_jkiss_t *s);
|
|||
|
||||
void md4once(const unsigned char *block, unsigned int len, unsigned char digest[16]);
|
||||
]]
|
||||
|
||||
ffi.cdef[[
|
||||
int32_t ksqrt(uint32_t num);
|
||||
]]
|
||||
|
||||
ffi.cdef "double gethitickms(void);"
|
||||
-- XXX: "digest" --> dummy?
|
||||
|
||||
|
||||
|
||||
|
@ -567,9 +417,6 @@ local setmetatable = setmetatable
|
|||
local setfenv = setfenv
|
||||
local type = type
|
||||
|
||||
local string = string
|
||||
local table = table
|
||||
|
||||
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
|
||||
-- as it allows to see implementations of functions.
|
||||
--local string_dump = string.dump
|
||||
|
@ -967,46 +814,20 @@ end
|
|||
|
||||
-- error(..., 2) is to blame the caller and get its line numbers
|
||||
|
||||
-- set metatable and forbid setting it further
|
||||
local function setmtonce(tab, mt)
|
||||
mt.__metatable = true
|
||||
return setmetatable(tab, mt)
|
||||
end
|
||||
|
||||
local tmpmt = {
|
||||
__index = function() error('dummy variable: read access forbidden', 2) end,
|
||||
__newindex = function() error('dummy variable: write access forbidden', 2) end,
|
||||
}
|
||||
setmtonce(dummy_empty_table, tmpmt)
|
||||
defs_c.setmtonce(dummy_empty_table, tmpmt)
|
||||
|
||||
gv = gv_
|
||||
local tmpmt = {
|
||||
__index = ffiC,
|
||||
__newindex = function() error("cannot create new or write into existing fields of 'gv'", 2) end,
|
||||
}
|
||||
setmtonce(gv, tmpmt)
|
||||
defs_c.setmtonce(gv, tmpmt)
|
||||
|
||||
---- indirect C array access ----
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key >= 0 and key < ffiC.numsectors) then return ffiC.sector[key] end
|
||||
error('out-of-bounds sector[] read access', 2)
|
||||
end,
|
||||
|
||||
__newindex = function(tab, key, val) error('cannot write directly to sector[] struct', 2) end,
|
||||
}
|
||||
sector = setmtonce({}, tmpmt)
|
||||
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key >= 0 and key < ffiC.numwalls) then return ffiC.wall[key] end
|
||||
error('out-of-bounds wall[] read access', 2)
|
||||
end,
|
||||
|
||||
__newindex = function(tab, key, val) error('cannot write directly to wall[] struct', 2) end,
|
||||
}
|
||||
wall = setmtonce({}, tmpmt)
|
||||
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key >= 0 and key < ffiC.playerswhenstarted) then
|
||||
|
@ -1017,126 +838,37 @@ local tmpmt = {
|
|||
|
||||
__newindex = function(tab, key, val) error('cannot write directly to player[] struct', 2) end,
|
||||
}
|
||||
player = setmtonce({}, tmpmt)
|
||||
player = defs_c.setmtonce({}, tmpmt)
|
||||
|
||||
-- create a safe indirection for an ffi.C array
|
||||
local function creategtab(ctab, maxidx, name)
|
||||
local tab = {}
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key>=0 and key < maxidx) then
|
||||
return ctab[key]
|
||||
end
|
||||
error('out-of-bounds '..name..' read access', 2)
|
||||
end,
|
||||
__newindex = function(tab, key, val)
|
||||
error('cannot write directly to '..name, 2)
|
||||
end,
|
||||
}
|
||||
-- structs
|
||||
sector = defs_c.sector;
|
||||
wall = defs_c.wall;
|
||||
sprite = defs_c.sprite
|
||||
spriteext = defs_c.spriteext
|
||||
|
||||
return setmtonce(tab, tmpmt)
|
||||
end
|
||||
headspritesect = defs_c.headspritesect
|
||||
headspritestat = defs_c.headspritestat
|
||||
nextspritesect = defs_c.nextspritesect
|
||||
nextspritestat = defs_c.nextspritestat
|
||||
prevspritesect = defs_c.prevspritesect
|
||||
prevspritestat = defs_c.prevspritestat
|
||||
|
||||
sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[] struct')
|
||||
spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[] struct')
|
||||
headspritesect = creategtab(ffiC.headspritesect, ffiC.MAXSECTORS, 'headspritesect[]')
|
||||
-- TODO: allow sprite freelist access via the status list for CON compatibility?
|
||||
headspritestat = creategtab(ffiC.headspritestat, ffiC.MAXSTATUS, 'headspritestat[]')
|
||||
nextspritesect = creategtab(ffiC.nextspritesect, ffiC.MAXSPRITES, 'nextspritesect[]')
|
||||
nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritestat[]')
|
||||
prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]')
|
||||
prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, 'prevspritestat[]')
|
||||
actor = defs_c.creategtab(ffiC.actor, ffiC.MAXSPRITES, 'actor[]')
|
||||
|
||||
-- functions
|
||||
spritesofsect = defs_c.spritesofsect
|
||||
spritesofstat = defs_c.spritesofstat
|
||||
sectorsofbunch = defs_c.sectorsofbunch
|
||||
|
||||
getbunch = defs_c.getbunch
|
||||
|
||||
hitscan = defs_c.hitscan
|
||||
|
||||
actor = creategtab(ffiC.actor, ffiC.MAXSPRITES, 'actor[]')
|
||||
|
||||
function TEMP_getvollev() -- REMOVE
|
||||
return ffiC.ud.volume_number+1, ffiC.ud.level_number+1
|
||||
end
|
||||
|
||||
---- per-sector/per-statnum sprite iterators ----
|
||||
local function iter_spritesofsect(sect, i)
|
||||
if (i < 0) then
|
||||
i = ffiC.headspritesect[sect]
|
||||
else
|
||||
i = ffiC.nextspritesect[i]
|
||||
end
|
||||
|
||||
if (i >= 0) then return i end
|
||||
end
|
||||
|
||||
function spritesofsect(sect)
|
||||
if (sect < 0 or sect >= ffiC.numsectors) then
|
||||
error("passed invalid sectnum to spritesofsect iterator", 2)
|
||||
end
|
||||
|
||||
return iter_spritesofsect, sect, -1
|
||||
end
|
||||
|
||||
local function iter_spritesofstat(stat, i)
|
||||
if (i < 0) then
|
||||
i = ffiC.headspritestat[stat]
|
||||
else
|
||||
i = ffiC.nextspritestat[i]
|
||||
end
|
||||
|
||||
if (i >= 0) then return i end
|
||||
end
|
||||
|
||||
function spritesofstat(stat)
|
||||
if (stat < 0 or stat >= ffiC.MAXSTATUS) then
|
||||
error("passed invalid statnum to spritesofstat iterator", 2)
|
||||
end
|
||||
|
||||
return iter_spritesofstat, stat, -1
|
||||
end
|
||||
|
||||
-- TROR iterators
|
||||
local function iter_sectorsofbunch(cf, i)
|
||||
if (i < 0) then
|
||||
i = ffiC.headsectbunch[cf][-i-1];
|
||||
else
|
||||
i = ffiC.nextsectbunch[cf][i];
|
||||
end
|
||||
|
||||
if (i >= 0) then return i end
|
||||
end
|
||||
|
||||
function sectorsofbunch(bunchnum, cf)
|
||||
if (bunchnum < 0 or bunchnum >= ffiC.numyaxbunches) then
|
||||
error("passed invalid bunchnum to sectorsofbunch iterator", 2)
|
||||
end
|
||||
if (cf ~= 0 and cf ~= 1) then
|
||||
error("passed invalid 'cf' to sectorsofbunch iterator, must be 0 or 1", 2)
|
||||
end
|
||||
|
||||
return iter_sectorsofbunch, cf, -bunchnum-1
|
||||
end
|
||||
|
||||
function getbunch(sectnum, cf)
|
||||
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
|
||||
error('passed out-of-bounds sector number'..sectnum, 2)
|
||||
end
|
||||
if (cf ~= 0 and cf ~= 1) then
|
||||
error("passed invalid 'cf' to getbunch, must be 0 or 1", 2)
|
||||
end
|
||||
|
||||
return ffiC.yax_getbunch(sectnum, cf)
|
||||
end
|
||||
|
||||
|
||||
---=== Engine functions, wrapped for Lua convenience ===---
|
||||
-- returns a hitdata_ct
|
||||
function hitscan(x,y,z, sectnum, vx,vy,vz, cliptype)
|
||||
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
|
||||
error('passed out-of-bounds sector number'..sectnum, 2)
|
||||
end
|
||||
|
||||
local vec = vec3_ct(x,y,z)
|
||||
local hitdata = hitdata_ct()
|
||||
|
||||
ffiC.hitscan(vec, sectnum, vx,vy,vz, hitdata, cliptype)
|
||||
return hitdata
|
||||
end
|
||||
|
||||
---=== Game variables ===---
|
||||
|
||||
|
|
324
polymer/eduke32/source/lunatic/defs_common.lua
Normal file
324
polymer/eduke32/source/lunatic/defs_common.lua
Normal file
|
@ -0,0 +1,324 @@
|
|||
|
||||
-- This file contains LuaJIT definitions of stuff that's common to the game and
|
||||
-- editor. The 'decl' is expected to be defined in the global environment.
|
||||
|
||||
local ffi = require("ffi")
|
||||
local ffiC = ffi.C
|
||||
|
||||
local error = error
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local decl = decl
|
||||
|
||||
|
||||
module(...)
|
||||
|
||||
|
||||
--== Core engine structs ==--
|
||||
|
||||
ffi.cdef[[
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
const int16_t wallptr, wallnum;
|
||||
int32_t ceilingz, floorz;
|
||||
int16_t ceilingstat, floorstat;
|
||||
int16_t ceilingpicnum, ceilingheinum;
|
||||
int8_t ceilingshade;
|
||||
uint8_t ceilingpal, ceilingxpanning, ceilingypanning;
|
||||
int16_t floorpicnum, floorheinum;
|
||||
int8_t floorshade;
|
||||
uint8_t floorpal, floorxpanning, floorypanning;
|
||||
uint8_t visibility, filler;
|
||||
int16_t lotag, hitag, extra;
|
||||
} sectortype;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t x, y;
|
||||
const int16_t point2, nextwall, nextsector;
|
||||
int16_t cstat;
|
||||
int16_t picnum, overpicnum;
|
||||
int8_t shade;
|
||||
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
|
||||
int16_t lotag, hitag, extra;
|
||||
} walltype;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t x, y, z;
|
||||
int16_t cstat, picnum;
|
||||
int8_t shade;
|
||||
uint8_t pal, clipdist, filler;
|
||||
uint8_t xrepeat, yrepeat;
|
||||
int8_t xoffset, yoffset;
|
||||
const int16_t sectnum, statnum;
|
||||
int16_t ang, owner, xvel, yvel, zvel;
|
||||
int16_t lotag, hitag, extra;
|
||||
} spritetype;
|
||||
|
||||
typedef struct {
|
||||
const uint32_t mdanimtims;
|
||||
const int16_t mdanimcur;
|
||||
int16_t angoff, pitch, roll;
|
||||
int32_t xoff, yoff, zoff;
|
||||
uint8_t flags;
|
||||
uint8_t xpanning, ypanning;
|
||||
const uint8_t filler;
|
||||
float alpha;
|
||||
const int32_t _do_not_use1;
|
||||
const int32_t _do_not_use2;
|
||||
} spriteext_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t x, y, z;
|
||||
} vec3_t;
|
||||
|
||||
typedef struct {
|
||||
vec3_t pos;
|
||||
int16_t sprite, wall, sect;
|
||||
} hitdata_t;
|
||||
|
||||
typedef struct {
|
||||
char r,g,b,f;
|
||||
} palette_t;
|
||||
#pragma pack(pop)
|
||||
]]
|
||||
|
||||
local vec3_ct = ffi.typeof("vec3_t")
|
||||
local hitdata_ct = ffi.typeof("hitdata_t")
|
||||
|
||||
-- TODO: add 'const'
|
||||
ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]]
|
||||
|
||||
|
||||
--== Engine data and functions ==--
|
||||
|
||||
|
||||
-- NOTE TO SELF: This is not C, never EVER write
|
||||
-- if (x)
|
||||
-- when checking a C variable x for 'thuthiness'
|
||||
if (ffiC.engine_main_arrays_are_static ~= 0) then
|
||||
decl[[
|
||||
sectortype sector[];
|
||||
walltype wall[];
|
||||
spritetype sprite[];
|
||||
spriteext_t spriteext[];
|
||||
]]
|
||||
else
|
||||
decl[[
|
||||
sectortype *sector;
|
||||
walltype *wall;
|
||||
spritetype *sprite;
|
||||
spriteext_t *spriteext;
|
||||
]]
|
||||
end
|
||||
|
||||
if (ffiC.engine_v8 == 0) then
|
||||
-- V7
|
||||
ffi.cdef[[
|
||||
enum
|
||||
{
|
||||
MAXSECTORS = 1024,
|
||||
MAXWALLS = 8192,
|
||||
MAXSPRITES = 4096,
|
||||
}
|
||||
]]
|
||||
else
|
||||
-- V8
|
||||
ffi.cdef[[
|
||||
enum
|
||||
{
|
||||
MAXSECTORS = 4096,
|
||||
MAXWALLS = 16384,
|
||||
MAXSPRITES = 16384,
|
||||
}
|
||||
]]
|
||||
end
|
||||
|
||||
ffi.cdef[[
|
||||
enum {
|
||||
MAXSTATUS = 1024,
|
||||
MAXTILES = 30720,
|
||||
|
||||
MAXBUNCHES = 256,
|
||||
CEILING = 0,
|
||||
FLOOR = 1,
|
||||
|
||||
CLIPMASK0 = (1<<16)+1, // blocking
|
||||
CLIPMASK1 = (256<<16)+64, // hittable
|
||||
};
|
||||
]]
|
||||
|
||||
ffi.cdef[[
|
||||
const int16_t numsectors, numwalls;
|
||||
const int32_t numyaxbunches;
|
||||
const int32_t totalclock;
|
||||
const int32_t xdim, ydim;
|
||||
]]
|
||||
|
||||
decl[[
|
||||
const int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
|
||||
const int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
|
||||
const int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
|
||||
|
||||
const int16_t headsectbunch[2][MAXBUNCHES], nextsectbunch[2][MAXSECTORS];
|
||||
|
||||
int16_t yax_getbunch(int16_t i, int16_t cf);
|
||||
|
||||
int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
|
||||
hitdata_t *hitinfo, uint32_t cliptype);
|
||||
|
||||
void rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
|
||||
int8_t dashade, char dapalnum, int32_t dastat,
|
||||
int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2);
|
||||
]]
|
||||
|
||||
-- misc. functions
|
||||
ffi.cdef[[
|
||||
int32_t ksqrt(uint32_t num);
|
||||
double gethitickms(void);
|
||||
]]
|
||||
|
||||
|
||||
---=== Restricted access to C variables from Lunatic ===---
|
||||
|
||||
-- set metatable and forbid setting it further
|
||||
function setmtonce(tab, mt)
|
||||
mt.__metatable = true
|
||||
return setmetatable(tab, mt)
|
||||
end
|
||||
|
||||
---- indirect C array access ----
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key >= 0 and key < ffiC.numsectors) then return ffiC.sector[key] end
|
||||
error('out-of-bounds sector[] read access', 2)
|
||||
end,
|
||||
|
||||
__newindex = function(tab, key, val) error('cannot write directly to sector[] struct', 2) end,
|
||||
}
|
||||
sector = setmtonce({}, tmpmt)
|
||||
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key >= 0 and key < ffiC.numwalls) then return ffiC.wall[key] end
|
||||
error('out-of-bounds wall[] read access', 2)
|
||||
end,
|
||||
|
||||
__newindex = function(tab, key, val) error('cannot write directly to wall[] struct', 2) end,
|
||||
}
|
||||
wall = setmtonce({}, tmpmt)
|
||||
|
||||
-- create a safe indirection for an ffi.C array
|
||||
function creategtab(ctab, maxidx, name)
|
||||
local tab = {}
|
||||
local tmpmt = {
|
||||
__index = function(tab, key)
|
||||
if (key>=0 and key < maxidx) then
|
||||
return ctab[key]
|
||||
end
|
||||
error('out-of-bounds '..name..' read access', 2)
|
||||
end,
|
||||
__newindex = function(tab, key, val)
|
||||
error('cannot write directly to '..name, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
return setmtonce(tab, tmpmt)
|
||||
end
|
||||
|
||||
sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[] struct')
|
||||
spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[] struct')
|
||||
headspritesect = creategtab(ffiC.headspritesect, ffiC.MAXSECTORS, 'headspritesect[]')
|
||||
-- TODO: allow sprite freelist access via the status list for CON compatibility?
|
||||
headspritestat = creategtab(ffiC.headspritestat, ffiC.MAXSTATUS, 'headspritestat[]')
|
||||
nextspritesect = creategtab(ffiC.nextspritesect, ffiC.MAXSPRITES, 'nextspritesect[]')
|
||||
nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritestat[]')
|
||||
prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]')
|
||||
prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, 'prevspritestat[]')
|
||||
|
||||
--== Per-sector/per-statnum sprite iterators ==--
|
||||
local function iter_spritesofsect(sect, i)
|
||||
if (i < 0) then
|
||||
i = ffiC.headspritesect[sect]
|
||||
else
|
||||
i = ffiC.nextspritesect[i]
|
||||
end
|
||||
|
||||
if (i >= 0) then return i end
|
||||
end
|
||||
|
||||
function spritesofsect(sect)
|
||||
if (sect < 0 or sect >= ffiC.numsectors) then
|
||||
error("passed invalid sectnum to spritesofsect iterator", 2)
|
||||
end
|
||||
|
||||
return iter_spritesofsect, sect, -1
|
||||
end
|
||||
|
||||
local function iter_spritesofstat(stat, i)
|
||||
if (i < 0) then
|
||||
i = ffiC.headspritestat[stat]
|
||||
else
|
||||
i = ffiC.nextspritestat[i]
|
||||
end
|
||||
|
||||
if (i >= 0) then return i end
|
||||
end
|
||||
|
||||
function spritesofstat(stat)
|
||||
if (stat < 0 or stat >= ffiC.MAXSTATUS) then
|
||||
error("passed invalid statnum to spritesofstat iterator", 2)
|
||||
end
|
||||
|
||||
return iter_spritesofstat, stat, -1
|
||||
end
|
||||
|
||||
--== TROR iterators ==--
|
||||
local function iter_sectorsofbunch(cf, i)
|
||||
if (i < 0) then
|
||||
i = ffiC.headsectbunch[cf][-i-1];
|
||||
else
|
||||
i = ffiC.nextsectbunch[cf][i];
|
||||
end
|
||||
|
||||
if (i >= 0) then return i end
|
||||
end
|
||||
|
||||
function sectorsofbunch(bunchnum, cf)
|
||||
if (bunchnum < 0 or bunchnum >= ffiC.numyaxbunches) then
|
||||
error("passed invalid bunchnum to sectorsofbunch iterator", 2)
|
||||
end
|
||||
if (cf ~= 0 and cf ~= 1) then
|
||||
error("passed invalid 'cf' to sectorsofbunch iterator, must be 0 or 1", 2)
|
||||
end
|
||||
|
||||
return iter_sectorsofbunch, cf, -bunchnum-1
|
||||
end
|
||||
|
||||
function getbunch(sectnum, cf)
|
||||
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
|
||||
error('passed out-of-bounds sector number'..sectnum, 2)
|
||||
end
|
||||
if (cf ~= 0 and cf ~= 1) then
|
||||
error("passed invalid 'cf' to getbunch, must be 0 or 1", 2)
|
||||
end
|
||||
|
||||
return ffiC.yax_getbunch(sectnum, cf)
|
||||
end
|
||||
|
||||
|
||||
---=== Engine functions, wrapped for Lua convenience ===---
|
||||
-- returns a hitdata_ct
|
||||
function hitscan(x,y,z, sectnum, vx,vy,vz, cliptype)
|
||||
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
|
||||
error('passed out-of-bounds sector number'..sectnum, 2)
|
||||
end
|
||||
|
||||
local vec = vec3_ct(x,y,z)
|
||||
local hitdata = hitdata_ct()
|
||||
|
||||
ffiC.hitscan(vec, sectnum, vx,vy,vz, hitdata, cliptype)
|
||||
return hitdata
|
||||
end
|
31
polymer/eduke32/source/lunatic/defs_m32.ilua
Normal file
31
polymer/eduke32/source/lunatic/defs_m32.ilua
Normal file
|
@ -0,0 +1,31 @@
|
|||
-- INTERNAL
|
||||
-- definitions of BUILD and game types for the Lunatic Interpreter
|
||||
|
||||
local ffi = require("ffi")
|
||||
local ffiC = ffi.C
|
||||
|
||||
--== First, load the definitions common to the game's and editor's Lua interface.
|
||||
decl = ffi.cdef
|
||||
local defs_c = require("defs_common")
|
||||
|
||||
-- structs
|
||||
sector = defs_c.sector;
|
||||
wall = defs_c.wall;
|
||||
sprite = defs_c.sprite
|
||||
spriteext = defs_c.spriteext
|
||||
|
||||
headspritesect = defs_c.headspritesect
|
||||
headspritestat = defs_c.headspritestat
|
||||
nextspritesect = defs_c.nextspritesect
|
||||
nextspritestat = defs_c.nextspritestat
|
||||
prevspritesect = defs_c.prevspritesect
|
||||
prevspritestat = defs_c.prevspritestat
|
||||
|
||||
-- functions
|
||||
spritesofsect = defs_c.spritesofsect
|
||||
spritesofstat = defs_c.spritesofstat
|
||||
sectorsofbunch = defs_c.sectorsofbunch
|
||||
|
||||
getbunch = defs_c.getbunch
|
||||
|
||||
hitscan = defs_c.hitscan
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
#include "gameexec.h"
|
||||
#include "gamedef.h" // EventNames[], MAXEVENTS
|
||||
|
||||
#include "lunatic.h"
|
||||
#include "lunatic_priv.h"
|
||||
|
||||
// this serves two purposes:
|
||||
// the values as booleans and the addresses as keys to the Lua registry
|
||||
|
@ -86,16 +88,6 @@ void El_PrintTimes(void)
|
|||
OSD_Printf(" },\n}\n");
|
||||
}
|
||||
|
||||
static void check_and_register_function(lua_State *L, void *keyaddr)
|
||||
{
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
|
||||
lua_pushlightuserdata(L, keyaddr); // 3, push address
|
||||
lua_pushvalue(L, -2); // 4, push copy of lua function
|
||||
|
||||
lua_settable(L, LUA_REGISTRYINDEX); // "registry[keyaddr] = <lua function>", pop 2
|
||||
}
|
||||
|
||||
|
||||
// 0: success, <0: failure
|
||||
int32_t El_CreateState(El_State *estate, const char *name)
|
||||
|
@ -119,12 +111,7 @@ int32_t El_CreateState(El_State *estate, const char *name)
|
|||
luaopen_lpeg(L);
|
||||
lua_pop(L, lua_gettop(L)); // pop off whatever lpeg leaves on the stack
|
||||
|
||||
// get debug.traceback
|
||||
lua_getglobal(L, "debug");
|
||||
lua_getfield(L, -1, "traceback");
|
||||
Bassert(lua_isfunction(L, -1));
|
||||
check_and_register_function(L, &debug_traceback_key);
|
||||
lua_pop(L, 2);
|
||||
setup_debug_traceback(L);
|
||||
|
||||
// create misc. global functions in the Lua state
|
||||
lua_pushcfunction(L, SetEvent_luacf);
|
||||
|
@ -157,88 +144,7 @@ void El_DestroyState(El_State *estate)
|
|||
// 4: runtime error while executing lua file
|
||||
int32_t El_RunOnce(El_State *estate, const char *fn)
|
||||
{
|
||||
int32_t fid, flen, i;
|
||||
char *buf;
|
||||
|
||||
lua_State *const L = estate->L;
|
||||
|
||||
fid = kopen4load(fn, 0); // TODO: g_loadFromGroupOnly, kopen4loadfrommod ?
|
||||
|
||||
if (fid < 0)
|
||||
return 1;
|
||||
|
||||
flen = kfilelength(fid);
|
||||
if (flen == 0)
|
||||
return 0; // empty script ...
|
||||
|
||||
buf = Bmalloc(flen+1);
|
||||
if (!buf)
|
||||
{
|
||||
kclose(fid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = kread(fid, buf, flen);
|
||||
kclose(fid);
|
||||
|
||||
if (i != flen)
|
||||
{
|
||||
Bfree(buf);
|
||||
return 2;
|
||||
}
|
||||
|
||||
buf[flen] = 0;
|
||||
|
||||
// -- lua --
|
||||
Bassert(lua_gettop(L)==0);
|
||||
|
||||
// get debug.traceback
|
||||
lua_pushlightuserdata(L, &debug_traceback_key);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
Bassert(lua_isfunction(L, -1));
|
||||
|
||||
i = luaL_loadstring(L, buf);
|
||||
Bassert(lua_gettop(L)==2);
|
||||
Bfree(buf);
|
||||
|
||||
if (i == LUA_ERRMEM)
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == LUA_ERRSYNTAX)
|
||||
{
|
||||
OSD_Printf("state \"%s\" syntax error: %s\n", estate->name,
|
||||
lua_tostring(L, -1)); // get err msg
|
||||
lua_pop(L, 2); // pop errmsg and debug.traceback
|
||||
return 3;
|
||||
}
|
||||
|
||||
// -- call the lua chunk! --
|
||||
|
||||
i = lua_pcall(L, 0, 0, -2);
|
||||
Bassert(lua_gettop(L) == 1+!!i);
|
||||
Bassert(i != LUA_ERRERR); // we expect debug.traceback not to fail
|
||||
|
||||
if (i == LUA_ERRMEM) // XXX: should be more sophisticated. Clean up stack? Do GC?
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == LUA_ERRRUN)
|
||||
{
|
||||
Bassert(lua_type(L, -1)==LUA_TSTRING);
|
||||
OSD_Printf("state \"%s\" runtime error: %s\n", estate->name,
|
||||
lua_tostring(L, -1)); // get err msg
|
||||
lua_pop(L, 2); // pop errmsg and debug.traceback
|
||||
return 4;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
return lunatic_run_once(estate->L, fn, estate->name);
|
||||
}
|
||||
|
||||
|
||||
|
|
35
polymer/eduke32/source/lunatic/lunatic_m32.c
Normal file
35
polymer/eduke32/source/lunatic/lunatic_m32.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* The Lunatic Interpreter, part of EDuke32/Mapster32 */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "lunatic_m32.h"
|
||||
#include "lunatic_priv.h"
|
||||
|
||||
|
||||
Em_State *Em_CreateState(void)
|
||||
{
|
||||
lua_State *L = luaL_newstate();
|
||||
|
||||
if (L == NULL)
|
||||
return NULL;
|
||||
|
||||
luaL_openlibs(L);
|
||||
setup_debug_traceback(L);
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
// -1: alloc failure
|
||||
// 0: success
|
||||
// 1: didn't find file
|
||||
// 2: couldn't read whole file
|
||||
// 3: syntax error in lua file
|
||||
// 4: runtime error while executing lua file
|
||||
int32_t Em_RunOnce(Em_State *L, const char *fn)
|
||||
{
|
||||
return lunatic_run_once(L, fn, "test");
|
||||
}
|
19
polymer/eduke32/source/lunatic/lunatic_m32.h
Normal file
19
polymer/eduke32/source/lunatic/lunatic_m32.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef EDUKE32_LUNATIC_M32_H_
|
||||
#define EDUKE32_LUNATIC_M32_H_
|
||||
|
||||
#include <lua.h>
|
||||
|
||||
|
||||
typedef lua_State Em_State;
|
||||
|
||||
|
||||
Em_State *Em_CreateState(void);
|
||||
|
||||
static inline void Em_DestroyState(Em_State *L)
|
||||
{
|
||||
lua_close(L);
|
||||
}
|
||||
|
||||
int32_t Em_RunOnce(Em_State *L, const char *fn);
|
||||
|
||||
#endif
|
117
polymer/eduke32/source/lunatic/lunatic_priv.h
Normal file
117
polymer/eduke32/source/lunatic/lunatic_priv.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* Private, game/editor-common Lunatic routines. */
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "cache1d.h"
|
||||
#include "osd.h"
|
||||
|
||||
|
||||
// Lua-registry key for debug.traceback
|
||||
static uint8_t debug_traceback_key;
|
||||
|
||||
static void check_and_register_function(lua_State *L, void *regkeyaddr)
|
||||
{
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
|
||||
lua_pushlightuserdata(L, regkeyaddr); // 3, push address
|
||||
lua_pushvalue(L, -2); // 4, push copy of lua function
|
||||
|
||||
lua_settable(L, LUA_REGISTRYINDEX); // "registry[regkeyaddr] = <lua function>", pop 2
|
||||
}
|
||||
|
||||
static void setup_debug_traceback(lua_State *L)
|
||||
{
|
||||
// get debug.traceback
|
||||
lua_getglobal(L, "debug");
|
||||
lua_getfield(L, -1, "traceback");
|
||||
Bassert(lua_isfunction(L, -1));
|
||||
check_and_register_function(L, &debug_traceback_key);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
|
||||
static int32_t lunatic_run_once(lua_State *L, const char *fn, const char *statename)
|
||||
{
|
||||
int32_t fid, flen, i;
|
||||
char *buf;
|
||||
|
||||
fid = kopen4load(fn, 0); // TODO: g_loadFromGroupOnly, kopen4loadfrommod ?
|
||||
|
||||
if (fid < 0)
|
||||
return 1;
|
||||
|
||||
flen = kfilelength(fid);
|
||||
if (flen == 0)
|
||||
return 0; // empty script ...
|
||||
|
||||
buf = Bmalloc(flen+1);
|
||||
if (!buf)
|
||||
{
|
||||
kclose(fid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = kread(fid, buf, flen);
|
||||
kclose(fid);
|
||||
|
||||
if (i != flen)
|
||||
{
|
||||
Bfree(buf);
|
||||
return 2;
|
||||
}
|
||||
|
||||
buf[flen] = 0;
|
||||
|
||||
// -- lua --
|
||||
Bassert(lua_gettop(L)==0);
|
||||
|
||||
// get debug.traceback
|
||||
lua_pushlightuserdata(L, &debug_traceback_key);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
Bassert(lua_isfunction(L, -1));
|
||||
|
||||
i = luaL_loadstring(L, buf);
|
||||
Bassert(lua_gettop(L)==2);
|
||||
Bfree(buf);
|
||||
|
||||
if (i == LUA_ERRMEM)
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == LUA_ERRSYNTAX)
|
||||
{
|
||||
OSD_Printf("state \"%s\" syntax error: %s\n", statename,
|
||||
lua_tostring(L, -1)); // get err msg
|
||||
lua_pop(L, 2); // pop errmsg and debug.traceback
|
||||
return 3;
|
||||
}
|
||||
|
||||
// -- call the lua chunk! --
|
||||
|
||||
i = lua_pcall(L, 0, 0, -2);
|
||||
Bassert(lua_gettop(L) == 1+!!i);
|
||||
Bassert(i != LUA_ERRERR); // we expect debug.traceback not to fail
|
||||
|
||||
if (i == LUA_ERRMEM) // XXX: should be more sophisticated. Clean up stack? Do GC?
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == LUA_ERRRUN)
|
||||
{
|
||||
int32_t stringp = (lua_type(L, -1)==LUA_TSTRING);
|
||||
|
||||
// get error message if possible
|
||||
OSD_Printf("state \"%s\" runtime error: %s\n", statename,
|
||||
stringp ? lua_tostring(L, -1) : "??? (errmsg not a string)");
|
||||
lua_pop(L, 2); // pop errmsg and debug.traceback
|
||||
return 4;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue