/* The Lunatic Interpreter, part of EDuke32. Game-side stuff. */ #include #include #include #include "build.h" // printext256 #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: el_actor_t g_elActors[MAXTILES]; int32_t g_elCallDepth = 0; // 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, maxlen=0; char buf[32]; const char nn = Bstrlen("EVENT_"); for (i=0; ihaveit = 1; a->strength = strength; a->movflags = movflags; Bmemcpy(&a->act, act, sizeof(con_action_t)); Bmemcpy(&a->mov, mov, sizeof(con_move_t)); 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; g_elCallDepth++; i = call_regd_function3(L, &g_elEvents[eventidx], iActor, iPlayer, lDist); g_elCallDepth--; if (i == LUA_ERRRUN) { const char *errstr; if (lua_isboolean(L, -1)) { lua_pop(L, 1); return 0; } errstr = lua_tostring(L, -1); Bassert(lua_type(L, -1)==LUA_TSTRING); OSD_Printf(OSD_ERROR "event \"%s\" (state \"%s\") runtime error: %s\n", EventNames[eventidx], estate->name, errstr); if (L_ErrorFunc) L_ErrorFunc(errstr); lua_pop(L, 1); return -1; } 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; g_elCallDepth++; i = call_regd_function3(L, &g_elActors[actortile], iActor, iPlayer, lDist); g_elCallDepth--; if (i == LUA_ERRRUN) { const char *errstr; if (lua_isboolean(L, -1)) { int32_t killit = lua_toboolean(L, -1); lua_pop(L, 1); return killit; } Bassert(lua_type(L, -1)==LUA_TSTRING); errstr = lua_tostring(L, -1); OSD_Printf(OSD_ERROR "actor %d (sprite %d, state \"%s\") runtime error: %s\n", actortile, iActor, estate->name, errstr); if (L_ErrorFunc) L_ErrorFunc(errstr); lua_pop(L, 1); return -1; } return 0; }