Subversion Repositories eduke32

Rev

Rev 4766 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3148 helixhorne 1
/* The Lunatic Interpreter, part of EDuke32. Game-side stuff. */
2034 helixhorne 2
 
3
#include <stdint.h>
3946 helixhorne 4
#include <stdlib.h>  // getenv
5
#include <errno.h>
6
#include <string.h>  // strerror
2034 helixhorne 7
 
4286 helixhorne 8
#ifdef __cplusplus
9
extern "C" {
10
#endif
11
 
4107 helixhorne 12
#ifdef USE_LUAJIT_2_1
13
# include <luajit-2.1/lualib.h>
14
# include <luajit-2.1/lauxlib.h>
15
#else
16
# include <luajit-2.0/lualib.h>
17
# include <luajit-2.0/lauxlib.h>
18
#endif
2034 helixhorne 19
 
4286 helixhorne 20
#ifdef __cplusplus
21
}
22
#endif
23
 
3319 helixhorne 24
#include "build.h"  // printext256
25
 
3148 helixhorne 26
#include "lunatic_game.h"
27
 
2034 helixhorne 28
#include "osd.h"
3148 helixhorne 29
#include "gamedef.h"  // EventNames[]
2034 helixhorne 30
 
3056 helixhorne 31
 
3148 helixhorne 32
L_State g_ElState;
2034 helixhorne 33
 
3148 helixhorne 34
 
2329 helixhorne 35
// this serves two purposes:
36
// the values as booleans and the addresses as keys to the Lua registry
2746 helixhorne 37
uint8_t g_elEvents[MAXEVENTS];
2034 helixhorne 38
 
2747 helixhorne 39
// same thing for actors:
3315 helixhorne 40
el_actor_t g_elActors[MAXTILES];
2329 helixhorne 41
 
4112 helixhorne 42
// Session variable. Never restored except by 'readgamevar'.
43
int32_t g_elSessionVar[8];  // MAXSESSIONVARS, KEEPINSYNC con_lang.lua
44
 
3593 helixhorne 45
// Set to 1 on error in event.
46
int32_t g_elEventError;
47
 
4236 helixhorne 48
// Will be set to 0 after the first time that user Lua modules are run.
49
int32_t g_elFirstTime = 1;
50
 
3320 helixhorne 51
int32_t g_elCallDepth = 0;
3601 helixhorne 52
int32_t g_RETURN;
3320 helixhorne 53
 
2842 helixhorne 54
// for timing events and actors
3788 helixhorne 55
static int32_t g_timingInited = 0;
2842 helixhorne 56
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
3557 helixhorne 57
double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES];
2827 helixhorne 58
 
3535 helixhorne 59
// Used as Lua registry key to the tweak_traceback_msg() function, set to 1 if
60
// such a function has been registered.
61
static uint8_t g_tweakTracebackMsg = 0;
2842 helixhorne 62
 
2329 helixhorne 63
// forward-decls...
3352 helixhorne 64
static int32_t SetEvent_CF(lua_State *L);
65
static int32_t SetActor_CF(lua_State *L);
2329 helixhorne 66
 
4286 helixhorne 67
 
68
#ifdef __cplusplus
69
extern "C" {
70
#endif
71
 
2650 helixhorne 72
// in lpeg.o
73
extern int luaopen_lpeg(lua_State *L);
2329 helixhorne 74
 
4286 helixhorne 75
#ifdef __cplusplus
76
}
77
#endif
2857 helixhorne 78
 
4286 helixhorne 79
 
2857 helixhorne 80
 
81
// See: Good Practice in (Pseudo) Random Number Generation for
82
//      Bioinformatics Applications, by David Jones
3341 helixhorne 83
ATTRIBUTE_OPTIMIZE("O2")
3932 helixhorne 84
LUNATIC_EXTERN uint32_t rand_jkiss_u32(rng_jkiss_t *s)
2857 helixhorne 85
{
86
    uint64_t t;
87
    s->x = 314527869 * s->x + 1234567;
88
    s->y ^= s->y << 5; s->y ^= s->y >> 7; s->y ^= s->y << 22;
89
    t = 4294584393ULL * s->z + s->c; s->c = t >> 32; s->z = t;
90
    return s->x + s->y + s->z;
91
}
92
 
3341 helixhorne 93
ATTRIBUTE_OPTIMIZE("O2")
3932 helixhorne 94
LUNATIC_EXTERN double rand_jkiss_dbl(rng_jkiss_t *s)
2857 helixhorne 95
{
96
    double x;
97
    unsigned int a, b;
98
    a = rand_jkiss_u32(s) >> 6; /* Upper 26 bits */
99
    b = rand_jkiss_u32(s) >> 5; /* Upper 27 bits */
100
    x = (a * 134217728.0 + b) / 9007199254740992.0;
101
    return x;
102
}
103
 
104
 
2842 helixhorne 105
void El_PrintTimes(void)
106
{
3946 helixhorne 107
    int32_t i;
3258 helixhorne 108
    const char nn = Bstrlen("EVENT_");
2650 helixhorne 109
 
3946 helixhorne 110
    // Try environment variable specifying the base name (sans ".actors.csv" or
111
    // ".events.csv") for a CSV file to output, for further processing in e.g.
112
    // GSL shell: http://www.nongnu.org/gsl-shell/
113
    const char *basefn = getenv("LUNATIC_TIMING_BASEFN");
114
 
115
    if (basefn != NULL)
3258 helixhorne 116
    {
3946 helixhorne 117
        const int32_t baselen = Bstrlen(basefn);
118
        const int32_t addnlen = Bstrlen(".actors.csv");  // MUST equal that of ".events.csv"
3258 helixhorne 119
 
4491 helixhorne 120
        char *fullfn = (char *)Xmalloc(baselen + addnlen + 1);
3946 helixhorne 121
        BFILE *outf;
122
 
123
        if (fullfn == NULL)
124
            return;
125
 
126
        Bmemcpy(fullfn, basefn, baselen);
127
 
128
        // EVENTS
129
        Bmemcpy(fullfn+baselen, ".events.csv", addnlen+1);
130
        outf = Bfopen(fullfn, "w");
131
        if (outf == NULL)
3258 helixhorne 132
        {
3946 helixhorne 133
            OSD_Printf("Couldn't open \"%s\" for writing timing data: %s", fullfn, strerror(errno));
134
            goto finish;
135
        }
3258 helixhorne 136
 
3946 helixhorne 137
        Bfprintf(outf, "evtname,numcalls,total_ms,mean_us\n");  // times in usecs are per-call
138
        for (i=0; i<MAXEVENTS; i++)
139
            if (g_eventCalls[i])
140
                Bfprintf(outf, "%s,%d,%f,%f\n", EventNames[i]+nn, g_eventCalls[i], g_eventTotalMs[i],
141
                         1000*g_eventTotalMs[i]/g_eventCalls[i]);
142
        Bfclose(outf);
3258 helixhorne 143
 
3946 helixhorne 144
        // ACTORS
145
        Bmemcpy(fullfn+baselen, ".actors.csv", addnlen+1);
146
        outf = Bfopen(fullfn, "w");
147
        if (outf == NULL)
148
        {
149
            OSD_Printf("Couldn't open \"%s\" for writing timing data: %s", fullfn, strerror(errno));
150
            goto finish;
3258 helixhorne 151
        }
2842 helixhorne 152
 
3946 helixhorne 153
        Bfprintf(outf, "tilenum,numcalls,total_ms,min_us,mean_us,max_us\n");
154
        for (i=0; i<MAXTILES; i++)
155
            if (g_actorCalls[i])
156
                Bfprintf(outf, "%d,%d,%f,%f,%f,%f\n", i, g_actorCalls[i], g_actorTotalMs[i],
157
                         1000*g_actorMinMs[i],
158
                         1000*g_actorTotalMs[i]/g_actorCalls[i],
159
                         1000*g_actorMaxMs[i]);
160
        Bfclose(outf);
161
 
162
        OSD_Printf("Wrote timing data to \"%s.*.csv\"\n", basefn);
163
finish:
164
        Bfree(fullfn);
165
        return;
166
    }
167
    else
168
    {
169
        // If not writing out CSV files, print timing data to log instead.
170
 
171
        char buf[32];
172
        int32_t maxlen = 0;
4178 helixhorne 173
        int32_t haveev=0, haveac=0;
3946 helixhorne 174
 
175
        for (i=0; i<MAXEVENTS; i++)
176
        {
177
            int32_t len = Bstrlen(EventNames[i]+nn);
178
            Bassert(len < (int32_t)sizeof(buf));
179
            maxlen = max(len, maxlen);
180
        }
181
 
182
        for (i=0; i<MAXEVENTS; i++)
183
            if (g_eventCalls[i])
184
            {
185
                int32_t n=Bsprintf(buf, "%s", EventNames[i]+nn);
186
 
4178 helixhorne 187
                if (!haveev)
188
                {
189
                    haveev = 1;
190
                    OSD_Printf("\n  -- event times: [event]={ total calls, total time [ms], mean time/call [us] }\n");
191
                }
192
 
3946 helixhorne 193
                for (; n<maxlen; n++)
194
                    buf[n] = ' ';
195
                buf[maxlen] = 0;
196
 
197
                OSD_Printf("  [%s]={ %8d, %10.3f, %10.3f },\n",
198
                           buf, g_eventCalls[i], g_eventTotalMs[i],
199
                           1000*g_eventTotalMs[i]/g_eventCalls[i]);
200
            }
201
 
202
        for (i=0; i<MAXTILES; i++)
203
            if (g_actorCalls[i])
4178 helixhorne 204
            {
205
                if (!haveac)
206
                {
207
                    haveac = 1;
208
                    OSD_Printf("\n  -- actor times: [tile]={ total calls, total time [ms], {min,mean,max} time/call [us] }\n");
209
                }
210
 
3946 helixhorne 211
                OSD_Printf("  [%5d]={ %8d, %9.3f, %9.3f, %9.3f, %9.3f },\n",
212
                           i, g_actorCalls[i], g_actorTotalMs[i],
213
                           1000*g_actorMinMs[i],
214
                           1000*g_actorTotalMs[i]/g_actorCalls[i],
215
                           1000*g_actorMaxMs[i]);
4178 helixhorne 216
            }
3946 helixhorne 217
    }
2842 helixhorne 218
}
219
 
3319 helixhorne 220
////////// ERROR REPORTING //////////
3320 helixhorne 221
#define EL_MAXERRORS 20
3319 helixhorne 222
static int32_t el_numErrors=0, el_tooMuchErrors;
223
static char *el_errorMsgs[EL_MAXERRORS];
4134 helixhorne 224
int8_t el_addNewErrors = 1;  // add new errors to display?
2827 helixhorne 225
 
3319 helixhorne 226
// Compare against all other error messages.
227
// Strictly seen, this is quadratic-time, but EL_MAXERRORS is small and
228
// errors should be fixed anyway.
229
static int32_t cmp_against_others(const char *str, int32_t slen)
230
{
231
    int32_t i;
232
    for (i=0; i<el_numErrors; i++)
233
        if (!Bstrncmp(str, el_errorMsgs[i], slen))
234
            return 1;
235
    return 0;
236
}
237
 
4118 helixhorne 238
LUNATIC_EXTERN void El_OnError(const char *str)
3319 helixhorne 239
{
4134 helixhorne 240
    if (el_addNewErrors && !el_tooMuchErrors)
3319 helixhorne 241
    {
242
        char *errstr = NULL;
243
        const char *nl = Bstrchr(str, '\n');
244
 
245
        // First, check whether the error message matches an already saved one
246
        if (nl)
247
        {
248
            // cut off string after the newline
249
            if (cmp_against_others(str, nl-str))
250
                return;
251
        }
252
        else
253
        {
254
            // save string fully
255
            if (cmp_against_others(str, Bstrlen(str)))
256
                return;
257
        }
258
 
259
        // If the (EL_MAXERRORS+1)'th distinct error appeared, we have too many.
260
        if (el_numErrors==EL_MAXERRORS)
261
        {
262
            el_tooMuchErrors = 1;
263
            return;
264
        }
265
 
266
        // Otherwise, allocate storage for the potentially clipped error string...
267
        if (nl)
268
        {
4491 helixhorne 269
            errstr = (char *)Xmalloc(nl-str+1);
270
            Bmemcpy(errstr, str, nl-str);
271
            errstr[nl-str] = 0;
3319 helixhorne 272
        }
273
        else
274
        {
4491 helixhorne 275
            errstr = Xstrdup(str);
3319 helixhorne 276
        }
277
 
278
        // ...and save it:
4491 helixhorne 279
        el_errorMsgs[el_numErrors++] = errstr;
3319 helixhorne 280
    }
281
}
282
 
283
void El_ClearErrors(void)
284
{
285
    int32_t i;
286
    for (i=0; i<EL_MAXERRORS; i++)
287
    {
288
        Bfree(el_errorMsgs[i]);
289
        el_errorMsgs[i] = NULL;
290
    }
291
    el_numErrors = el_tooMuchErrors = 0;
292
}
293
 
294
void El_DisplayErrors(void)
295
{
296
    int32_t i;
297
    for (i=0; i<el_numErrors; i++)
298
        printext256(8, 8+8*i, 242, 0, el_errorMsgs[i], 0);
299
    if (el_tooMuchErrors)
300
        printext256(8, 8+8*EL_MAXERRORS, 242, 0, "(more distinct errors ...)", 0);
301
}
302
 
303
 
3148 helixhorne 304
////////// STATE CREATION/DESTRUCTIION //////////
305
 
3352 helixhorne 306
static int our_traceback_CF(lua_State *L)
307
{
308
    Bassert(lua_gettop(L)==1);
309
 
310
    if (lua_type(L, 1)==LUA_TBOOLEAN)
311
    {
312
        lua_pushvalue(L, 1);  // duplicate it
313
        return 1;  // and tell Lua to return it
314
    }
315
 
316
    Bassert(lua_type(L, 1)==LUA_TSTRING);
317
 
318
    // call debug.traceback with the string
319
    L_PushDebugTraceback(L);
320
    lua_pushvalue(L, 1);
321
    lua_call(L, 1, 1);
322
    Bassert(lua_gettop(L)==2);  // Lua will pop off args
323
 
3535 helixhorne 324
    if (g_tweakTracebackMsg)
325
    {
326
        // Get tweak_traceback_msg() onto the stack.
327
        lua_pushlightuserdata(L, &g_tweakTracebackMsg);
328
        lua_gettable(L, LUA_REGISTRYINDEX);
329
 
330
        lua_pushvalue(L, -2);  // push copy of error message string
331
        Bassert(lua_type(L, -1)==LUA_TSTRING);
332
 
333
        // Call tweak_traceback_msg(). CAREFUL, it's unprotected!
334
        lua_call(L, 1, 1);
335
    }
336
 
3352 helixhorne 337
    return 1;
338
}
339
 
3535 helixhorne 340
// Registers a function: str = tweak_traceback_msg(str)
341
static int32_t SetTweakTracebackMsg_CF(lua_State *L)
342
{
343
    Bassert(lua_gettop(L)==1);
344
    L_CheckAndRegisterFunction(L, &g_tweakTracebackMsg);
345
    g_tweakTracebackMsg = 1;
346
    return 0;
347
}
348
 
349
 
3520 helixhorne 350
////// Lua C-API interfaces for C game functions that may call events.
351
// http://www.freelists.org/post/luajit/intermitten-lua-pcall-crash-on-x86-64-linux,1
352
 
353
// Some of these are duplicate declarations:
4766 hendricks2 354
#ifdef __cplusplus
355
extern "C" {
356
#endif
3520 helixhorne 357
extern void P_AddWeaponMaybeSwitchI(int32_t snum, int32_t weap);
358
extern void P_CheckWeaponI(int32_t snum);
359
extern int32_t A_ShootWithZvel(int32_t i, int32_t atwith, int32_t override_zvel);
360
extern int32_t A_Spawn(int32_t j, int32_t pn);
361
extern void VM_FallSprite(int32_t i);
5039 hendricks2 362
extern int32_t VM_ResetPlayer2(int32_t snum, int32_t flags);
3520 helixhorne 363
extern void A_RadiusDamage(int32_t i, int32_t r, int32_t, int32_t, int32_t, int32_t);
364
extern void G_OperateSectors(int32_t sn, int32_t ii);
365
extern void G_OperateActivators(int32_t low,int32_t snum);
366
extern int32_t A_InsertSprite(int32_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int32_t s_pn,int32_t s_s,
367
                              int32_t s_xr,int32_t s_yr,int32_t s_a,int32_t s_ve,int32_t s_zv,int32_t s_ow,int32_t s_ss);
368
extern void A_AddToDeleteQueue(int32_t i);
369
extern int32_t A_PlaySound(uint32_t num, int32_t i);
3821 helixhorne 370
extern void A_DeleteSprite(int32_t s);
3948 helixhorne 371
extern void G_ShowView(int32_t x, int32_t y, int32_t z, int32_t a, int32_t horiz, int32_t sect,
372
                       int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t unbiasedp);
4766 hendricks2 373
extern void G_GameExit(const char *msg);
374
#ifdef __cplusplus
375
}
376
#endif
3520 helixhorne 377
 
378
#define LARG(index) lua_tointeger(L, index)
379
 
380
#define ONE_ARG LARG(1)
381
#define TWO_ARGS LARG(1), LARG(2)
382
#define THREE_ARGS LARG(1), LARG(2), LARG(3)
383
 
384
#define CALL_WITH_RET(Name, ...) \
385
    int32_t ret = Name(__VA_ARGS__); \
386
    lua_pushinteger(L, ret); \
387
    return 1
388
 
389
#define CALL_WITHOUT_RET(Name, ...) \
390
    Name(__VA_ARGS__); \
391
    return 0
392
 
393
#define DEFINE_RET_CFUNC(Name, ...) \
394
static int32_t Name##_CF(lua_State *L) \
395
{ \
396
    CALL_WITH_RET(Name, __VA_ARGS__); \
397
}
398
 
399
#define DEFINE_VOID_CFUNC(Name, ...) \
400
static int32_t Name##_CF(lua_State *L) \
401
{ \
402
    CALL_WITHOUT_RET(Name, __VA_ARGS__); \
403
}
404
 
405
// NOTE: player struct -> player index -> player struct ugliness because
406
// pointers to FFI cdata apparently can't be reliably passed via lua_getpointer().
407
// Not to mention that lua_getpointer() returns _const_ void*.
408
DEFINE_VOID_CFUNC(P_AddWeaponMaybeSwitchI, TWO_ARGS)
409
DEFINE_VOID_CFUNC(P_CheckWeaponI, ONE_ARG)
410
DEFINE_RET_CFUNC(A_ShootWithZvel, THREE_ARGS)
411
DEFINE_RET_CFUNC(A_Spawn, TWO_ARGS)
412
DEFINE_VOID_CFUNC(VM_FallSprite, ONE_ARG)
5039 hendricks2 413
DEFINE_RET_CFUNC(VM_ResetPlayer2, TWO_ARGS)
3520 helixhorne 414
DEFINE_VOID_CFUNC(A_RadiusDamage, LARG(1), LARG(2), LARG(3), LARG(4), LARG(5), LARG(6))
415
DEFINE_VOID_CFUNC(G_OperateSectors, TWO_ARGS)
416
DEFINE_VOID_CFUNC(G_OperateActivators, TWO_ARGS)
417
DEFINE_RET_CFUNC(A_InsertSprite, LARG(1), LARG(2), LARG(3), LARG(4), LARG(5), LARG(6),
418
                 LARG(7), LARG(8), LARG(9), LARG(10), LARG(11), LARG(12), LARG(13))
419
DEFINE_VOID_CFUNC(A_AddToDeleteQueue, ONE_ARG)
420
DEFINE_RET_CFUNC(A_PlaySound, TWO_ARGS)
3821 helixhorne 421
DEFINE_VOID_CFUNC(A_DeleteSprite, ONE_ARG)
3948 helixhorne 422
DEFINE_VOID_CFUNC(G_ShowView, LARG(1), LARG(2), LARG(3), LARG(4), LARG(5), LARG(6),
423
                  LARG(7), LARG(8), LARG(9), LARG(10), LARG(11))
3520 helixhorne 424
 
425
#define CFUNC_REG(Name) { #Name, Name##_CF }
426
 
4286 helixhorne 427
static struct { const char *name; lua_CFunction func; } cfuncs[] =
3520 helixhorne 428
{
429
    CFUNC_REG(P_AddWeaponMaybeSwitchI),
430
    CFUNC_REG(P_CheckWeaponI),
431
    CFUNC_REG(A_ShootWithZvel),
432
    CFUNC_REG(A_Spawn),
433
    CFUNC_REG(VM_FallSprite),
434
    CFUNC_REG(VM_ResetPlayer2),
435
    CFUNC_REG(A_RadiusDamage),
436
    CFUNC_REG(G_OperateSectors),
437
    CFUNC_REG(G_OperateActivators),
438
    CFUNC_REG(A_InsertSprite),
439
    CFUNC_REG(A_Spawn),
440
    CFUNC_REG(A_AddToDeleteQueue),
441
    CFUNC_REG(A_PlaySound),
3821 helixhorne 442
    CFUNC_REG(A_DeleteSprite),
3948 helixhorne 443
    CFUNC_REG(G_ShowView),
3520 helixhorne 444
};
445
 
446
// Creates a global table "CF" containing the functions from cfuncs[].
447
static void El_PushCFunctions(lua_State *L)
448
{
449
    int32_t i;
450
 
451
    lua_newtable(L);
452
 
453
    for (i=0; i<(signed)sizeof(cfuncs)/(signed)sizeof(cfuncs[0]); i++)
454
    {
455
        lua_pushstring(L, cfuncs[i].name);
456
        lua_pushcfunction(L, cfuncs[i].func);
457
        lua_settable(L, -3);
458
    }
459
 
460
    lua_setglobal(L, "CF");
461
}
462
 
463
//////
464
 
4119 helixhorne 465
LUNATIC_CB int32_t (*El_RestoreGamevars)(const char *savecode);
466
 
3148 helixhorne 467
static void El_StateSetup(lua_State *L)
2034 helixhorne 468
{
2827 helixhorne 469
    luaopen_lpeg(L);
470
    lua_pop(L, lua_gettop(L));  // pop off whatever lpeg leaves on the stack
2034 helixhorne 471
 
2329 helixhorne 472
    // create misc. global functions in the Lua state
3352 helixhorne 473
    lua_pushcfunction(L, SetEvent_CF);
3320 helixhorne 474
    lua_setglobal(L, "gameevent_internal");
3352 helixhorne 475
    lua_pushcfunction(L, SetActor_CF);
3315 helixhorne 476
    lua_setglobal(L, "gameactor_internal");
3535 helixhorne 477
    lua_pushcfunction(L, SetTweakTracebackMsg_CF);
478
    lua_setglobal(L, "set_tweak_traceback_internal");
2329 helixhorne 479
 
3520 helixhorne 480
    El_PushCFunctions(L);
481
 
2827 helixhorne 482
    Bassert(lua_gettop(L)==0);
3352 helixhorne 483
 
3375 helixhorne 484
    // This is for engine-side Lua:
3352 helixhorne 485
    lua_pushcfunction(L, &our_traceback_CF);
2034 helixhorne 486
}
487
 
4766 hendricks2 488
static void El_OnOutOfMem(void)
489
{
490
    G_GameExit("Out of memory in Lunatic.");
491
}
492
 
3148 helixhorne 493
// 0: success, <0: failure
494
int32_t El_CreateState(L_State *estate, const char *name)
2034 helixhorne 495
{
3557 helixhorne 496
    int32_t i;
497
 
3788 helixhorne 498
    if (!g_timingInited)
499
    {
500
        g_timingInited = 1;
501
        for (i=0; i<MAXTILES; i++)
502
            g_actorMinMs[i] = 1e308;
503
    }
3557 helixhorne 504
 
3319 helixhorne 505
    L_ErrorFunc = El_OnError;
3352 helixhorne 506
    L_OutOfMemFunc = El_OnOutOfMem;
3319 helixhorne 507
 
3148 helixhorne 508
    return L_CreateState(estate, name, &El_StateSetup);
2034 helixhorne 509
}
510
 
3148 helixhorne 511
void El_DestroyState(L_State *estate)
2034 helixhorne 512
{
3148 helixhorne 513
    L_DestroyState(estate);
3788 helixhorne 514
 
3790 helixhorne 515
    g_tweakTracebackMsg = 0;
516
 
3788 helixhorne 517
    // XXX: It would be cleaner to also clear stuff like g_elEvents[], but
518
    // currently, when the game Lua state is recreated, the array should have
519
    // the same values as before, so we're skipping that for now.
2034 helixhorne 520
}
2329 helixhorne 521
 
2747 helixhorne 522
 
523
////////// Lua_CFunctions //////////
524
 
525
// gameevent(EVENT_..., lua_function)
3352 helixhorne 526
static int32_t SetEvent_CF(lua_State *L)
2329 helixhorne 527
{
2827 helixhorne 528
    int32_t eventidx;
2329 helixhorne 529
 
3320 helixhorne 530
    Bassert(lua_gettop(L) == 2);
2827 helixhorne 531
    eventidx = luaL_checkint(L, 1);
3320 helixhorne 532
    Bassert((unsigned)eventidx < MAXEVENTS);
2827 helixhorne 533
 
3148 helixhorne 534
    L_CheckAndRegisterFunction(L, &g_elEvents[eventidx]);
2747 helixhorne 535
    g_elEvents[eventidx] = 1;
2329 helixhorne 536
 
2747 helixhorne 537
    return 0;
538
}
2329 helixhorne 539
 
3315 helixhorne 540
// gameactor(actortile, strength, act, mov, movflags, lua_function)
3352 helixhorne 541
static int32_t SetActor_CF(lua_State *L)
2747 helixhorne 542
{
3629 helixhorne 543
    int32_t actortile;
3315 helixhorne 544
    el_actor_t *a;
2827 helixhorne 545
 
3315 helixhorne 546
    Bassert(lua_gettop(L) == 6);
547
 
2827 helixhorne 548
    actortile = luaL_checkint(L, 1);
3315 helixhorne 549
    Bassert((unsigned)actortile < MAXTILES);
2827 helixhorne 550
 
3315 helixhorne 551
    a = &g_elActors[actortile];
552
    L_CheckAndRegisterFunction(L, a);
553
 
3629 helixhorne 554
    // Set actor properties. They can only be nil if we're chaining actor code.
3315 helixhorne 555
 
3629 helixhorne 556
    if (!lua_isnil(L, 2))
557
        a->strength = luaL_checkint(L, 2);
558
    if (!lua_isnil(L, 5))
559
        a->movflags = luaL_checkint(L, 5);
3315 helixhorne 560
 
3629 helixhorne 561
    if (!lua_isnil(L, 3))
562
        Bmemcpy(&a->act, lua_topointer(L, 3), sizeof(con_action_t));
563
    if (!lua_isnil(L, 4))
564
        Bmemcpy(&a->mov, lua_topointer(L, 4), sizeof(con_move_t));
565
 
566
    a->haveit = 1;
567
 
2329 helixhorne 568
    return 0;
569
}
570
 
2747 helixhorne 571
//////////////////////////////
572
 
3148 helixhorne 573
static int32_t call_regd_function3(lua_State *L, void *keyaddr,
574
                                   int32_t iActor, int32_t iPlayer, int32_t lDist)
2329 helixhorne 575
{
3557 helixhorne 576
#if !defined NDEBUG
3948 helixhorne 577
    const int32_t top = lua_gettop(L);
3557 helixhorne 578
#endif
3375 helixhorne 579
    lua_pushcfunction(L, &our_traceback_CF);
580
 
2827 helixhorne 581
    // get the Lua function from the registry
582
    lua_pushlightuserdata(L, keyaddr);
583
    lua_gettable(L, LUA_REGISTRYINDEX);
2329 helixhorne 584
 
2746 helixhorne 585
    lua_pushinteger(L, iActor);
586
    lua_pushinteger(L, iPlayer);
587
    lua_pushinteger(L, lDist);
588
 
2329 helixhorne 589
    // -- call it! --
3948 helixhorne 590
    {
591
        const int32_t i = lua_pcall(L, 3, 0, -5);
592
        const int32_t haveerr = (i != 0);
3345 helixhorne 593
 
3948 helixhorne 594
        Bassert(lua_iscfunction(L, -1-haveerr));
595
        lua_remove(L, -1-haveerr);
2329 helixhorne 596
 
3948 helixhorne 597
        Bassert(lua_gettop(L) == top+haveerr);
598
 
599
        return i;
600
    }
2747 helixhorne 601
}
602
 
3352 helixhorne 603
static int32_t g_eventIdx = 0;
604
static void El_EventErrorPrint(const char *errmsg)
605
{
606
    OSD_Printf(OSD_ERROR "event \"%s\" runtime error: %s\n",
607
               EventNames[g_eventIdx], errmsg);
608
}
609
 
3526 helixhorne 610
int32_t El_CallEvent(L_State *estate, int32_t eventidx, int32_t iActor, int32_t iPlayer, int32_t lDist, int32_t *iReturn)
2747 helixhorne 611
{
612
    // XXX: estate must be the one where the events were registered...
613
    //      make a global?
614
 
615
    lua_State *const L = estate->L;
3320 helixhorne 616
    int32_t i;
2747 helixhorne 617
 
3601 helixhorne 618
    const int32_t o_RETURN = g_RETURN;
619
    g_RETURN = *iReturn;
3526 helixhorne 620
 
3320 helixhorne 621
    g_elCallDepth++;
622
    i = call_regd_function3(L, &g_elEvents[eventidx], iActor, iPlayer, lDist);
623
    g_elCallDepth--;
2747 helixhorne 624
 
3601 helixhorne 625
    *iReturn = g_RETURN;
626
    g_RETURN = o_RETURN;
3526 helixhorne 627
 
3352 helixhorne 628
    if (i != 0)
2329 helixhorne 629
    {
3593 helixhorne 630
        g_elEventError = 1;
3352 helixhorne 631
        g_eventIdx = eventidx;
632
        return L_HandleError(L, i, &El_EventErrorPrint);
2329 helixhorne 633
    }
634
 
635
    return 0;
636
}
2747 helixhorne 637
 
3352 helixhorne 638
static int32_t g_actorTile, g_iActor;
639
static void El_ActorErrorPrint(const char *errmsg)
640
{
641
    OSD_Printf(OSD_ERROR "actor %d (sprite %d) runtime error: %s\n",
642
               g_actorTile, g_iActor, errmsg);
643
}
644
 
3148 helixhorne 645
int32_t El_CallActor(L_State *estate, int32_t actortile, int32_t iActor, int32_t iPlayer, int32_t lDist)
2747 helixhorne 646
{
647
    lua_State *const L = estate->L;
3320 helixhorne 648
    int32_t i;
2747 helixhorne 649
 
3320 helixhorne 650
    g_elCallDepth++;
651
    i = call_regd_function3(L, &g_elActors[actortile], iActor, iPlayer, lDist);
652
    g_elCallDepth--;
2747 helixhorne 653
 
3352 helixhorne 654
    if (i != 0)
2747 helixhorne 655
    {
3352 helixhorne 656
        g_actorTile = actortile;
657
        g_iActor = iActor;
658
        return L_HandleError(L, i, &El_ActorErrorPrint);
2747 helixhorne 659
    }
660
 
661
    return 0;
662
}