mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-16 17:32:13 +00:00
3bcdc5acb8
On the engine side (functions starting with L_), there are now the basic parts like state creation and running code from strings and files. The game and editor can add to that by e.g. loading whatever they please into the state. Their functions start with El_ and Em_, respectively. The Lua scripts still reside in source/lunatic, even for the common ones. This is because they will be embedded into the binaries as bytecode or compressed source eventually, so their location on disk will be irrelevant. git-svn-id: https://svn.eduke32.com/eduke32@3148 1a8010ca-5511-0410-912e-c29ae57300e0
217 lines
5.6 KiB
C
217 lines
5.6 KiB
C
/* The Lunatic Interpreter, part of EDuke32. Game-side stuff. */
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <lualib.h>
|
|
#include <lauxlib.h>
|
|
|
|
#include "lunatic_game.h"
|
|
|
|
#include "osd.h"
|
|
#include "gamedef.h" // EventNames[]
|
|
|
|
|
|
L_State g_ElState;
|
|
|
|
|
|
// this serves two purposes:
|
|
// the values as booleans and the addresses as keys to the Lua registry
|
|
uint8_t g_elEvents[MAXEVENTS];
|
|
|
|
// same thing for actors:
|
|
uint8_t g_elActors[MAXTILES];
|
|
|
|
// for timing events and actors
|
|
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
|
|
double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES];
|
|
|
|
|
|
// forward-decls...
|
|
static int32_t SetEvent_luacf(lua_State *L);
|
|
static int32_t SetActor_luacf(lua_State *L);
|
|
|
|
// in lpeg.o
|
|
extern int luaopen_lpeg(lua_State *L);
|
|
|
|
|
|
typedef struct {
|
|
uint32_t x, y, z, c;
|
|
} rng_jkiss_t;
|
|
|
|
// See: Good Practice in (Pseudo) Random Number Generation for
|
|
// Bioinformatics Applications, by David Jones
|
|
ATTRIBUTE((optimize("O2")))
|
|
uint32_t rand_jkiss_u32(rng_jkiss_t *s)
|
|
{
|
|
uint64_t t;
|
|
s->x = 314527869 * s->x + 1234567;
|
|
s->y ^= s->y << 5; s->y ^= s->y >> 7; s->y ^= s->y << 22;
|
|
t = 4294584393ULL * s->z + s->c; s->c = t >> 32; s->z = t;
|
|
return s->x + s->y + s->z;
|
|
}
|
|
|
|
ATTRIBUTE((optimize("O2")))
|
|
double rand_jkiss_dbl(rng_jkiss_t *s)
|
|
{
|
|
double x;
|
|
unsigned int a, b;
|
|
a = rand_jkiss_u32(s) >> 6; /* Upper 26 bits */
|
|
b = rand_jkiss_u32(s) >> 5; /* Upper 27 bits */
|
|
x = (a * 134217728.0 + b) / 9007199254740992.0;
|
|
return x;
|
|
}
|
|
|
|
|
|
void El_PrintTimes(void)
|
|
{
|
|
int32_t i;
|
|
|
|
OSD_Printf("{\n {\n");
|
|
OSD_Printf(" -- event times, [event]={ total calls, total time in ms, time per call in us }\n");
|
|
for (i=0; i<MAXEVENTS; i++)
|
|
if (g_eventCalls[i])
|
|
OSD_Printf(" [%2d]={ %8d, %9.3f, %9.3f },\n",
|
|
i, g_eventCalls[i], g_eventTotalMs[i],
|
|
1000*g_eventTotalMs[i]/g_eventCalls[i]);
|
|
|
|
OSD_Printf(" },\n\n {\n");
|
|
OSD_Printf(" -- actor times, [tile]={ total calls, total time in ms, time per call in us }\n");
|
|
for (i=0; i<MAXTILES; i++)
|
|
if (g_actorCalls[i])
|
|
OSD_Printf(" [%5d]={ %8d, %9.3f, %9.3f },\n",
|
|
i, g_actorCalls[i], g_actorTotalMs[i],
|
|
1000*g_actorTotalMs[i]/g_actorCalls[i]);
|
|
OSD_Printf(" },\n}\n");
|
|
}
|
|
|
|
|
|
////////// STATE CREATION/DESTRUCTIION //////////
|
|
|
|
static void El_StateSetup(lua_State *L)
|
|
{
|
|
luaL_openlibs(L); // NOTE: we set up the sandbox in defs.ilua
|
|
luaopen_lpeg(L);
|
|
lua_pop(L, lua_gettop(L)); // pop off whatever lpeg leaves on the stack
|
|
|
|
L_SetupDebugTraceback(L);
|
|
|
|
// create misc. global functions in the Lua state
|
|
lua_pushcfunction(L, SetEvent_luacf);
|
|
lua_setglobal(L, "gameevent");
|
|
lua_pushcfunction(L, SetActor_luacf);
|
|
lua_setglobal(L, "gameactor");
|
|
|
|
Bassert(lua_gettop(L)==0);
|
|
}
|
|
|
|
// 0: success, <0: failure
|
|
int32_t El_CreateState(L_State *estate, const char *name)
|
|
{
|
|
return L_CreateState(estate, name, &El_StateSetup);
|
|
}
|
|
|
|
void El_DestroyState(L_State *estate)
|
|
{
|
|
L_DestroyState(estate);
|
|
}
|
|
|
|
|
|
////////// Lua_CFunctions //////////
|
|
|
|
// gameevent(EVENT_..., lua_function)
|
|
static int32_t SetEvent_luacf(lua_State *L)
|
|
{
|
|
int32_t eventidx;
|
|
|
|
if (lua_gettop(L) != 2)
|
|
luaL_error(L, "gameevent: must pass exactly two arguments");
|
|
|
|
eventidx = luaL_checkint(L, 1);
|
|
|
|
luaL_argcheck(L, (unsigned)eventidx < MAXEVENTS, 1, "must be an event number (0 .. MAXEVENTS-1)");
|
|
L_CheckAndRegisterFunction(L, &g_elEvents[eventidx]);
|
|
g_elEvents[eventidx] = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// gameactor(<actortile>, lua_function)
|
|
static int32_t SetActor_luacf(lua_State *L)
|
|
{
|
|
int32_t actortile;
|
|
|
|
if (lua_gettop(L) != 2)
|
|
luaL_error(L, "gameactor: must pass exactly two arguments");
|
|
|
|
actortile = luaL_checkint(L, 1);
|
|
|
|
luaL_argcheck(L, (unsigned)actortile < MAXTILES, 1, "must be an tile number (0 .. MAXTILES-1)");
|
|
L_CheckAndRegisterFunction(L, &g_elActors[actortile]);
|
|
g_elActors[actortile] = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////
|
|
|
|
static int32_t call_regd_function3(lua_State *L, void *keyaddr,
|
|
int32_t iActor, int32_t iPlayer, int32_t lDist)
|
|
{
|
|
int32_t i;
|
|
|
|
// get the Lua function from the registry
|
|
lua_pushlightuserdata(L, keyaddr);
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
lua_pushinteger(L, iActor);
|
|
lua_pushinteger(L, iPlayer);
|
|
lua_pushinteger(L, lDist);
|
|
|
|
// -- call it! --
|
|
|
|
i = lua_pcall(L, 3, 0, 0);
|
|
if (i == LUA_ERRMEM)
|
|
{
|
|
lua_pop(L, 1);
|
|
// XXX: should be more sophisticated. Clean up stack? Do GC?
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
int32_t El_CallEvent(L_State *estate, int32_t eventidx, int32_t iActor, int32_t iPlayer, int32_t lDist)
|
|
{
|
|
// XXX: estate must be the one where the events were registered...
|
|
// make a global?
|
|
|
|
lua_State *const L = estate->L;
|
|
|
|
int32_t i = call_regd_function3(L, &g_elEvents[eventidx], iActor, iPlayer, lDist);
|
|
|
|
if (i == LUA_ERRRUN)
|
|
{
|
|
OSD_Printf("event \"%s\" (state \"%s\") runtime error: %s\n", EventNames[eventidx].text,
|
|
estate->name, lua_tostring(L, -1)); // get err msg
|
|
lua_pop(L, 1);
|
|
return 4;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t El_CallActor(L_State *estate, int32_t actortile, int32_t iActor, int32_t iPlayer, int32_t lDist)
|
|
{
|
|
lua_State *const L = estate->L;
|
|
|
|
int32_t i = call_regd_function3(L, &g_elActors[actortile], iActor, iPlayer, lDist);
|
|
|
|
if (i == LUA_ERRRUN)
|
|
{
|
|
OSD_Printf("actor %d (sprite %d, state \"%s\") runtime error: %s\n", actortile, iActor,
|
|
estate->name, lua_tostring(L, -1)); // get err msg
|
|
lua_pop(L, 1);
|
|
return 4;
|
|
}
|
|
|
|
return 0;
|
|
}
|