Subversion Repositories eduke32

Rev

Rev 6224 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2611 helixhorne 1
-- INTERNAL
2034 helixhorne 2
-- definitions of BUILD and game types for the Lunatic Interpreter
3
 
3256 helixhorne 4
local require = require
2034 helixhorne 5
local ffi = require("ffi")
2863 helixhorne 6
local ffiC = ffi.C
2034 helixhorne 7
 
3821 helixhorne 8
-- Lua C API functions.
9
local CF = CF
10
 
3247 helixhorne 11
local bit = bit
3891 helixhorne 12
local coroutine = coroutine
3056 helixhorne 13
local string = string
14
local table = table
3253 helixhorne 15
local math = math
3256 helixhorne 16
 
17
local assert = assert
18
local error = error
3642 helixhorne 19
local getfenv = getfenv
3597 helixhorne 20
local getmetatable = getmetatable
3256 helixhorne 21
local ipairs = ipairs
22
local loadstring = loadstring
23
local pairs = pairs
5026 helixhorne 24
local pcall = pcall
3256 helixhorne 25
local rawget = rawget
26
local rawset = rawset
3597 helixhorne 27
local select = select
3256 helixhorne 28
local setmetatable = setmetatable
29
local setfenv = setfenv
30
local tonumber = tonumber
3319 helixhorne 31
local tostring = tostring
3256 helixhorne 32
local type = type
33
 
3914 helixhorne 34
-- Create a new module for passing stuff to other modules.
35
local lprivate = {}
36
require("package").loaded.lprivate = lprivate
37
 
3641 helixhorne 38
require("jit.opt").start("maxmcode=10240")  -- in KiB
39
 
3056 helixhorne 40
-- The "gv" global will provide access to C global *scalars* and safe functions.
3406 helixhorne 41
-- NOTE: This exposes C library functions from e.g. the global C namespace, but
42
-- without their declarations, they will be sitting there like a stone.
43
local gv_ = {}
3409 helixhorne 44
-- [key]=<boolean> forbids, [key]=<non-boolean (e.g. table, function)> overrides
3406 helixhorne 45
local gv_access = {}
2786 helixhorne 46
 
2842 helixhorne 47
-- This is for declarations of arrays or pointers which should not be
3060 helixhorne 48
-- accessible through the "gv" global. The "defs_common" module will
3056 helixhorne 49
-- use this function.
3060 helixhorne 50
--
3530 helixhorne 51
-- Notes: do not declare multiple scalars on one line (this is bad:
52
-- "int32_t a, b"). Do not name array arguments (or add a space
3227 helixhorne 53
-- between the identifier and the '[' instead).
3512 helixhorne 54
function decl(str, ...)
3227 helixhorne 55
    -- NOTE that the regexp also catches non-array/non-function identifiers
56
    -- like "user_defs ud;"
2786 helixhorne 57
    for varname in string.gmatch(str, "([%a_][%w_]*)[[(;]") do
3406 helixhorne 58
        if (ffiC._DEBUG_LUNATIC ~= 0) then
59
            print("FORBID "..varname)
60
        end
61
        gv_access[varname] = true
2786 helixhorne 62
    end
63
 
3512 helixhorne 64
    ffi.cdef(str, ...)
2786 helixhorne 65
end
66
 
4147 helixhorne 67
lprivate.decl = decl
68
 
4236 helixhorne 69
ffi.cdef[[
70
enum {
71
    LUNATIC_CLIENT_MAPSTER32 = 0,
72
    LUNATIC_CLIENT_EDUKE32 = 1,
73
 
74
    LUNATIC_CLIENT = LUNATIC_CLIENT_EDUKE32
75
}
76
]]
77
 
3320 helixhorne 78
-- Load the definitions common to the game's and editor's Lua interface.
3056 helixhorne 79
local defs_c = require("defs_common")
3256 helixhorne 80
local cansee = defs_c.cansee
3248 helixhorne 81
local strip_const = defs_c.strip_const
3253 helixhorne 82
local setmtonce = defs_c.setmtonce
2317 helixhorne 83
 
3319 helixhorne 84
-- Must be after loading "defs_common" which redefines "print" to use
85
-- OSD_Printf()
3642 helixhorne 86
local print, printf = print, defs_c.printf
3253 helixhorne 87
 
3319 helixhorne 88
 
3056 helixhorne 89
---=== EDuke32 game definitions ===---
2668 helixhorne 90
 
3564 helixhorne 91
local INV_NAMES = {
92
    "STEROIDS",
93
    "SHIELD",
94
    "SCUBA",
95
    "HOLODUKE",
96
    "JETPACK",
97
    "DUMMY1",
98
    "ACCESS",
99
    "HEATS",
100
    "DUMMY2",
101
    "FIRSTAID",
102
    "BOOTS",
103
}
104
 
105
local WEAPON_NAMES = {
106
    "KNEE",
107
    "PISTOL",
108
    "SHOTGUN",
109
    "CHAINGUN",
110
    "RPG",
111
    "HANDBOMB",
112
    "SHRINKER",
113
    "DEVISTATOR",
114
    "TRIPBOMB",
115
    "FREEZE",
116
    "HANDREMOTE",
117
    "GROW",
118
}
119
 
2317 helixhorne 120
---- game structs ----
2786 helixhorne 121
 
4030 helixhorne 122
lprivate.GET = defs_c.conststruct(INV_NAMES)
123
lprivate.WEAPON = defs_c.conststruct(WEAPON_NAMES)
2786 helixhorne 124
 
4030 helixhorne 125
ffi.cdef([[
2786 helixhorne 126
enum {
4030 helixhorne 127
    GET_MAX = 11,
128
    MAX_WEAPONS = 12,
2786 helixhorne 129
    MAXPLAYERS = 16,
3928 helixhorne 130
    GTICSPERSEC = 30,  // The real number of movement updates per second
2786 helixhorne 131
};
3564 helixhorne 132
]])
2786 helixhorne 133
 
3227 helixhorne 134
ffi.cdef[[
2864 helixhorne 135
struct action {
136
    int16_t startframe, numframes;
137
    int16_t viewtype, incval, delay;
5849 hendricks2 138
    uint16_t flags;
2864 helixhorne 139
};
140
 
141
struct move {
142
    int16_t hvel, vvel;
143
};
144
 
3463 helixhorne 145
#pragma pack(push,1)
2864 helixhorne 146
typedef struct { int32_t id; struct move mv; } con_move_t;
147
typedef struct { int32_t id; struct action ac; } con_action_t;
3463 helixhorne 148
#pragma pack(pop)
2864 helixhorne 149
 
2869 helixhorne 150
typedef struct {
151
    int32_t id;
152
    con_action_t act;
153
    con_move_t mov;
154
    int32_t movflags;
155
} con_ai_t;
3227 helixhorne 156
]]
2869 helixhorne 157
 
3928 helixhorne 158
defs_c.bitint_new_struct_type("int16_t", "SBit16")
3643 helixhorne 159
defs_c.bitint_new_struct_type("int32_t", "SBit32")
3928 helixhorne 160
defs_c.bitint_new_struct_type("uint32_t", "UBit32")
3643 helixhorne 161
 
3227 helixhorne 162
-- Struct template for actor_t. It already has 'const' fields (TODO: might need
163
-- to make more 'const'), but still has array members exposed, so is unsuited
164
-- for external exposure.
165
local ACTOR_STRUCT = [[
3968 helixhorne 166
struct {
3864 helixhorne 167
    const int32_t t_data[10];
2869 helixhorne 168
    const struct move mv;
169
    const struct action ac;
3922 helixhorne 170
    const uint16_t actiontics;
2864 helixhorne 171
 
3643 helixhorne 172
]]..defs_c.bitint_member("SBit32", "flags")..[[
3314 helixhorne 173
    vec3_t bpos; //12b
3261 helixhorne 174
    int32_t floorz,ceilingz,lastvx,lastvy; //16b
175
    int32_t lasttransport; //4b
176
 
3253 helixhorne 177
    const int16_t picnum;
178
    int16_t ang, extra;
179
    const int16_t owner;
3928 helixhorne 180
    // NOTE: not to be confused with .movflags:
181
]]..defs_c.bitint_member("SBit16", "_movflag")..[[
182
    int16_t tempang, timetosleep;
2193 helixhorne 183
 
3874 helixhorne 184
    int16_t stayputsect;
3253 helixhorne 185
    const int16_t dispicnum;
3922 helixhorne 186
    // Movement flags, sprite[i].hitag in C-CON.
187
    // XXX: more research where it was used in EDuke32's C code? (also .lotag <-> actiontics)
188
    // XXX: what if CON code knew of the above implementation detail?
189
]]..defs_c.bitint_member("UBit16", "movflags")..[[
190
    int16_t cgg;
3559 helixhorne 191
 
192
    const int16_t lightId, lightcount, lightmaxrange;
3932 helixhorne 193
    // NOTE: on 32-bit, C's lightptr+filler <=> this dummy:
3559 helixhorne 194
    const union { intptr_t ptr; uint64_t dummy; } _light;
3227 helixhorne 195
}
2786 helixhorne 196
]]
2193 helixhorne 197
 
3435 helixhorne 198
local bcarray = require("bcarray")
199
 
3445 helixhorne 200
local bcheck = require("bcheck")
201
local check_sector_idx, check_tile_idx = bcheck.sector_idx, bcheck.tile_idx
3526 helixhorne 202
local check_sprite_idx = bcheck.sprite_idx
3445 helixhorne 203
local check_weapon_idx, check_inventory_idx = bcheck.weapon_idx, bcheck.inventory_idx
204
local check_sound_idx = bcheck.sound_idx
3883 helixhorne 205
local check_number = bcheck.number
3954 helixhorne 206
local check_type = bcheck.type
3445 helixhorne 207
 
3564 helixhorne 208
bcarray.new("int16_t", 64, "loogie", "int16_x_64")  -- TODO: randomize member names
209
bcarray.new("int16_t", ffiC.MAX_WEAPONS, "weapon", "int16_x_MAX_WEAPONS", WEAPON_NAMES)
210
bcarray.new("int16_t", ffiC.GET_MAX, "inventory", "int16_x_GET_MAX", INV_NAMES)
3435 helixhorne 211
 
3530 helixhorne 212
-- NOTE: writing e.g. "ps.jetpack_on" in Lua when "ps.jetpack_on~=0" was meant
213
-- is probably one of the most commonly committed errors, so we make it a bool
214
-- type instead of uint8_t. The only issue is that if CON coders used these
215
-- fields to store more than just one bit, we're in trouble.
216
-- This will need to be documented and frozen for release.
3227 helixhorne 217
local DUKEPLAYER_STRUCT = [[
3458 helixhorne 218
__attribute__((packed)) struct {
2786 helixhorne 219
    vec3_t pos, opos, vel, npos;
4710 helixhorne 220
    vec2_t bobpos, fric;
2786 helixhorne 221
    int32_t truefz, truecz, player_par;
222
    int32_t randomflamex, exitx, exity;
223
    int32_t runspeed, max_player_health, max_shield_amount;
3109 helixhorne 224
    int32_t autostep, autostep_sbw;
2786 helixhorne 225
 
226
    uint32_t interface_toggle_flag;
227
 
3409 helixhorne 228
    int32_t pipebombControl, pipebombLifetime, pipebombLifetimeVar;
229
    int32_t tripbombControl, tripbombLifetime, tripbombLifetimeVar;
230
 
3366 helixhorne 231
    int32_t zrange;
232
    int16_t angrange, autoaimang;
233
 
2786 helixhorne 234
    uint16_t max_actors_killed, actors_killed;
4217 helixhorne 235
]]..defs_c.bitint_member("UBit16", "gotweapon")..[[
236
    uint16_t zoom;
3227 helixhorne 237
 
3435 helixhorne 238
    int16_x_64 loogiex;
239
    int16_x_64 loogiey;
2786 helixhorne 240
    int16_t sbs, sound_pitch;
241
 
3253 helixhorne 242
    int16_t ang, oang, angvel;
3653 helixhorne 243
    const<S> int16_t cursectnum;
3253 helixhorne 244
    int16_t look_ang, last_extra, subweapon;
3435 helixhorne 245
    int16_x_MAX_WEAPONS max_ammo_amount;
246
    int16_x_MAX_WEAPONS ammo_amount;
247
    int16_x_GET_MAX inv_amount;
3653 helixhorne 248
    const<I-> int16_t wackedbyactor;
3652 helixhorne 249
    int16_t pyoff, opyoff;
2786 helixhorne 250
 
251
    int16_t horiz, horizoff, ohoriz, ohorizoff;
5192 helixhorne 252
    const<I-> int16_t newowner;
3253 helixhorne 253
    int16_t jumping_counter, airleft;
3498 helixhorne 254
    int16_t fta;
3653 helixhorne 255
    const<Q> int16_t ftq;
256
    const int16_t access_wallnum, access_spritenum;
2786 helixhorne 257
    int16_t got_access, weapon_ang, visibility;
3249 helixhorne 258
    int16_t somethingonplayer, on_crane;
259
    const int16_t i;
3253 helixhorne 260
    const int16_t one_parallax_sectnum;
2786 helixhorne 261
    int16_t random_club_frame, one_eighty_count;
3653 helixhorne 262
    const<I-> int16_t dummyplayersprite;
3254 helixhorne 263
    int16_t extra_extra8;
264
    int16_t actorsqu, timebeforeexit;
3653 helixhorne 265
    const<X-> int16_t customexitsound;
3254 helixhorne 266
    int16_t last_pissed_time;
3227 helixhorne 267
 
3435 helixhorne 268
    int16_x_MAX_WEAPONS weaprecs;
2786 helixhorne 269
    int16_t weapon_sway, crack_time, bobcounter;
270
 
271
    int16_t orotscrnang, rotscrnang, dead_flag;   // JBF 20031220: added orotscrnang
272
    int16_t holoduke_on, pycount;
2854 helixhorne 273
    int16_t transporter_hold;
2786 helixhorne 274
 
275
    uint8_t max_secret_rooms, secret_rooms;
276
    uint8_t frag, fraggedself, quick_kick, last_quick_kick;
3530 helixhorne 277
    uint8_t return_to_center;
278
    bool reloading;
3444 helixhorne 279
    const uint8_t weapreccnt;
2786 helixhorne 280
    uint8_t aim_mode, auto_aim, weaponswitch, movement_lock, team;
3652 helixhorne 281
    uint8_t tipincs, hbomb_hold_delay;
3653 helixhorne 282
    const<P> uint8_t frag_ps;
3652 helixhorne 283
    uint8_t kickback_pic;
2786 helixhorne 284
 
3530 helixhorne 285
    uint8_t gm;
286
    bool on_warping_sector;
287
    uint8_t footprintcount, hurt_delay;
288
    bool hbomb_on, jumping_toggle, rapid_fire_hold, on_ground;
3516 helixhorne 289
    // NOTE: there's array indexing with inven_icon, but always after a
290
    // bound check:
3530 helixhorne 291
    uint8_t inven_icon, buttonpalette;
292
    bool over_shoulder_on;
293
    uint8_t show_empty_weapon;
2786 helixhorne 294
 
3530 helixhorne 295
    bool jetpack_on, spritebridge;
296
    uint8_t lastrandomspot;  // unused
297
    bool scuba_on;
298
    uint8_t footprintpal;
299
    bool heat_on;
300
    uint8_t invdisptime;
2786 helixhorne 301
 
3530 helixhorne 302
    bool holster_weapon;
303
    uint8_t falling_counter, footprintshade;
3652 helixhorne 304
    uint8_t refresh_inventory;
3817 helixhorne 305
    const<W> uint8_t last_full_weapon;
2786 helixhorne 306
 
4179 helixhorne 307
    const uint8_t toggle_key_flag;
3530 helixhorne 308
    uint8_t knuckle_incs, knee_incs, access_incs;
2786 helixhorne 309
    uint8_t walking_snd_toggle, palookup, hard_landing, fist_incs;
310
 
4179 helixhorne 311
    int8_t numloogs, loogcnt;
312
    const int8_t scream_voice;
3653 helixhorne 313
    const<W-> int8_t last_weapon;
4179 helixhorne 314
    const int8_t cheat_phase;
315
    int8_t weapon_pos;
3653 helixhorne 316
    const<W-> int8_t wantweaponfire;
317
    const<W> int8_t curr_weapon;
2786 helixhorne 318
 
4260 helixhorne 319
    const uint8_t palette;
3444 helixhorne 320
    palette_t _pals;
3893 helixhorne 321
    int8_t _palsfadespeed, _palsfadenext, _palsfadeprio, _padding2;
3227 helixhorne 322
 
3407 helixhorne 323
    // NOTE: In C, the struct type has no name. We only have it here to define
324
    // a metatype later.
325
    const weaponaccess_t weapon;
326
    const int8_t _padding;
3227 helixhorne 327
}
2786 helixhorne 328
]]
2854 helixhorne 329
 
3469 helixhorne 330
local PROJECTILE_STRUCT = [[
331
struct {
332
    int32_t workslike, cstat;
333
    int32_t hitradius, range, flashcolor;
334
    const int16_t spawns;
3865 helixhorne 335
    const int16_t sound, isound;
336
    int16_t vel;
3469 helixhorne 337
    const int16_t decal, trail;
338
    int16_t tnum, drop;
3865 helixhorne 339
    int16_t offset, bounces;
340
    const int16_t bsound;
3469 helixhorne 341
    int16_t toffset;
342
    int16_t extra, extra_rand;
343
    int8_t sxrepeat, syrepeat, txrepeat, tyrepeat;
344
    int8_t shade, xrepeat, yrepeat, pal;
345
    int8_t movecnt;
346
    uint8_t clipdist;
3866 helixhorne 347
    int8_t filler[2];
348
    int32_t userdata;
3469 helixhorne 349
}
350
]]
351
 
3574 helixhorne 352
-- KEEPINSYNC weapondata_mt below.
353
local WEAPONDATA_STRUCT = "struct {"..table.concat(con_lang.wdata_members, ';').."; }"
354
 
3227 helixhorne 355
local randgen = require("randgen")
2786 helixhorne 356
 
3227 helixhorne 357
local ma_rand = randgen.new(true)  -- initialize to "random" (time-based) seed
358
local ma_count = nil
359
 
360
local function ma_replace_array(typestr, neltstr)
361
    local nelts = tonumber(neltstr)
362
    if (nelts==nil) then
363
        nelts = ffiC[neltstr]
364
        assert(type(nelts)=="number")
365
    end
366
 
367
    local strtab = { "const ", typestr.." " }
368
    for i=1,nelts do
369
        local ch1 = 97 + (ma_rand:getu32() % 25)  -- 'a'..'z'
3435 helixhorne 370
        strtab[i+2] = string.format("_%c%x%s", ch1, ma_count, (i<nelts) and "," or ";")
3227 helixhorne 371
        ma_count = ma_count+1
372
    end
373
 
374
    return table.concat(strtab)
375
end
376
 
3653 helixhorne 377
---=== Protection of scalars in (currently only) DukePlayer_t struct. ===---
378
-- This is more convenient than writing dozens of set-member methods.
379
local prot_scalar_chkfunc = {
380
    S = check_sector_idx,
381
    I = check_sprite_idx,
382
 
383
    P = bcheck.player_idx,
384
    W = check_weapon_idx,
385
    X = check_sound_idx,
386
    Q = bcheck.quote_idx,
387
}
388
 
389
local DukePlayer_prot_allowneg = {}  -- [<member name>] = true if setting <0 allowed
390
local DukePlayer_prot_chkfunc = {}  -- [<member name>] = <checking function>
391
 
392
local function ma_replace_scalar(what, typestr, membname)
393
    DukePlayer_prot_chkfunc[membname] = assert(prot_scalar_chkfunc[what:sub(1,1)])
394
    DukePlayer_prot_allowneg[membname] = (what:sub(2)=="-")
395
    return ma_replace_array(typestr, 1)
396
end
397
 
3227 helixhorne 398
-- Converts a template struct definition to an external one, in which arrays
399
-- have been substituted by randomly named scalar fields.
3653 helixhorne 400
-- <also_scalars>: also handle protected scalars like "const<W-> ..." etc.
401
local function mangle_arrays(structstr, also_scalars)
3227 helixhorne 402
    ma_count = 0
403
    -- NOTE: regexp only works for non-nested arrays and for one array per line.
3653 helixhorne 404
    structstr = structstr:gsub("const%s+([%w_]+)[^\n]+%[([%w_]+)%];", ma_replace_array)
405
 
406
    if (also_scalars) then
407
        -- One protected scalar per line, too.
408
        structstr = structstr:gsub("const<(.-)>%s+([%w_]-)%s+([%w_]-);", ma_replace_scalar)
409
    end
410
 
411
    return structstr
3227 helixhorne 412
end
413
 
3653 helixhorne 414
--print(mangle_arrays(DUKEPLAYER_STRUCT, true))
3227 helixhorne 415
 
3392 helixhorne 416
--- default defines etc.
417
local con_lang = require("con_lang")
4590 helixhorne 418
local xmath = require("xmath")
3392 helixhorne 419
 
3227 helixhorne 420
ffi.cdef([[
3407 helixhorne 421
typedef struct { int32_t _p; } weaponaccess_t;
422
 
2786 helixhorne 423
typedef struct {
3928 helixhorne 424
]]..defs_c.bitint_member("UBit32", "bits")..[[
4710 helixhorne 425
    int16_t fvel, svel, avel;
426
    int8_t horz, extbits;
2786 helixhorne 427
} input_t;
428
 
3458 helixhorne 429
typedef
430
]].. mangle_arrays(ACTOR_STRUCT) ..[[
431
actor_t;
432
 
433
typedef
3653 helixhorne 434
]].. mangle_arrays(DUKEPLAYER_STRUCT, true) ..[[
3458 helixhorne 435
DukePlayer_t;
436
 
3463 helixhorne 437
typedef __attribute__((packed)) struct {
2786 helixhorne 438
    DukePlayer_t *ps;
439
    input_t *sync;
440
 
441
    int32_t netsynctime;
442
    int16_t ping, filler;
443
    int32_t pcolor, pteam;
444
    uint8_t frags[MAXPLAYERS], wchoice[MAX_WEAPONS];
445
 
3109 helixhorne 446
    char vote, gotvote, pingcnt, playerquitflag, ready;
2786 helixhorne 447
    char user_name[32];
448
    uint32_t revision;
449
} playerdata_t;
3259 helixhorne 450
 
451
typedef struct {
3408 helixhorne 452
    int32_t cur, count;
453
    int32_t gunposx, lookhalfang;
454
    int32_t gunposy, lookhoriz;
455
    int32_t shade;
456
} hudweapon_t;
457
 
3469 helixhorne 458
typedef
3590 helixhorne 459
]].. WEAPONDATA_STRUCT ..[[
460
weapondata_t;
461
 
462
typedef
3469 helixhorne 463
]].. PROJECTILE_STRUCT ..[[
464
projectile_t;
3259 helixhorne 465
 
466
typedef struct {
3939 helixhorne 467
    uint32_t _flags;  // XXX: do we want to have this accessible at game time?
4291 helixhorne 468
    int32_t _cacherange;
5188 helixhorne 469
    projectile_t *_proj;
470
    const projectile_t *_defproj;
3259 helixhorne 471
} tiledata_t;
2291 helixhorne 472
 
3405 helixhorne 473
typedef struct {
474
    vec3_t pos;
475
    int32_t dist, clock;
476
    int16_t ang, horiz;
3887 helixhorne 477
    int16_t sect;  // NOTE: protected in camera_mt's __newindex
3405 helixhorne 478
} camera_t;
479
 
2319 helixhorne 480
enum
481
{
482
    MAXMOUSEBUTTONS = 10,
483
    MAXMOUSEAXES = 2,
4826 hendricks2 484
    MAXJOYBUTTONS = 32,
485
    MAXJOYBUTTONSANDHATS = (32+4),
4829 helixhorne 486
    MAXJOYAXES = 9,
487
 
2319 helixhorne 488
    NUMGAMEFUNCTIONS = 56,
4829 helixhorne 489
 
490
    // game.h
4472 hendricks2 491
    MAXRIDECULE = 10,
492
    MAXRIDECULELENGTH = 40,
493
    MAXSAVEGAMENAME = 22,
494
    MAXPWLOCKOUT = 128,
495
    MAXRTSNAME = 128,
2319 helixhorne 496
};
2298 helixhorne 497
 
498
typedef struct {
499
    int32_t const_visibility,uw_framerate;
500
    int32_t camera_time,folfvel,folavel,folx,foly,fola;
501
    int32_t reccnt,crosshairscale;
502
 
503
    int32_t runkey_mode,statusbarscale,mouseaiming,weaponswitch,drawweapon;   // JBF 20031125
504
    int32_t democams,color,msgdisptime,statusbarmode;
505
    int32_t m_noexits,noexits,autovote,automsg,idplayers;
506
    int32_t team, viewbob, weaponsway, althud, weaponscale, textscale;
507
 
508
    int32_t entered_name,screen_tilting,shadows,fta_on,executions,auto_run;
509
    int32_t coords,tickrate,levelstats,m_coop,coop,screen_size,lockout,crosshair;
510
    int32_t playerai,angleinterpolation,obituaries;
511
 
512
    int32_t respawn_monsters,respawn_items,respawn_inventory,recstat,monsters_off,brightness;
513
    int32_t m_respawn_items,m_respawn_monsters,m_respawn_inventory,m_recstat,m_monsters_off,detail;
514
    int32_t m_ffire,ffire,m_player_skill,m_level_number,m_volume_number,multimode;
515
    int32_t player_skill,level_number,volume_number,m_marker,marker,mouseflip;
516
 
4945 hendricks2 517
    vec2_t m_origin;
4968 hendricks2 518
    int32_t playerbest;
4945 hendricks2 519
 
6224 terminx 520
    int32_t configversion, bgstretch;
2298 helixhorne 521
 
522
    int16_t pause_on,from_bonus;
523
    int16_t camerasprite,last_camsprite;
6224 terminx 524
    int16_t last_level,secretlevel;
2298 helixhorne 525
 
526
    struct {
527
        int32_t UseJoystick;
528
        int32_t UseMouse;
529
        int32_t AutoAim;
530
        int32_t ShowOpponentWeapons;
531
        int32_t MouseDeadZone,MouseBias;
532
        int32_t SmoothInput;
533
 
534
        // JBF 20031211: Store the input settings because
6056 hendricks2 535
        // (currently) mact can't regurgitate them
2319 helixhorne 536
        int32_t MouseFunctions[MAXMOUSEBUTTONS][2];
537
        int32_t MouseDigitalFunctions[MAXMOUSEAXES][2];
538
        int32_t MouseAnalogueAxes[MAXMOUSEAXES];
539
        int32_t MouseAnalogueScale[MAXMOUSEAXES];
4826 hendricks2 540
        int32_t JoystickFunctions[MAXJOYBUTTONSANDHATS][2];
2319 helixhorne 541
        int32_t JoystickDigitalFunctions[MAXJOYAXES][2];
542
        int32_t JoystickAnalogueAxes[MAXJOYAXES];
543
        int32_t JoystickAnalogueScale[MAXJOYAXES];
544
        int32_t JoystickAnalogueDead[MAXJOYAXES];
545
        int32_t JoystickAnalogueSaturate[MAXJOYAXES];
546
        uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
2298 helixhorne 547
 
548
        //
549
        // Sound variables
550
        //
4004 helixhorne 551
        int32_t MasterVolume;
2298 helixhorne 552
        int32_t FXVolume;
553
        int32_t MusicVolume;
554
        int32_t SoundToggle;
555
        int32_t MusicToggle;
556
        int32_t VoiceToggle;
557
        int32_t AmbienceToggle;
558
 
559
        int32_t NumVoices;
560
        int32_t NumChannels;
561
        int32_t NumBits;
562
        int32_t MixRate;
563
 
564
        int32_t ReverseStereo;
565
 
566
        //
567
        // Screen variables
568
        //
569
 
570
        int32_t ScreenMode;
571
 
572
        int32_t ScreenWidth;
573
        int32_t ScreenHeight;
574
        int32_t ScreenBPP;
575
 
576
        int32_t ForceSetup;
577
        int32_t NoAutoLoad;
578
 
3516 helixhorne 579
        const int32_t scripthandle;
2298 helixhorne 580
        int32_t setupread;
581
 
582
        int32_t CheckForUpdates;
583
        int32_t LastUpdateCheck;
584
        int32_t useprecache;
585
    } config;
586
 
587
    char overhead_on,last_overhead,showweapons;
588
    char god,warp_on,cashman,eog,showallmap;
2454 helixhorne 589
    char show_help,scrollmode,noclip;
4472 hendricks2 590
    char ridecule[MAXRIDECULE][MAXRIDECULELENGTH];
591
    char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME];
2298 helixhorne 592
    char display_bonus_screen;
593
    char show_level_text;
5186 helixhorne 594
    char wchoice[MAX_WEAPONS];
2298 helixhorne 595
} user_defs;
3512 helixhorne 596
 
597
typedef struct {
598
    int32_t partime, designertime;
4948 hendricks2 599
    char *name, *filename, *musicfn;
3512 helixhorne 600
    void *savedstate;
601
} map_t;
2786 helixhorne 602
]])
2193 helixhorne 603
 
3931 helixhorne 604
bcarray.new("weapondata_t", ffiC.MAX_WEAPONS, "weapon", "weapondata_x_MAX_WEAPONS", WEAPON_NAMES)
4112 helixhorne 605
bcarray.new("int32_t", con_lang.MAXSESSIONVARS, "sessionvar", "int32_x_MAXSESSIONVARS")
3931 helixhorne 606
 
3409 helixhorne 607
-- EXTERNALLY EXPOSED GAME VARIABLES
608
ffi.cdef[[
609
const int32_t screenpeek;
610
hudweapon_t hudweap;
3556 helixhorne 611
int32_t g_logoFlags;
3409 helixhorne 612
]]
613
 
614
-- INTERNAL VARIABLES/FUNCTIONS
5991 hendricks2 615
decl("map_t g_mapInfo[$*$];", con_lang.MAXVOLUMES+1, con_lang.MAXLEVELS)
5988 hendricks2 616
decl("char g_volumeNames[$][33];", con_lang.MAXVOLUMES)
3512 helixhorne 617
 
2786 helixhorne 618
decl[[
4285 helixhorne 619
const int32_t myconnectindex;
4031 helixhorne 620
int32_t g_RETURN;
3787 helixhorne 621
int32_t g_elCONSize;
622
char *g_elCON;
623
void El_SetCON(const char *conluacode);
4118 helixhorne 624
void El_OnError(const char *str);
3787 helixhorne 625
 
3891 helixhorne 626
char *g_elSavecode;
627
void El_FreeSaveCode(void);
4119 helixhorne 628
const char *(*El_SerializeGamevars)(int32_t *slenptr, int32_t levelnum);
629
int32_t (*El_RestoreGamevars)(const char *savecode);
4370 helixhorne 630
int32_t (*El_GetLabelValue)(const char *label);
3796 helixhorne 631
 
3512 helixhorne 632
const char *s_buildRev;
2786 helixhorne 633
const char *g_sizes_of_what[];
634
int32_t g_sizes_of[];
4236 helixhorne 635
int32_t g_elFirstTime;
3320 helixhorne 636
int32_t g_elCallDepth;
3821 helixhorne 637
int32_t block_deletesprite;
3788 helixhorne 638
const char **g_elModules;
3516 helixhorne 639
char g_modDir[];
4112 helixhorne 640
int32_x_MAXSESSIONVARS g_elSessionVar;
2319 helixhorne 641
actor_t actor[MAXSPRITES];
3406 helixhorne 642
camera_t g_camera;
2298 helixhorne 643
user_defs ud;
4961 helixhorne 644
playerdata_t *const g_player;
3477 helixhorne 645
DukePlayer_t *g_player_ps[MAXPLAYERS];
3931 helixhorne 646
weapondata_x_MAX_WEAPONS g_playerWeapon[MAXPLAYERS];
3848 helixhorne 647
weapondata_t g_weaponOverridden[MAX_WEAPONS];
3943 helixhorne 648
int16_t WeaponPickupSprites[MAX_WEAPONS];
3345 helixhorne 649
tiledata_t g_tile[MAXTILES];
3463 helixhorne 650
projectile_t SpriteProjectile[MAXSPRITES];
2923 helixhorne 651
 
3830 helixhorne 652
int32_t g_noResetVars;
653
void (*A_ResetVars)(int32_t iActor);
654
 
3847 helixhorne 655
// Used from lunacon.lua for dynamic {tile,sound} remapping:
3568 helixhorne 656
struct
657
{
658
    const char *str;
659
    int32_t *dynvalptr;
660
    const int16_t staticval;
3847 helixhorne 661
} g_dynTileList[], g_dynSoundList[];
3568 helixhorne 662
 
5992 hendricks2 663
char *apStrings[];
3357 helixhorne 664
 
5995 hendricks2 665
const int32_t g_mostConcurrentPlayers;
5994 hendricks2 666
int16_t g_deleteQueueSize;
5987 hendricks2 667
int16_t g_blimpSpawnItems[15];
3343 helixhorne 668
int32_t g_scriptVersion;
5993 hendricks2 669
const int32_t g_frameRate;
3431 helixhorne 670
const int32_t g_currentMenu;
3480 helixhorne 671
uint16_t g_earthquakeTime;
3928 helixhorne 672
uint32_t g_moveThingsCount;
3516 helixhorne 673
char CheatKeys[2];
3247 helixhorne 674
 
3520 helixhorne 675
// Must not have functions here that may call events directly or
676
// indirectly. See lunatic_game.c.
3519 helixhorne 677
 
3247 helixhorne 678
int32_t A_IncurDamage(int32_t sn);  // not bound-checked!
3487 helixhorne 679
int32_t G_CheckActivatorMotion(int32_t lotag);
3254 helixhorne 680
int32_t A_Dodge(spritetype *s);
4590 helixhorne 681
int32_t A_MoveSpriteClipdist(int32_t spritenum, const vec3_t *change, uint32_t cliptype, int32_t clipdist);
3357 helixhorne 682
void P_DoQuote(int32_t q, DukePlayer_t *p);
5348 hendricks2 683
void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, int32_t set);
3504 helixhorne 684
void G_AddUserQuote(const char *daquote);
3357 helixhorne 685
void G_ClearCameraView(DukePlayer_t *ps);
5755 hendricks2 686
void VM_DrawTileGeneric(int32_t x, int32_t y, int32_t zoom, int32_t tilenum,
3480 helixhorne 687
                       int32_t shade, int32_t orientation, int32_t p);
3487 helixhorne 688
void G_InitTimer(int32_t ticspersec);
689
void G_GetTimeDate(int32_t *vals);
690
int32_t G_ToggleWallInterpolation(int32_t w, int32_t doset);
3491 helixhorne 691
int32_t G_StartTrack(int32_t level);
3640 helixhorne 692
int32_t VM_CheckSquished2(int32_t i, int32_t snum);
5990 hendricks2 693
void Menu_Change(int32_t cm);
3366 helixhorne 694
 
3504 helixhorne 695
const char *KB_ScanCodeToString(uint8_t scancode);
696
 
3366 helixhorne 697
int32_t A_CheckAnySoundPlaying(int32_t i);
698
int32_t S_CheckSoundPlaying(int32_t i, int32_t num);
3373 helixhorne 699
void S_StopEnvSound(int32_t num, int32_t i);
5989 hendricks2 700
void S_StopAllSounds(void);
3431 helixhorne 701
void S_ChangeSoundPitch(int32_t num, int32_t i, int32_t pitchoffset);
4928 hendricks2 702
int32_t S_GetMusicPosition(void);
703
void S_SetMusicPosition(int32_t position);
3501 helixhorne 704
 
705
int32_t minitext_(int32_t x,int32_t y,const char *t,int32_t s,int32_t p,int32_t sb);
706
void G_DrawTXDigiNumZ(int32_t starttile, int32_t x,int32_t y,int32_t n,int32_t s,int32_t pal,
707
                      int32_t cs,int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t z);
6210 hendricks2 708
void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t,
709
                     int32_t s, int32_t p, int32_t o,
710
                     int32_t x1, int32_t y1, int32_t x2, int32_t y2,
711
                     int32_t z, int32_t a);
3845 helixhorne 712
vec2_t G_ScreenText(const int32_t font,
713
                    int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle,
4428 helixhorne 714
                    const char *str, const int32_t shade, int32_t pal, int32_t o, int32_t alpha,
3845 helixhorne 715
                    int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f,
716
                    const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2);
717
vec2_t G_ScreenTextSize(const int32_t font,
718
                        int32_t x, int32_t y, const int32_t z, const int32_t blockangle,
719
                        const char *str, const int32_t o,
720
                        int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween,
721
                        const int32_t f,
722
                        int32_t x1, int32_t y1, int32_t x2, int32_t y2);
4972 helixhorne 723
const char* G_PrintYourTime(void);
724
const char* G_PrintParTime(void);
725
const char* G_PrintDesignerTime(void);
726
const char* G_PrintBestTime(void);
3845 helixhorne 727
 
4814 helixhorne 728
void G_UpdateScreenArea(void);
3794 helixhorne 729
void G_SaveMapState(void);
730
void G_RestoreMapState(void);
5231 helixhorne 731
void G_FreeMapState(int32_t mapnum);
2193 helixhorne 732
]]
733
 
2837 helixhorne 734
decl[[
735
int32_t kopen4loadfrommod(const char *filename, char searchfirst);
3343 helixhorne 736
 
3388 helixhorne 737
char **g_scriptModules;
738
int32_t g_scriptModulesNum;
739
 
3343 helixhorne 740
const char *G_ConFile(void);
741
void G_DoGameStartup(const int32_t *params);
3406 helixhorne 742
int32_t C_DefineSound(int32_t sndidx, const char *fn, int32_t args [5]);
3373 helixhorne 743
void C_DefineMusic(int32_t vol, int32_t lev, const char *fn);
3357 helixhorne 744
void C_DefineQuote(int32_t qnum, const char *qstr);
3373 helixhorne 745
void C_DefineVolumeName(int32_t vol, const char *name);
5033 hendricks2 746
void C_DefineVolumeFlags(int32_t vol, int32_t flags);
4977 hendricks2 747
void C_UndefineVolume(int32_t vol);
3375 helixhorne 748
void C_DefineSkillName(int32_t skill, const char *name);
4977 hendricks2 749
void C_UndefineSkill(int32_t skill);
3373 helixhorne 750
void C_DefineLevelName(int32_t vol, int32_t lev, const char *fn,
751
                       int32_t partime, int32_t designertime,
752
                       const char *levelname);
4977 hendricks2 753
void C_UndefineLevel(int32_t vol, int32_t lev);
3463 helixhorne 754
void C_DefineProjectile(int32_t j, int32_t what, int32_t val);
3516 helixhorne 755
void C_DefineGameFuncName(int32_t idx, const char *name);
3826 helixhorne 756
void C_DefineGameType(int32_t idx, int32_t flags, const char *name);
3516 helixhorne 757
int32_t C_SetDefName(const char *name);
4143 helixhorne 758
void C_SetCfgName(const char *cfgname);
3533 helixhorne 759
 
760
int32_t SCRIPT_GetNumber(int32_t scripthandle, const char *sectionname, const char *entryname, int32_t *number);
761
void SCRIPT_PutNumber(int32_t scripthandle, const char *sectionname, const char *entryname, int32_t number,
762
                      int32_t hexadecimal, int32_t defaultvalue);
2837 helixhorne 763
]]
764
 
2857 helixhorne 765
 
2863 helixhorne 766
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
767
-- as it allows to see implementations of functions.
768
--local string_dump = string.dump
769
string.dump = nil
770
 
771
 
2786 helixhorne 772
-- sanity-check struct type sizes
3109 helixhorne 773
local good = true
3865 helixhorne 774
for i=0,10 do
3109 helixhorne 775
    local what = ffi.string(ffiC.g_sizes_of_what[i])
776
    local fsz = ffi.sizeof(what)
777
    local csz = ffiC.g_sizes_of[i]
3407 helixhorne 778
    if (ffiC._DEBUG_LUNATIC ~= 0) then
779
        print(i..": "..what..": C sizeof = "..tostring(csz)..", FFI sizeof = "..tostring(fsz))
780
    end
3109 helixhorne 781
    if (fsz ~= csz) then
782
        good = false;
783
    end
2786 helixhorne 784
end
785
 
3109 helixhorne 786
if (not good) then
787
    error("Some sizes don't match between C and LuaJIT/FFI.")
788
end
2864 helixhorne 789
 
3109 helixhorne 790
 
3477 helixhorne 791
--== "player" global, needed by the "control" module ==--
792
 
4209 helixhorne 793
local player_static_members = defs_c.static_members_tab()
3477 helixhorne 794
 
4047 helixhorne 795
--[[
3843 helixhorne 796
player_static_members._INPUT_BITS = defs_c.conststruct
3477 helixhorne 797
{
798
    JUMP =                      1,
799
    CROUCH =                    2,
800
    FIRE =                      4,
801
    AIM_UP =                    8,
802
    AIM_DOWN =                 16,
803
    RUNNING =                  32,
804
    LOOK_LEFT =                64,
805
    LOOK_RIGHT =              128,
806
    -- weapons...
807
    STEROIDS =               4096,
808
    LOOK_UP =                8192,
809
    LOOK_DOWN =             16384,
810
    NIGHTVISION =           32768,
811
    MEDKIT =                65536,
812
    RESERVED =             131072,
813
    CENTER_VIEW =          262144,
814
    HOLSTER_WEAPON =       524288,
815
    INVENTORY_LEFT =      1048576,
816
    PAUSE =               2097152,
817
    QUICK_KICK =          4194304,
818
    AIM_MODE =            8388608,
819
    HOLODUKE =           16777216,
820
    JETPACK =            33554432,
821
    QUIT =               67108864,
822
    INVENTORY_RIGHT =   134217728,
823
    TURN_AROUND =       268435456,
824
    OPEN =              536870912,
825
    INVENTORY =        1073741824,
826
    ESC =              2147483648,
3253 helixhorne 827
}
828
 
3843 helixhorne 829
player_static_members._INPUT_EXT_BITS = defs_c.conststruct
3477 helixhorne 830
{
3597 helixhorne 831
    MOVE_FORWARD =  1,
832
    MOVE_BACKWARD = 2,
833
    STRAFE_LEFT =   4,
834
    STRAFE_RIGHT =  8,
835
    TURN_LEFT =    16,
836
    TURN_RIGHT =   32,
3477 helixhorne 837
}
4047 helixhorne 838
--]]
3477 helixhorne 839
 
3928 helixhorne 840
local band = bit.band
841
local lsh = bit.lshift
4590 helixhorne 842
local ivec3 = xmath.ivec3
3928 helixhorne 843
 
844
do
845
    -- player.all() iterator
846
    local function iter_allplayers(_nil, pli)
5995 hendricks2 847
        if (pli+1 < ffiC.g_mostConcurrentPlayers) then
3928 helixhorne 848
            return pli+1
849
        end
850
    end
851
 
852
    function player_static_members.all()
853
        return iter_allplayers, nil, -1
854
    end
855
 
856
    -- player.holdskey(pli, keyname)
857
    local KEYS = {  -- SK_CROUCH etc. -- "sync keys"
858
        CROUCH = lsh(1,1),
859
        RUN = lsh(1,5),
860
        OPEN = lsh(1,29),
861
    }
862
 
863
    function player_static_members.holdskey(pli, keyname)
864
        bcheck.player_idx(pli)
865
        if (KEYS[keyname] == nil) then
866
            error("invalid key name: "..tostring(keyname), 2)
867
        end
868
 
869
        return ffiC.g_player[pli].sync.bitsbits:test(KEYS[keyname])
870
    end
871
end
872
 
873
local player_holdskey = player_static_members.holdskey
874
 
3597 helixhorne 875
-- Actor flags
4209 helixhorne 876
local actor_static_members = defs_c.static_members_tab()
3597 helixhorne 877
do
878
    local our_SFLAG = {}
879
    local ext_SFLAG = con_lang.labels[4]  -- external actor flags only
880
    local USER_MASK = 0
881
 
882
    for name, flag in pairs(ext_SFLAG) do
883
        our_SFLAG[name:sub(7)] = flag  -- strip "SFLAG_"
884
        USER_MASK = bit.bor(USER_MASK, flag)
885
    end
886
 
887
    -- Add a couple of convenience defines.
888
    our_SFLAG.enemy = con_lang.SFLAG.SFLAG_BADGUY
889
    our_SFLAG.enemystayput = con_lang.SFLAG.SFLAG_BADGUY + con_lang.SFLAG.SFLAG_BADGUYSTAYPUT
890
    our_SFLAG.rotfixed = con_lang.SFLAG.SFLAG_ROTFIXED
891
 
3629 helixhorne 892
    -- Callback function chaining control flags.
4374 helixhorne 893
    our_SFLAG.replace = 0x08000000
894
    our_SFLAG.replace_soft = 0x08000000  -- compat
895
    our_SFLAG.replace_hard = 0x08000000  -- compat, deprecated
3829 helixhorne 896
    our_SFLAG.chain_beg = 0x20000000
897
    our_SFLAG.chain_end = 0x40000000
3873 helixhorne 898
    our_SFLAG._CHAIN_MASK_ACTOR = 0x78000000
899
    our_SFLAG._CHAIN_MASK_EVENT = 0x68000000
3629 helixhorne 900
 
3597 helixhorne 901
    -- XXX: CON doesn't export BADGUYSTAYPUT or ROTFIXED SFLAGs, but they are considered
902
    -- external for Lunatic.
903
    our_SFLAG.USER_MASK = bit.bor(USER_MASK, our_SFLAG.enemystayput, our_SFLAG.rotfixed)
904
 
905
    actor_static_members.FLAGS = defs_c.conststruct(our_SFLAG)
3860 helixhorne 906
 
907
    -- Sprite status numbers. Kept in 'actor', because it's more of a game-side
908
    -- concept (event though status lists are implemented in the engine), and
909
    -- to prevent confusion with sprite.CSTAT.
910
    local our_STAT = {}
911
 
912
    for name, statnum in pairs(con_lang.STAT) do
913
        -- Strip 'STAT_'.
914
        our_STAT[name:sub(6)] = statnum
915
    end
916
 
917
    actor_static_members.STAT = defs_c.conststruct(our_STAT)
3887 helixhorne 918
 
3917 helixhorne 919
    actor_static_members.MOVFLAGS = defs_c.conststruct
920
    {
921
        -- NOTE: no underscores, like in DEFS.CON.
922
        faceplayer = 1,
923
        geth = 2,
924
        getv = 4,
925
        randomangle = 8,
926
        faceplayerslow = 16,
927
        spin = 32,
928
        faceplayersmart = 64,
929
        fleeenemy = 128,
4378 helixhorne 930
        jumptoplayer_only = 256,
931
        jumptoplayer_bits = 257,  -- NOTE: two bits set!
3917 helixhorne 932
        jumptoplayer = 257,
933
        seekplayer = 512,
934
        furthestdir = 1024,
935
        dodgebullet = 4096,
936
    }
3597 helixhorne 937
end
938
 
3924 helixhorne 939
function actor_static_members.fall(i)
940
    check_sprite_idx(i)
941
    CF.VM_FallSprite(i)
942
end
943
 
4590 helixhorne 944
-- actor.move(i, vec, cliptype [, clipdist])
945
function actor_static_members.move(i, vec, cliptype, clipdist)
946
    check_sprite_idx(i)
947
    local vel = ivec3(vec.x, vec.y, vec.z)
5026 helixhorne 948
    return ffiC.A_MoveSpriteClipdist(i, vel, cliptype, clipdist or -1)
4590 helixhorne 949
end
950
 
3821 helixhorne 951
-- Delete sprite with index <i>.
952
function actor_static_members.delete(i)
953
    check_sprite_idx(i)
954
 
955
    if (ffiC.sprite[i].statnum == ffiC.MAXSTATUS) then
956
        error("Attempt to delete a sprite already not in the game world", 2)
957
    end
958
 
959
    if (ffiC.block_deletesprite ~= 0) then
960
        error("Attempt to delete sprite in EVENT_EGS", 2)
961
    end
962
 
3826 helixhorne 963
    -- TODO_MP
3821 helixhorne 964
    if (ffiC.g_player_ps[0].i == i) then
965
        error("Attempt to delete player 0's APLAYER sprite", 2)
966
    end
967
 
968
    CF.A_DeleteSprite(i)
969
end
970
 
4209 helixhorne 971
local tile_static_members = defs_c.static_members_tab()
3597 helixhorne 972
do
4731 helixhorne 973
    tile_static_members.sizx = defs_c.creategtab_membidx(ffiC.tilesiz, "x", ffiC.MAXTILES, "tilesizx[]")
974
    tile_static_members.sizy = defs_c.creategtab_membidx(ffiC.tilesiz, "y", ffiC.MAXTILES, "tilesizy[]")
3597 helixhorne 975
end
3562 helixhorne 976
 
3529 helixhorne 977
-- XXX: error message will say "g_player_ps"
5995 hendricks2 978
player = setmtonce({}, defs_c.GenStructMetatable("g_player_ps", "g_mostConcurrentPlayers", player_static_members))
3477 helixhorne 979
 
3345 helixhorne 980
-- needed by "control"
3597 helixhorne 981
actor = setmtonce({}, defs_c.GenStructMetatable("actor", "MAXSPRITES", actor_static_members))
3829 helixhorne 982
-- Some bitwise NOTs of various actor flag masks.
983
local BNOT = {
984
    USER_MASK = bit.bnot(actor.FLAGS.USER_MASK),
3873 helixhorne 985
    CHAIN_MASK_ACTOR = bit.bnot(actor.FLAGS._CHAIN_MASK_ACTOR),
986
    CHAIN_MASK_EVENT = bit.bnot(actor.FLAGS._CHAIN_MASK_EVENT),
3829 helixhorne 987
}
3345 helixhorne 988
 
5188 helixhorne 989
local projectile = defs_c.creategtab_membidx_ptr(ffiC.g_tile, "_proj", ffiC.MAXTILES, "projectile")
3562 helixhorne 990
local g_tile = setmtonce({}, defs_c.GenStructMetatable("g_tile", "MAXTILES", tile_static_members))
3463 helixhorne 991
 
2864 helixhorne 992
--== Custom operations for BUILD data structures ==--
3345 helixhorne 993
-- Among other things, declares struct action and struct move, and their
994
-- ID-wrapped types con_action_t and con_move_t
2871 helixhorne 995
local con = require("control")
2864 helixhorne 996
 
4590 helixhorne 997
do
998
    local isenemytile = con.isenemytile
3427 helixhorne 999
 
4590 helixhorne 1000
    -- Add game-side metamethods to "spritetype" and register it with "metatype"
1001
    local spr_mt_index_add = {
1002
        isenemy = function(s)
1003
            return isenemytile(s.picnum)
1004
        end,
1005
    }
1006
 
1007
    defs_c.finish_spritetype(spr_mt_index_add)
1008
end
1009
 
3916 helixhorne 1010
-- Check a literal numeric action or move value.
2923 helixhorne 1011
local function check_literal_am(am, typename)
2869 helixhorne 1012
    if (type(am) ~= "number") then
2923 helixhorne 1013
        error("bad argument: expected number or "..typename, 3)
2869 helixhorne 1014
    end
1015
 
3916 helixhorne 1016
    -- Negative values are generated as con.action/con.move IDs.
2869 helixhorne 1017
    if (not (am >= 0 and am <= 32767)) then
1018
        error("bad argument: expected number in [0 .. 32767]", 3)
1019
    end
1020
end
1021
 
3437 helixhorne 1022
-- An unrestricted actor_t pointer, for internal use:
3458 helixhorne 1023
local actor_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(ACTOR_STRUCT)))
1024
local player_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(DUKEPLAYER_STRUCT)))
3469 helixhorne 1025
local projectile_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(PROJECTILE_STRUCT)))
3954 helixhorne 1026
-- An unrestricted weapondata_t pointer, but with the member names stripped of
1027
-- the leading underscore, too:
3590 helixhorne 1028
local weapondata_ptr_ct = ffi.typeof("$ *", ffi.typeof((strip_const(WEAPONDATA_STRUCT):gsub(" _"," "))))
2872 helixhorne 1029
 
3916 helixhorne 1030
local con_action_ct = ffi.typeof("const con_action_t")
1031
local con_move_ct = ffi.typeof("const con_move_t")
1032
local con_ai_ct = ffi.typeof("const con_ai_t")
1033
 
1034
-- All-zero bare action and move.
1035
local nullac, nullmv = ffi.new("const struct action"), ffi.new("const struct move")
1036
-- All-zero action and move with IDs. Mostly for CON support.
1037
local literal_act = { [0]=con_action_ct(0), [1]=con_action_ct(1) }
1038
local literal_mov = { [0]=con_move_ct(0), [1]=con_move_ct(1) }
1039
 
3466 helixhorne 1040
local function get_actor_idx(a)
1041
    local i = ffi.cast(actor_ptr_ct, a)-ffi.cast(actor_ptr_ct, ffiC.actor)
3964 helixhorne 1042
--    assert(not (i >= ffiC.MAXSPRITES+0ULL))
3466 helixhorne 1043
    return i
1044
end
1045
 
4796 helixhorne 1046
local actor_methods = {
1047
    -- action
1048
    set_action = function(a, act)
1049
        a = ffi.cast(actor_ptr_ct, a)
3916 helixhorne 1050
 
4796 helixhorne 1051
        if (ffi.istype(con_action_ct, act)) then
1052
            a.t_data[4] = act.id
1053
            a.ac = act.ac
1054
        else
1055
            check_literal_am(act, "action")
1056
            a.t_data[4] = act
1057
            a.ac = nullac
1058
        end
2869 helixhorne 1059
 
4796 helixhorne 1060
        a.t_data[2] = 0
1061
        a.t_data[3] = 0
1062
    end,
2864 helixhorne 1063
 
4796 helixhorne 1064
    has_action = function(a, act)
1065
        a = ffi.cast(actor_ptr_ct, a)
3916 helixhorne 1066
 
4796 helixhorne 1067
        if (ffi.istype(con_action_ct, act)) then
1068
            return (a.t_data[4]==act.id)
1069
        else
1070
            check_literal_am(act, "action")
1071
            return (a.t_data[4]==act)
1072
        end
1073
    end,
2869 helixhorne 1074
 
4796 helixhorne 1075
    -- count
1076
    set_count = function(a, count)
1077
        ffi.cast(actor_ptr_ct, a).t_data[0] = count
1078
    end,
2869 helixhorne 1079
 
4796 helixhorne 1080
    get_count = function(a)
1081
        return ffi.cast(actor_ptr_ct, a).t_data[0]
1082
    end,
2869 helixhorne 1083
 
4796 helixhorne 1084
    -- action count
1085
    reset_acount = function(a)
1086
        ffi.cast(actor_ptr_ct, a).t_data[2] = 0
1087
    end,
2869 helixhorne 1088
 
4796 helixhorne 1089
    get_acount = function(a)
1090
        return ffi.cast(actor_ptr_ct, a).t_data[2]
1091
    end,
2869 helixhorne 1092
 
4796 helixhorne 1093
    -- Override action delay. The action ID is kept.
1094
    set_action_delay = function(a, delay)
1095
        ffi.cast(actor_ptr_ct, a).ac.delay = delay
1096
    end,
3918 helixhorne 1097
 
4796 helixhorne 1098
    -- move
1099
    set_move = function(a, mov, movflags)
1100
        a = ffi.cast(actor_ptr_ct, a)
3916 helixhorne 1101
 
4796 helixhorne 1102
        if (ffi.istype(con_move_ct, mov)) then
1103
            a.t_data[1] = mov.id
1104
            a.mv = mov.mv
1105
        else
1106
            check_literal_am(mov, "move")
1107
            a.t_data[1] = mov
1108
            a.mv = nullmv
1109
        end
2869 helixhorne 1110
 
4796 helixhorne 1111
        a.t_data[0] = 0
1112
        a.movflags = movflags or 0
1113
        local spr = ffiC.sprite[get_actor_idx(a)]
2869 helixhorne 1114
 
4796 helixhorne 1115
        if (not spr:isenemy() or spr.extra > 0) then
1116
            if (bit.band(a.movflags, 8) ~= 0) then  -- random_angle
1117
                spr.ang = bit.band(ffiC.krand(), 2047)
3887 helixhorne 1118
            end
4796 helixhorne 1119
        end
1120
    end,
2869 helixhorne 1121
 
4796 helixhorne 1122
    has_move = function(a, mov)
1123
        a = ffi.cast(actor_ptr_ct, a)
3916 helixhorne 1124
 
4796 helixhorne 1125
        if (ffi.istype(con_move_ct, mov)) then
1126
            return (a.t_data[1]==mov.id)
1127
        else
1128
            check_literal_am(mov, "move")
1129
            return (a.t_data[1]==mov)
1130
        end
1131
    end,
2869 helixhorne 1132
 
4796 helixhorne 1133
    -- Override velocity, keeping move ID.
1134
    set_hvel = function(a, hvel)
1135
        ffi.cast(actor_ptr_ct, a).mv.hvel = hvel
1136
    end,
3918 helixhorne 1137
 
4796 helixhorne 1138
    set_vvel = function(a, vvel)
1139
        ffi.cast(actor_ptr_ct, a).mv.vvel = vvel
1140
    end,
3918 helixhorne 1141
 
4796 helixhorne 1142
    -- ai
1143
    set_ai = function(a, ai)
1144
        local oa = a
1145
        a = ffi.cast(actor_ptr_ct, a)
2869 helixhorne 1146
 
4796 helixhorne 1147
        -- TODO: literal number AIs?
1148
        if (not ffi.istype(con_ai_ct, ai)) then
1149
            error("bad argument: expected ai", 2)
1150
        end
2869 helixhorne 1151
 
4796 helixhorne 1152
        -- NOTE: compare with gameexec.c, "CON_AI:"
1153
        a.t_data[5] = ai.id
2869 helixhorne 1154
 
4796 helixhorne 1155
        oa:set_action(ai.act)
1156
        oa:set_move(ai.mov, ai.movflags)
2869 helixhorne 1157
 
4796 helixhorne 1158
        -- Already reset with set_move():
1159
--        a.t_data[0] = 0
1160
    end,
2869 helixhorne 1161
 
4796 helixhorne 1162
    has_ai = function(a, ai)
1163
        a = ffi.cast(actor_ptr_ct, a)
2869 helixhorne 1164
 
4796 helixhorne 1165
        if (ffi.istype(con_ai_ct, ai)) then
1166
            return (a.t_data[5]==ai.id)
1167
        else
1168
            check_literal_am(ai, "ai")
1169
            return (a.t_data[5]==ai)
1170
        end
1171
    end,
3259 helixhorne 1172
 
4796 helixhorne 1173
    -- Getters/setters.
1174
    _get_t_data = function(a, idx)
1175
        if (not (idx >= 0 and idx < 10)) then
1176
            error("invalid t_data index "..idx, 2)
1177
        end
1178
        return ffi.cast(actor_ptr_ct, a).t_data[idx]
1179
    end,
3446 helixhorne 1180
 
4796 helixhorne 1181
    _set_t_data = function(a, idx, val)
1182
        if (not (idx >= 0 and idx < 10)) then
1183
            error("invalid t_data index "..idx, 2)
1184
        end
1185
        ffi.cast(actor_ptr_ct, a).t_data[idx] = val
1186
    end,
3454 helixhorne 1187
 
4796 helixhorne 1188
    set_picnum = function(a, picnum)
1189
        if (not (picnum < 0)) then
1190
            check_tile_idx(picnum)
1191
        end
1192
        ffi.cast(actor_ptr_ct, a).picnum = picnum
1193
    end,
3454 helixhorne 1194
 
4796 helixhorne 1195
    set_owner = function(a, owner)
1196
        -- XXX: is it permissible to set to -1?
1197
        check_sprite_idx(owner)
1198
        ffi.cast(actor_ptr_ct, a).owner = owner
1199
    end,
3928 helixhorne 1200
 
4796 helixhorne 1201
    --- Custom methods ---
3928 helixhorne 1202
 
4796 helixhorne 1203
    -- Checkers for whether the movement update made the actor hit
1204
    -- something.
3928 helixhorne 1205
 
4796 helixhorne 1206
    checkhit = function(a)
1207
        -- Check whether we hit *anything*, including ceiling/floor.
1208
        return a._movflagbits:test(49152)
1209
    end,
3928 helixhorne 1210
 
4796 helixhorne 1211
    checkbump = function(a)
1212
        -- Check whether we bumped into a wall or sprite.
1213
        return (a._movflagbits:mask(49152) >= 32768)
1214
    end,
3928 helixhorne 1215
 
4796 helixhorne 1216
    hitwall = function(a)
1217
        if (a._movflagbits:mask(49152) == 32768) then
1218
            return a._movflagbits:mask(32767)
1219
        end
1220
    end,
3928 helixhorne 1221
 
4796 helixhorne 1222
    hitsprite = function(a)
1223
        if (a._movflagbits:mask(49152) == 49152) then
1224
            return a._movflagbits:mask(32767)
1225
        end
1226
    end,
3928 helixhorne 1227
 
4796 helixhorne 1228
    -- NOTE: no 'hitsector' or 'hitceiling' / 'hitfloor' for now because
1229
    -- more research is needed as to what the best way of checking c/f is.
2864 helixhorne 1230
}
3466 helixhorne 1231
 
4796 helixhorne 1232
local actor_mt = {
1233
    __index = function(a, key)
1234
        if (actor_methods[key] ~= nil) then
1235
            return actor_methods[key]
1236
        elseif (key == "proj") then
1237
            return ffiC.SpriteProjectile[get_actor_idx(a)]
1238
        else
1239
            error("invalid indexing key to actor object", 2)
1240
        end
1241
    end,
1242
}
3466 helixhorne 1243
 
2864 helixhorne 1244
ffi.metatype("actor_t", actor_mt)
1245
 
1246
 
3407 helixhorne 1247
--- PER-PLAYER WEAPON SETTINGS
3954 helixhorne 1248
local wd_sound_member = {}
1249
for _, declstr in pairs(con_lang.wdata_members) do
1250
    local member = declstr:match("const int32_t _(.*sound)$")
1251
    if (member) then
1252
        wd_sound_member[member] = true
1253
        if (ffiC._DEBUG_LUNATIC ~= 0) then
1254
            printf("weapondata_t member %s denotes a sound", member)
1255
        end
1256
    end
1257
end
1258
 
3407 helixhorne 1259
local weapondata_mt = {
3595 helixhorne 1260
    __index = function(wd, member)
1261
        -- Handle protected members that are renamed (e.g. shoots/_shoots).
3653 helixhorne 1262
        return ffi.cast(weapondata_ptr_ct, wd)[0][member]
3595 helixhorne 1263
    end,
1264
 
3407 helixhorne 1265
    __newindex = function(wd, member, val)
3848 helixhorne 1266
        -- Set to 'true' if we set a tile or sound member.
1267
        local didit = false
1268
 
3954 helixhorne 1269
        check_type(member, "string")  -- MEMBER_IS_STRING
3883 helixhorne 1270
        check_number(val)
1271
 
3954 helixhorne 1272
        if (wd_sound_member[member]) then  -- XXX: sound2time is a time, not a sound
3574 helixhorne 1273
            if (val < 0) then
3954 helixhorne 1274
                val = 0  -- Set to 0 if negative (e.g. CrackDown).
3574 helixhorne 1275
            else
1276
                check_sound_idx(val)
1277
            end
3848 helixhorne 1278
            didit = true
3463 helixhorne 1279
        elseif (member=="workslike") then
1280
            check_weapon_idx(val)
3574 helixhorne 1281
        elseif (member=="spawn" or member=="shoots") then
1282
            if (val < 0) then
1283
                -- Set to 0 if oob (e.g. CrackDown). This is a bit problematic
1284
                -- for .shoots because it's used unconditionally except in one
1285
                -- case (see player.c).
1286
                val = 0
1287
            else
1288
                check_tile_idx(val)
1289
            end
3848 helixhorne 1290
            didit = true
3463 helixhorne 1291
        end
3392 helixhorne 1292
 
3954 helixhorne 1293
        -- DEBUG:
1294
--        printf("assigning %s to weapon's %s", tostring(val), member)
3848 helixhorne 1295
 
3954 helixhorne 1296
        -- NOTE: we're indexing a *pointer* with the user-supplied 'member',
1297
        -- which could be dangerouns if it could be a number. However, we have
1298
        -- assured that is is not in MEMBER_IS_STRING above.
1299
        ffi.cast(weapondata_ptr_ct, wd)[member] = val
1300
 
3848 helixhorne 1301
        if (didit and ffiC.g_elCallDepth==0) then
1302
            -- Signal that we overrode this member at CON translation time.
1303
 
1304
            -- Get weapon index as pointer difference first. PLAYER_0.
3931 helixhorne 1305
            local wi = ffi.cast(weapondata_ptr_ct, wd)
1306
                     - ffi.cast(weapondata_ptr_ct, ffiC.g_playerWeapon)
3964 helixhorne 1307
            assert(wi >= 0 and wi < ffiC.MAX_WEAPONS)
3848 helixhorne 1308
 
1309
            -- Set g_weaponOverridden[wi][member], but without invoking
1310
            -- weapondata_t's __newindex metamethod (i.e. us)!
1311
            ffi.cast(weapondata_ptr_ct, ffiC.g_weaponOverridden[wi])[member] = 1
1312
        end
3407 helixhorne 1313
    end,
1314
}
1315
ffi.metatype("weapondata_t", weapondata_mt)
3392 helixhorne 1316
 
3407 helixhorne 1317
local weaponaccess_mt = {
3931 helixhorne 1318
    -- Syntax like "player[0].weapon.KNEE.shoots" possible because
1319
    -- g_playerWeapon[] is declared as an array of corresponding bcarray types
1320
    -- for us.
3407 helixhorne 1321
    __index = function(wa, key)
3931 helixhorne 1322
        if (type(key)~="number" and type(key)~="string") then
1323
            error("must access weapon either by number or by name")
3407 helixhorne 1324
        end
3392 helixhorne 1325
 
3931 helixhorne 1326
        return ffiC.g_playerWeapon[wa._p][key]
3407 helixhorne 1327
    end,
1328
}
1329
ffi.metatype("weaponaccess_t", weaponaccess_mt)
3392 helixhorne 1330
 
3893 helixhorne 1331
 
1332
local function clamp(num, min, max)
1333
    return num < min and min
1334
        or num > max and max
1335
        or num
1336
end
1337
 
1338
local function clamp0to1(num)
1339
    check_number(num, 4)
1340
    return clamp(num, 0, 1)
1341
end
1342
 
4796 helixhorne 1343
local player_methods = {
1344
    -- CON-like addammo/addweapon, but without the non-local control flow
1345
    -- (returns true if weapon's ammo was at the max. instead).
1346
    addammo = con._addammo,
1347
    addweapon = con._addweapon,
3254 helixhorne 1348
 
4796 helixhorne 1349
    stomp = con._pstomp,
3253 helixhorne 1350
 
4796 helixhorne 1351
    holdskey = function(p, keyname)
1352
        -- XXX: on invalid <keyname>, error will point to this next line:
1353
        return player_holdskey(p.weapon._p, keyname)
1354
    end,
3433 helixhorne 1355
 
4796 helixhorne 1356
    has_weapon = function(p, weap)
1357
        return p.gotweaponbits:test(lsh(1,weap))
1358
    end,
3928 helixhorne 1359
 
4796 helixhorne 1360
    give_weapon = function(p, weap)
1361
        p.gotweaponbits:set(lsh(1,weap))
1362
    end,
3444 helixhorne 1363
 
4796 helixhorne 1364
    take_weapon = function(p, weap)
1365
        p.gotweaponbits:clear(lsh(1,weap))
1366
    end,
3444 helixhorne 1367
 
4796 helixhorne 1368
    -- Give or take weapon, for implementation of CON's .gotweapon access.
1369
    _gt_weapon = function(p, weap, give_p)
1370
        if (give_p ~= 0) then
1371
            p:give_weapon(weap)
1372
        else
1373
            p:take_weapon(weap)
1374
        end
1375
    end,
3444 helixhorne 1376
 
4796 helixhorne 1377
    whack = function(p, no_return_to_center)
1378
        p.horiz = p.horiz + 64
1379
        if (not no_return_to_center) then
1380
            p.return_to_center = 9
1381
        end
1382
        local n = bit.arshift(128-band(ffiC.krand(),255), 1)
1383
        p.rotscrnang = n
1384
        p.look_ang = n
1385
    end,
3254 helixhorne 1386
 
4796 helixhorne 1387
    -- External, improved 'palfrom'.
1388
    -- <speed>: possibly fractional speed of tint fading, in pals.f decrements per gametic.
1389
    --          XXX: exposes internals.
1390
    -- <prio>: a value from -128 to 127, higher ones trump lower or equal ones
1391
    fadecol = function(p, fadefrac, r, g, b, speed, prio)
1392
        -- Validate inargs: clamp f,r,g,b to [0 .. 1] first and multiply by
1393
        -- 63 for the internal handling.
1394
        fadefrac = clamp0to1(fadefrac)*63
1395
        -- NOTE: a fadefrac of now <1 is allowed, e.g. for clearing the tint.
1396
        r = clamp0to1(r)*63
1397
        g = clamp0to1(g)*63
1398
        b = clamp0to1(b)*63
3893 helixhorne 1399
 
4796 helixhorne 1400
        if (speed ~= nil) then
1401
            check_number(speed)
1402
            -- Clamp to sensible values; the speed is stored in an int8_t
1403
            -- (see below).
1404
            speed = clamp(speed, 1/128, 127)
1405
        else
1406
            speed = 1
1407
        end
3893 helixhorne 1408
 
4796 helixhorne 1409
        if (prio ~= nil) then
1410
            check_number(prio)
3893 helixhorne 1411
 
4796 helixhorne 1412
            if (not (prio >= -128 and prio < 127)) then
1413
                error("invalid argument #6 (priority): must be in [-128 .. 127]", 2)
3893 helixhorne 1414
            end
4796 helixhorne 1415
        else
1416
            prio = 0
1417
        end
3893 helixhorne 1418
 
4796 helixhorne 1419
        -- Check if a currently active tint has higher priority.
1420
        if (p._pals.f > 0 and p._palsfadeprio > prio) then
1421
            return
1422
        end
3893 helixhorne 1423
 
4796 helixhorne 1424
        -- The passed tint can be applied now.
1425
        p:_palfrom(fadefrac, r, g, b)
1426
        p._palsfadeprio = prio
3893 helixhorne 1427
 
4796 helixhorne 1428
        -- Calculate .palsfade{speed,next}
1429
        if (speed >= 1) then
1430
            -- Will round to the nearest integer ("banker's
1431
            -- rounding"). NOTE: This is not correct for all numbers, see
1432
            -- http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
1433
            p._palsfadespeed = speed + 0.5
1434
            p._palsfadenext = 0
1435
        else
1436
            -- NOTE: Values that round to 0 have are equivalent behavior to
1437
            -- passing a <speed> of 1.
1438
            local negspeedrecip = -((1/speed) + 0.5)  -- [-128.5 .. 1/127+0.5]
1439
            p._palsfadespeed = negspeedrecip
1440
            p._palsfadenext = negspeedrecip
1441
        end
1442
    end,
3893 helixhorne 1443
 
4796 helixhorne 1444
    -- INTERNAL and CON-only.
1445
    _palfrom = function(p, f, r,g,b)
1446
        local pals = p._pals
1447
        -- Assume that CON's palfrom starts with prio 0 and speed 0.
1448
        if (pals.f == 0 or p._palsfadeprio <= 0) then
1449
            pals.f = f
1450
            pals.r, pals.g, pals.b = r, g, b
1451
            p._palsfadespeed, p._palsfadenext = 0, 0
1452
        end
1453
    end,
1454
}
3653 helixhorne 1455
 
4796 helixhorne 1456
local player_mt = {
1457
    __index = function(p, key)
1458
        if (player_methods[key] ~= nil) then
1459
            return player_methods[key]
1460
        elseif (key == "_input") then
1461
            return ffiC.g_player[p.weapon._p].sync[0]
1462
        else
1463
            -- Read access to protected player members.
1464
            return ffi.cast(player_ptr_ct, p)[0][key]
1465
        end
1466
    end,
1467
 
3653 helixhorne 1468
    __newindex = function(p, key, val)
1469
        -- Write access to protected player members.
1470
 
1471
        local allowneg = DukePlayer_prot_allowneg[key]
1472
        assert(type(allowneg)=="boolean")
1473
 
5192 helixhorne 1474
        if (allowneg==false or not (val == -1)) then
3653 helixhorne 1475
            DukePlayer_prot_chkfunc[key](val)
1476
        end
1477
        ffi.cast(player_ptr_ct, p)[key] = val
1478
    end,
3247 helixhorne 1479
}
3477 helixhorne 1480
 
3247 helixhorne 1481
ffi.metatype("DukePlayer_t", player_mt)
1482
 
3865 helixhorne 1483
local function GenProjectileSetFunc(Member, checkfunc)
1484
    return function(self, idx)
1485
        if (not (idx == -1)) then
1486
            checkfunc(idx)
3469 helixhorne 1487
        end
3865 helixhorne 1488
        ffi.cast(projectile_ptr_ct, self)[Member] = idx
3469 helixhorne 1489
    end
1490
end
1491
 
1492
local projectile_mt = {
1493
    __index = {
3865 helixhorne 1494
        set_spawns = GenProjectileSetFunc("spawns", check_tile_idx),
1495
        set_decal = GenProjectileSetFunc("decal", check_tile_idx),
1496
        set_trail = GenProjectileSetFunc("trail", check_tile_idx),
1497
 
1498
        set_sound = GenProjectileSetFunc("sound", check_sound_idx),
1499
        set_isound = GenProjectileSetFunc("isound", check_sound_idx),
1500
        set_bsound = GenProjectileSetFunc("bsound", check_sound_idx),
3469 helixhorne 1501
    },
1502
}
1503
ffi.metatype("projectile_t", projectile_mt)
1504
 
3473 helixhorne 1505
local user_defs_mt = {
1506
    __index = {
1507
        set_screen_size = function(ud, screen_size)
4814 helixhorne 1508
            if (ud.screen_size ~= screen_size) then
1509
                ud.screen_size = screen_size
1510
                ffiC.G_UpdateScreenArea()
1511
            end
3473 helixhorne 1512
        end,
1513
 
1514
        set_volume_number = function(ud, volume_number)
3843 helixhorne 1515
            -- NOTE: allow volume_number==MAXVOLUMES.
1516
            if (not (volume_number==con_lang.MAXVOLUMES)) then
1517
                bcheck.volume_idx(volume_number)
1518
            end
3473 helixhorne 1519
            ud.volume_number = volume_number
1520
        end,
3826 helixhorne 1521
 
4567 helixhorne 1522
        set_m_volume_number = function(ud, volume_number)
1523
            -- NOTE: allow volume_number==MAXVOLUMES.
1524
            if (not (volume_number==con_lang.MAXVOLUMES)) then
1525
                bcheck.volume_idx(volume_number)
1526
            end
1527
            ud.m_volume_number = volume_number
1528
        end,
1529
 
3826 helixhorne 1530
        set_level_number = function(ud, level_number)
1531
            bcheck.level_idx(level_number)
1532
            ud.level_number = level_number
1533
        end,
3473 helixhorne 1534
    },
1535
}
1536
ffi.metatype("user_defs", user_defs_mt)
1537
 
3409 helixhorne 1538
--- CUSTOM "gv" VARIABLES
3406 helixhorne 1539
local camera_mt = {
1540
    -- TODO: "set position" method, which also updates the sectnum
1541
    __index = ffiC.g_camera,
1542
    __newindex = function(_, key, val)
1543
        if (key=="sect") then
3445 helixhorne 1544
            check_sector_idx(val)
3406 helixhorne 1545
        end
1546
        ffiC.g_camera[key] = val
1547
    end,
1548
}
1549
 
3435 helixhorne 1550
gv_access.cam = setmtonce({}, camera_mt)
3473 helixhorne 1551
gv_access._ud = ffiC.ud
3406 helixhorne 1552
 
3601 helixhorne 1553
-- Support for some CON global system gamevars. RETURN handled separately.
1554
gv_access._csv = ffi.new "struct { int32_t LOTAG, HITAG, TEXTURE; }"
3466 helixhorne 1555
 
3928 helixhorne 1556
gv_access.REND = defs_c.conststruct
1557
{
1558
    CLASSIC = 0,
1559
    POLYMOST = 3,
1560
    POLYMER = 4,
1561
}
1562
 
4030 helixhorne 1563
gv_access.WEAPON = lprivate.WEAPON
1564
gv_access.GET = lprivate.GET
1565
 
3475 helixhorne 1566
function gv_access._get_yxaspect()
1567
    return ffiC.yxaspect
1568
end
1569
 
3480 helixhorne 1570
function gv_access._get_viewingrange()
1571
    return ffiC.viewingrange
1572
end
1573
 
3431 helixhorne 1574
function gv_access._currentFramerate()
5993 hendricks2 1575
    return ffiC.g_frameRate
3409 helixhorne 1576
end
1577
 
3431 helixhorne 1578
function gv_access._currentMenu()
1579
    return ffiC.g_currentMenu
1580
end
1581
 
3656 helixhorne 1582
function gv_access._changeMenu(cm)
5990 hendricks2 1583
    ffiC.Menu_Change(cm)
3656 helixhorne 1584
end
1585
 
3498 helixhorne 1586
function gv_access._set_guniqhudid(id)
1587
    local MAXUNIQHUDID = 256  -- KEEPINSYNC build.h
3964 helixhorne 1588
    if (not (id >= 0 and id < MAXUNIQHUDID)) then
3498 helixhorne 1589
        error("invalid unique HUD ID "..id)
1590
    end
1591
    ffiC.guniqhudid = id
1592
end
1593
 
3409 helixhorne 1594
function gv_access.currentEpisode()
4260 helixhorne 1595
    return ffiC.ud.volume_number + 1
3409 helixhorne 1596
end
1597
 
1598
function gv_access.currentLevel()
4260 helixhorne 1599
    return ffiC.ud.level_number + 1
3409 helixhorne 1600
end
1601
 
3480 helixhorne 1602
function gv_access.doQuake(gametics, snd)
1603
    ffiC.g_earthquakeTime = gametics
1604
    if (snd ~= nil) then
1605
        con._globalsound(ffiC.screenpeek, snd)
1606
    end
1607
end
1608
 
3366 helixhorne 1609
-- Declare all con_lang.labels constants in the global FFI namespace.
2863 helixhorne 1610
for i=1,#con_lang.labels do
3597 helixhorne 1611
    if (getmetatable(con_lang.labels[i]) ~= "noffiC") then
1612
        local strbuf = {"enum {"}
1613
        for label, val in pairs(con_lang.labels[i]) do
1614
            strbuf[#strbuf+1] = string.format("%s = %d,", label, val)
1615
        end
1616
        strbuf[#strbuf+1] = "};"
2762 helixhorne 1617
 
3597 helixhorne 1618
        ffi.cdef(table.concat(strbuf))
2762 helixhorne 1619
    end
1620
end
1621
 
1622
 
2648 helixhorne 1623
---=== Set up restricted global environment ===---
1624
 
2828 helixhorne 1625
local allowed_modules = {
1626
    coroutine=coroutine, bit=bit, table=table, math=math, string=string,
2855 helixhorne 1627
 
1628
    os = {
3935 helixhorne 1629
        clock = function() return gv_.gethiticks()*0.001 end,
2855 helixhorne 1630
    },
1631
 
3227 helixhorne 1632
    randgen = randgen,
4236 helixhorne 1633
    engine = require("engine"),
2858 helixhorne 1634
    stat = require("stat"),
2862 helixhorne 1635
    bitar = require("bitar"),
4590 helixhorne 1636
    xmath = xmath,
4147 helixhorne 1637
    fs = require("fs"),
2864 helixhorne 1638
 
1639
    con = con,
2828 helixhorne 1640
}
1641
 
3914 helixhorne 1642
do
1643
    local ctype_cansave = {}
1644
 
1645
    -- Register as "serializeable" the type of cdata object <v>.
1646
    local function reg_serializable_cv(v)
1647
        assert(type(v)=="cdata")
1648
        assert(type(v._serialize)=="function")
1649
        -- NOTE: tonumber() on a ctype cdata object gets its LuaJIT-internal
1650
        -- ID, the one that would be shown with tostring(), e.g.
1651
        -- ctype<struct 95>
1652
        ctype_cansave[tonumber(ffi.typeof(v))] = true
1653
    end
1654
 
1655
    function lprivate.cansave_cdata(v)
1656
        return type(v)=="cdata" and ctype_cansave[tonumber(ffi.typeof(v))]
1657
    end
1658
 
4590 helixhorne 1659
    reg_serializable_cv(xmath.vec3())
1660
    reg_serializable_cv(ivec3())
3914 helixhorne 1661
end
1662
 
3597 helixhorne 1663
-- Protect base modules.
3917 helixhorne 1664
local function basemod_newidx()
3870 helixhorne 1665
    error("modifying base module table forbidden", 2)
1666
end
2828 helixhorne 1667
 
3870 helixhorne 1668
for modname, themodule in pairs(allowed_modules) do
1669
    local mt = {
1670
        __index = themodule,
3917 helixhorne 1671
        __newindex = basemod_newidx,
3870 helixhorne 1672
    }
3597 helixhorne 1673
 
3870 helixhorne 1674
    allowed_modules[modname] = setmtonce({}, mt)
2828 helixhorne 1675
end
1676
 
3642 helixhorne 1677
 
3796 helixhorne 1678
---=== Module stuff ===---
1679
 
1680
local package_loaded = {}  -- [<modname>] = false/true/table
3642 helixhorne 1681
local modname_stack = {}  -- [<depth>]=string
1682
local module_gamevars = {}  -- [<modname>] = { <gvname1>, <gvname2>, ... }
3858 helixhorne 1683
local module_gvlocali = {}  -- [<modname>] = { <localidx_beg>, <localidx_end> }
3891 helixhorne 1684
local module_thread = {}  -- [<modname>] = <module_thread>
3642 helixhorne 1685
 
1686
local function getcurmodname(thisfuncname)
1687
    if (#modname_stack == 0) then
1688
        error("'"..thisfuncname.."' must be called at the top level of a require'd file", 3)
1689
        -- ... as opposed to "at runtime".
2837 helixhorne 1690
    end
1691
 
3642 helixhorne 1692
    return modname_stack[#modname_stack]
2837 helixhorne 1693
end
1694
 
3642 helixhorne 1695
 
2837 helixhorne 1696
local function errorf(level, fmt, ...)
1697
    local errmsg = string.format(fmt, ...)
1698
    error(errmsg, level+1)
1699
end
1700
 
3734 helixhorne 1701
local function readintostr_mod(fn)
3736 helixhorne 1702
    -- TODO: g_loadFromGroupOnly?
1703
    local fd = ffiC.kopen4loadfrommod(fn, 0)
1704
    if (fd < 0) then
1705
        return nil
1706
    end
1707
 
5809 helixhorne 1708
    local ret = defs_c.readintostr(fd)
1709
    ffiC.kclose(fd)
1710
    return ret
2854 helixhorne 1711
end
1712
 
3642 helixhorne 1713
 
3858 helixhorne 1714
local debug = require("debug")
1715
 
1716
-- Get the number of active locals in the function that calls the function
1717
-- calling this one.
1718
local function getnumlocals(l)
1719
    -- 200 is the max. number of locals at one level
1720
    for i=1,200 do
1721
        -- level:
4570 helixhorne 1722
        -- 0 is debug.getlocal() itself.
3891 helixhorne 1723
        -- 1 is this function (getnumlocals).
3858 helixhorne 1724
        -- 2 is the function calling getnumlocals()
1725
        -- 3 is the function calling that one.
1726
        if (debug.getlocal(3, i) == nil) then
1727
            return i-1
1728
        end
1729
    end
1730
end
1731
 
3928 helixhorne 1732
local function error_on_nil_read(_, varname)
1733
    error("attempt to read nil variable '"..varname.."'", 2)
1734
end
1735
 
3642 helixhorne 1736
local required_module_mt = {
3928 helixhorne 1737
    __index = error_on_nil_read,
1738
 
3642 helixhorne 1739
    __newindex = function()
1740
        error("modifying module table forbidden", 2)
1741
    end,
3928 helixhorne 1742
 
3642 helixhorne 1743
    __metatable = true,
1744
}
1745
 
3891 helixhorne 1746
-- Will contain a function to restore gamevars when running from savegame
1747
-- restoration. See SAVEFUNC_ARGS for its arguments.
1748
local g_restorefunc = nil
1749
 
1750
-- Local gamevar restoration function run from
1751
-- our_require('end_gamevars') <- [user module].
1752
local function restore_local(li, lval)
1753
    -- level:
1754
    -- 0 is getlocal() itself.
1755
    -- 1 is this function (restore_local).
1756
    -- 2 is the function calling restore_local(), the savecode.
1757
    -- 3 is the function calling the savecode, our_require.
1758
    -- 4 is the function calling our_require, the module function.
1759
    if (ffiC._DEBUG_LUNATIC ~= 0) then
1760
        printf("Restoring index #%d (%s) with value %s",
1761
               li, debug.getlocal(4, li), tostring(lval))
1762
    end
1763
 
1764
    assert(debug.setlocal(4, li, lval))
1765
end
1766
 
2828 helixhorne 1767
-- The "require" function accessible to Lunatic code.
1768
-- Base modules in allowed_modules are wrapped so that they cannot be
2837 helixhorne 1769
-- modified, user modules are searched in the EDuke32 search
3390 helixhorne 1770
-- path.  Also, our require
1771
--  * never messes with the global environment, it only returns the module.
1772
--  * allows passing varargs beyond the name to the module.
1773
local function our_require(modname, ...)
3734 helixhorne 1774
    local ERRLEV = 5
1775
 
3642 helixhorne 1776
    -- Check module name is valid first.
1777
    -- TODO: restrict valid names?
3788 helixhorne 1778
    if (type(modname) ~= "string" or #modname==0) then
1779
        error("module name must be a nonempty string", 2)
3642 helixhorne 1780
    end
2828 helixhorne 1781
 
3966 helixhorne 1782
    -- For _LUNATIC_DBG
1783
    if (modname:match("^_LUNATIC") and ffiC._DEBUG_LUNATIC == 0) then
1784
        return nil
1785
    end
1786
 
3642 helixhorne 1787
    -- Handle the section between module() and require("end_gamevars").
1788
    if (modname == "end_gamevars") then
1789
        local thismodname = getcurmodname("require")
1790
 
1791
        if (module_gamevars[thismodname] ~= nil) then
1792
            error("\"require 'end_gamevars'\" must be called at most once per require'd file", 2)
1793
        end
1794
 
1795
        local gvnames = {}
1796
 
1797
        for name in pairs(getfenv(2)) do
3857 helixhorne 1798
            gvnames[#gvnames+1] = name
3642 helixhorne 1799
            if (ffiC._DEBUG_LUNATIC ~= 0) then
1800
                printf("MODULE %s GAMEVAR %s", thismodname, name)
1801
            end
1802
        end
1803
 
1804
        module_gamevars[thismodname] = gvnames
3858 helixhorne 1805
        local gvmodi = module_gvlocali[thismodname]
1806
        gvmodi[2] = getnumlocals()
3642 helixhorne 1807
 
3858 helixhorne 1808
        if (ffiC._DEBUG_LUNATIC ~= 0) then
3891 helixhorne 1809
            local numlocals = gvmodi[2]-gvmodi[1]+1
1810
            if (numlocals > 0) then
1811
                printf("Module '%s' has %d locals, index %d to %d",
1812
                       thismodname, numlocals, gvmodi[1], gvmodi[2])
1813
            end
3858 helixhorne 1814
        end
1815
 
3891 helixhorne 1816
        -- Potentially restore gamevars.
1817
        if (g_restorefunc) then
1818
            local modtab = package_loaded[thismodname]
1819
            assert(type(modtab)=="table")
1820
            -- SAVEFUNC_ARGS.
1821
            g_restorefunc(thismodname, modtab, restore_local)
1822
        end
1823
 
1824
        -- Return whether we're NOT running from a savegame restore in the
1825
        -- second outarg. (Lunatic-private!)
1826
        return nil, (g_restorefunc==nil)
3642 helixhorne 1827
    end
1828
 
1829
    -- See whether it's a base module name.
2837 helixhorne 1830
    if (allowed_modules[modname] ~= nil) then
1831
        return allowed_modules[modname]
2828 helixhorne 1832
    end
1833
 
3642 helixhorne 1834
    --- Search user modules...
2837 helixhorne 1835
 
3867 helixhorne 1836
    if (modname:find("[/\\]")) then
1837
        error("Module name must not contain directory separators", ERRLEV-1)
1838
    end
1839
    -- Instead, dots are translated to directory separators. For EDuke32's
3894 helixhorne 1840
    -- virtual file system, this is always a forward slash. Keep the original
1841
    -- module name for passing to the module function.
1842
    local omodname = modname
3867 helixhorne 1843
    modname = modname:gsub("%.", "/")
1844
 
3530 helixhorne 1845
    local omod = package_loaded[modname]
1846
    if (omod ~= nil) then
3642 helixhorne 1847
        if (omod==false) then
3530 helixhorne 1848
            error("Loop while loading modules", ERRLEV-1)
1849
        end
1850
 
2837 helixhorne 1851
        -- already loaded
3642 helixhorne 1852
        assert(omod==true or type(omod)=="table")
3530 helixhorne 1853
        return omod
2837 helixhorne 1854
    end
1855
 
3343 helixhorne 1856
    local modfn = modname .. ".lua"
3734 helixhorne 1857
    local str = readintostr_mod(modfn)
3343 helixhorne 1858
    if (str == nil) then
1859
        errorf(ERRLEV-1, "Couldn't open file \"%s\"", modfn)
1860
    end
2837 helixhorne 1861
 
3891 helixhorne 1862
    -- Implant code that yields the module thread just before it would return
1863
    -- otherwise.
1864
    str = str.."\nrequire('coroutine').yield()"
1865
 
3804 helixhorne 1866
    local modfunc, errmsg = loadstring(str, modfn)
2837 helixhorne 1867
    if (modfunc == nil) then
2857 helixhorne 1868
        errorf(ERRLEV-1, "Couldn't load \"%s\": %s", modname, errmsg)
2837 helixhorne 1869
    end
1870
 
3642 helixhorne 1871
    package_loaded[modname] = false  -- 'not yet loaded'
2863 helixhorne 1872
    table.insert(modname_stack, modname)
2837 helixhorne 1873
 
3891 helixhorne 1874
    -- Run the module code in a separate Lua thread!
1875
    local modthread = coroutine.create(modfunc)
3894 helixhorne 1876
    local ok, retval = coroutine.resume(modthread, omodname, ...)
2840 helixhorne 1877
 
3891 helixhorne 1878
    if (not ok) then
3916 helixhorne 1879
        errorf(ERRLEV-1, "Failed running \"%s\": %s\n%s", modname,
1880
               retval, debug.traceback(modthread))
3891 helixhorne 1881
    end
1882
 
2863 helixhorne 1883
    table.remove(modname_stack)
2840 helixhorne 1884
 
2863 helixhorne 1885
    local modtab = package_loaded[modname]
1886
 
3891 helixhorne 1887
    if (type(modtab) ~= "table") then
1888
        -- The module didn't call our 'module'. Check if it returned a table.
1889
        -- In that case, the coroutine has finished its main function and has
1890
        -- not reached our implanted 'yield'.
1891
        if (coroutine.status(modthread)=="dead" and type(retval)=="table") then
1892
            modtab = retval
1893
            package_loaded[modname] = modtab
1894
        else
1895
            package_loaded[modname] = true
1896
        end
1897
    end
1898
 
2863 helixhorne 1899
    if (type(modtab) == "table") then
3891 helixhorne 1900
        -- Protect module table in any case (i.e. either if the module used our
1901
        -- 'module' or if it returned a table).
3642 helixhorne 1902
        setmetatable(modtab, required_module_mt)
2837 helixhorne 1903
    end
1904
 
3891 helixhorne 1905
    local gvmodi = module_gvlocali[modname]
1906
 
3965 helixhorne 1907
    if (gvmodi and gvmodi[2] and gvmodi[2]>=gvmodi[1]) then
3891 helixhorne 1908
        if (coroutine.status(modthread)=="suspended") then
1909
            -- Save off the suspended thread so that we may get its locals later on.
1910
            -- It is never resumed, but only ever used for debug.getlocal().
1911
            module_thread[modname] = modthread
1912
 
1913
            if (ffiC._DEBUG_LUNATIC ~= 0) then
1914
                printf("Keeping coroutine for module \"%s\"", modname)
1915
            end
1916
        end
1917
    end
1918
 
2840 helixhorne 1919
    return modtab
2828 helixhorne 1920
end
1921
 
2837 helixhorne 1922
 
2839 helixhorne 1923
local module_mt = {
3928 helixhorne 1924
    __index = error_on_nil_read,
2839 helixhorne 1925
}
1926
 
2863 helixhorne 1927
-- Our 'module' replacement doesn't get the module name from the function args
1928
-- since a malicious user could remove other loaded modules this way.
3642 helixhorne 1929
-- Also, our 'module' takes no varargs ("option functions" in Lua).
2863 helixhorne 1930
-- TODO: make transactional?
1931
local function our_module()
3642 helixhorne 1932
    if (#modname_stack == 0) then
2863 helixhorne 1933
        error("'module' must be called at the top level of a require'd file", 2)
3642 helixhorne 1934
        -- ... as opposed to "at runtime".
2863 helixhorne 1935
    end
2837 helixhorne 1936
 
3642 helixhorne 1937
    local modname = getcurmodname("module")
1938
 
3891 helixhorne 1939
    if (package_loaded[modname]) then
3642 helixhorne 1940
        error("'module' must be called at most once per require'd file", 2)
1941
    end
1942
 
2863 helixhorne 1943
    local M = setmetatable({}, module_mt)
2837 helixhorne 1944
    package_loaded[modname] = M
1945
    -- change the environment of the function which called us:
2863 helixhorne 1946
    setfenv(2, M)
3858 helixhorne 1947
 
1948
    module_gvlocali[modname] = { getnumlocals()+1 }
2837 helixhorne 1949
end
1950
 
2838 helixhorne 1951
-- overridden 'error' that always passes a string to the base 'error'
1952
local function our_error(errmsg, level)
1953
    if (type(errmsg) ~= "string") then
2863 helixhorne 1954
        error("error using 'error': error message must be a string", 2)
2838 helixhorne 1955
    end
1956
 
1957
    if (level) then
1958
        if (type(level) ~= "number") then
2863 helixhorne 1959
            error("error using 'error': error level must be a number", 2)
2838 helixhorne 1960
        end
1961
 
2863 helixhorne 1962
        error(errmsg, level==0 and 0 or level+1)
2838 helixhorne 1963
    end
1964
 
2863 helixhorne 1965
    error(errmsg, 2)
2838 helixhorne 1966
end
1967
 
3390 helixhorne 1968
 
1969
-- _G tweaks -- pull in only 'safe' stuff
1970
local G_ = {}  -- our soon-to-be global environment
1971
 
2074 helixhorne 1972
G_.assert = assert
2863 helixhorne 1973
G_.error = our_error
2074 helixhorne 1974
G_.ipairs = ipairs
2863 helixhorne 1975
G_.pairs = pairs
1976
G_.pcall = pcall
3319 helixhorne 1977
G_.print = print
2863 helixhorne 1978
G_.module = our_module
2074 helixhorne 1979
G_.next = next
2863 helixhorne 1980
G_.require = our_require
2074 helixhorne 1981
G_.select = select
2863 helixhorne 1982
G_.tostring = tostring
1983
G_.tonumber = tonumber
2074 helixhorne 1984
G_.type = type
2863 helixhorne 1985
G_.unpack = unpack
1986
G_.xpcall = xpcall
1987
G_._VERSION = _VERSION
2074 helixhorne 1988
 
2863 helixhorne 1989
-- Available through our 'require':
1990
-- bit, coroutine, math, string, table
1991
 
1992
-- Not available:
1993
-- collectgarbage, debug, dofile, gcinfo (DEPRECATED), getfenv, getmetatable,
1994
-- jit, load, loadfile, loadstring, newproxy (NOT STD?), package, rawequal,
1995
-- rawget, rawset, setfenv, setmetatable
1996
 
2074 helixhorne 1997
G_._G = G_
1998
 
3629 helixhorne 1999
-- Chain together two functions taking 3 input args.
2000
local function chain_func3(func1, func2)
2001
    if (func1==nil or func2==nil) then
2002
        return assert(func1 or func2)
2003
    end
2004
 
2005
    -- Return a function that runs <func1> first and then tail-calls <func2>.
2006
    return function(aci, pli, dist)
2007
        func1(aci, pli, dist)
2008
        return func2(aci, pli, dist)
2009
    end
2010
end
2011
 
3916 helixhorne 2012
-- Determines the last numeric index of a table using *pairs*, so that in
2013
-- arg-lists with "holes" (e.g. {1, 2, nil, function() end}) are handled
2014
-- properly.
3873 helixhorne 2015
local function ourmaxn(tab)
2016
    local maxi = 0
3916 helixhorne 2017
    for i in pairs(tab) do
2018
        if (type(i)=="number") then
2019
            maxi = math.max(i, maxi)
2020
        end
3873 helixhorne 2021
    end
4375 helixhorne 2022
    assert(tab[maxi] ~= nil)
3873 helixhorne 2023
    return maxi
2024
end
2025
 
3829 helixhorne 2026
-- Running for the very first time?
2027
local g_firstRun = (ffiC.g_elCONSize == 0)
2028
 
3629 helixhorne 2029
-- Actor functions, saved for actor chaining
2030
local actor_funcs = {}
3937 helixhorne 2031
-- Event functions, saved for event chaining
2032
local event_funcs = {}
3629 helixhorne 2033
 
3937 helixhorne 2034
-- Per-actor sprite animation callbacks
2035
local animsprite_funcs = {}
2036
 
3315 helixhorne 2037
local gameactor_internal = gameactor_internal  -- included in lunatic.c
3937 helixhorne 2038
local gameevent_internal = gameevent_internal  -- included in lunatic.c
2039
 
2040
local function animate_all_sprites()
2041
    for i=0,ffiC.spritesortcnt-1 do
2042
        local tspr = ffiC.tsprite[i]
2043
 
2044
        if (tspr.owner < ffiC.MAXSPRITES+0ULL) then
2045
            local spr = tspr:getspr()
2046
            local animfunc = animsprite_funcs[spr.picnum]
2047
 
2048
            if (animfunc) then
2049
                animfunc(tspr)
2050
            end
2051
        end
2052
    end
2053
end
2054
 
2055
 
5026 helixhorne 2056
local function check_arg_number(name, argpos, val)
4375 helixhorne 2057
    if (type(val) ~= "number") then
2058
        errorf(3, "invalid '%s' argument (#%d) to gameactor: must be a number", name, argpos)
2059
    end
2060
end
2061
 
3873 helixhorne 2062
-- gameactor{tilenum [, flags [, strength [, action [, move [, movflags]]]]], func}
2063
-- Every arg may be positional OR key=val (with the name indicated above as key),
2064
-- but not both.
2065
local function our_gameactor(args)
3541 helixhorne 2066
    bcheck.top_level("gameactor")
3320 helixhorne 2067
 
3873 helixhorne 2068
    if (type(args)~="table") then
2069
        error("invalid gameactor call: must be passed a table")
2070
    end
2071
 
2072
    local tilenum = args[1]
3315 helixhorne 2073
    if (type(tilenum) ~= "number") then
2074
        error("invalid argument #1 to gameactor: must be a number", 2)
2075
    end
3964 helixhorne 2076
    if (not (tilenum >= 0 and tilenum < ffiC.MAXTILES)) then
3597 helixhorne 2077
        error("invalid argument #1 to gameactor: must be a tile number [0..gv.MAXTILES-1]", 2)
3315 helixhorne 2078
    end
3597 helixhorne 2079
 
3873 helixhorne 2080
    local lastargi = ourmaxn(args)
2081
    local func = args[lastargi]
2082
    if (type(func) ~= "function") then
2083
        func = args.func
2084
        lastargi = 1/0
3315 helixhorne 2085
    end
3873 helixhorne 2086
    if (type(func) ~= "function") then
3928 helixhorne 2087
        error("invalid gameactor call: must provide a function with last numeric arg or .func", 2)
3320 helixhorne 2088
    end
3315 helixhorne 2089
 
3873 helixhorne 2090
    local flags = (lastargi > 2 and args[2]) or args.flags or 0
4375 helixhorne 2091
    check_arg_number("flags", 2, flags)
3597 helixhorne 2092
 
3629 helixhorne 2093
    local AF = actor.FLAGS
3928 helixhorne 2094
    local chainflags = band(flags, AF._CHAIN_MASK_ACTOR)
2095
    flags = band(flags, BNOT.CHAIN_MASK_ACTOR)
3629 helixhorne 2096
 
2097
    if (chainflags == 0) then
4374 helixhorne 2098
        -- Default chaining behavior: don't, replace the old actor instead.
2099
        chainflags = AF.replace
3928 helixhorne 2100
    elseif (band(chainflags, chainflags-1) ~= 0) then
3829 helixhorne 2101
        error("invalid chaining control flags to gameactor", 2)
3629 helixhorne 2102
    end
2103
 
4374 helixhorne 2104
    local replacep = (chainflags==AF.replace)
3629 helixhorne 2105
    if (not replacep and not actor_funcs[tilenum]) then
2106
        error("attempt to chain code to nonexistent actor tile "..tilenum, 2)
2107
    end
2108
 
3928 helixhorne 2109
    local flags_rbits = band(flags, BNOT.USER_MASK)
3597 helixhorne 2110
    if (flags_rbits ~= 0) then
3873 helixhorne 2111
        error("invalid 'flags' argument (#2) to gameactor: must not set reserved bits (0x"
3597 helixhorne 2112
              ..(bit.tohex(flags_rbits))..")", 2)
2113
    end
2114
 
3873 helixhorne 2115
    local strength = ((lastargi > 3 and args[3]) or args.strength) or (replacep and 0 or nil)
3629 helixhorne 2116
    if (replacep or strength~=nil) then
4375 helixhorne 2117
        check_arg_number("strength", 3, strength)
3315 helixhorne 2118
    end
2119
 
3916 helixhorne 2120
    local act = ((lastargi > 4 and args[4]) or args.action) or (replacep and literal_act[0] or nil)
3629 helixhorne 2121
    if (replacep or act ~= nil) then
3916 helixhorne 2122
        if (type(act)=="number" and (act==0 or act==1)) then
2123
            act = literal_act[act]
2124
        elseif (not ffi.istype(con_action_ct, act)) then
2125
            error("invalid 'action' argument (#4) to gameactor: must be an action", 2)
3629 helixhorne 2126
        end
3315 helixhorne 2127
    end
2128
 
3916 helixhorne 2129
    local mov = ((lastargi > 5 and args[5]) or args.move) or (replacep and literal_mov[0] or nil)
3629 helixhorne 2130
    if (replacep or mov ~= nil) then
3916 helixhorne 2131
        if (type(mov)=="number" and (mov==0 or mov==1)) then
2132
            mov = literal_mov[mov]
2133
        elseif (not ffi.istype(con_move_ct, mov)) then
2134
            error("invalid 'move' argument (#5) to gameactor: must be a move", 2)
3629 helixhorne 2135
        end
3315 helixhorne 2136
    end
2137
 
3873 helixhorne 2138
    local movflags = ((lastargi > 6 and args[6]) or args.movflags) or (replacep and 0 or nil)
3629 helixhorne 2139
    if (replacep or movflags ~= nil) then
4375 helixhorne 2140
        check_arg_number("movflags", 6, movflags)
3315 helixhorne 2141
    end
2142
 
3937 helixhorne 2143
    -- Register a potentially passed drawn sprite animation callback function.
2144
    -- TODO: allow registering without main actor execution callback.
2145
    local animfunc = args.animate
2146
    if (animfunc ~= nil) then
2147
        if (type(animfunc) ~= "function") then
2148
            error("invalid 'animate' argument to gameactor: must be a function", 2)
2149
        end
2150
 
2151
        animsprite_funcs[tilenum] = replacep and func
2152
            or (chainflags==AF.chain_beg) and chain_func3(animfunc, animsprite_funcs[tilenum])
2153
            or (chainflags==AF.chain_end) and chain_func3(animsprite_funcs[tilenum], animfunc)
2154
            or assert(false)
2155
 
2156
        -- Register our EVENT_ANIMATEALLSPRITES only now so that it is not
2157
        -- called if there are no 'animate' definitions.
4515 hendricks2 2158
        gameevent_internal(97, animate_all_sprites)  -- EVENT_ANIMATEALLSPRITES
3937 helixhorne 2159
    end
2160
 
4374 helixhorne 2161
    -- All good, bitwise-OR the tile bits and register the actor!
2162
    ffiC.g_tile[tilenum]._flags = bit.bor(ffiC.g_tile[tilenum]._flags, flags)
3597 helixhorne 2163
 
3629 helixhorne 2164
    local newfunc = replacep and func
2165
        or (chainflags==AF.chain_beg) and chain_func3(func, actor_funcs[tilenum])
2166
        or (chainflags==AF.chain_end) and chain_func3(actor_funcs[tilenum], func)
2167
        or assert(false)
2168
 
2169
    gameactor_internal(tilenum, strength, act, mov, movflags, newfunc)
2170
    actor_funcs[tilenum] = newfunc
3315 helixhorne 2171
end
2172
 
3320 helixhorne 2173
 
3873 helixhorne 2174
-- gameevent{<event idx or string> [, flags], <event function>}
2175
local function our_gameevent(args)
3872 helixhorne 2176
    bcheck.top_level("gameevent")
2177
 
3873 helixhorne 2178
    if (type(args)~="table") then
2179
        error("invalid gameevent call: must be passed a table")
2180
    end
2181
 
2182
    local event = args[1]
2183
 
3320 helixhorne 2184
    if (type(event) == "string") then
2185
        if (event:sub(1,6) ~= "EVENT_") then
2186
            event = "EVENT_"..event
2187
        end
3380 helixhorne 2188
        local eventidx = con_lang.EVENT[event]
3320 helixhorne 2189
        if (eventidx == nil) then
2190
            errorf(2, "gameevent: invalid event label %q", event)
2191
        end
2192
        event = eventidx
2193
    end
2194
    if (type(event) ~= "number") then
3629 helixhorne 2195
        error("invalid argument #1 to gameevent: must be a number or event label", 2)
3320 helixhorne 2196
    end
3964 helixhorne 2197
    if (not (event >= 0 and event < con_lang.MAXEVENTS)) then
3320 helixhorne 2198
        error("invalid argument #1 to gameevent: must be an event number (0 .. MAXEVENTS-1)", 2)
2199
    end
2200
 
3629 helixhorne 2201
    local AF = actor.FLAGS
3320 helixhorne 2202
 
3873 helixhorne 2203
    -- Kind of CODEDUP from our_gameactor.
2204
    local lastargi = ourmaxn(args)
2205
    local func = args[lastargi]
2206
    if (type(func) ~= "function") then
2207
        func = args.func
2208
        lastargi = 1/0
2209
    end
2210
    if (type(func) ~= "function") then
2211
        error("invalid gameevent call: must provide a function with last numeric arg or .func", 2)
2212
    end
2213
 
3629 helixhorne 2214
    -- Event chaining: in Lunatic, chaining at the *end* is the default.
3873 helixhorne 2215
    local flags = (lastargi > 2 and args[2]) or args.flags or AF.chain_end
2216
    if (type(flags) ~= "number") then
2217
        error("invalid 'flags' argument (#2) to gameevent: must be a number", 2)
3320 helixhorne 2218
    end
2219
 
3928 helixhorne 2220
    if (band(flags, BNOT.CHAIN_MASK_EVENT) ~= 0) then
3873 helixhorne 2221
        error("invalid 'flags' argument to gameevent: must not set reserved bits", 2)
3629 helixhorne 2222
    end
2223
 
3873 helixhorne 2224
    local newfunc = (flags==AF.replace) and func
3629 helixhorne 2225
        or (flags==AF.chain_beg) and chain_func3(func, event_funcs[event])
2226
        or (flags==AF.chain_end) and chain_func3(event_funcs[event], func)
2227
        or assert(false)
2228
 
3320 helixhorne 2229
    gameevent_internal(event, newfunc)
2230
    event_funcs[event] = newfunc
2231
end
2232
 
2650 helixhorne 2233
--- non-default data and functions
3320 helixhorne 2234
G_.gameevent = our_gameevent
3315 helixhorne 2235
G_.gameactor = our_gameactor
3463 helixhorne 2236
-- These come from above:
2237
G_.player = player
2238
G_.actor = actor
2239
G_.projectile = projectile
3562 helixhorne 2240
G_.g_tile = g_tile
2650 helixhorne 2241
 
4236 helixhorne 2242
G_.LUNATIC_FIRST_TIME = (ffiC.g_elFirstTime ~= 0)
2243
 
4147 helixhorne 2244
-- A table that can be used for temporary data when debugging from the OSD.
2245
G_.d = {}
2650 helixhorne 2246
 
4147 helixhorne 2247
 
3790 helixhorne 2248
---=== Lunatic translator setup ===---
2650 helixhorne 2249
 
3790 helixhorne 2250
read_into_string = readintostr_mod  -- for lunacon
2251
local lunacon = require("lunacon")
2252
 
2253
local concode, lineinfo
2650 helixhorne 2254
 
3787 helixhorne 2255
--- Get Lua code for CON (+ mutator) code.
3788 helixhorne 2256
if (g_firstRun) then
3787 helixhorne 2257
    -- Compiling CON for the first time.
3388 helixhorne 2258
    local confn = { ffi.string(ffiC.G_ConFile()) }
2259
 
2260
    local nummods = ffiC.g_scriptModulesNum
2261
    if (nummods > 0) then
2262
        assert(ffiC.g_scriptModules ~= nil)
2263
 
2264
        for i=1,nummods do
2265
            confn[i+1] = ffi.string(ffiC.g_scriptModules[i-1])
2266
        end
2267
    end
2268
 
3535 helixhorne 2269
    concode, lineinfo = lunacon.compile(confn)
2270
 
3390 helixhorne 2271
    if (concode == nil) then
2272
        error("Failure compiling CON code, exiting.", 0)
2273
    end
3558 helixhorne 2274
    assert(lineinfo)
3535 helixhorne 2275
 
3787 helixhorne 2276
    -- Back up the translated code on the C side.
2277
    assert(type(concode)=="string")
2278
    ffiC.El_SetCON(concode)
2279
else
2280
    -- CON was already compiled.
2281
    concode = ffi.string(ffiC.g_elCON, ffiC.g_elCONSize)
3790 helixhorne 2282
    lineinfo = lunacon.get_lineinfo(concode)
3787 helixhorne 2283
end
2284
 
3790 helixhorne 2285
if (ffiC._DEBUG_LUNATIC ~= 0) then
2286
    -- XXX: lineinfo of 2nd up time has one line less.
2287
    printf("CON line info has %d Lua lines", #lineinfo.llines)
2288
end
2289
 
3787 helixhorne 2290
do
3535 helixhorne 2291
    -- Translate one Lua line number to a CON file name + line number
2292
    local function transline(lnum)
2293
        return string.format("%s:%d", lineinfo:getfline(tonumber(lnum)))
2294
    end
2295
 
2296
    -- Register the function that tweaks an error message, looking out for
2297
    -- errors from CON and translating the line numbers.
2298
    local function tweak_traceback_msg(errmsg)
2299
        return errmsg:gsub('%[string "CON"%]:([0-9]+)', transline)
2300
    end
2301
 
4142 helixhorne 2302
    lprivate.tweak_traceback_msg = tweak_traceback_msg
2303
 
3535 helixhorne 2304
    set_tweak_traceback_internal(tweak_traceback_msg)
3343 helixhorne 2305
end
2306
 
3796 helixhorne 2307
-- XXX: May still be require'd from user code, we don't want that (at least not
2308
-- under this name).
2309
local CON_MODULE_NAME = "_CON\0"
2310
 
2311
-- Set up Lunatic gamevar serialization.
2312
do
6145 hendricks2 2313
    local savegame = require("lunasave")
3796 helixhorne 2314
 
4119 helixhorne 2315
    -- Callback for: const char *(int32_t *slenptr, int32_t levelnum);
2316
    ffiC.El_SerializeGamevars = function(slenptr, levelnum)
3796 helixhorne 2317
        local sb = savegame.savebuffer()
2318
 
3891 helixhorne 2319
        -- Module name, module table, restore_local. See SAVEFUNC_ARGS.
2320
        sb:addraw("local N,M,F=...")
2321
        -- A local to temporarily hold module locals.
2322
        sb:addraw("local L")
3796 helixhorne 2323
 
3891 helixhorne 2324
        -- XXX: System gamevars? Most of them ought to be saved with C data.
3796 helixhorne 2325
        for modname, modvars in pairs(module_gamevars) do
4570 helixhorne 2326
            local isCON = (modname==CON_MODULE_NAME)
2327
 
3908 helixhorne 2328
            sb:startmod(modname)
3891 helixhorne 2329
 
2330
            -- Handle global gamevars first.
3796 helixhorne 2331
            for i=1,#modvars do
2332
                local varname = modvars[i]
4570 helixhorne 2333
                local excludedVars = isCON and varname=="_V" and
4140 helixhorne 2334
                    package_loaded[CON_MODULE_NAME]._V._IS_NORESET_GAMEVAR or nil
2335
 
3796 helixhorne 2336
                -- Serialize gamevar named 'varname' from module named 'modname'.
2337
                -- XXX: May error. This will terminate EDuke32 since this callback
2338
                -- is run unprotected.
4140 helixhorne 2339
                if (sb:add("M."..varname, package_loaded[modname][varname], excludedVars)) then
3796 helixhorne 2340
                    -- We couldn't serialize that gamevar.
2341
                    slenptr[0] = -1
2342
                    -- Signal which gamevar that was.
4570 helixhorne 2343
                    return (isCON and "<CON>" or modname).."."..varname
3796 helixhorne 2344
                end
2345
            end
3891 helixhorne 2346
 
2347
            local modthread = module_thread[modname]
2348
 
2349
            if (modthread) then
2350
                -- Handle local gamevars.
2351
                local gvmodi = module_gvlocali[modname]
2352
 
2353
                for li=gvmodi[1],gvmodi[2] do
2354
                    -- Serialize local with index <li>. Get its value first.
2355
                    local lname, lval = debug.getlocal(modthread, 1, li)
2356
 
2357
                    if (sb:add("L", lval)) then
2358
                        -- We couldn't serialize that gamevar.
2359
                        slenptr[0] = -1
2360
                        return "local "..modname.."."..lname
2361
                    end
2362
 
4118 helixhorne 2363
                    -- Emit code to call restore_local.
3891 helixhorne 2364
                    sb:addrawf("F(%d,L)", li)
2365
                end
2366
            end
2367
 
3908 helixhorne 2368
            sb:endmod()
3796 helixhorne 2369
        end
2370
 
2371
        -- Get the whole code as a string.
2372
        local savecode = sb:getcode()
2373
 
2374
        if (ffiC._DEBUG_LUNATIC ~= 0) then
4570 helixhorne 2375
            -- Dump the code if Lunatic debugging is enabled (-Lopts=diag) and
2376
            -- there is a LUNATIC_SAVECODE_FN variable in the environment.
3796 helixhorne 2377
            local os = require("os")
2378
            local fn = os.getenv("LUNATIC_SAVECODE_FN")
2379
 
2380
            if (fn ~= nil) then
4119 helixhorne 2381
                if (levelnum >= 0) then
2382
                    fn = fn .. levelnum
2383
                end
2384
 
3796 helixhorne 2385
                local io = require("io")
2386
                local f = io.open(fn, "w")
2387
 
2388
                if (f ~= nil) then
2389
                    f:write(savecode)
2390
                    f:close()
2391
                    printf("Wrote Lunatic gamevar restoration code to \"%s\".", fn)
2392
                end
2393
            end
2394
        end
2395
 
2396
        -- Set the size of the code and return the code to C.
2397
        slenptr[0] = #savecode
2398
        return savecode
2399
    end
2400
end
2401
 
2648 helixhorne 2402
-- change the environment of this chunk to the table G_
2827 helixhorne 2403
-- NOTE: all references to global variables from this point on
2404
-- (also in functions created after this point) refer to G_ !
2648 helixhorne 2405
setfenv(1, G_)
2406
 
2863 helixhorne 2407
-- Print keys and values of a table.
2648 helixhorne 2408
local function printkv(label, table)
3060 helixhorne 2409
    print("========== Keys and values of "..label.." ("..tostring(table)..")")
2863 helixhorne 2410
    for k,v in pairs(table) do
3343 helixhorne 2411
        print(k .. ": " .. tostring(v))
2648 helixhorne 2412
    end
3343 helixhorne 2413
    print("----------")
2648 helixhorne 2414
end
2415
 
2710 helixhorne 2416
--printkv('_G AFTER SETFENV', _G)
2648 helixhorne 2417
 
2418
 
2419
---=== Restricted access to C variables from Lunatic ===---
2420
 
2298 helixhorne 2421
-- error(..., 2) is to blame the caller and get its line numbers
2294 helixhorne 2422
 
3928 helixhorne 2423
-- Map of 'gv' variable names to C ones.
2424
local varnameMap = {
2425
    gametic = "g_moveThingsCount",
4031 helixhorne 2426
    RETURN = "g_RETURN",
4112 helixhorne 2427
    _sessionVar = "g_elSessionVar",
3928 helixhorne 2428
}
2429
 
2430
gv_access.gametic = true
4031 helixhorne 2431
gv_access.RETURN = true
4112 helixhorne 2432
gv_access._sessionVar = true
3928 helixhorne 2433
 
2044 helixhorne 2434
local tmpmt = {
3597 helixhorne 2435
    __index = function(_, key)
3406 helixhorne 2436
        if (gv_access[key] == nil) then
3928 helixhorne 2437
            -- Read access allowed.
3406 helixhorne 2438
            return ffiC[key]
3928 helixhorne 2439
        elseif (type(gv_access[key])~="boolean") then
2440
            -- Overridden 'gv' pseudo-member...
3406 helixhorne 2441
            return gv_access[key]
3928 helixhorne 2442
        elseif (varnameMap[key]) then
2443
            -- Variable known under a different name on the C side.
2444
            return ffiC[varnameMap[key]]
3406 helixhorne 2445
        end
2446
        error("access forbidden", 2)
2447
    end,
3556 helixhorne 2448
 
3597 helixhorne 2449
    __newindex = function(_, key, val)
3593 helixhorne 2450
        if (gv_access[key] == nil) then
4030 helixhorne 2451
            -- Variables declared 'const' are handled by LuaJIT.
3556 helixhorne 2452
            ffiC[key] = val
4031 helixhorne 2453
        elseif (varnameMap[key]) then
2454
            ffiC[varnameMap[key]] = val
3556 helixhorne 2455
        else
2456
            error("write access forbidden", 2)
2457
        end
2458
    end,
2044 helixhorne 2459
}
3597 helixhorne 2460
gv = setmtonce(gv_, tmpmt)
2044 helixhorne 2461
 
3060 helixhorne 2462
-- This will create 'sprite', 'wall', etc. HERE, i.e. in the environment of this chunk
2463
defs_c.create_globals(_G)
2863 helixhorne 2464
 
2648 helixhorne 2465
-- REMOVE this for release
3966 helixhorne 2466
if (ffiC._DEBUG_LUNATIC ~= 0) then
2467
    local DBG_ = {}
2468
    DBG_.debug = require("debug")
2469
    DBG_.printkv = printkv
2470
    DBG_.loadstring = loadstring
2471
    DBG_.oom = function()
2472
        local s = "1"
2473
        for i=1,math.huge do
2474
            s = s..s
2475
        end
3380 helixhorne 2476
    end
2611 helixhorne 2477
 
3966 helixhorne 2478
    -- Test reading from all struct members
2479
    DBG_.testmembread = function()
2480
        for _1, sac in pairs { con_lang.StructAccessCode, con_lang.StructAccessCode2 } do
2481
            for what, labels in pairs(sac) do
2482
                if (what~="tspr") then
2483
                    for _3, membaccode in pairs(labels) do
2484
                        if (type(membaccode)=="table") then
2485
                            membaccode = membaccode[1]
2486
                        end
2487
                        if (membaccode) then
2488
                            local codestr = [[
3650 helixhorne 2489
do
2490
    local _bit,_math=require'bit',require'math'
4209 helixhorne 2491
    local _con=require'con'
3650 helixhorne 2492
    local _band,_gv=_bit.band,gv
2493
local tmp=]]..
4375 helixhorne 2494
                            membaccode:gsub("^_gud%(_pli%)", "_con._get_userdef(0)"):gsub("%%s","0").." end"
3966 helixhorne 2495
                            local code = assert(loadstring(codestr))
2496
                            code()
2497
                        end
3475 helixhorne 2498
                    end
2499
                end
2500
            end
2501
        end
2502
    end
3966 helixhorne 2503
 
2504
    allowed_modules._LUNATIC_DBG = DBG_
3475 helixhorne 2505
end
2611 helixhorne 2506
 
2648 helixhorne 2507
---=== Finishing environment setup ===---
2611 helixhorne 2508
 
2710 helixhorne 2509
--printkv('_G AFTER DECLS', _G)
2193 helixhorne 2510
 
4047 helixhorne 2511
local index_error_mt = {
2512
    __index = function(_, key)
2513
        error("attempt to read undeclared variable '"..key.."'", 2)
2514
    end,
2193 helixhorne 2515
 
4047 helixhorne 2516
    __metatable = true,
2517
}
2518
 
2310 helixhorne 2519
-- PiL 14.2 continued
2648 helixhorne 2520
-- We need this at the end because we were previously doing just that!
4047 helixhorne 2521
setmetatable(G_, index_error_mt)
3642 helixhorne 2522
 
3967 helixhorne 2523
local global_mt = {
2524
    __index = G_,
2525
 
2526
    __newindex = function()
2527
        error("attempt to write into the global environment")
2528
    end,
2529
 
2530
    __metatable = true,
2531
}
2532
 
2648 helixhorne 2533
-- Change the environment of the running Lua thread so that everything
2534
-- what we've set up will be available when this chunk is left.
3473 helixhorne 2535
-- In particular, we need the globals defined after setting this chunk's
2648 helixhorne 2536
-- environment earlier.
3967 helixhorne 2537
setfenv(0, setmetatable({}, global_mt))
3343 helixhorne 2538
 
3891 helixhorne 2539
do
2540
    -- If we're running from a savegame restoration, create the restoration
2541
    -- function. Must be here, after the above setfenv(), because it must be
2542
    -- created in this protected ('user') context!
2543
    local cstr = ffiC.g_elSavecode
2544
    if (cstr~=nil) then
2545
        local restorecode = ffi.string(cstr)
2546
        ffiC.El_FreeSaveCode()
2547
 
2548
        g_restorefunc = assert(loadstring(restorecode))
2549
    end
2550
end
2551
 
4119 helixhorne 2552
-- Restore CON gamevars from loadmapstate.
2553
-- TODO: non-user-defined gamevars.
2554
-- TODO: savegames.
2555
-- int32_t El_RestoreGamevars(const char *)
2556
ffiC.El_RestoreGamevars = function(savecode)
2557
    savecode = ffi.string(savecode)
2558
    local restorefunc = assert(loadstring(savecode))
2559
    restorefunc(CON_MODULE_NAME, package_loaded[CON_MODULE_NAME], nil)
2560
    return 0
2561
end
2562
 
3788 helixhorne 2563
-- Run the CON code translated into Lua.
4370 helixhorne 2564
if (assert(concode ~= nil)) then
3343 helixhorne 2565
    local confunc, conerrmsg = loadstring(concode, "CON")
2566
    if (confunc == nil) then
3558 helixhorne 2567
        error("Failure loading translated CON code: "..conerrmsg, 0)
3343 helixhorne 2568
    end
3796 helixhorne 2569
 
3891 helixhorne 2570
    -- Emulate our 'require' for the CON module when running it, for
2571
    -- our_module() which is called from the generated Lua code.
2572
    table.insert(modname_stack, CON_MODULE_NAME)
3917 helixhorne 2573
    local conlabels, conaction, conmove, conai = confunc()
3891 helixhorne 2574
    table.remove(modname_stack)
3870 helixhorne 2575
 
3917 helixhorne 2576
    local function protect_con_table(tab)
4047 helixhorne 2577
        -- NOTE: Some of our code specifically excepts the name tables to be
4570 helixhorne 2578
        -- indexable with nonexistent keys. See e.g. control.lua: _A_SpawnGlass()
4050 helixhorne 2579
        if (ffiC._LUNATIC_STRICT ~= 0) then
2580
            tab = setmetatable(tab, index_error_mt)
2581
        end
3917 helixhorne 2582
        return setmtonce({}, { __index=tab, __newindex=basemod_newidx })
2583
    end
3871 helixhorne 2584
 
3917 helixhorne 2585
    -- Set up CON.* modules, providing access to diffenrent kinds of labels
2586
    -- defined in CON from Lua. See CONCODE_RETURN in lunacon.lua.
2587
    allowed_modules["CON.DEFS"] = protect_con_table(conlabels)
2588
    allowed_modules["CON.ACTION"] = protect_con_table(conaction)
2589
    allowed_modules["CON.MOVE"] = protect_con_table(conmove)
2590
    allowed_modules["CON.AI"] = protect_con_table(conai)
2591
 
3871 helixhorne 2592
    -- Propagate potentially remapped defines to the control module.
2593
    con._setuplabels(conlabels)
4370 helixhorne 2594
 
4376 helixhorne 2595
    local function getLabelValue(str, doupper)
2596
        return conlabels[doupper and string.upper(str) or str]
2597
    end
2598
 
4370 helixhorne 2599
    ffiC.El_GetLabelValue = function(label)
2600
        local str = ffi.string(label)
4376 helixhorne 2601
        local ok, val = pcall(getLabelValue, str, false)
2602
        if (not ok or type(val)~="number") then
2603
            ok, val = pcall(getLabelValue, str, true)
2604
        end
2605
        return (ok and type(val)=="number") and val or bit.tobit(0x80000000)
4370 helixhorne 2606
    end
3343 helixhorne 2607
end
3788 helixhorne 2608
 
2609
-- When starting a map, load Lua modules given on the command line.
2610
if (not g_firstRun) then
2611
    local i=0
2612
    while (ffiC.g_elModules[i] ~= nil) do
3867 helixhorne 2613
        -- Get the module name and strip the trailing extension.
2614
        local modname = ffi.string(ffiC.g_elModules[i]):gsub("%.lua$","")
2615
 
2616
        if (modname:find("%.")) then
2617
            -- Because they will be replaced by dirseps in our_require().
2618
            error("Dots are not permitted in module names", 0)
2619
        end
2620
        -- Allow forward slashes in module names from the cmdline.
2621
        our_require((modname:gsub("%.lua$",""):gsub("/",".")))
2622
 
3788 helixhorne 2623
        i = i+1
2624
    end
4236 helixhorne 2625
 
2626
    ffiC.g_elFirstTime = 0
3788 helixhorne 2627
end
4570 helixhorne 2628
 
2629
if (g_restorefunc) then
2630
    -- Clear it so that it may be garbage-collected.
2631
    g_restorefunc = nil
2632
end