Subversion Repositories eduke32

Rev

Rev 6569 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 6569 Rev 8777
1
-- INTERNAL
1
-- INTERNAL
2
-- definitions of BUILD and game types for the Lunatic Interpreter
2
-- definitions of BUILD and game types for the Lunatic Interpreter
3
3
4
local require = require
4
local require = require
5
local ffi = require("ffi")
5
local ffi = require("ffi")
6
local ffiC = ffi.C
6
local ffiC = ffi.C
7
7
8
-- Lua C API functions.
8
-- Lua C API functions.
9
local CF = CF
9
local CF = CF
10
10
11
local bit = bit
11
local bit = bit
12
local coroutine = coroutine
12
local coroutine = coroutine
13
local string = string
13
local string = string
14
local table = table
14
local table = table
15
local math = math
15
local math = math
16
16
17
local assert = assert
17
local assert = assert
18
local error = error
18
local error = error
19
local getfenv = getfenv
19
local getfenv = getfenv
20
local getmetatable = getmetatable
20
local getmetatable = getmetatable
21
local ipairs = ipairs
21
local ipairs = ipairs
22
local loadstring = loadstring
22
local loadstring = loadstring
23
local pairs = pairs
23
local pairs = pairs
24
local pcall = pcall
24
local pcall = pcall
25
local rawget = rawget
25
local rawget = rawget
26
local rawset = rawset
26
local rawset = rawset
27
local select = select
27
local select = select
28
local setmetatable = setmetatable
28
local setmetatable = setmetatable
29
local setfenv = setfenv
29
local setfenv = setfenv
30
local tonumber = tonumber
30
local tonumber = tonumber
31
local tostring = tostring
31
local tostring = tostring
32
local type = type
32
local type = type
33
33
34
-- Create a new module for passing stuff to other modules.
34
-- Create a new module for passing stuff to other modules.
35
local lprivate = {}
35
local lprivate = {}
36
require("package").loaded.lprivate = lprivate
36
require("package").loaded.lprivate = lprivate
37
37
38
require("jit.opt").start("maxmcode=10240")  -- in KiB
38
require("jit.opt").start("maxmcode=10240")  -- in KiB
39
39
40
-- The "gv" global will provide access to C global *scalars* and safe functions.
40
-- The "gv" global will provide access to C global *scalars* and safe functions.
41
-- NOTE: This exposes C library functions from e.g. the global C namespace, but
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.
42
-- without their declarations, they will be sitting there like a stone.
43
local gv_ = {}
43
local gv_ = {}
44
-- [key]=<boolean> forbids, [key]=<non-boolean (e.g. table, function)> overrides
44
-- [key]=<boolean> forbids, [key]=<non-boolean (e.g. table, function)> overrides
45
local gv_access = {}
45
local gv_access = {}
46
46
47
-- This is for declarations of arrays or pointers which should not be
47
-- This is for declarations of arrays or pointers which should not be
48
-- accessible through the "gv" global. The "defs_common" module will
48
-- accessible through the "gv" global. The "defs_common" module will
49
-- use this function.
49
-- use this function.
50
--
50
--
51
-- Notes: do not declare multiple scalars on one line (this is bad:
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
52
-- "int32_t a, b"). Do not name array arguments (or add a space
53
-- between the identifier and the '[' instead).
53
-- between the identifier and the '[' instead).
54
function decl(str, ...)
54
function decl(str, ...)
55
    -- NOTE that the regexp also catches non-array/non-function identifiers
55
    -- NOTE that the regexp also catches non-array/non-function identifiers
56
    -- like "user_defs ud;"
56
    -- like "user_defs ud;"
57
    for varname in string.gmatch(str, "([%a_][%w_]*)[[(;]") do
57
    for varname in string.gmatch(str, "([%a_][%w_]*)[[(;]") do
58
        if (ffiC._DEBUG_LUNATIC ~= 0) then
58
        if (ffiC._DEBUG_LUNATIC ~= 0) then
59
            print("FORBID "..varname)
59
            print("FORBID "..varname)
60
        end
60
        end
61
        gv_access[varname] = true
61
        gv_access[varname] = true
62
    end
62
    end
63
63
64
    ffi.cdef(str, ...)
64
    ffi.cdef(str, ...)
65
end
65
end
66
66
67
lprivate.decl = decl
67
lprivate.decl = decl
68
68
69
ffi.cdef[[
69
ffi.cdef[[
70
enum {
70
enum {
71
    LUNATIC_CLIENT_MAPSTER32 = 0,
71
    LUNATIC_CLIENT_MAPSTER32 = 0,
72
    LUNATIC_CLIENT_EDUKE32 = 1,
72
    LUNATIC_CLIENT_EDUKE32 = 1,
73
73
74
    LUNATIC_CLIENT = LUNATIC_CLIENT_EDUKE32
74
    LUNATIC_CLIENT = LUNATIC_CLIENT_EDUKE32
75
}
75
}
76
]]
76
]]
77
77
78
-- Load the definitions common to the game's and editor's Lua interface.
78
-- Load the definitions common to the game's and editor's Lua interface.
79
local defs_c = require("defs_common")
79
local defs_c = require("defs_common")
80
local cansee = defs_c.cansee
80
local cansee = defs_c.cansee
81
local strip_const = defs_c.strip_const
81
local strip_const = defs_c.strip_const
82
local setmtonce = defs_c.setmtonce
82
local setmtonce = defs_c.setmtonce
83
83
84
-- Must be after loading "defs_common" which redefines "print" to use
84
-- Must be after loading "defs_common" which redefines "print" to use
85
-- OSD_Printf()
85
-- OSD_Printf()
86
local print, printf = print, defs_c.printf
86
local print, printf = print, defs_c.printf
87
87
88
88
89
---=== EDuke32 game definitions ===---
89
---=== EDuke32 game definitions ===---
90
90
91
local INV_NAMES = {
91
local INV_NAMES = {
92
    "STEROIDS",
92
    "STEROIDS",
93
    "SHIELD",
93
    "SHIELD",
94
    "SCUBA",
94
    "SCUBA",
95
    "HOLODUKE",
95
    "HOLODUKE",
96
    "JETPACK",
96
    "JETPACK",
97
    "DUMMY1",
97
    "DUMMY1",
98
    "ACCESS",
98
    "ACCESS",
99
    "HEATS",
99
    "HEATS",
100
    "DUMMY2",
100
    "DUMMY2",
101
    "FIRSTAID",
101
    "FIRSTAID",
102
    "BOOTS",
102
    "BOOTS",
103
}
103
}
104
104
105
local WEAPON_NAMES = {
105
local WEAPON_NAMES = {
106
    "KNEE",
106
    "KNEE",
107
    "PISTOL",
107
    "PISTOL",
108
    "SHOTGUN",
108
    "SHOTGUN",
109
    "CHAINGUN",
109
    "CHAINGUN",
110
    "RPG",
110
    "RPG",
111
    "HANDBOMB",
111
    "HANDBOMB",
112
    "SHRINKER",
112
    "SHRINKER",
113
    "DEVISTATOR",
113
    "DEVISTATOR",
114
    "TRIPBOMB",
114
    "TRIPBOMB",
115
    "FREEZE",
115
    "FREEZE",
116
    "HANDREMOTE",
116
    "HANDREMOTE",
117
    "GROW",
117
    "GROW",
118
}
118
}
119
119
120
---- game structs ----
120
---- game structs ----
121
121
122
lprivate.GET = defs_c.conststruct(INV_NAMES)
122
lprivate.GET = defs_c.conststruct(INV_NAMES)
123
lprivate.WEAPON = defs_c.conststruct(WEAPON_NAMES)
123
lprivate.WEAPON = defs_c.conststruct(WEAPON_NAMES)
124
124
125
ffi.cdef([[
125
ffi.cdef([[
126
enum {
126
enum {
127
    GET_MAX = 11,
127
    GET_MAX = 11,
128
    MAX_WEAPONS = 12,
128
    MAX_WEAPONS = 12,
129
    MAXPLAYERS = 16,
129
    MAXPLAYERS = 16,
130
    GTICSPERSEC = 30,  // The real number of movement updates per second
130
    GTICSPERSEC = 30,  // The real number of movement updates per second
131
};
131
};
132
]])
132
]])
133
133
134
ffi.cdef[[
134
ffi.cdef[[
135
struct action {
135
struct action {
136
    int16_t startframe, numframes;
136
    int16_t startframe, numframes;
137
    int16_t viewtype, incval, delay;
137
    int16_t viewtype, incval, delay;
138
    uint16_t flags;
138
    uint16_t flags;
139
};
139
};
140
140
141
struct move {
141
struct move {
142
    int16_t hvel, vvel;
142
    int16_t hvel, vvel;
143
};
143
};
144
144
145
#pragma pack(push,1)
145
#pragma pack(push,1)
146
typedef struct { int32_t id; struct move mv; } con_move_t;
146
typedef struct { int32_t id; struct move mv; } con_move_t;
147
typedef struct { int32_t id; struct action ac; } con_action_t;
147
typedef struct { int32_t id; struct action ac; } con_action_t;
148
#pragma pack(pop)
148
#pragma pack(pop)
149
149
150
typedef struct {
150
typedef struct {
151
    int32_t id;
151
    int32_t id;
152
    con_action_t act;
152
    con_action_t act;
153
    con_move_t mov;
153
    con_move_t mov;
154
    int32_t movflags;
154
    int32_t movflags;
155
} con_ai_t;
155
} con_ai_t;
156
]]
156
]]
157
157
158
defs_c.bitint_new_struct_type("int16_t", "SBit16")
158
defs_c.bitint_new_struct_type("int16_t", "SBit16")
159
defs_c.bitint_new_struct_type("int32_t", "SBit32")
159
defs_c.bitint_new_struct_type("int32_t", "SBit32")
160
defs_c.bitint_new_struct_type("uint32_t", "UBit32")
160
defs_c.bitint_new_struct_type("uint32_t", "UBit32")
161
161
162
-- Struct template for actor_t. It already has 'const' fields (TODO: might need
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
163
-- to make more 'const'), but still has array members exposed, so is unsuited
164
-- for external exposure.
164
-- for external exposure.
165
local ACTOR_STRUCT = [[
165
local ACTOR_STRUCT = [[
166
struct {
166
struct {
167
    const int32_t t_data[10];
167
    const int32_t t_data[10];
168
    const struct move mv;
168
    const struct move mv;
169
    const struct action ac;
169
    const struct action ac;
170
    const uint16_t actiontics;
170
    const uint16_t actiontics;
171
171
172
]]..defs_c.bitint_member("SBit32", "flags")..[[
172
]]..defs_c.bitint_member("SBit32", "flags")..[[
173
    vec3_t bpos; //12b
173
    vec3_t bpos; //12b
174
    int32_t floorz,ceilingz,lastvx,lastvy; //16b
174
    int32_t floorz,ceilingz,lastvx,lastvy; //16b
175
    int32_t lasttransport; //4b
175
    int32_t lasttransport; //4b
176
176
177
    const int16_t picnum;
177
    const int16_t picnum;
178
    int16_t ang, extra;
178
    int16_t ang, extra;
179
    const int16_t owner;
179
    const int16_t owner;
180
    // NOTE: not to be confused with .movflags:
180
    // NOTE: not to be confused with .movflags:
181
]]..defs_c.bitint_member("SBit16", "_movflag")..[[
181
]]..defs_c.bitint_member("SBit16", "_movflag")..[[
182
    int16_t tempang, timetosleep;
182
    int16_t tempang, timetosleep;
183
183
184
    int16_t stayputsect;
184
    int16_t stayputsect;
185
    const int16_t dispicnum;
185
    const int16_t dispicnum;
186
    // Movement flags, sprite[i].hitag in C-CON.
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)
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?
188
    // XXX: what if CON code knew of the above implementation detail?
189
]]..defs_c.bitint_member("UBit16", "movflags")..[[
189
]]..defs_c.bitint_member("UBit16", "movflags")..[[
190
    int16_t cgg;
190
    int16_t cgg;
191

191

192
    const int16_t lightId, lightcount, lightmaxrange;
192
    const int16_t lightId, lightcount, lightmaxrange;
193
    // NOTE: on 32-bit, C's lightptr+filler <=> this dummy:
193
    // NOTE: on 32-bit, C's lightptr+filler <=> this dummy:
194
    const union { intptr_t ptr; uint64_t dummy; } _light;
194
    const union { intptr_t ptr; uint64_t dummy; } _light;
195
}
195
}
196
]]
196
]]
197
197
198
local bcarray = require("bcarray")
198
local bcarray = require("bcarray")
199
199
200
local bcheck = require("bcheck")
200
local bcheck = require("bcheck")
201
local check_sector_idx, check_tile_idx = bcheck.sector_idx, bcheck.tile_idx
201
local check_sector_idx, check_tile_idx = bcheck.sector_idx, bcheck.tile_idx
202
local check_sprite_idx = bcheck.sprite_idx
202
local check_sprite_idx = bcheck.sprite_idx
203
local check_weapon_idx, check_inventory_idx = bcheck.weapon_idx, bcheck.inventory_idx
203
local check_weapon_idx, check_inventory_idx = bcheck.weapon_idx, bcheck.inventory_idx
204
local check_sound_idx = bcheck.sound_idx
204
local check_sound_idx = bcheck.sound_idx
205
local check_number = bcheck.number
205
local check_number = bcheck.number
206
local check_type = bcheck.type
206
local check_type = bcheck.type
207
207
208
bcarray.new("int16_t", 64, "loogie", "int16_x_64")  -- TODO: randomize member names
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)
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)
210
bcarray.new("int16_t", ffiC.GET_MAX, "inventory", "int16_x_GET_MAX", INV_NAMES)
211
211
212
-- NOTE: writing e.g. "ps.jetpack_on" in Lua when "ps.jetpack_on~=0" was meant
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
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
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.
215
-- fields to store more than just one bit, we're in trouble.
216
-- This will need to be documented and frozen for release.
216
-- This will need to be documented and frozen for release.
217
local DUKEPLAYER_STRUCT = [[
217
local DUKEPLAYER_STRUCT = [[
218
__attribute__((packed)) struct {
218
__attribute__((packed)) struct {
219
    vec3_t pos, opos, vel, npos;
219
    vec3_t pos, opos, vel, npos;
220
    vec2_t bobpos, fric;
220
    vec2_t bobpos, fric;
221
    int32_t truefz, truecz, player_par;
221
    int32_t truefz, truecz, player_par;
222
    int32_t randomflamex, exitx, exity;
222
    int32_t randomflamex, exitx, exity;
223
    int32_t runspeed, max_player_health, max_shield_amount;
223
    int32_t runspeed, max_player_health, max_shield_amount;
224
    int32_t autostep, autostep_sbw;
224
    int32_t autostep, autostep_sbw;
225
225
226
    uint32_t interface_toggle_flag;
226
    uint32_t interface_toggle_flag;
227
227
228
    int32_t pipebombControl, pipebombLifetime, pipebombLifetimeVar;
228
    int32_t pipebombControl, pipebombLifetime, pipebombLifetimeVar;
229
    int32_t tripbombControl, tripbombLifetime, tripbombLifetimeVar;
229
    int32_t tripbombControl, tripbombLifetime, tripbombLifetimeVar;
230
230
231
    int32_t zrange;
231
    int32_t zrange;
232
    int16_t angrange, autoaimang;
232
    int16_t angrange, autoaimang;
233
233
234
    uint16_t max_actors_killed, actors_killed;
234
    uint16_t max_actors_killed, actors_killed;
235
]]..defs_c.bitint_member("UBit16", "gotweapon")..[[
235
]]..defs_c.bitint_member("UBit16", "gotweapon")..[[
236
    uint16_t zoom;
236
    uint16_t zoom;
237
237
238
    int16_x_64 loogiex;
238
    int16_x_64 loogiex;
239
    int16_x_64 loogiey;
239
    int16_x_64 loogiey;
240
    int16_t sbs, sound_pitch;
240
    int16_t sbs, sound_pitch;
241
241
242
    int16_t ang, oang, angvel;
242
    int16_t ang, oang, angvel;
243
    const<S> int16_t cursectnum;
243
    const<S> int16_t cursectnum;
244
    int16_t look_ang, last_extra, subweapon;
244
    int16_t look_ang, last_extra, subweapon;
245
    int16_x_MAX_WEAPONS max_ammo_amount;
245
    int16_x_MAX_WEAPONS max_ammo_amount;
246
    int16_x_MAX_WEAPONS ammo_amount;
246
    int16_x_MAX_WEAPONS ammo_amount;
247
    int16_x_GET_MAX inv_amount;
247
    int16_x_GET_MAX inv_amount;
248
    const<I-> int16_t wackedbyactor;
248
    const<I-> int16_t wackedbyactor;
249
    int16_t pyoff, opyoff;
249
    int16_t pyoff, opyoff;
250
250
251
    int16_t horiz, horizoff, ohoriz, ohorizoff;
251
    int16_t horiz, horizoff, ohoriz, ohorizoff;
252
    const<I-> int16_t newowner;
252
    const<I-> int16_t newowner;
253
    int16_t jumping_counter, airleft;
253
    int16_t jumping_counter, airleft;
254
    int16_t fta;
254
    int16_t fta;
255
    const<Q> int16_t ftq;
255
    const<Q> int16_t ftq;
256
    const int16_t access_wallnum, access_spritenum;
256
    const int16_t access_wallnum, access_spritenum;
257
    int16_t got_access, weapon_ang, visibility;
257
    int16_t got_access, weapon_ang, visibility;
258
    int16_t somethingonplayer, on_crane;
258
    int16_t somethingonplayer, on_crane;
259
    const int16_t i;
259
    const int16_t i;
260
    const int16_t one_parallax_sectnum;
260
    const int16_t one_parallax_sectnum;
261
    int16_t random_club_frame, one_eighty_count;
261
    int16_t random_club_frame, one_eighty_count;
262
    const<I-> int16_t dummyplayersprite;
262
    const<I-> int16_t dummyplayersprite;
263
    int16_t extra_extra8;
263
    int16_t extra_extra8;
264
    int16_t actorsqu, timebeforeexit;
264
    int16_t actorsqu, timebeforeexit;
265
    const<X-> int16_t customexitsound;
265
    const<X-> int16_t customexitsound;
266
    int16_t last_pissed_time;
266
    int16_t last_pissed_time;
267
267
268
    int16_x_MAX_WEAPONS weaprecs;
268
    int16_x_MAX_WEAPONS weaprecs;
269
    int16_t weapon_sway, crack_time, bobcounter;
269
    int16_t weapon_sway, crack_time, bobcounter;
270
270
271
    int16_t orotscrnang, rotscrnang, dead_flag;   // JBF 20031220: added orotscrnang
271
    int16_t orotscrnang, rotscrnang, dead_flag;   // JBF 20031220: added orotscrnang
272
    int16_t holoduke_on, pycount;
272
    int16_t holoduke_on, pycount;
273
    int16_t transporter_hold;
273
    int16_t transporter_hold;
274
274
275
    uint8_t max_secret_rooms, secret_rooms;
275
    uint8_t max_secret_rooms, secret_rooms;
276
    uint8_t frag, fraggedself, quick_kick, last_quick_kick;
276
    uint8_t frag, fraggedself, quick_kick, last_quick_kick;
277
    uint8_t return_to_center;
277
    uint8_t return_to_center;
278
    bool reloading;
278
    bool reloading;
279
    const uint8_t weapreccnt;
279
    const uint8_t weapreccnt;
280
    uint8_t aim_mode, auto_aim, weaponswitch, movement_lock, team;
280
    uint8_t aim_mode, auto_aim, weaponswitch, movement_lock, team;
281
    uint8_t tipincs, hbomb_hold_delay;
281
    uint8_t tipincs, hbomb_hold_delay;
282
    const<P> uint8_t frag_ps;
282
    const<P> uint8_t frag_ps;
283
    uint8_t kickback_pic;
283
    uint8_t kickback_pic;
284
284
285
    uint8_t gm;
285
    uint8_t gm;
286
    bool on_warping_sector;
286
    bool on_warping_sector;
287
    uint8_t footprintcount, hurt_delay;
287
    uint8_t footprintcount, hurt_delay;
288
    bool hbomb_on, jumping_toggle, rapid_fire_hold, on_ground;
288
    bool hbomb_on, jumping_toggle, rapid_fire_hold, on_ground;
289
    // NOTE: there's array indexing with inven_icon, but always after a
289
    // NOTE: there's array indexing with inven_icon, but always after a
290
    // bound check:
290
    // bound check:
291
    uint8_t inven_icon, buttonpalette;
291
    uint8_t inven_icon, buttonpalette;
292
    bool over_shoulder_on;
292
    bool over_shoulder_on;
293
    uint8_t show_empty_weapon;
293
    uint8_t show_empty_weapon;
294

294

295
    bool jetpack_on, spritebridge;
295
    bool jetpack_on, spritebridge;
296
    uint8_t lastrandomspot;  // unused
296
    uint8_t lastrandomspot;  // unused
297
    bool scuba_on;
297
    bool scuba_on;
298
    uint8_t footprintpal;
298
    uint8_t footprintpal;
299
    bool heat_on;
299
    bool heat_on;
300
    uint8_t invdisptime;
300
    uint8_t invdisptime;
301

301

302
    bool holster_weapon;
302
    bool holster_weapon;
303
    uint8_t falling_counter, footprintshade;
303
    uint8_t falling_counter, footprintshade;
304
    uint8_t refresh_inventory;
304
    uint8_t refresh_inventory;
305
    const<W> uint8_t last_full_weapon;
305
    const<W> uint8_t last_full_weapon;
306

306

307
    const uint8_t toggle_key_flag;
307
    const uint8_t toggle_key_flag;
308
    uint8_t knuckle_incs, knee_incs, access_incs;
308
    uint8_t knuckle_incs, knee_incs, access_incs;
309
    uint8_t walking_snd_toggle, palookup, hard_landing, fist_incs;
309
    uint8_t walking_snd_toggle, palookup, hard_landing, fist_incs;
310

310

311
    int8_t numloogs, loogcnt;
311
    int8_t numloogs, loogcnt;
312
    const int8_t scream_voice;
312
    const int8_t scream_voice;
313
    const<W-> int8_t last_weapon;
313
    const<W-> int8_t last_weapon;
314
    const int8_t cheat_phase;
314
    const int8_t cheat_phase;
315
    int8_t weapon_pos;
315
    int8_t weapon_pos;
316
    const<W-> int8_t wantweaponfire;
316
    const<W-> int8_t wantweaponfire;
317
    const<W> int8_t curr_weapon;
317
    const<W> int8_t curr_weapon;
318

318

319
    const uint8_t palette;
319
    const uint8_t palette;
320
    palette_t _pals;
320
    palette_t _pals;
321
    int8_t _palsfadespeed, _palsfadenext, _palsfadeprio, _padding2;
321
    int8_t _palsfadespeed, _palsfadenext, _palsfadeprio, _padding2;
322

322

323
    // NOTE: In C, the struct type has no name. We only have it here to define
323
    // NOTE: In C, the struct type has no name. We only have it here to define
324
    // a metatype later.
324
    // a metatype later.
325
    const weaponaccess_t weapon;
325
    const weaponaccess_t weapon;
326
    const int8_t _padding;
326
    const int8_t _padding;
327
}
327
}
328
]]
328
]]
329

329

330
local PROJECTILE_STRUCT = [[
330
local PROJECTILE_STRUCT = [[
331
struct {
331
struct {
332
    int32_t workslike, cstat;
332
    int32_t workslike, cstat;
333
    int32_t hitradius, range, flashcolor;
333
    int32_t hitradius, range, flashcolor;
334
    const int16_t spawns;
334
    const int16_t spawns;
335
    const int16_t sound, isound;
335
    const int16_t sound, isound;
336
    int16_t vel;
336
    int16_t vel;
337
    const int16_t decal, trail;
337
    const int16_t decal, trail;
338
    int16_t tnum, drop;
338
    int16_t tnum, drop;
339
    int16_t offset, bounces;
339
    int16_t offset, bounces;
340
    const int16_t bsound;
340
    const int16_t bsound;
341
    int16_t toffset;
341
    int16_t toffset;
342
    int16_t extra, extra_rand;
342
    int16_t extra, extra_rand;
343
    int8_t sxrepeat, syrepeat, txrepeat, tyrepeat;
343
    int8_t sxrepeat, syrepeat, txrepeat, tyrepeat;
344
    int8_t shade, xrepeat, yrepeat, pal;
344
    int8_t shade, xrepeat, yrepeat, pal;
345
    int8_t movecnt;
345
    int8_t movecnt;
346
    uint8_t clipdist;
346
    uint8_t clipdist;
347
    int8_t filler[2];
347
    int8_t filler[2];
348
    int32_t userdata;
348
    int32_t userdata;
349
}
349
}
350
]]
350
]]
351

351

352
-- KEEPINSYNC weapondata_mt below.
352
-- KEEPINSYNC weapondata_mt below.
353
local WEAPONDATA_STRUCT = "struct {"..table.concat(con_lang.wdata_members, ';').."; }"
353
local WEAPONDATA_STRUCT = "struct {"..table.concat(con_lang.wdata_members, ';').."; }"
354

354

355
local randgen = require("randgen")
355
local randgen = require("randgen")
356

356

357
local ma_rand = randgen.new(true)  -- initialize to "random" (time-based) seed
357
local ma_rand = randgen.new(true)  -- initialize to "random" (time-based) seed
358
local ma_count = nil
358
local ma_count = nil
359

359

360
local function ma_replace_array(typestr, neltstr)
360
local function ma_replace_array(typestr, neltstr)
361
    local nelts = tonumber(neltstr)
361
    local nelts = tonumber(neltstr)
362
    if (nelts==nil) then
362
    if (nelts==nil) then
363
        nelts = ffiC[neltstr]
363
        nelts = ffiC[neltstr]
364
        assert(type(nelts)=="number")
364
        assert(type(nelts)=="number")
365
    end
365
    end
366

366

367
    local strtab = { "const ", typestr.." " }
367
    local strtab = { "const ", typestr.." " }
368
    for i=1,nelts do
368
    for i=1,nelts do
369
        local ch1 = 97 + (ma_rand:getu32() % 25)  -- 'a'..'z'
369
        local ch1 = 97 + (ma_rand:getu32() % 25)  -- 'a'..'z'
370
        strtab[i+2] = string.format("_%c%x%s", ch1, ma_count, (i<nelts) and "," or ";")
370
        strtab[i+2] = string.format("_%c%x%s", ch1, ma_count, (i<nelts) and "," or ";")
371
        ma_count = ma_count+1
371
        ma_count = ma_count+1
372
    end
372
    end
373

373

374
    return table.concat(strtab)
374
    return table.concat(strtab)
375
end
375
end
376

376

377
---=== Protection of scalars in (currently only) DukePlayer_t struct. ===---
377
---=== Protection of scalars in (currently only) DukePlayer_t struct. ===---
378
-- This is more convenient than writing dozens of set-member methods.
378
-- This is more convenient than writing dozens of set-member methods.
379
local prot_scalar_chkfunc = {
379
local prot_scalar_chkfunc = {
380
    S = check_sector_idx,
380
    S = check_sector_idx,
381
    I = check_sprite_idx,
381
    I = check_sprite_idx,
382

382

383
    P = bcheck.player_idx,
383
    P = bcheck.player_idx,
384
    W = check_weapon_idx,
384
    W = check_weapon_idx,
385
    X = check_sound_idx,
385
    X = check_sound_idx,
386
    Q = bcheck.quote_idx,
386
    Q = bcheck.quote_idx,
387
}
387
}
388

388

389
local DukePlayer_prot_allowneg = {}  -- [<member name>] = true if setting <0 allowed
389
local DukePlayer_prot_allowneg = {}  -- [<member name>] = true if setting <0 allowed
390
local DukePlayer_prot_chkfunc = {}  -- [<member name>] = <checking function>
390
local DukePlayer_prot_chkfunc = {}  -- [<member name>] = <checking function>
391

391

392
local function ma_replace_scalar(what, typestr, membname)
392
local function ma_replace_scalar(what, typestr, membname)
393
    DukePlayer_prot_chkfunc[membname] = assert(prot_scalar_chkfunc[what:sub(1,1)])
393
    DukePlayer_prot_chkfunc[membname] = assert(prot_scalar_chkfunc[what:sub(1,1)])
394
    DukePlayer_prot_allowneg[membname] = (what:sub(2)=="-")
394
    DukePlayer_prot_allowneg[membname] = (what:sub(2)=="-")
395
    return ma_replace_array(typestr, 1)
395
    return ma_replace_array(typestr, 1)
396
end
396
end
397

397

398
-- Converts a template struct definition to an external one, in which arrays
398
-- Converts a template struct definition to an external one, in which arrays
399
-- have been substituted by randomly named scalar fields.
399
-- have been substituted by randomly named scalar fields.
400
-- <also_scalars>: also handle protected scalars like "const<W-> ..." etc.
400
-- <also_scalars>: also handle protected scalars like "const<W-> ..." etc.
401
local function mangle_arrays(structstr, also_scalars)
401
local function mangle_arrays(structstr, also_scalars)
402
    ma_count = 0
402
    ma_count = 0
403
    -- NOTE: regexp only works for non-nested arrays and for one array per line.
403
    -- NOTE: regexp only works for non-nested arrays and for one array per line.
404
    structstr = structstr:gsub("const%s+([%w_]+)[^\n]+%[([%w_]+)%];", ma_replace_array)
404
    structstr = structstr:gsub("const%s+([%w_]+)[^\n]+%[([%w_]+)%];", ma_replace_array)
405

405

406
    if (also_scalars) then
406
    if (also_scalars) then
407
        -- One protected scalar per line, too.
407
        -- One protected scalar per line, too.
408
        structstr = structstr:gsub("const<(.-)>%s+([%w_]-)%s+([%w_]-);", ma_replace_scalar)
408
        structstr = structstr:gsub("const<(.-)>%s+([%w_]-)%s+([%w_]-);", ma_replace_scalar)
409
    end
409
    end
410

410

411
    return structstr
411
    return structstr
412
end
412
end
413

413

414
--print(mangle_arrays(DUKEPLAYER_STRUCT, true))
414
--print(mangle_arrays(DUKEPLAYER_STRUCT, true))
415

415

416
--- default defines etc.
416
--- default defines etc.
417
local con_lang = require("con_lang")
417
local con_lang = require("con_lang")
418
local xmath = require("xmath")
418
local xmath = require("xmath")
419

419

420
ffi.cdef([[
420
ffi.cdef([[
421
typedef struct { int32_t _p; } weaponaccess_t;
421
typedef struct { int32_t _p; } weaponaccess_t;
422

422

423
typedef struct {
423
typedef struct {
424
]]..defs_c.bitint_member("UBit32", "bits")..[[
424
]]..defs_c.bitint_member("UBit32", "bits")..[[
425
    int16_t fvel, svel, avel;
425
    int16_t fvel, svel, avel;
426
    int8_t horz, extbits;
426
    int8_t horz, extbits;
427
} input_t;
427
} input_t;
428

428

429
typedef
429
typedef
430
]].. mangle_arrays(ACTOR_STRUCT) ..[[
430
]].. mangle_arrays(ACTOR_STRUCT) ..[[
431
actor_t;
431
actor_t;
432

432

433
typedef
433
typedef
434
]].. mangle_arrays(DUKEPLAYER_STRUCT, true) ..[[
434
]].. mangle_arrays(DUKEPLAYER_STRUCT, true) ..[[
435
DukePlayer_t;
435
DukePlayer_t;
436

436

437
typedef __attribute__((packed)) struct {
437
typedef __attribute__((packed)) struct {
438
    DukePlayer_t *ps;
438
    DukePlayer_t *ps;
439
    input_t *sync;
439
    input_t *sync;
440

440

441
    int32_t netsynctime;
441
    int32_t netsynctime;
442
    int16_t ping, filler;
442
    int16_t ping, filler;
443
    int32_t pcolor, pteam;
443
    int32_t pcolor, pteam;
444
    uint8_t frags[MAXPLAYERS], wchoice[MAX_WEAPONS];
444
    uint8_t frags[MAXPLAYERS], wchoice[MAX_WEAPONS];
445

445

446
    char vote, gotvote, pingcnt, playerquitflag, ready;
446
    char vote, gotvote, pingcnt, playerquitflag, ready;
447
    char user_name[32];
447
    char user_name[32];
448
    uint32_t revision;
448
    uint32_t revision;
449
} playerdata_t;
449
} playerdata_t;
450

450

451
typedef struct {
451
typedef struct {
452
    int32_t cur, count;
452
    int32_t cur, count;
453
    int32_t gunposx, lookhalfang;
453
    int32_t gunposx, lookhalfang;
454
    int32_t gunposy, lookhoriz;
454
    int32_t gunposy, lookhoriz;
455
    int32_t shade;
455
    int32_t shade;
456
} hudweapon_t;
456
} hudweapon_t;
457

457

458
typedef
458
typedef
459
]].. WEAPONDATA_STRUCT ..[[
459
]].. WEAPONDATA_STRUCT ..[[
460
weapondata_t;
460
weapondata_t;
461

461

462
typedef
462
typedef
463
]].. PROJECTILE_STRUCT ..[[
463
]].. PROJECTILE_STRUCT ..[[
464
projectile_t;
464
projectile_t;
465

465

466
typedef struct {
466
typedef struct {
467
    uint32_t _flags;  // XXX: do we want to have this accessible at game time?
467
    uint32_t _flags;  // XXX: do we want to have this accessible at game time?
468
    int32_t _cacherange;
468
    int32_t _cacherange;
469
    projectile_t *_proj;
469
    projectile_t *_proj;
470
    const projectile_t *_defproj;
470
    const projectile_t *_defproj;
471
} tiledata_t;
471
} tiledata_t;
472

472

473
typedef struct {
473
typedef struct {
474
    vec3_t pos;
474
    vec3_t pos;
475
    int32_t dist, clock;
475
    int32_t dist, clock;
476
    int16_t ang, horiz;
476
    int16_t ang, horiz;
477
    int16_t sect;  // NOTE: protected in camera_mt's __newindex
477
    int16_t sect;  // NOTE: protected in camera_mt's __newindex
478
} camera_t;
478
} camera_t;
479
479
480
enum
480
enum
481
{
481
{
482
    MAXMOUSEBUTTONS = 10,
482
    MAXMOUSEBUTTONS = 10,
483
    MAXMOUSEAXES = 2,
483
    MAXMOUSEAXES = 2,
484
    MAXJOYBUTTONS = 32,
484
    MAXJOYBUTTONS = 32,
485
    MAXJOYBUTTONSANDHATS = (32+4),
485
    MAXJOYBUTTONSANDHATS = (32+4),
486
    MAXJOYAXES = 9,
486
    MAXJOYAXES = 9,
487
487
488
    NUMGAMEFUNCTIONS = 56,
488
    NUMGAMEFUNCTIONS = 56,
489
489
490
    // game.h
490
    // game.h
491
    MAXRIDECULE = 10,
491
    MAXRIDECULE = 10,
492
    MAXRIDECULELENGTH = 40,
492
    MAXRIDECULELENGTH = 40,
493
    MAXSAVEGAMENAME = 22,
493
    MAXSAVEGAMENAME = 22,
494
    MAXPWLOCKOUT = 128,
494
    MAXPWLOCKOUT = 128,
495
    MAXRTSNAME = 128,
495
    MAXRTSNAME = 128,
496
};
496
};
497
497
498
typedef struct {
498
typedef struct {
499
    int32_t const_visibility,uw_framerate;
499
    int32_t const_visibility,uw_framerate;
500
    int32_t camera_time,folfvel,folavel,folx,foly,fola;
500
    int32_t camera_time,folfvel,folavel,folx,foly,fola;
501
    int32_t reccnt,crosshairscale;
501
    int32_t reccnt,crosshairscale;
502
502
503
    int32_t runkey_mode,statusbarscale,mouseaiming,weaponswitch,drawweapon;   // JBF 20031125
503
    int32_t runkey_mode,statusbarscale,mouseaiming,weaponswitch,drawweapon;   // JBF 20031125
504
    int32_t democams,color,msgdisptime,statusbarmode;
504
    int32_t democams,color,msgdisptime,statusbarmode;
505
    int32_t m_noexits,noexits,autovote,automsg,idplayers;
505
    int32_t m_noexits,noexits,autovote,automsg,idplayers;
506
    int32_t team, viewbob, weaponsway, althud, weaponscale, textscale;
506
    int32_t team, viewbob, weaponsway, althud, weaponscale, textscale;
507
507
508
    int32_t entered_name,screen_tilting,shadows,fta_on,executions,auto_run;
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;
509
    int32_t coords,tickrate,levelstats,m_coop,coop,screen_size,lockout,crosshair;
510
    int32_t playerai,angleinterpolation,obituaries;
510
    int32_t playerai,angleinterpolation,obituaries;
511
511
512
    int32_t respawn_monsters,respawn_items,respawn_inventory,recstat,monsters_off,brightness;
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;
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;
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;
515
    int32_t player_skill,level_number,volume_number,m_marker,marker,mouseflip;
516
516
517
    vec2_t m_origin;
517
    vec2_t m_origin;
518
    int32_t playerbest;
518
    int32_t playerbest;
519
519
520
    int32_t configversion, bgstretch;
520
    int32_t configversion, bgstretch;
521
521
522
    int16_t pause_on,from_bonus;
522
    int16_t pause_on,from_bonus;
523
    int16_t camerasprite,last_camsprite;
523
    int16_t camerasprite,last_camsprite;
524
    int16_t last_level,secretlevel;
524
    int16_t last_level,secretlevel;
525
525
526
    struct {
526
    struct {
527
        int32_t UseJoystick;
527
        int32_t UseJoystick;
528
        int32_t UseMouse;
528
        int32_t UseMouse;
529
        int32_t AutoAim;
529
        int32_t AutoAim;
530
        int32_t ShowOpponentWeapons;
530
        int32_t ShowOpponentWeapons;
531
        int32_t MouseDeadZone,MouseBias;
531
        int32_t MouseDeadZone,MouseBias;
532
        int32_t SmoothInput;
532
        int32_t SmoothInput;
533
533
534
        // JBF 20031211: Store the input settings because
534
        // JBF 20031211: Store the input settings because
535
        // (currently) mact can't regurgitate them
535
        // (currently) mact can't regurgitate them
536
        int32_t MouseFunctions[MAXMOUSEBUTTONS][2];
536
        int32_t MouseFunctions[MAXMOUSEBUTTONS][2];
537
        int32_t MouseDigitalFunctions[MAXMOUSEAXES][2];
-
 
538
        int32_t MouseAnalogueAxes[MAXMOUSEAXES];
537
        int32_t MouseAnalogueAxes[MAXMOUSEAXES];
539
        int32_t MouseAnalogueScale[MAXMOUSEAXES];
538
        int32_t MouseAnalogueScale[MAXMOUSEAXES];
540
        int32_t JoystickFunctions[MAXJOYBUTTONSANDHATS][2];
539
        int32_t JoystickFunctions[MAXJOYBUTTONSANDHATS][2];
541
        int32_t JoystickDigitalFunctions[MAXJOYAXES][2];
540
        int32_t JoystickDigitalFunctions[MAXJOYAXES][2];
542
        int32_t JoystickAnalogueAxes[MAXJOYAXES];
541
        int32_t JoystickAnalogueAxes[MAXJOYAXES];
543
        int32_t JoystickAnalogueScale[MAXJOYAXES];
542
        int32_t JoystickAnalogueScale[MAXJOYAXES];
544
        int32_t JoystickAnalogueDead[MAXJOYAXES];
543
        int32_t JoystickAnalogueDead[MAXJOYAXES];
545
        int32_t JoystickAnalogueSaturate[MAXJOYAXES];
544
        int32_t JoystickAnalogueSaturate[MAXJOYAXES];
546
        uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
545
        uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
547

546

548
        //
547
        //
549
        // Sound variables
548
        // Sound variables
550
        //
549
        //
551
        int32_t MasterVolume;
550
        int32_t MasterVolume;
552
        int32_t FXVolume;
551
        int32_t FXVolume;
553
        int32_t MusicVolume;
552
        int32_t MusicVolume;
554
        int32_t SoundToggle;
553
        int32_t SoundToggle;
555
        int32_t MusicToggle;
554
        int32_t MusicToggle;
556
        int32_t VoiceToggle;
555
        int32_t VoiceToggle;
557
        int32_t AmbienceToggle;
556
        int32_t AmbienceToggle;
558

557

559
        int32_t NumVoices;
558
        int32_t NumVoices;
560
        int32_t NumChannels;
559
        int32_t NumChannels;
561
        int32_t NumBits;
560
        int32_t NumBits;
562
        int32_t MixRate;
561
        int32_t MixRate;
563

562

564
        int32_t ReverseStereo;
563
        int32_t ReverseStereo;
565

564

566
        //
565
        //
567
        // Screen variables
566
        // Screen variables
568
        //
567
        //
569

568

570
        int32_t ScreenMode;
569
        int32_t ScreenMode;
571

570

572
        int32_t ScreenWidth;
571
        int32_t ScreenWidth;
573
        int32_t ScreenHeight;
572
        int32_t ScreenHeight;
574
        int32_t ScreenBPP;
573
        int32_t ScreenBPP;
575

574

576
        int32_t ForceSetup;
575
        int32_t ForceSetup;
577
        int32_t NoAutoLoad;
576
        int32_t NoAutoLoad;
578

577

579
        const int32_t scripthandle;
578
        const int32_t scripthandle;
580
        int32_t setupread;
579
        int32_t setupread;
581

580

582
        int32_t CheckForUpdates;
581
        int32_t CheckForUpdates;
583
        int32_t LastUpdateCheck;
582
        int32_t LastUpdateCheck;
584
        int32_t useprecache;
583
        int32_t useprecache;
585
    } config;
584
    } config;
586

585

587
    char overhead_on,last_overhead,showweapons;
586
    char overhead_on,last_overhead,showweapons;
588
    char god,warp_on,cashman,eog,showallmap;
587
    char god,warp_on,cashman,eog,showallmap;
589
    char show_help,scrollmode,noclip;
588
    char show_help,scrollmode,noclip;
590
    char ridecule[MAXRIDECULE][MAXRIDECULELENGTH];
589
    char ridecule[MAXRIDECULE][MAXRIDECULELENGTH];
591
    char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME];
590
    char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME];
592
    char display_bonus_screen;
591
    char display_bonus_screen;
593
    char show_level_text;
592
    char show_level_text;
594
    char wchoice[MAX_WEAPONS];
593
    char wchoice[MAX_WEAPONS];
595
} user_defs;
594
} user_defs;
596

595

597
typedef struct {
596
typedef struct {
598
    int32_t partime, designertime;
597
    int32_t partime, designertime;
599
    char *name, *filename, *musicfn;
598
    char *name, *filename, *musicfn;
600
    void *savedstate;
599
    void *savedstate;
601
} map_t;
600
} map_t;
602
]])
601
]])
603

602

604
bcarray.new("weapondata_t", ffiC.MAX_WEAPONS, "weapon", "weapondata_x_MAX_WEAPONS", WEAPON_NAMES)
603
bcarray.new("weapondata_t", ffiC.MAX_WEAPONS, "weapon", "weapondata_x_MAX_WEAPONS", WEAPON_NAMES)
605
bcarray.new("int32_t", con_lang.MAXSESSIONVARS, "sessionvar", "int32_x_MAXSESSIONVARS")
604
bcarray.new("int32_t", con_lang.MAXSESSIONVARS, "sessionvar", "int32_x_MAXSESSIONVARS")
606

605

607
-- EXTERNALLY EXPOSED GAME VARIABLES
606
-- EXTERNALLY EXPOSED GAME VARIABLES
608
ffi.cdef[[
607
ffi.cdef[[
609
const int32_t screenpeek;
608
const int32_t screenpeek;
610
hudweapon_t hudweap;
609
hudweapon_t hudweap;
611
int32_t g_logoFlags;
610
int32_t g_logoFlags;
612
]]
611
]]
613

612

614
-- INTERNAL VARIABLES/FUNCTIONS
613
-- INTERNAL VARIABLES/FUNCTIONS
615
decl("map_t g_mapInfo[$*$];", con_lang.MAXVOLUMES+1, con_lang.MAXLEVELS)
614
decl("map_t g_mapInfo[$*$];", con_lang.MAXVOLUMES+1, con_lang.MAXLEVELS)
616
decl("char g_volumeNames[$][33];", con_lang.MAXVOLUMES)
615
decl("char g_volumeNames[$][33];", con_lang.MAXVOLUMES)
617

616

618
decl[[
617
decl[[
619
const int32_t myconnectindex;
618
const int32_t myconnectindex;
620
int32_t g_RETURN;
619
int32_t g_RETURN;
621
int32_t g_elCONSize;
620
int32_t g_elCONSize;
622
char *g_elCON;
621
char *g_elCON;
623
void El_SetCON(const char *conluacode);
622
void El_SetCON(const char *conluacode);
624
void El_OnError(const char *str);
623
void El_OnError(const char *str);
625

624

626
char *g_elSavecode;
625
char *g_elSavecode;
627
void El_FreeSaveCode(void);
626
void El_FreeSaveCode(void);
628
const char *(*El_SerializeGamevars)(int32_t *slenptr, int32_t levelnum);
627
const char *(*El_SerializeGamevars)(int32_t *slenptr, int32_t levelnum);
629
int32_t (*El_RestoreGamevars)(const char *savecode);
628
int32_t (*El_RestoreGamevars)(const char *savecode);
630
int32_t (*El_GetLabelValue)(const char *label);
629
int32_t (*El_GetLabelValue)(const char *label);
631

630

632
const char *s_buildRev;
631
const char *s_buildRev;
633
const char *g_sizes_of_what[];
632
const char *g_sizes_of_what[];
634
int32_t g_sizes_of[];
633
int32_t g_sizes_of[];
635
int32_t g_elFirstTime;
634
int32_t g_elFirstTime;
636
int32_t g_elCallDepth;
635
int32_t g_elCallDepth;
637
int32_t block_deletesprite;
636
int32_t block_deletesprite;
638
const char **g_elModules;
637
const char **g_elModules;
639
char g_modDir[];
638
char g_modDir[];
640
int32_x_MAXSESSIONVARS g_elSessionVar;
639
int32_x_MAXSESSIONVARS g_elSessionVar;
641
actor_t actor[MAXSPRITES];
640
actor_t actor[MAXSPRITES];
642
camera_t g_camera;
641
camera_t g_camera;
643
user_defs ud;
642
user_defs ud;
644
playerdata_t *const g_player;
643
playerdata_t *const g_player;
645
DukePlayer_t *g_player_ps[MAXPLAYERS];
644
DukePlayer_t *g_player_ps[MAXPLAYERS];
646
weapondata_x_MAX_WEAPONS g_playerWeapon[MAXPLAYERS];
645
weapondata_x_MAX_WEAPONS g_playerWeapon[MAXPLAYERS];
647
weapondata_t g_weaponOverridden[MAX_WEAPONS];
646
weapondata_t g_weaponOverridden[MAX_WEAPONS];
648
int16_t WeaponPickupSprites[MAX_WEAPONS];
647
int16_t WeaponPickupSprites[MAX_WEAPONS];
649
tiledata_t g_tile[MAXTILES];
648
tiledata_t g_tile[MAXTILES];
650
projectile_t SpriteProjectile[MAXSPRITES];
649
projectile_t SpriteProjectile[MAXSPRITES];
651

650

652
int32_t g_noResetVars;
651
int32_t g_noResetVars;
653
void (*A_ResetVars)(int32_t iActor);
652
void (*A_ResetVars)(int32_t iActor);
654

653

655
// Used from lunacon.lua for dynamic {tile,sound} remapping:
654
// Used from lunacon.lua for dynamic {tile,sound} remapping:
656
struct
655
struct
657
{
656
{
658
    const char *str;
657
    const char *str;
659
    int32_t *dynvalptr;
658
    int32_t *dynvalptr;
660
    const int16_t staticval;
659
    const int16_t staticval;
661
} g_dynTileList[], g_dynSoundList[];
660
} g_dynTileList[], g_dynSoundList[];
662

661

663
char *apStrings[];
662
char *apStrings[];
664

663

665
const int32_t g_mostConcurrentPlayers;
664
const int32_t g_mostConcurrentPlayers;
666
int16_t g_deleteQueueSize;
665
int16_t g_deleteQueueSize;
667
int16_t g_blimpSpawnItems[15];
666
int16_t g_blimpSpawnItems[15];
668
int32_t g_scriptVersion;
667
int32_t g_scriptVersion;
669
const int32_t g_frameRate;
668
const int32_t g_frameRate;
670
const int32_t g_currentMenu;
669
const int32_t g_currentMenu;
671
uint16_t g_earthquakeTime;
670
uint16_t g_earthquakeTime;
672
uint32_t g_moveThingsCount;
671
uint32_t g_moveThingsCount;
673
char CheatKeys[2];
672
char CheatKeys[2];
674

673

675
// Must not have functions here that may call events directly or
674
// Must not have functions here that may call events directly or
676
// indirectly. See lunatic_game.c.
675
// indirectly. See lunatic_game.c.
677

676

678
int32_t A_IncurDamage(int32_t sn);  // not bound-checked!
677
int32_t A_IncurDamage(int32_t sn);  // not bound-checked!
679
int32_t G_CheckActivatorMotion(int32_t lotag);
678
int32_t G_CheckActivatorMotion(int32_t lotag);
680
int32_t A_Dodge(spritetype *s);
679
int32_t A_Dodge(spritetype *s);
681
int32_t A_MoveSpriteClipdist(int32_t spritenum, const vec3_t *change, uint32_t cliptype, int32_t clipdist);
680
int32_t A_MoveSpriteClipdist(int32_t spritenum, const vec3_t *change, uint32_t cliptype, int32_t clipdist);
682
void P_DoQuote(int32_t q, DukePlayer_t *p);
681
void P_DoQuote(int32_t q, DukePlayer_t *p);
683
void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, int32_t set);
682
void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, int32_t set);
684
void G_AddUserQuote(const char *daquote);
683
void G_AddUserQuote(const char *daquote);
685
void G_ClearCameraView(DukePlayer_t *ps);
684
void G_ClearCameraView(DukePlayer_t *ps);
686
void VM_DrawTileGeneric(int32_t x, int32_t y, int32_t zoom, int32_t tilenum,
685
void VM_DrawTileGeneric(int32_t x, int32_t y, int32_t zoom, int32_t tilenum,
687
                       int32_t shade, int32_t orientation, int32_t p);
686
                       int32_t shade, int32_t orientation, int32_t p);
688
void G_InitTimer(int32_t ticspersec);
687
void G_InitTimer(int32_t ticspersec);
689
void G_GetTimeDate(int32_t *vals);
688
void G_GetTimeDate(int32_t *vals);
690
int32_t G_ToggleWallInterpolation(int32_t w, int32_t doset);
689
int32_t G_ToggleWallInterpolation(int32_t w, int32_t doset);
691
int32_t G_StartTrack(int32_t level);
690
int32_t G_StartTrack(int32_t level);
692
int32_t VM_CheckSquished2(int32_t i, int32_t snum);
691
int32_t VM_CheckSquished2(int32_t i, int32_t snum);
693
void Menu_Change(int32_t cm);
692
void Menu_Change(int32_t cm);
694

693

695
const char *KB_ScanCodeToString(uint8_t scancode);
694
const char *KB_ScanCodeToString(uint8_t scancode);
696

695

697
int32_t A_CheckAnySoundPlaying(int32_t i);
696
int32_t A_CheckAnySoundPlaying(int32_t i);
698
int32_t S_CheckSoundPlaying(int32_t i, int32_t num);
697
int32_t S_CheckSoundPlaying(int32_t i, int32_t num);
699
void S_StopEnvSound(int32_t num, int32_t i);
698
void S_StopEnvSound(int32_t num, int32_t i);
700
void S_StopAllSounds(void);
699
void S_StopAllSounds(void);
701
void S_ChangeSoundPitch(int32_t num, int32_t i, int32_t pitchoffset);
700
void S_ChangeSoundPitch(int32_t num, int32_t i, int32_t pitchoffset);
702
int32_t S_GetMusicPosition(void);
701
int32_t S_GetMusicPosition(void);
703
void S_SetMusicPosition(int32_t position);
702
void S_SetMusicPosition(int32_t position);
704

703

705
int32_t minitext_(int32_t x,int32_t y,const char *t,int32_t s,int32_t p,int32_t sb);
704
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,
705
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);
706
                      int32_t cs,int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t z);
708
void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t,
707
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,
708
                     int32_t s, int32_t p, int32_t o,
710
                     int32_t x1, int32_t y1, int32_t x2, int32_t y2,
709
                     int32_t x1, int32_t y1, int32_t x2, int32_t y2,
711
                     int32_t z, int32_t a);
710
                     int32_t z, int32_t a);
712
vec2_t G_ScreenText(const int32_t font,
711
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,
712
                    int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle,
714
                    const char *str, const int32_t shade, int32_t pal, int32_t o, int32_t alpha,
713
                    const char *str, const int32_t shade, int32_t pal, int32_t o, int32_t alpha,
715
                    int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f,
714
                    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);
715
                    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,
716
vec2_t G_ScreenTextSize(const int32_t font,
718
                        int32_t x, int32_t y, const int32_t z, const int32_t blockangle,
717
                        int32_t x, int32_t y, const int32_t z, const int32_t blockangle,
719
                        const char *str, const int32_t o,
718
                        const char *str, const int32_t o,
720
                        int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween,
719
                        int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween,
721
                        const int32_t f,
720
                        const int32_t f,
722
                        int32_t x1, int32_t y1, int32_t x2, int32_t y2);
721
                        int32_t x1, int32_t y1, int32_t x2, int32_t y2);
723
const char* G_PrintYourTime(void);
722
const char* G_PrintYourTime(void);
724
const char* G_PrintParTime(void);
723
const char* G_PrintParTime(void);
725
const char* G_PrintDesignerTime(void);
724
const char* G_PrintDesignerTime(void);
726
const char* G_PrintBestTime(void);
725
const char* G_PrintBestTime(void);
727

726

728
void G_UpdateScreenArea(void);
727
void G_UpdateScreenArea(void);
729
void G_SaveMapState(void);
728
void G_SaveMapState(void);
730
void G_RestoreMapState(void);
729
void G_RestoreMapState(void);
731
void G_FreeMapState(int32_t mapnum);
730
void G_FreeMapState(int32_t mapnum);
732
]]
731
]]
733

732

734
decl[[
733
decl[[
735
int32_t kopen4loadfrommod(const char *filename, char searchfirst);
734
int32_t kopen4loadfrommod(const char *filename, char searchfirst);
736

735

737
char **g_scriptModules;
736
char **g_scriptModules;
738
int32_t g_scriptModulesNum;
737
int32_t g_scriptModulesNum;
739

738

740
const char *G_ConFile(void);
739
const char *G_ConFile(void);
741
void G_DoGameStartup(const int32_t *params);
740
void G_DoGameStartup(const int32_t *params);
742
int32_t C_DefineSound(int32_t sndidx, const char *fn, int32_t args [5]);
741
int32_t C_DefineSound(int32_t sndidx, const char *fn, int32_t args [5]);
743
void C_DefineMusic(int32_t vol, int32_t lev, const char *fn);
742
void C_DefineMusic(int32_t vol, int32_t lev, const char *fn);
744
void C_DefineQuote(int32_t qnum, const char *qstr);
743
void C_DefineQuote(int32_t qnum, const char *qstr);
745
void C_DefineVolumeName(int32_t vol, const char *name);
744
void C_DefineVolumeName(int32_t vol, const char *name);
746
void C_DefineVolumeFlags(int32_t vol, int32_t flags);
745
void C_DefineVolumeFlags(int32_t vol, int32_t flags);
747
void C_UndefineVolume(int32_t vol);
746
void C_UndefineVolume(int32_t vol);
748
void C_DefineSkillName(int32_t skill, const char *name);
747
void C_DefineSkillName(int32_t skill, const char *name);
749
void C_UndefineSkill(int32_t skill);
748
void C_UndefineSkill(int32_t skill);
750
void C_DefineLevelName(int32_t vol, int32_t lev, const char *fn,
749
void C_DefineLevelName(int32_t vol, int32_t lev, const char *fn,
751
                       int32_t partime, int32_t designertime,
750
                       int32_t partime, int32_t designertime,
752
                       const char *levelname);
751
                       const char *levelname);
753
void C_UndefineLevel(int32_t vol, int32_t lev);
752
void C_UndefineLevel(int32_t vol, int32_t lev);
754
void C_DefineProjectile(int32_t j, int32_t what, int32_t val);
753
void C_DefineProjectile(int32_t j, int32_t what, int32_t val);
755
void C_DefineGameFuncName(int32_t idx, const char *name);
754
void C_DefineGameFuncName(int32_t idx, const char *name);
756
void C_DefineGameType(int32_t idx, int32_t flags, const char *name);
755
void C_DefineGameType(int32_t idx, int32_t flags, const char *name);
757
int32_t C_SetDefName(const char *name);
756
int32_t C_SetDefName(const char *name);
758
void C_SetCfgName(const char *cfgname);
757
void C_SetCfgName(const char *cfgname);
759

758

760
int32_t SCRIPT_GetNumber(int32_t scripthandle, const char *sectionname, const char *entryname, int32_t *number);
759
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,
760
void SCRIPT_PutNumber(int32_t scripthandle, const char *sectionname, const char *entryname, int32_t number,
762
                      int32_t hexadecimal, int32_t defaultvalue);
761
                      int32_t hexadecimal, int32_t defaultvalue);
763
]]
762
]]
764

763

765

764

766
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
765
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
767
-- as it allows to see implementations of functions.
766
-- as it allows to see implementations of functions.
768
--local string_dump = string.dump
767
--local string_dump = string.dump
769
string.dump = nil
768
string.dump = nil
770

769

771

770

772
-- sanity-check struct type sizes
771
-- sanity-check struct type sizes
773
local good = true
772
local good = true
774
for i=0,10 do
773
for i=0,10 do
775
    local what = ffi.string(ffiC.g_sizes_of_what[i])
774
    local what = ffi.string(ffiC.g_sizes_of_what[i])
776
    local fsz = ffi.sizeof(what)
775
    local fsz = ffi.sizeof(what)
777
    local csz = ffiC.g_sizes_of[i]
776
    local csz = ffiC.g_sizes_of[i]
778
    if (ffiC._DEBUG_LUNATIC ~= 0) then
777
    if (ffiC._DEBUG_LUNATIC ~= 0) then
779
        print(i..": "..what..": C sizeof = "..tostring(csz)..", FFI sizeof = "..tostring(fsz))
778
        print(i..": "..what..": C sizeof = "..tostring(csz)..", FFI sizeof = "..tostring(fsz))
780
    end
779
    end
781
    if (fsz ~= csz) then
780
    if (fsz ~= csz) then
782
        good = false;
781
        good = false;
783
    end
782
    end
784
end
783
end
785

784

786
if (not good) then
785
if (not good) then
787
    error("Some sizes don't match between C and LuaJIT/FFI.")
786
    error("Some sizes don't match between C and LuaJIT/FFI.")
788
end
787
end
789

788

790

789

791
--== "player" global, needed by the "control" module ==--
790
--== "player" global, needed by the "control" module ==--
792

791

793
local player_static_members = defs_c.static_members_tab()
792
local player_static_members = defs_c.static_members_tab()
794

793

795
--[[
794
--[[
796
player_static_members._INPUT_BITS = defs_c.conststruct
795
player_static_members._INPUT_BITS = defs_c.conststruct
797
{
796
{
798
    JUMP =                      1,
797
    JUMP =                      1,
799
    CROUCH =                    2,
798
    CROUCH =                    2,
800
    FIRE =                      4,
799
    FIRE =                      4,
801
    AIM_UP =                    8,
800
    AIM_UP =                    8,
802
    AIM_DOWN =                 16,
801
    AIM_DOWN =                 16,
803
    RUNNING =                  32,
802
    RUNNING =                  32,
804
    LOOK_LEFT =                64,
803
    LOOK_LEFT =                64,
805
    LOOK_RIGHT =              128,
804
    LOOK_RIGHT =              128,
806
    -- weapons...
805
    -- weapons...
807
    STEROIDS =               4096,
806
    STEROIDS =               4096,
808
    LOOK_UP =                8192,
807
    LOOK_UP =                8192,
809
    LOOK_DOWN =             16384,
808
    LOOK_DOWN =             16384,
810
    NIGHTVISION =           32768,
809
    NIGHTVISION =           32768,
811
    MEDKIT =                65536,
810
    MEDKIT =                65536,
812
    RESERVED =             131072,
811
    RESERVED =             131072,
813
    CENTER_VIEW =          262144,
812
    CENTER_VIEW =          262144,
814
    HOLSTER_WEAPON =       524288,
813
    HOLSTER_WEAPON =       524288,
815
    INVENTORY_LEFT =      1048576,
814
    INVENTORY_LEFT =      1048576,
816
    PAUSE =               2097152,
815
    PAUSE =               2097152,
817
    QUICK_KICK =          4194304,
816
    QUICK_KICK =          4194304,
818
    AIM_MODE =            8388608,
817
    AIM_MODE =            8388608,
819
    HOLODUKE =           16777216,
818
    HOLODUKE =           16777216,
820
    JETPACK =            33554432,
819
    JETPACK =            33554432,
821
    QUIT =               67108864,
820
    QUIT =               67108864,
822
    INVENTORY_RIGHT =   134217728,
821
    INVENTORY_RIGHT =   134217728,
823
    TURN_AROUND =       268435456,
822
    TURN_AROUND =       268435456,
824
    OPEN =              536870912,
823
    OPEN =              536870912,
825
    INVENTORY =        1073741824,
824
    INVENTORY =        1073741824,
826
    ESC =              2147483648,
825
    ESC =              2147483648,
827
}
826
}
828

827

829
player_static_members._INPUT_EXT_BITS = defs_c.conststruct
828
player_static_members._INPUT_EXT_BITS = defs_c.conststruct
830
{
829
{
831
    MOVE_FORWARD =  1,
830
    MOVE_FORWARD =  1,
832
    MOVE_BACKWARD = 2,
831
    MOVE_BACKWARD = 2,
833
    STRAFE_LEFT =   4,
832
    STRAFE_LEFT =   4,
834
    STRAFE_RIGHT =  8,
833
    STRAFE_RIGHT =  8,
835
    TURN_LEFT =    16,
834
    TURN_LEFT =    16,
836
    TURN_RIGHT =   32,
835
    TURN_RIGHT =   32,
837
}
836
}
838
--]]
837
--]]
839

838

840
local band = bit.band
839
local band = bit.band
841
local lsh = bit.lshift
840
local lsh = bit.lshift
842
local ivec3 = xmath.ivec3
841
local ivec3 = xmath.ivec3
843

842

844
do
843
do
845
    -- player.all() iterator
844
    -- player.all() iterator
846
    local function iter_allplayers(_nil, pli)
845
    local function iter_allplayers(_nil, pli)
847
        if (pli+1 < ffiC.g_mostConcurrentPlayers) then
846
        if (pli+1 < ffiC.g_mostConcurrentPlayers) then
848
            return pli+1
847
            return pli+1
849
        end
848
        end
850
    end
849
    end
851

850

852
    function player_static_members.all()
851
    function player_static_members.all()
853
        return iter_allplayers, nil, -1
852
        return iter_allplayers, nil, -1
854
    end
853
    end
855

854

856
    -- player.holdskey(pli, keyname)
855
    -- player.holdskey(pli, keyname)
857
    local KEYS = {  -- SK_CROUCH etc. -- "sync keys"
856
    local KEYS = {  -- SK_CROUCH etc. -- "sync keys"
858
        CROUCH = lsh(1,1),
857
        CROUCH = lsh(1,1),
859
        RUN = lsh(1,5),
858
        RUN = lsh(1,5),
860
        OPEN = lsh(1,29),
859
        OPEN = lsh(1,29),
861
    }
860
    }
862

861

863
    function player_static_members.holdskey(pli, keyname)
862
    function player_static_members.holdskey(pli, keyname)
864
        bcheck.player_idx(pli)
863
        bcheck.player_idx(pli)
865
        if (KEYS[keyname] == nil) then
864
        if (KEYS[keyname] == nil) then
866
            error("invalid key name: "..tostring(keyname), 2)
865
            error("invalid key name: "..tostring(keyname), 2)
867
        end
866
        end
868

867

869
        return ffiC.g_player[pli].sync.bitsbits:test(KEYS[keyname])
868
        return ffiC.g_player[pli].sync.bitsbits:test(KEYS[keyname])
870
    end
869
    end
871
end
870
end
872

871

873
local player_holdskey = player_static_members.holdskey
872
local player_holdskey = player_static_members.holdskey
874

873

875
-- Actor flags
874
-- Actor flags
876
local actor_static_members = defs_c.static_members_tab()
875
local actor_static_members = defs_c.static_members_tab()
877
do
876
do
878
    local our_SFLAG = {}
877
    local our_SFLAG = {}
879
    local ext_SFLAG = con_lang.labels[4]  -- external actor flags only
878
    local ext_SFLAG = con_lang.labels[4]  -- external actor flags only
880
    local USER_MASK = 0
879
    local USER_MASK = 0
881

880

882
    for name, flag in pairs(ext_SFLAG) do
881
    for name, flag in pairs(ext_SFLAG) do
883
        our_SFLAG[name:sub(7)] = flag  -- strip "SFLAG_"
882
        our_SFLAG[name:sub(7)] = flag  -- strip "SFLAG_"
884
        USER_MASK = bit.bor(USER_MASK, flag)
883
        USER_MASK = bit.bor(USER_MASK, flag)
885
    end
884
    end
886

885

887
    -- Add a couple of convenience defines.
886
    -- Add a couple of convenience defines.
888
    our_SFLAG.enemy = con_lang.SFLAG.SFLAG_BADGUY
887
    our_SFLAG.enemy = con_lang.SFLAG.SFLAG_BADGUY
889
    our_SFLAG.enemystayput = con_lang.SFLAG.SFLAG_BADGUY + con_lang.SFLAG.SFLAG_BADGUYSTAYPUT
888
    our_SFLAG.enemystayput = con_lang.SFLAG.SFLAG_BADGUY + con_lang.SFLAG.SFLAG_BADGUYSTAYPUT
890
    our_SFLAG.rotfixed = con_lang.SFLAG.SFLAG_ROTFIXED
889
    our_SFLAG.rotfixed = con_lang.SFLAG.SFLAG_ROTFIXED
891

890

892
    -- Callback function chaining control flags.
891
    -- Callback function chaining control flags.
893
    our_SFLAG.replace = 0x08000000
892
    our_SFLAG.replace = 0x08000000
894
    our_SFLAG.replace_soft = 0x08000000  -- compat
893
    our_SFLAG.replace_soft = 0x08000000  -- compat
895
    our_SFLAG.replace_hard = 0x08000000  -- compat, deprecated
894
    our_SFLAG.replace_hard = 0x08000000  -- compat, deprecated
896
    our_SFLAG.chain_beg = 0x20000000
895
    our_SFLAG.chain_beg = 0x20000000
897
    our_SFLAG.chain_end = 0x40000000
896
    our_SFLAG.chain_end = 0x40000000
898
    our_SFLAG._CHAIN_MASK_ACTOR = 0x78000000
897
    our_SFLAG._CHAIN_MASK_ACTOR = 0x78000000
899
    our_SFLAG._CHAIN_MASK_EVENT = 0x68000000
898
    our_SFLAG._CHAIN_MASK_EVENT = 0x68000000
900

899

901
    -- XXX: CON doesn't export BADGUYSTAYPUT or ROTFIXED SFLAGs, but they are considered
900
    -- XXX: CON doesn't export BADGUYSTAYPUT or ROTFIXED SFLAGs, but they are considered
902
    -- external for Lunatic.
901
    -- external for Lunatic.
903
    our_SFLAG.USER_MASK = bit.bor(USER_MASK, our_SFLAG.enemystayput, our_SFLAG.rotfixed)
902
    our_SFLAG.USER_MASK = bit.bor(USER_MASK, our_SFLAG.enemystayput, our_SFLAG.rotfixed)
904

903

905
    actor_static_members.FLAGS = defs_c.conststruct(our_SFLAG)
904
    actor_static_members.FLAGS = defs_c.conststruct(our_SFLAG)
906

905

907
    -- Sprite status numbers. Kept in 'actor', because it's more of a game-side
906
    -- 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
907
    -- concept (event though status lists are implemented in the engine), and
909
    -- to prevent confusion with sprite.CSTAT.
908
    -- to prevent confusion with sprite.CSTAT.
910
    local our_STAT = {}
909
    local our_STAT = {}
911

910

912
    for name, statnum in pairs(con_lang.STAT) do
911
    for name, statnum in pairs(con_lang.STAT) do
913
        -- Strip 'STAT_'.
912
        -- Strip 'STAT_'.
914
        our_STAT[name:sub(6)] = statnum
913
        our_STAT[name:sub(6)] = statnum
915
    end
914
    end
916

915

917
    actor_static_members.STAT = defs_c.conststruct(our_STAT)
916
    actor_static_members.STAT = defs_c.conststruct(our_STAT)
918

917

919
    actor_static_members.MOVFLAGS = defs_c.conststruct
918
    actor_static_members.MOVFLAGS = defs_c.conststruct
920
    {
919
    {
921
        -- NOTE: no underscores, like in DEFS.CON.
920
        -- NOTE: no underscores, like in DEFS.CON.
922
        faceplayer = 1,
921
        faceplayer = 1,
923
        geth = 2,
922
        geth = 2,
924
        getv = 4,
923
        getv = 4,
925
        randomangle = 8,
924
        randomangle = 8,
926
        faceplayerslow = 16,
925
        faceplayerslow = 16,
927
        spin = 32,
926
        spin = 32,
928
        faceplayersmart = 64,
927
        faceplayersmart = 64,
929
        fleeenemy = 128,
928
        fleeenemy = 128,
930
        jumptoplayer_only = 256,
929
        jumptoplayer_only = 256,
931
        jumptoplayer_bits = 257,  -- NOTE: two bits set!
930
        jumptoplayer_bits = 257,  -- NOTE: two bits set!
932
        jumptoplayer = 257,
931
        jumptoplayer = 257,
933
        seekplayer = 512,
932
        seekplayer = 512,
934
        furthestdir = 1024,
933
        furthestdir = 1024,
935
        dodgebullet = 4096,
934
        dodgebullet = 4096,
936
    }
935
    }
937
end
936
end
938

937

939
function actor_static_members.fall(i)
938
function actor_static_members.fall(i)
940
    check_sprite_idx(i)
939
    check_sprite_idx(i)
941
    CF.VM_FallSprite(i)
940
    CF.VM_FallSprite(i)
942
end
941
end
943

942

944
-- actor.move(i, vec, cliptype [, clipdist])
943
-- actor.move(i, vec, cliptype [, clipdist])
945
function actor_static_members.move(i, vec, cliptype, clipdist)
944
function actor_static_members.move(i, vec, cliptype, clipdist)
946
    check_sprite_idx(i)
945
    check_sprite_idx(i)
947
    local vel = ivec3(vec.x, vec.y, vec.z)
946
    local vel = ivec3(vec.x, vec.y, vec.z)
948
    return ffiC.A_MoveSpriteClipdist(i, vel, cliptype, clipdist or -1)
947
    return ffiC.A_MoveSpriteClipdist(i, vel, cliptype, clipdist or -1)
949
end
948
end
950

949

951
-- Delete sprite with index <i>.
950
-- Delete sprite with index <i>.
952
function actor_static_members.delete(i)
951
function actor_static_members.delete(i)
953
    check_sprite_idx(i)
952
    check_sprite_idx(i)
954

953

955
    if (ffiC.sprite[i].statnum == ffiC.MAXSTATUS) then
954
    if (ffiC.sprite[i].statnum == ffiC.MAXSTATUS) then
956
        error("Attempt to delete a sprite already not in the game world", 2)
955
        error("Attempt to delete a sprite already not in the game world", 2)
957
    end
956
    end
958

957

959
    if (ffiC.block_deletesprite ~= 0) then
958
    if (ffiC.block_deletesprite ~= 0) then
960
        error("Attempt to delete sprite in EVENT_EGS", 2)
959
        error("Attempt to delete sprite in EVENT_EGS", 2)
961
    end
960
    end
962

961

963
    -- TODO_MP
962
    -- TODO_MP
964
    if (ffiC.g_player_ps[0].i == i) then
963
    if (ffiC.g_player_ps[0].i == i) then
965
        error("Attempt to delete player 0's APLAYER sprite", 2)
964
        error("Attempt to delete player 0's APLAYER sprite", 2)
966
    end
965
    end
967

966

968
    CF.A_DeleteSprite(i)
967
    CF.A_DeleteSprite(i)
969
end
968
end
970

969

971
local tile_static_members = defs_c.static_members_tab()
970
local tile_static_members = defs_c.static_members_tab()
972
do
971
do
973
    tile_static_members.sizx = defs_c.creategtab_membidx(ffiC.tilesiz, "x", ffiC.MAXTILES, "tilesizx[]")
972
    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[]")
973
    tile_static_members.sizy = defs_c.creategtab_membidx(ffiC.tilesiz, "y", ffiC.MAXTILES, "tilesizy[]")
975
end
974
end
976

975

977
-- XXX: error message will say "g_player_ps"
976
-- XXX: error message will say "g_player_ps"
978
player = setmtonce({}, defs_c.GenStructMetatable("g_player_ps", "g_mostConcurrentPlayers", player_static_members))
977
player = setmtonce({}, defs_c.GenStructMetatable("g_player_ps", "g_mostConcurrentPlayers", player_static_members))
979

978

980
-- needed by "control"
979
-- needed by "control"
981
actor = setmtonce({}, defs_c.GenStructMetatable("actor", "MAXSPRITES", actor_static_members))
980
actor = setmtonce({}, defs_c.GenStructMetatable("actor", "MAXSPRITES", actor_static_members))
982
-- Some bitwise NOTs of various actor flag masks.
981
-- Some bitwise NOTs of various actor flag masks.
983
local BNOT = {
982
local BNOT = {
984
    USER_MASK = bit.bnot(actor.FLAGS.USER_MASK),
983
    USER_MASK = bit.bnot(actor.FLAGS.USER_MASK),
985
    CHAIN_MASK_ACTOR = bit.bnot(actor.FLAGS._CHAIN_MASK_ACTOR),
984
    CHAIN_MASK_ACTOR = bit.bnot(actor.FLAGS._CHAIN_MASK_ACTOR),
986
    CHAIN_MASK_EVENT = bit.bnot(actor.FLAGS._CHAIN_MASK_EVENT),
985
    CHAIN_MASK_EVENT = bit.bnot(actor.FLAGS._CHAIN_MASK_EVENT),
987
}
986
}
988

987

989
local projectile = defs_c.creategtab_membidx_ptr(ffiC.g_tile, "_proj", ffiC.MAXTILES, "projectile")
988
local projectile = defs_c.creategtab_membidx_ptr(ffiC.g_tile, "_proj", ffiC.MAXTILES, "projectile")
990
local g_tile = setmtonce({}, defs_c.GenStructMetatable("g_tile", "MAXTILES", tile_static_members))
989
local g_tile = setmtonce({}, defs_c.GenStructMetatable("g_tile", "MAXTILES", tile_static_members))
991

990

992
--== Custom operations for BUILD data structures ==--
991
--== Custom operations for BUILD data structures ==--
993
-- Among other things, declares struct action and struct move, and their
992
-- Among other things, declares struct action and struct move, and their
994
-- ID-wrapped types con_action_t and con_move_t
993
-- ID-wrapped types con_action_t and con_move_t
995
local con = require("control")
994
local con = require("control")
996

995

997
do
996
do
998
    local isenemytile = con.isenemytile
997
    local isenemytile = con.isenemytile
999

998

1000
    -- Add game-side metamethods to "spritetype" and register it with "metatype"
999
    -- Add game-side metamethods to "spritetype" and register it with "metatype"
1001
    local spr_mt_index_add = {
1000
    local spr_mt_index_add = {
1002
        isenemy = function(s)
1001
        isenemy = function(s)
1003
            return isenemytile(s.picnum)
1002
            return isenemytile(s.picnum)
1004
        end,
1003
        end,
1005
    }
1004
    }
1006

1005

1007
    defs_c.finish_spritetype(spr_mt_index_add)
1006
    defs_c.finish_spritetype(spr_mt_index_add)
1008
end
1007
end
1009

1008

1010
-- Check a literal numeric action or move value.
1009
-- Check a literal numeric action or move value.
1011
local function check_literal_am(am, typename)
1010
local function check_literal_am(am, typename)
1012
    if (type(am) ~= "number") then
1011
    if (type(am) ~= "number") then
1013
        error("bad argument: expected number or "..typename, 3)
1012
        error("bad argument: expected number or "..typename, 3)
1014
    end
1013
    end
1015

1014

1016
    -- Negative values are generated as con.action/con.move IDs.
1015
    -- Negative values are generated as con.action/con.move IDs.
1017
    if (not (am >= 0 and am <= 32767)) then
1016
    if (not (am >= 0 and am <= 32767)) then
1018
        error("bad argument: expected number in [0 .. 32767]", 3)
1017
        error("bad argument: expected number in [0 .. 32767]", 3)
1019
    end
1018
    end
1020
end
1019
end
1021

1020

1022
-- An unrestricted actor_t pointer, for internal use:
1021
-- An unrestricted actor_t pointer, for internal use:
1023
local actor_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(ACTOR_STRUCT)))
1022
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)))
1023
local player_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(DUKEPLAYER_STRUCT)))
1025
local projectile_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(PROJECTILE_STRUCT)))
1024
local projectile_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(PROJECTILE_STRUCT)))
1026
-- An unrestricted weapondata_t pointer, but with the member names stripped of
1025
-- An unrestricted weapondata_t pointer, but with the member names stripped of
1027
-- the leading underscore, too:
1026
-- the leading underscore, too:
1028
local weapondata_ptr_ct = ffi.typeof("$ *", ffi.typeof((strip_const(WEAPONDATA_STRUCT):gsub(" _"," "))))
1027
local weapondata_ptr_ct = ffi.typeof("$ *", ffi.typeof((strip_const(WEAPONDATA_STRUCT):gsub(" _"," "))))
1029

1028

1030
local con_action_ct = ffi.typeof("const con_action_t")
1029
local con_action_ct = ffi.typeof("const con_action_t")
1031
local con_move_ct = ffi.typeof("const con_move_t")
1030
local con_move_ct = ffi.typeof("const con_move_t")
1032
local con_ai_ct = ffi.typeof("const con_ai_t")
1031
local con_ai_ct = ffi.typeof("const con_ai_t")
1033

1032

1034
-- All-zero bare action and move.
1033
-- All-zero bare action and move.
1035
local nullac, nullmv = ffi.new("const struct action"), ffi.new("const struct move")
1034
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.
1035
-- 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) }
1036
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) }
1037
local literal_mov = { [0]=con_move_ct(0), [1]=con_move_ct(1) }
1039

1038

1040
local function get_actor_idx(a)
1039
local function get_actor_idx(a)
1041
    local i = ffi.cast(actor_ptr_ct, a)-ffi.cast(actor_ptr_ct, ffiC.actor)
1040
    local i = ffi.cast(actor_ptr_ct, a)-ffi.cast(actor_ptr_ct, ffiC.actor)
1042
--    assert(not (i >= ffiC.MAXSPRITES+0ULL))
1041
--    assert(not (i >= ffiC.MAXSPRITES+0ULL))
1043
    return i
1042
    return i
1044
end
1043
end
1045

1044

1046
local actor_methods = {
1045
local actor_methods = {
1047
    -- action
1046
    -- action
1048
    set_action = function(a, act)
1047
    set_action = function(a, act)
1049
        a = ffi.cast(actor_ptr_ct, a)
1048
        a = ffi.cast(actor_ptr_ct, a)
1050

1049

1051
        if (ffi.istype(con_action_ct, act)) then
1050
        if (ffi.istype(con_action_ct, act)) then
1052
            a.t_data[4] = act.id
1051
            a.t_data[4] = act.id
1053
            a.ac = act.ac
1052
            a.ac = act.ac
1054
        else
1053
        else
1055
            check_literal_am(act, "action")
1054
            check_literal_am(act, "action")
1056
            a.t_data[4] = act
1055
            a.t_data[4] = act
1057
            a.ac = nullac
1056
            a.ac = nullac
1058
        end
1057
        end
1059

1058

1060
        a.t_data[2] = 0
1059
        a.t_data[2] = 0
1061
        a.t_data[3] = 0
1060
        a.t_data[3] = 0
1062
    end,
1061
    end,
1063

1062

1064
    has_action = function(a, act)
1063
    has_action = function(a, act)
1065
        a = ffi.cast(actor_ptr_ct, a)
1064
        a = ffi.cast(actor_ptr_ct, a)
1066

1065

1067
        if (ffi.istype(con_action_ct, act)) then
1066
        if (ffi.istype(con_action_ct, act)) then
1068
            return (a.t_data[4]==act.id)
1067
            return (a.t_data[4]==act.id)
1069
        else
1068
        else
1070
            check_literal_am(act, "action")
1069
            check_literal_am(act, "action")
1071
            return (a.t_data[4]==act)
1070
            return (a.t_data[4]==act)
1072
        end
1071
        end
1073
    end,
1072
    end,
1074

1073

1075
    -- count
1074
    -- count
1076
    set_count = function(a, count)
1075
    set_count = function(a, count)
1077
        ffi.cast(actor_ptr_ct, a).t_data[0] = count
1076
        ffi.cast(actor_ptr_ct, a).t_data[0] = count
1078
    end,
1077
    end,
1079

1078

1080
    get_count = function(a)
1079
    get_count = function(a)
1081
        return ffi.cast(actor_ptr_ct, a).t_data[0]
1080
        return ffi.cast(actor_ptr_ct, a).t_data[0]
1082
    end,
1081
    end,
1083

1082

1084
    -- action count
1083
    -- action count
1085
    reset_acount = function(a)
1084
    reset_acount = function(a)
1086
        ffi.cast(actor_ptr_ct, a).t_data[2] = 0
1085
        ffi.cast(actor_ptr_ct, a).t_data[2] = 0
1087
    end,
1086
    end,
1088

1087

1089
    get_acount = function(a)
1088
    get_acount = function(a)
1090
        return ffi.cast(actor_ptr_ct, a).t_data[2]
1089
        return ffi.cast(actor_ptr_ct, a).t_data[2]
1091
    end,
1090
    end,
1092

1091

1093
    -- Override action delay. The action ID is kept.
1092
    -- Override action delay. The action ID is kept.
1094
    set_action_delay = function(a, delay)
1093
    set_action_delay = function(a, delay)
1095
        ffi.cast(actor_ptr_ct, a).ac.delay = delay
1094
        ffi.cast(actor_ptr_ct, a).ac.delay = delay
1096
    end,
1095
    end,
1097

1096

1098
    -- move
1097
    -- move
1099
    set_move = function(a, mov, movflags)
1098
    set_move = function(a, mov, movflags)
1100
        a = ffi.cast(actor_ptr_ct, a)
1099
        a = ffi.cast(actor_ptr_ct, a)
1101

1100

1102
        if (ffi.istype(con_move_ct, mov)) then
1101
        if (ffi.istype(con_move_ct, mov)) then
1103
            a.t_data[1] = mov.id
1102
            a.t_data[1] = mov.id
1104
            a.mv = mov.mv
1103
            a.mv = mov.mv
1105
        else
1104
        else
1106
            check_literal_am(mov, "move")
1105
            check_literal_am(mov, "move")
1107
            a.t_data[1] = mov
1106
            a.t_data[1] = mov
1108
            a.mv = nullmv
1107
            a.mv = nullmv
1109
        end
1108
        end
1110

1109

1111
        a.t_data[0] = 0
1110
        a.t_data[0] = 0
1112
        a.movflags = movflags or 0
1111
        a.movflags = movflags or 0
1113
        local spr = ffiC.sprite[get_actor_idx(a)]
1112
        local spr = ffiC.sprite[get_actor_idx(a)]
1114

1113

1115
        if (not spr:isenemy() or spr.extra > 0) then
1114
        if (not spr:isenemy() or spr.extra > 0) then
1116
            if (bit.band(a.movflags, 8) ~= 0) then  -- random_angle
1115
            if (bit.band(a.movflags, 8) ~= 0) then  -- random_angle
1117
                spr.ang = bit.band(ffiC.krand(), 2047)
1116
                spr.ang = bit.band(ffiC.krand(), 2047)
1118
            end
1117
            end
1119
        end
1118
        end
1120
    end,
1119
    end,
1121

1120

1122
    has_move = function(a, mov)
1121
    has_move = function(a, mov)
1123
        a = ffi.cast(actor_ptr_ct, a)
1122
        a = ffi.cast(actor_ptr_ct, a)
1124

1123

1125
        if (ffi.istype(con_move_ct, mov)) then
1124
        if (ffi.istype(con_move_ct, mov)) then
1126
            return (a.t_data[1]==mov.id)
1125
            return (a.t_data[1]==mov.id)
1127
        else
1126
        else
1128
            check_literal_am(mov, "move")
1127
            check_literal_am(mov, "move")
1129
            return (a.t_data[1]==mov)
1128
            return (a.t_data[1]==mov)
1130
        end
1129
        end
1131
    end,
1130
    end,
1132

1131

1133
    -- Override velocity, keeping move ID.
1132
    -- Override velocity, keeping move ID.
1134
    set_hvel = function(a, hvel)
1133
    set_hvel = function(a, hvel)
1135
        ffi.cast(actor_ptr_ct, a).mv.hvel = hvel
1134
        ffi.cast(actor_ptr_ct, a).mv.hvel = hvel
1136
    end,
1135
    end,
1137

1136

1138
    set_vvel = function(a, vvel)
1137
    set_vvel = function(a, vvel)
1139
        ffi.cast(actor_ptr_ct, a).mv.vvel = vvel
1138
        ffi.cast(actor_ptr_ct, a).mv.vvel = vvel
1140
    end,
1139
    end,
1141

1140

1142
    -- ai
1141
    -- ai
1143
    set_ai = function(a, ai)
1142
    set_ai = function(a, ai)
1144
        local oa = a
1143
        local oa = a
1145
        a = ffi.cast(actor_ptr_ct, a)
1144
        a = ffi.cast(actor_ptr_ct, a)
1146

1145

1147
        -- TODO: literal number AIs?
1146
        -- TODO: literal number AIs?
1148
        if (not ffi.istype(con_ai_ct, ai)) then
1147
        if (not ffi.istype(con_ai_ct, ai)) then
1149
            error("bad argument: expected ai", 2)
1148
            error("bad argument: expected ai", 2)
1150
        end
1149
        end
1151

1150

1152
        -- NOTE: compare with gameexec.c, "CON_AI:"
1151
        -- NOTE: compare with gameexec.c, "CON_AI:"
1153
        a.t_data[5] = ai.id
1152
        a.t_data[5] = ai.id
1154

1153

1155
        oa:set_action(ai.act)
1154
        oa:set_action(ai.act)
1156
        oa:set_move(ai.mov, ai.movflags)
1155
        oa:set_move(ai.mov, ai.movflags)
1157

1156

1158
        -- Already reset with set_move():
1157
        -- Already reset with set_move():
1159
--        a.t_data[0] = 0
1158
--        a.t_data[0] = 0
1160
    end,
1159
    end,
1161

1160

1162
    has_ai = function(a, ai)
1161
    has_ai = function(a, ai)
1163
        a = ffi.cast(actor_ptr_ct, a)
1162
        a = ffi.cast(actor_ptr_ct, a)
1164

1163

1165
        if (ffi.istype(con_ai_ct, ai)) then
1164
        if (ffi.istype(con_ai_ct, ai)) then
1166
            return (a.t_data[5]==ai.id)
1165
            return (a.t_data[5]==ai.id)
1167
        else
1166
        else
1168
            check_literal_am(ai, "ai")
1167
            check_literal_am(ai, "ai")
1169
            return (a.t_data[5]==ai)
1168
            return (a.t_data[5]==ai)
1170
        end
1169
        end
1171
    end,
1170
    end,
1172

1171

1173
    -- Getters/setters.
1172
    -- Getters/setters.
1174
    _get_t_data = function(a, idx)
1173
    _get_t_data = function(a, idx)
1175
        if (not (idx >= 0 and idx < 10)) then
1174
        if (not (idx >= 0 and idx < 10)) then
1176
            error("invalid t_data index "..idx, 2)
1175
            error("invalid t_data index "..idx, 2)
1177
        end
1176
        end
1178
        return ffi.cast(actor_ptr_ct, a).t_data[idx]
1177
        return ffi.cast(actor_ptr_ct, a).t_data[idx]
1179
    end,
1178
    end,
1180

1179

1181
    _set_t_data = function(a, idx, val)
1180
    _set_t_data = function(a, idx, val)
1182
        if (not (idx >= 0 and idx < 10)) then
1181
        if (not (idx >= 0 and idx < 10)) then
1183
            error("invalid t_data index "..idx, 2)
1182
            error("invalid t_data index "..idx, 2)
1184
        end
1183
        end
1185
        ffi.cast(actor_ptr_ct, a).t_data[idx] = val
1184
        ffi.cast(actor_ptr_ct, a).t_data[idx] = val
1186
    end,
1185
    end,
1187

1186

1188
    set_picnum = function(a, picnum)
1187
    set_picnum = function(a, picnum)
1189
        if (not (picnum < 0)) then
1188
        if (not (picnum < 0)) then
1190
            check_tile_idx(picnum)
1189
            check_tile_idx(picnum)
1191
        end
1190
        end
1192
        ffi.cast(actor_ptr_ct, a).picnum = picnum
1191
        ffi.cast(actor_ptr_ct, a).picnum = picnum
1193
    end,
1192
    end,
1194

1193

1195
    set_owner = function(a, owner)
1194
    set_owner = function(a, owner)
1196
        -- XXX: is it permissible to set to -1?
1195
        -- XXX: is it permissible to set to -1?
1197
        check_sprite_idx(owner)
1196
        check_sprite_idx(owner)
1198
        ffi.cast(actor_ptr_ct, a).owner = owner
1197
        ffi.cast(actor_ptr_ct, a).owner = owner
1199
    end,
1198
    end,
1200

1199

1201
    --- Custom methods ---
1200
    --- Custom methods ---
1202

1201

1203
    -- Checkers for whether the movement update made the actor hit
1202
    -- Checkers for whether the movement update made the actor hit
1204
    -- something.
1203
    -- something.
1205

1204

1206
    checkhit = function(a)
1205
    checkhit = function(a)
1207
        -- Check whether we hit *anything*, including ceiling/floor.
1206
        -- Check whether we hit *anything*, including ceiling/floor.
1208
        return a._movflagbits:test(49152)
1207
        return a._movflagbits:test(49152)
1209
    end,
1208
    end,
1210

1209

1211
    checkbump = function(a)
1210
    checkbump = function(a)
1212
        -- Check whether we bumped into a wall or sprite.
1211
        -- Check whether we bumped into a wall or sprite.
1213
        return (a._movflagbits:mask(49152) >= 32768)
1212
        return (a._movflagbits:mask(49152) >= 32768)
1214
    end,
1213
    end,
1215

1214

1216
    hitwall = function(a)
1215
    hitwall = function(a)
1217
        if (a._movflagbits:mask(49152) == 32768) then
1216
        if (a._movflagbits:mask(49152) == 32768) then
1218
            return a._movflagbits:mask(32767)
1217
            return a._movflagbits:mask(32767)
1219
        end
1218
        end
1220
    end,
1219
    end,
1221

1220

1222
    hitsprite = function(a)
1221
    hitsprite = function(a)
1223
        if (a._movflagbits:mask(49152) == 49152) then
1222
        if (a._movflagbits:mask(49152) == 49152) then
1224
            return a._movflagbits:mask(32767)
1223
            return a._movflagbits:mask(32767)
1225
        end
1224
        end
1226
    end,
1225
    end,
1227

1226

1228
    -- NOTE: no 'hitsector' or 'hitceiling' / 'hitfloor' for now because
1227
    -- 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.
1228
    -- more research is needed as to what the best way of checking c/f is.
1230
}
1229
}
1231

1230

1232
local actor_mt = {
1231
local actor_mt = {
1233
    __index = function(a, key)
1232
    __index = function(a, key)
1234
        if (actor_methods[key] ~= nil) then
1233
        if (actor_methods[key] ~= nil) then
1235
            return actor_methods[key]
1234
            return actor_methods[key]
1236
        elseif (key == "proj") then
1235
        elseif (key == "proj") then
1237
            return ffiC.SpriteProjectile[get_actor_idx(a)]
1236
            return ffiC.SpriteProjectile[get_actor_idx(a)]
1238
        else
1237
        else
1239
            error("invalid indexing key to actor object", 2)
1238
            error("invalid indexing key to actor object", 2)
1240
        end
1239
        end
1241
    end,
1240
    end,
1242
}
1241
}
1243

1242

1244
ffi.metatype("actor_t", actor_mt)
1243
ffi.metatype("actor_t", actor_mt)
1245

1244

1246

1245

1247
--- PER-PLAYER WEAPON SETTINGS
1246
--- PER-PLAYER WEAPON SETTINGS
1248
local wd_sound_member = {}
1247
local wd_sound_member = {}
1249
for _, declstr in pairs(con_lang.wdata_members) do
1248
for _, declstr in pairs(con_lang.wdata_members) do
1250
    local member = declstr:match("const int32_t _(.*sound)$")
1249
    local member = declstr:match("const int32_t _(.*sound)$")
1251
    if (member) then
1250
    if (member) then
1252
        wd_sound_member[member] = true
1251
        wd_sound_member[member] = true
1253
        if (ffiC._DEBUG_LUNATIC ~= 0) then
1252
        if (ffiC._DEBUG_LUNATIC ~= 0) then
1254
            printf("weapondata_t member %s denotes a sound", member)
1253
            printf("weapondata_t member %s denotes a sound", member)
1255
        end
1254
        end
1256
    end
1255
    end
1257
end
1256
end
1258

1257

1259
local weapondata_mt = {
1258
local weapondata_mt = {
1260
    __index = function(wd, member)
1259
    __index = function(wd, member)
1261
        -- Handle protected members that are renamed (e.g. shoots/_shoots).
1260
        -- Handle protected members that are renamed (e.g. shoots/_shoots).
1262
        return ffi.cast(weapondata_ptr_ct, wd)[0][member]
1261
        return ffi.cast(weapondata_ptr_ct, wd)[0][member]
1263
    end,
1262
    end,
1264

1263

1265
    __newindex = function(wd, member, val)
1264
    __newindex = function(wd, member, val)
1266
        -- Set to 'true' if we set a tile or sound member.
1265
        -- Set to 'true' if we set a tile or sound member.
1267
        local didit = false
1266
        local didit = false
1268

1267

1269
        check_type(member, "string")  -- MEMBER_IS_STRING
1268
        check_type(member, "string")  -- MEMBER_IS_STRING
1270
        check_number(val)
1269
        check_number(val)
1271

1270

1272
        if (wd_sound_member[member]) then  -- XXX: sound2time is a time, not a sound
1271
        if (wd_sound_member[member]) then  -- XXX: sound2time is a time, not a sound
1273
            if (val < 0) then
1272
            if (val < 0) then
1274
                val = 0  -- Set to 0 if negative (e.g. CrackDown).
1273
                val = 0  -- Set to 0 if negative (e.g. CrackDown).
1275
            else
1274
            else
1276
                check_sound_idx(val)
1275
                check_sound_idx(val)
1277
            end
1276
            end
1278
            didit = true
1277
            didit = true
1279
        elseif (member=="workslike") then
1278
        elseif (member=="workslike") then
1280
            check_weapon_idx(val)
1279
            check_weapon_idx(val)
1281
        elseif (member=="spawn" or member=="shoots") then
1280
        elseif (member=="spawn" or member=="shoots") then
1282
            if (val < 0) then
1281
            if (val < 0) then
1283
                -- Set to 0 if oob (e.g. CrackDown). This is a bit problematic
1282
                -- Set to 0 if oob (e.g. CrackDown). This is a bit problematic
1284
                -- for .shoots because it's used unconditionally except in one
1283
                -- for .shoots because it's used unconditionally except in one
1285
                -- case (see player.c).
1284
                -- case (see player.c).
1286
                val = 0
1285
                val = 0
1287
            else
1286
            else
1288
                check_tile_idx(val)
1287
                check_tile_idx(val)
1289
            end
1288
            end
1290
            didit = true
1289
            didit = true
1291
        end
1290
        end
1292
1291
1293
        -- DEBUG:
1292
        -- DEBUG:
1294
--        printf("assigning %s to weapon's %s", tostring(val), member)
1293
--        printf("assigning %s to weapon's %s", tostring(val), member)
1295
1294
1296
        -- NOTE: we're indexing a *pointer* with the user-supplied 'member',
1295
        -- 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
1296
        -- which could be dangerouns if it could be a number. However, we have
1298
        -- assured that is is not in MEMBER_IS_STRING above.
1297
        -- assured that is is not in MEMBER_IS_STRING above.
1299
        ffi.cast(weapondata_ptr_ct, wd)[member] = val
1298
        ffi.cast(weapondata_ptr_ct, wd)[member] = val
1300
1299
1301
        if (didit and ffiC.g_elCallDepth==0) then
1300
        if (didit and ffiC.g_elCallDepth==0) then
1302
            -- Signal that we overrode this member at CON translation time.
1301
            -- Signal that we overrode this member at CON translation time.
1303
1302
1304
            -- Get weapon index as pointer difference first. PLAYER_0.
1303
            -- Get weapon index as pointer difference first. PLAYER_0.
1305
            local wi = ffi.cast(weapondata_ptr_ct, wd)
1304
            local wi = ffi.cast(weapondata_ptr_ct, wd)
1306
                     - ffi.cast(weapondata_ptr_ct, ffiC.g_playerWeapon)
1305
                     - ffi.cast(weapondata_ptr_ct, ffiC.g_playerWeapon)
1307
            assert(wi >= 0 and wi < ffiC.MAX_WEAPONS)
1306
            assert(wi >= 0 and wi < ffiC.MAX_WEAPONS)
1308
1307
1309
            -- Set g_weaponOverridden[wi][member], but without invoking
1308
            -- Set g_weaponOverridden[wi][member], but without invoking
1310
            -- weapondata_t's __newindex metamethod (i.e. us)!
1309
            -- weapondata_t's __newindex metamethod (i.e. us)!
1311
            ffi.cast(weapondata_ptr_ct, ffiC.g_weaponOverridden[wi])[member] = 1
1310
            ffi.cast(weapondata_ptr_ct, ffiC.g_weaponOverridden[wi])[member] = 1
1312
        end
1311
        end
1313
    end,
1312
    end,
1314
}
1313
}
1315
ffi.metatype("weapondata_t", weapondata_mt)
1314
ffi.metatype("weapondata_t", weapondata_mt)
1316
1315
1317
local weaponaccess_mt = {
1316
local weaponaccess_mt = {
1318
    -- Syntax like "player[0].weapon.KNEE.shoots" possible because
1317
    -- Syntax like "player[0].weapon.KNEE.shoots" possible because
1319
    -- g_playerWeapon[] is declared as an array of corresponding bcarray types
1318
    -- g_playerWeapon[] is declared as an array of corresponding bcarray types
1320
    -- for us.
1319
    -- for us.
1321
    __index = function(wa, key)
1320
    __index = function(wa, key)
1322
        if (type(key)~="number" and type(key)~="string") then
1321
        if (type(key)~="number" and type(key)~="string") then
1323
            error("must access weapon either by number or by name")
1322
            error("must access weapon either by number or by name")
1324
        end
1323
        end
1325
1324
1326
        return ffiC.g_playerWeapon[wa._p][key]
1325
        return ffiC.g_playerWeapon[wa._p][key]
1327
    end,
1326
    end,
1328
}
1327
}
1329
ffi.metatype("weaponaccess_t", weaponaccess_mt)
1328
ffi.metatype("weaponaccess_t", weaponaccess_mt)
1330
1329
1331
1330
1332
local function clamp(num, min, max)
1331
local function clamp(num, min, max)
1333
    return num < min and min
1332
    return num < min and min
1334
        or num > max and max
1333
        or num > max and max
1335
        or num
1334
        or num
1336
end
1335
end
1337
1336
1338
local function clamp0to1(num)
1337
local function clamp0to1(num)
1339
    check_number(num, 4)
1338
    check_number(num, 4)
1340
    return clamp(num, 0, 1)
1339
    return clamp(num, 0, 1)
1341
end
1340
end
1342
1341
1343
local player_methods = {
1342
local player_methods = {
1344
    -- CON-like addammo/addweapon, but without the non-local control flow
1343
    -- CON-like addammo/addweapon, but without the non-local control flow
1345
    -- (returns true if weapon's ammo was at the max. instead).
1344
    -- (returns true if weapon's ammo was at the max. instead).
1346
    addammo = con._addammo,
1345
    addammo = con._addammo,
1347
    addweapon = con._addweapon,
1346
    addweapon = con._addweapon,
1348
1347
1349
    stomp = con._pstomp,
1348
    stomp = con._pstomp,
1350
1349
1351
    holdskey = function(p, keyname)
1350
    holdskey = function(p, keyname)
1352
        -- XXX: on invalid <keyname>, error will point to this next line:
1351
        -- XXX: on invalid <keyname>, error will point to this next line:
1353
        return player_holdskey(p.weapon._p, keyname)
1352
        return player_holdskey(p.weapon._p, keyname)
1354
    end,
1353
    end,
1355
1354
1356
    has_weapon = function(p, weap)
1355
    has_weapon = function(p, weap)
1357
        return p.gotweaponbits:test(lsh(1,weap))
1356
        return p.gotweaponbits:test(lsh(1,weap))
1358
    end,
1357
    end,
1359
1358
1360
    give_weapon = function(p, weap)
1359
    give_weapon = function(p, weap)
1361
        p.gotweaponbits:set(lsh(1,weap))
1360
        p.gotweaponbits:set(lsh(1,weap))
1362
    end,
1361
    end,
1363
1362
1364
    take_weapon = function(p, weap)
1363
    take_weapon = function(p, weap)
1365
        p.gotweaponbits:clear(lsh(1,weap))
1364
        p.gotweaponbits:clear(lsh(1,weap))
1366
    end,
1365
    end,
1367
1366
1368
    -- Give or take weapon, for implementation of CON's .gotweapon access.
1367
    -- Give or take weapon, for implementation of CON's .gotweapon access.
1369
    _gt_weapon = function(p, weap, give_p)
1368
    _gt_weapon = function(p, weap, give_p)
1370
        if (give_p ~= 0) then
1369
        if (give_p ~= 0) then
1371
            p:give_weapon(weap)
1370
            p:give_weapon(weap)
1372
        else
1371
        else
1373
            p:take_weapon(weap)
1372
            p:take_weapon(weap)
1374
        end
1373
        end
1375
    end,
1374
    end,
1376
1375
1377
    whack = function(p, no_return_to_center)
1376
    whack = function(p, no_return_to_center)
1378
        p.horiz = p.horiz + 64
1377
        p.horiz = p.horiz + 64
1379
        if (not no_return_to_center) then
1378
        if (not no_return_to_center) then
1380
            p.return_to_center = 9
1379
            p.return_to_center = 9
1381
        end
1380
        end
1382
        local n = bit.arshift(128-band(ffiC.krand(),255), 1)
1381
        local n = bit.arshift(128-band(ffiC.krand(),255), 1)
1383
        p.rotscrnang = n
1382
        p.rotscrnang = n
1384
        p.look_ang = n
1383
        p.look_ang = n
1385
    end,
1384
    end,
1386
1385
1387
    -- External, improved 'palfrom'.
1386
    -- External, improved 'palfrom'.
1388
    -- <speed>: possibly fractional speed of tint fading, in pals.f decrements per gametic.
1387
    -- <speed>: possibly fractional speed of tint fading, in pals.f decrements per gametic.
1389
    --          XXX: exposes internals.
1388
    --          XXX: exposes internals.
1390
    -- <prio>: a value from -128 to 127, higher ones trump lower or equal ones
1389
    -- <prio>: a value from -128 to 127, higher ones trump lower or equal ones
1391
    fadecol = function(p, fadefrac, r, g, b, speed, prio)
1390
    fadecol = function(p, fadefrac, r, g, b, speed, prio)
1392
        -- Validate inargs: clamp f,r,g,b to [0 .. 1] first and multiply by
1391
        -- Validate inargs: clamp f,r,g,b to [0 .. 1] first and multiply by
1393
        -- 63 for the internal handling.
1392
        -- 63 for the internal handling.
1394
        fadefrac = clamp0to1(fadefrac)*63
1393
        fadefrac = clamp0to1(fadefrac)*63
1395
        -- NOTE: a fadefrac of now <1 is allowed, e.g. for clearing the tint.
1394
        -- NOTE: a fadefrac of now <1 is allowed, e.g. for clearing the tint.
1396
        r = clamp0to1(r)*63
1395
        r = clamp0to1(r)*63
1397
        g = clamp0to1(g)*63
1396
        g = clamp0to1(g)*63
1398
        b = clamp0to1(b)*63
1397
        b = clamp0to1(b)*63
1399
1398
1400
        if (speed ~= nil) then
1399
        if (speed ~= nil) then
1401
            check_number(speed)
1400
            check_number(speed)
1402
            -- Clamp to sensible values; the speed is stored in an int8_t
1401
            -- Clamp to sensible values; the speed is stored in an int8_t
1403
            -- (see below).
1402
            -- (see below).
1404
            speed = clamp(speed, 1/128, 127)
1403
            speed = clamp(speed, 1/128, 127)
1405
        else
1404
        else
1406
            speed = 1
1405
            speed = 1
1407
        end
1406
        end
1408
1407
1409
        if (prio ~= nil) then
1408
        if (prio ~= nil) then
1410
            check_number(prio)
1409
            check_number(prio)
1411
1410
1412
            if (not (prio >= -128 and prio < 127)) then
1411
            if (not (prio >= -128 and prio < 127)) then
1413
                error("invalid argument #6 (priority): must be in [-128 .. 127]", 2)
1412
                error("invalid argument #6 (priority): must be in [-128 .. 127]", 2)
1414
            end
1413
            end
1415
        else
1414
        else
1416
            prio = 0
1415
            prio = 0
1417
        end
1416
        end
1418
1417
1419
        -- Check if a currently active tint has higher priority.
1418
        -- Check if a currently active tint has higher priority.
1420
        if (p._pals.f > 0 and p._palsfadeprio > prio) then
1419
        if (p._pals.f > 0 and p._palsfadeprio > prio) then
1421
            return
1420
            return
1422
        end
1421
        end
1423
1422
1424
        -- The passed tint can be applied now.
1423
        -- The passed tint can be applied now.
1425
        p:_palfrom(fadefrac, r, g, b)
1424
        p:_palfrom(fadefrac, r, g, b)
1426
        p._palsfadeprio = prio
1425
        p._palsfadeprio = prio
1427
1426
1428
        -- Calculate .palsfade{speed,next}
1427
        -- Calculate .palsfade{speed,next}
1429
        if (speed >= 1) then
1428
        if (speed >= 1) then
1430
            -- Will round to the nearest integer ("banker's
1429
            -- Will round to the nearest integer ("banker's
1431
            -- rounding"). NOTE: This is not correct for all numbers, see
1430
            -- rounding"). NOTE: This is not correct for all numbers, see
1432
            -- http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
1431
            -- http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
1433
            p._palsfadespeed = speed + 0.5
1432
            p._palsfadespeed = speed + 0.5
1434
            p._palsfadenext = 0
1433
            p._palsfadenext = 0
1435
        else
1434
        else
1436
            -- NOTE: Values that round to 0 have are equivalent behavior to
1435
            -- NOTE: Values that round to 0 have are equivalent behavior to
1437
            -- passing a <speed> of 1.
1436
            -- passing a <speed> of 1.
1438
            local negspeedrecip = -((1/speed) + 0.5)  -- [-128.5 .. 1/127+0.5]
1437
            local negspeedrecip = -((1/speed) + 0.5)  -- [-128.5 .. 1/127+0.5]
1439
            p._palsfadespeed = negspeedrecip
1438
            p._palsfadespeed = negspeedrecip
1440
            p._palsfadenext = negspeedrecip
1439
            p._palsfadenext = negspeedrecip
1441
        end
1440
        end
1442
    end,
1441
    end,
1443
1442
1444
    -- INTERNAL and CON-only.
1443
    -- INTERNAL and CON-only.
1445
    _palfrom = function(p, f, r,g,b)
1444
    _palfrom = function(p, f, r,g,b)
1446
        local pals = p._pals
1445
        local pals = p._pals
1447
        -- Assume that CON's palfrom starts with prio 0 and speed 0.
1446
        -- Assume that CON's palfrom starts with prio 0 and speed 0.
1448
        if (pals.f == 0 or p._palsfadeprio <= 0) then
1447
        if (pals.f == 0 or p._palsfadeprio <= 0) then
1449
            pals.f = f
1448
            pals.f = f
1450
            pals.r, pals.g, pals.b = r, g, b
1449
            pals.r, pals.g, pals.b = r, g, b
1451
            p._palsfadespeed, p._palsfadenext = 0, 0
1450
            p._palsfadespeed, p._palsfadenext = 0, 0
1452
        end
1451
        end
1453
    end,
1452
    end,
1454
}
1453
}
1455
1454
1456
local player_mt = {
1455
local player_mt = {
1457
    __index = function(p, key)
1456
    __index = function(p, key)
1458
        if (player_methods[key] ~= nil) then
1457
        if (player_methods[key] ~= nil) then
1459
            return player_methods[key]
1458
            return player_methods[key]
1460
        elseif (key == "_input") then
1459
        elseif (key == "_input") then
1461
            return ffiC.g_player[p.weapon._p].sync[0]
1460
            return ffiC.g_player[p.weapon._p].sync[0]
1462
        else
1461
        else
1463
            -- Read access to protected player members.
1462
            -- Read access to protected player members.
1464
            return ffi.cast(player_ptr_ct, p)[0][key]
1463
            return ffi.cast(player_ptr_ct, p)[0][key]
1465
        end
1464
        end
1466
    end,
1465
    end,
1467
1466
1468
    __newindex = function(p, key, val)
1467
    __newindex = function(p, key, val)
1469
        -- Write access to protected player members.
1468
        -- Write access to protected player members.
1470
1469
1471
        local allowneg = DukePlayer_prot_allowneg[key]
1470
        local allowneg = DukePlayer_prot_allowneg[key]
1472
        assert(type(allowneg)=="boolean")
1471
        assert(type(allowneg)=="boolean")
1473
1472
1474
        if (allowneg==false or not (val == -1)) then
1473
        if (allowneg==false or not (val == -1)) then
1475
            DukePlayer_prot_chkfunc[key](val)
1474
            DukePlayer_prot_chkfunc[key](val)
1476
        end
1475
        end
1477
        ffi.cast(player_ptr_ct, p)[key] = val
1476
        ffi.cast(player_ptr_ct, p)[key] = val
1478
    end,
1477
    end,
1479
}
1478
}
1480
1479
1481
ffi.metatype("DukePlayer_t", player_mt)
1480
ffi.metatype("DukePlayer_t", player_mt)
1482
1481
1483
local function GenProjectileSetFunc(Member, checkfunc)
1482
local function GenProjectileSetFunc(Member, checkfunc)
1484
    return function(self, idx)
1483
    return function(self, idx)
1485
        if (not (idx == -1)) then
1484
        if (not (idx == -1)) then
1486
            checkfunc(idx)
1485
            checkfunc(idx)
1487
        end
1486
        end
1488
        ffi.cast(projectile_ptr_ct, self)[Member] = idx
1487
        ffi.cast(projectile_ptr_ct, self)[Member] = idx
1489
    end
1488
    end
1490
end
1489
end
1491
1490
1492
local projectile_mt = {
1491
local projectile_mt = {
1493
    __index = {
1492
    __index = {
1494
        set_spawns = GenProjectileSetFunc("spawns", check_tile_idx),
1493
        set_spawns = GenProjectileSetFunc("spawns", check_tile_idx),
1495
        set_decal = GenProjectileSetFunc("decal", check_tile_idx),
1494
        set_decal = GenProjectileSetFunc("decal", check_tile_idx),
1496
        set_trail = GenProjectileSetFunc("trail", check_tile_idx),
1495
        set_trail = GenProjectileSetFunc("trail", check_tile_idx),
1497
1496
1498
        set_sound = GenProjectileSetFunc("sound", check_sound_idx),
1497
        set_sound = GenProjectileSetFunc("sound", check_sound_idx),
1499
        set_isound = GenProjectileSetFunc("isound", check_sound_idx),
1498
        set_isound = GenProjectileSetFunc("isound", check_sound_idx),
1500
        set_bsound = GenProjectileSetFunc("bsound", check_sound_idx),
1499
        set_bsound = GenProjectileSetFunc("bsound", check_sound_idx),
1501
    },
1500
    },
1502
}
1501
}
1503
ffi.metatype("projectile_t", projectile_mt)
1502
ffi.metatype("projectile_t", projectile_mt)
1504
1503
1505
local user_defs_mt = {
1504
local user_defs_mt = {
1506
    __index = {
1505
    __index = {
1507
        set_screen_size = function(ud, screen_size)
1506
        set_screen_size = function(ud, screen_size)
1508
            if (ud.screen_size ~= screen_size) then
1507
            if (ud.screen_size ~= screen_size) then
1509
                ud.screen_size = screen_size
1508
                ud.screen_size = screen_size
1510
                ffiC.G_UpdateScreenArea()
1509
                ffiC.G_UpdateScreenArea()
1511
            end
1510
            end
1512
        end,
1511
        end,
1513
1512
1514
        set_volume_number = function(ud, volume_number)
1513
        set_volume_number = function(ud, volume_number)
1515
            -- NOTE: allow volume_number==MAXVOLUMES.
1514
            -- NOTE: allow volume_number==MAXVOLUMES.
1516
            if (not (volume_number==con_lang.MAXVOLUMES)) then
1515
            if (not (volume_number==con_lang.MAXVOLUMES)) then
1517
                bcheck.volume_idx(volume_number)
1516
                bcheck.volume_idx(volume_number)
1518
            end
1517
            end
1519
            ud.volume_number = volume_number
1518
            ud.volume_number = volume_number
1520
        end,
1519
        end,
1521
1520
1522
        set_m_volume_number = function(ud, volume_number)
1521
        set_m_volume_number = function(ud, volume_number)
1523
            -- NOTE: allow volume_number==MAXVOLUMES.
1522
            -- NOTE: allow volume_number==MAXVOLUMES.
1524
            if (not (volume_number==con_lang.MAXVOLUMES)) then
1523
            if (not (volume_number==con_lang.MAXVOLUMES)) then
1525
                bcheck.volume_idx(volume_number)
1524
                bcheck.volume_idx(volume_number)
1526
            end
1525
            end
1527
            ud.m_volume_number = volume_number
1526
            ud.m_volume_number = volume_number
1528
        end,
1527
        end,
1529
1528
1530
        set_level_number = function(ud, level_number)
1529
        set_level_number = function(ud, level_number)
1531
            bcheck.level_idx(level_number)
1530
            bcheck.level_idx(level_number)
1532
            ud.level_number = level_number
1531
            ud.level_number = level_number
1533
        end,
1532
        end,
1534
    },
1533
    },
1535
}
1534
}
1536
ffi.metatype("user_defs", user_defs_mt)
1535
ffi.metatype("user_defs", user_defs_mt)
1537
1536
1538
--- CUSTOM "gv" VARIABLES
1537
--- CUSTOM "gv" VARIABLES
1539
local camera_mt = {
1538
local camera_mt = {
1540
    -- TODO: "set position" method, which also updates the sectnum
1539
    -- TODO: "set position" method, which also updates the sectnum
1541
    __index = ffiC.g_camera,
1540
    __index = ffiC.g_camera,
1542
    __newindex = function(_, key, val)
1541
    __newindex = function(_, key, val)
1543
        if (key=="sect") then
1542
        if (key=="sect") then
1544
            check_sector_idx(val)
1543
            check_sector_idx(val)
1545
        end
1544
        end
1546
        ffiC.g_camera[key] = val
1545
        ffiC.g_camera[key] = val
1547
    end,
1546
    end,
1548
}
1547
}
1549
1548
1550
gv_access.cam = setmtonce({}, camera_mt)
1549
gv_access.cam = setmtonce({}, camera_mt)
1551
gv_access._ud = ffiC.ud
1550
gv_access._ud = ffiC.ud
1552
1551
1553
-- Support for some CON global system gamevars. RETURN handled separately.
1552
-- Support for some CON global system gamevars. RETURN handled separately.
1554
gv_access._csv = ffi.new "struct { int32_t LOTAG, HITAG, TEXTURE; }"
1553
gv_access._csv = ffi.new "struct { int32_t LOTAG, HITAG, TEXTURE; }"
1555
1554
1556
gv_access.REND = defs_c.conststruct
1555
gv_access.REND = defs_c.conststruct
1557
{
1556
{
1558
    CLASSIC = 0,
1557
    CLASSIC = 0,
1559
    POLYMOST = 3,
1558
    POLYMOST = 3,
1560
    POLYMER = 4,
1559
    POLYMER = 4,
1561
}
1560
}
1562
1561
1563
gv_access.WEAPON = lprivate.WEAPON
1562
gv_access.WEAPON = lprivate.WEAPON
1564
gv_access.GET = lprivate.GET
1563
gv_access.GET = lprivate.GET
1565
1564
1566
function gv_access._get_yxaspect()
1565
function gv_access._get_yxaspect()
1567
    return ffiC.yxaspect
1566
    return ffiC.yxaspect
1568
end
1567
end
1569
1568
1570
function gv_access._get_viewingrange()
1569
function gv_access._get_viewingrange()
1571
    return ffiC.viewingrange
1570
    return ffiC.viewingrange
1572
end
1571
end
1573
1572
1574
function gv_access._currentFramerate()
1573
function gv_access._currentFramerate()
1575
    return ffiC.g_frameRate
1574
    return ffiC.g_frameRate
1576
end
1575
end
1577
1576
1578
function gv_access._currentMenu()
1577
function gv_access._currentMenu()
1579
    return ffiC.g_currentMenu
1578
    return ffiC.g_currentMenu
1580
end
1579
end
1581
1580
1582
function gv_access._changeMenu(cm)
1581
function gv_access._changeMenu(cm)
1583
    ffiC.Menu_Change(cm)
1582
    ffiC.Menu_Change(cm)
1584
end
1583
end
1585
1584
1586
function gv_access._set_guniqhudid(id)
1585
function gv_access._set_guniqhudid(id)
1587
    local MAXUNIQHUDID = 256  -- KEEPINSYNC build.h
1586
    local MAXUNIQHUDID = 256  -- KEEPINSYNC build.h
1588
    if (not (id >= 0 and id < MAXUNIQHUDID)) then
1587
    if (not (id >= 0 and id < MAXUNIQHUDID)) then
1589
        error("invalid unique HUD ID "..id)
1588
        error("invalid unique HUD ID "..id)
1590
    end
1589
    end
1591
    ffiC.guniqhudid = id
1590
    ffiC.guniqhudid = id
1592
end
1591
end
1593
1592
1594
function gv_access.currentEpisode()
1593
function gv_access.currentEpisode()
1595
    return ffiC.ud.volume_number + 1
1594
    return ffiC.ud.volume_number + 1
1596
end
1595
end
1597
1596
1598
function gv_access.currentLevel()
1597
function gv_access.currentLevel()
1599
    return ffiC.ud.level_number + 1
1598
    return ffiC.ud.level_number + 1
1600
end
1599
end
1601
1600
1602
function gv_access.doQuake(gametics, snd)
1601
function gv_access.doQuake(gametics, snd)
1603
    ffiC.g_earthquakeTime = gametics
1602
    ffiC.g_earthquakeTime = gametics
1604
    if (snd ~= nil) then
1603
    if (snd ~= nil) then
1605
        con._globalsound(ffiC.screenpeek, snd)
1604
        con._globalsound(ffiC.screenpeek, snd)
1606
    end
1605
    end
1607
end
1606
end
1608
1607
1609
-- Declare all con_lang.labels constants in the global FFI namespace.
1608
-- Declare all con_lang.labels constants in the global FFI namespace.
1610
for i=1,#con_lang.labels do
1609
for i=1,#con_lang.labels do
1611
    if (getmetatable(con_lang.labels[i]) ~= "noffiC") then
1610
    if (getmetatable(con_lang.labels[i]) ~= "noffiC") then
1612
        local strbuf = {"enum {"}
1611
        local strbuf = {"enum {"}
1613
        for label, val in pairs(con_lang.labels[i]) do
1612
        for label, val in pairs(con_lang.labels[i]) do
1614
            strbuf[#strbuf+1] = string.format("%s = %d,", label, val)
1613
            strbuf[#strbuf+1] = string.format("%s = %d,", label, val)
1615
        end
1614
        end
1616
        strbuf[#strbuf+1] = "};"
1615
        strbuf[#strbuf+1] = "};"
1617
1616
1618
        ffi.cdef(table.concat(strbuf))
1617
        ffi.cdef(table.concat(strbuf))
1619
    end
1618
    end
1620
end
1619
end
1621
1620
1622
1621
1623
---=== Set up restricted global environment ===---
1622
---=== Set up restricted global environment ===---
1624
1623
1625
local allowed_modules = {
1624
local allowed_modules = {
1626
    coroutine=coroutine, bit=bit, table=table, math=math, string=string,
1625
    coroutine=coroutine, bit=bit, table=table, math=math, string=string,
1627
1626
1628
    os = {
1627
    os = {
1629
        clock = function() return gv_.gethiticks()*0.001 end,
1628
        clock = function() return gv_.gethiticks()*0.001 end,
1630
    },
1629
    },
1631
1630
1632
    randgen = randgen,
1631
    randgen = randgen,
1633
    engine = require("engine"),
1632
    engine = require("engine"),
1634
    stat = require("stat"),
1633
    stat = require("stat"),
1635
    bitar = require("bitar"),
1634
    bitar = require("bitar"),
1636
    xmath = xmath,
1635
    xmath = xmath,
1637
    fs = require("fs"),
1636
    fs = require("fs"),
1638
1637
1639
    con = con,
1638
    con = con,
1640
}
1639
}
1641
1640
1642
do
1641
do
1643
    local ctype_cansave = {}
1642
    local ctype_cansave = {}
1644
1643
1645
    -- Register as "serializeable" the type of cdata object <v>.
1644
    -- Register as "serializeable" the type of cdata object <v>.
1646
    local function reg_serializable_cv(v)
1645
    local function reg_serializable_cv(v)
1647
        assert(type(v)=="cdata")
1646
        assert(type(v)=="cdata")
1648
        assert(type(v._serialize)=="function")
1647
        assert(type(v._serialize)=="function")
1649
        -- NOTE: tonumber() on a ctype cdata object gets its LuaJIT-internal
1648
        -- NOTE: tonumber() on a ctype cdata object gets its LuaJIT-internal
1650
        -- ID, the one that would be shown with tostring(), e.g.
1649
        -- ID, the one that would be shown with tostring(), e.g.
1651
        -- ctype<struct 95>
1650
        -- ctype<struct 95>
1652
        ctype_cansave[tonumber(ffi.typeof(v))] = true
1651
        ctype_cansave[tonumber(ffi.typeof(v))] = true
1653
    end
1652
    end
1654
1653
1655
    function lprivate.cansave_cdata(v)
1654
    function lprivate.cansave_cdata(v)
1656
        return type(v)=="cdata" and ctype_cansave[tonumber(ffi.typeof(v))]
1655
        return type(v)=="cdata" and ctype_cansave[tonumber(ffi.typeof(v))]
1657
    end
1656
    end
1658
1657
1659
    reg_serializable_cv(xmath.vec3())
1658
    reg_serializable_cv(xmath.vec3())
1660
    reg_serializable_cv(ivec3())
1659
    reg_serializable_cv(ivec3())
1661
end
1660
end
1662
1661
1663
-- Protect base modules.
1662
-- Protect base modules.
1664
local function basemod_newidx()
1663
local function basemod_newidx()
1665
    error("modifying base module table forbidden", 2)
1664
    error("modifying base module table forbidden", 2)
1666
end
1665
end
1667
1666
1668
for modname, themodule in pairs(allowed_modules) do
1667
for modname, themodule in pairs(allowed_modules) do
1669
    local mt = {
1668
    local mt = {
1670
        __index = themodule,
1669
        __index = themodule,
1671
        __newindex = basemod_newidx,
1670
        __newindex = basemod_newidx,
1672
    }
1671
    }
1673
1672
1674
    allowed_modules[modname] = setmtonce({}, mt)
1673
    allowed_modules[modname] = setmtonce({}, mt)
1675
end
1674
end
1676
1675
1677
1676
1678
---=== Module stuff ===---
1677
---=== Module stuff ===---
1679
1678
1680
local package_loaded = {}  -- [<modname>] = false/true/table
1679
local package_loaded = {}  -- [<modname>] = false/true/table
1681
local modname_stack = {}  -- [<depth>]=string
1680
local modname_stack = {}  -- [<depth>]=string
1682
local module_gamevars = {}  -- [<modname>] = { <gvname1>, <gvname2>, ... }
1681
local module_gamevars = {}  -- [<modname>] = { <gvname1>, <gvname2>, ... }
1683
local module_gvlocali = {}  -- [<modname>] = { <localidx_beg>, <localidx_end> }
1682
local module_gvlocali = {}  -- [<modname>] = { <localidx_beg>, <localidx_end> }
1684
local module_thread = {}  -- [<modname>] = <module_thread>
1683
local module_thread = {}  -- [<modname>] = <module_thread>
1685
1684
1686
local function getcurmodname(thisfuncname)
1685
local function getcurmodname(thisfuncname)
1687
    if (#modname_stack == 0) then
1686
    if (#modname_stack == 0) then
1688
        error("'"..thisfuncname.."' must be called at the top level of a require'd file", 3)
1687
        error("'"..thisfuncname.."' must be called at the top level of a require'd file", 3)
1689
        -- ... as opposed to "at runtime".
1688
        -- ... as opposed to "at runtime".
1690
    end
1689
    end
1691
1690
1692
    return modname_stack[#modname_stack]
1691
    return modname_stack[#modname_stack]
1693
end
1692
end
1694
1693
1695
1694
1696
local function errorf(level, fmt, ...)
1695
local function errorf(level, fmt, ...)
1697
    local errmsg = string.format(fmt, ...)
1696
    local errmsg = string.format(fmt, ...)
1698
    error(errmsg, level+1)
1697
    error(errmsg, level+1)
1699
end
1698
end
1700
1699
1701
local function readintostr_mod(fn)
1700
local function readintostr_mod(fn)
1702
    -- TODO: g_loadFromGroupOnly?
1701
    -- TODO: g_loadFromGroupOnly?
1703
    local fd = ffiC.kopen4loadfrommod(fn, 0)
1702
    local fd = ffiC.kopen4loadfrommod(fn, 0)
1704
    if (fd < 0) then
1703
    if (fd < 0) then
1705
        return nil
1704
        return nil
1706
    end
1705
    end
1707
1706
1708
    local ret = defs_c.readintostr(fd)
1707
    local ret = defs_c.readintostr(fd)
1709
    ffiC.kclose(fd)
1708
    ffiC.kclose(fd)
1710
    return ret
1709
    return ret
1711
end
1710
end
1712
1711
1713
1712
1714
local debug = require("debug")
1713
local debug = require("debug")
1715
1714
1716
-- Get the number of active locals in the function that calls the function
1715
-- Get the number of active locals in the function that calls the function
1717
-- calling this one.
1716
-- calling this one.
1718
local function getnumlocals(l)
1717
local function getnumlocals(l)
1719
    -- 200 is the max. number of locals at one level
1718
    -- 200 is the max. number of locals at one level
1720
    for i=1,200 do
1719
    for i=1,200 do
1721
        -- level:
1720
        -- level:
1722
        -- 0 is debug.getlocal() itself.
1721
        -- 0 is debug.getlocal() itself.
1723
        -- 1 is this function (getnumlocals).
1722
        -- 1 is this function (getnumlocals).
1724
        -- 2 is the function calling getnumlocals()
1723
        -- 2 is the function calling getnumlocals()
1725
        -- 3 is the function calling that one.
1724
        -- 3 is the function calling that one.
1726
        if (debug.getlocal(3, i) == nil) then
1725
        if (debug.getlocal(3, i) == nil) then
1727
            return i-1
1726
            return i-1
1728
        end
1727
        end
1729
    end
1728
    end
1730
end
1729
end
1731
1730
1732
local function error_on_nil_read(_, varname)
1731
local function error_on_nil_read(_, varname)
1733
    error("attempt to read nil variable '"..varname.."'", 2)
1732
    error("attempt to read nil variable '"..varname.."'", 2)
1734
end
1733
end
1735
1734
1736
local required_module_mt = {
1735
local required_module_mt = {
1737
    __index = error_on_nil_read,
1736
    __index = error_on_nil_read,
1738
1737
1739
    __newindex = function()
1738
    __newindex = function()
1740
        error("modifying module table forbidden", 2)
1739
        error("modifying module table forbidden", 2)
1741
    end,
1740
    end,
1742
1741
1743
    __metatable = true,
1742
    __metatable = true,
1744
}
1743
}
1745
1744
1746
-- Will contain a function to restore gamevars when running from savegame
1745
-- Will contain a function to restore gamevars when running from savegame
1747
-- restoration. See SAVEFUNC_ARGS for its arguments.
1746
-- restoration. See SAVEFUNC_ARGS for its arguments.
1748
local g_restorefunc = nil
1747
local g_restorefunc = nil
1749
1748
1750
-- Local gamevar restoration function run from
1749
-- Local gamevar restoration function run from
1751
-- our_require('end_gamevars') <- [user module].
1750
-- our_require('end_gamevars') <- [user module].
1752
local function restore_local(li, lval)
1751
local function restore_local(li, lval)
1753
    -- level:
1752
    -- level:
1754
    -- 0 is getlocal() itself.
1753
    -- 0 is getlocal() itself.
1755
    -- 1 is this function (restore_local).
1754
    -- 1 is this function (restore_local).
1756
    -- 2 is the function calling restore_local(), the savecode.
1755
    -- 2 is the function calling restore_local(), the savecode.
1757
    -- 3 is the function calling the savecode, our_require.
1756
    -- 3 is the function calling the savecode, our_require.
1758
    -- 4 is the function calling our_require, the module function.
1757
    -- 4 is the function calling our_require, the module function.
1759
    if (ffiC._DEBUG_LUNATIC ~= 0) then
1758
    if (ffiC._DEBUG_LUNATIC ~= 0) then
1760
        printf("Restoring index #%d (%s) with value %s",
1759
        printf("Restoring index #%d (%s) with value %s",
1761
               li, debug.getlocal(4, li), tostring(lval))
1760
               li, debug.getlocal(4, li), tostring(lval))
1762
    end
1761
    end
1763
1762
1764
    assert(debug.setlocal(4, li, lval))
1763
    assert(debug.setlocal(4, li, lval))
1765
end
1764
end
1766
1765
1767
-- The "require" function accessible to Lunatic code.
1766
-- The "require" function accessible to Lunatic code.
1768
-- Base modules in allowed_modules are wrapped so that they cannot be
1767
-- Base modules in allowed_modules are wrapped so that they cannot be
1769
-- modified, user modules are searched in the EDuke32 search
1768
-- modified, user modules are searched in the EDuke32 search
1770
-- path.  Also, our require
1769
-- path.  Also, our require
1771
--  * never messes with the global environment, it only returns the module.
1770
--  * never messes with the global environment, it only returns the module.
1772
--  * allows passing varargs beyond the name to the module.
1771
--  * allows passing varargs beyond the name to the module.
1773
local function our_require(modname, ...)
1772
local function our_require(modname, ...)
1774
    local ERRLEV = 5
1773
    local ERRLEV = 5
1775
1774
1776
    -- Check module name is valid first.
1775
    -- Check module name is valid first.
1777
    -- TODO: restrict valid names?
1776
    -- TODO: restrict valid names?
1778
    if (type(modname) ~= "string" or #modname==0) then
1777
    if (type(modname) ~= "string" or #modname==0) then
1779
        error("module name must be a nonempty string", 2)
1778
        error("module name must be a nonempty string", 2)
1780
    end
1779
    end
1781
1780
1782
    -- For _LUNATIC_DBG
1781
    -- For _LUNATIC_DBG
1783
    if (modname:match("^_LUNATIC") and ffiC._DEBUG_LUNATIC == 0) then
1782
    if (modname:match("^_LUNATIC") and ffiC._DEBUG_LUNATIC == 0) then
1784
        return nil
1783
        return nil
1785
    end
1784
    end
1786
1785
1787
    -- Handle the section between module() and require("end_gamevars").
1786
    -- Handle the section between module() and require("end_gamevars").
1788
    if (modname == "end_gamevars") then
1787
    if (modname == "end_gamevars") then
1789
        local thismodname = getcurmodname("require")
1788
        local thismodname = getcurmodname("require")
1790
1789
1791
        if (module_gamevars[thismodname] ~= nil) then
1790
        if (module_gamevars[thismodname] ~= nil) then
1792
            error("\"require 'end_gamevars'\" must be called at most once per require'd file", 2)
1791
            error("\"require 'end_gamevars'\" must be called at most once per require'd file", 2)
1793
        end
1792
        end
1794
1793
1795
        local gvnames = {}
1794
        local gvnames = {}
1796
1795
1797
        for name in pairs(getfenv(2)) do
1796
        for name in pairs(getfenv(2)) do
1798
            gvnames[#gvnames+1] = name
1797
            gvnames[#gvnames+1] = name
1799
            if (ffiC._DEBUG_LUNATIC ~= 0) then
1798
            if (ffiC._DEBUG_LUNATIC ~= 0) then
1800
                printf("MODULE %s GAMEVAR %s", thismodname, name)
1799
                printf("MODULE %s GAMEVAR %s", thismodname, name)
1801
            end
1800
            end
1802
        end
1801
        end
1803
1802
1804
        module_gamevars[thismodname] = gvnames
1803
        module_gamevars[thismodname] = gvnames
1805
        local gvmodi = module_gvlocali[thismodname]
1804
        local gvmodi = module_gvlocali[thismodname]
1806
        gvmodi[2] = getnumlocals()
1805
        gvmodi[2] = getnumlocals()
1807
1806
1808
        if (ffiC._DEBUG_LUNATIC ~= 0) then
1807
        if (ffiC._DEBUG_LUNATIC ~= 0) then
1809
            local numlocals = gvmodi[2]-gvmodi[1]+1
1808
            local numlocals = gvmodi[2]-gvmodi[1]+1
1810
            if (numlocals > 0) then
1809
            if (numlocals > 0) then
1811
                printf("Module '%s' has %d locals, index %d to %d",
1810
                printf("Module '%s' has %d locals, index %d to %d",
1812
                       thismodname, numlocals, gvmodi[1], gvmodi[2])
1811
                       thismodname, numlocals, gvmodi[1], gvmodi[2])
1813
            end
1812
            end
1814
        end
1813
        end
1815
1814
1816
        -- Potentially restore gamevars.
1815
        -- Potentially restore gamevars.
1817
        if (g_restorefunc) then
1816
        if (g_restorefunc) then
1818
            local modtab = package_loaded[thismodname]
1817
            local modtab = package_loaded[thismodname]
1819
            assert(type(modtab)=="table")
1818
            assert(type(modtab)=="table")
1820
            -- SAVEFUNC_ARGS.
1819
            -- SAVEFUNC_ARGS.
1821
            g_restorefunc(thismodname, modtab, restore_local)
1820
            g_restorefunc(thismodname, modtab, restore_local)
1822
        end
1821
        end
1823
1822
1824
        -- Return whether we're NOT running from a savegame restore in the
1823
        -- Return whether we're NOT running from a savegame restore in the
1825
        -- second outarg. (Lunatic-private!)
1824
        -- second outarg. (Lunatic-private!)
1826
        return nil, (g_restorefunc==nil)
1825
        return nil, (g_restorefunc==nil)
1827
    end
1826
    end
1828
1827
1829
    -- See whether it's a base module name.
1828
    -- See whether it's a base module name.
1830
    if (allowed_modules[modname] ~= nil) then
1829
    if (allowed_modules[modname] ~= nil) then
1831
        return allowed_modules[modname]
1830
        return allowed_modules[modname]
1832
    end
1831
    end
1833
1832
1834
    --- Search user modules...
1833
    --- Search user modules...
1835
1834
1836
    if (modname:find("[/\\]")) then
1835
    if (modname:find("[/\\]")) then
1837
        error("Module name must not contain directory separators", ERRLEV-1)
1836
        error("Module name must not contain directory separators", ERRLEV-1)
1838
    end
1837
    end
1839
    -- Instead, dots are translated to directory separators. For EDuke32's
1838
    -- Instead, dots are translated to directory separators. For EDuke32's
1840
    -- virtual file system, this is always a forward slash. Keep the original
1839
    -- virtual file system, this is always a forward slash. Keep the original
1841
    -- module name for passing to the module function.
1840
    -- module name for passing to the module function.
1842
    local omodname = modname
1841
    local omodname = modname
1843
    modname = modname:gsub("%.", "/")
1842
    modname = modname:gsub("%.", "/")
1844
1843
1845
    local omod = package_loaded[modname]
1844
    local omod = package_loaded[modname]
1846
    if (omod ~= nil) then
1845
    if (omod ~= nil) then
1847
        if (omod==false) then
1846
        if (omod==false) then
1848
            error("Loop while loading modules", ERRLEV-1)
1847
            error("Loop while loading modules", ERRLEV-1)
1849
        end
1848
        end
1850
1849
1851
        -- already loaded
1850
        -- already loaded
1852
        assert(omod==true or type(omod)=="table")
1851
        assert(omod==true or type(omod)=="table")
1853
        return omod
1852
        return omod
1854
    end
1853
    end
1855
1854
1856
    local modfn = modname .. ".lua"
1855
    local modfn = modname .. ".lua"
1857
    local str = readintostr_mod(modfn)
1856
    local str = readintostr_mod(modfn)
1858
    if (str == nil) then
1857
    if (str == nil) then
1859
        errorf(ERRLEV-1, "Couldn't open file \"%s\"", modfn)
1858
        errorf(ERRLEV-1, "Couldn't open file \"%s\"", modfn)
1860
    end
1859
    end
1861
1860
1862
    -- Implant code that yields the module thread just before it would return
1861
    -- Implant code that yields the module thread just before it would return
1863
    -- otherwise.
1862
    -- otherwise.
1864
    str = str.."\nrequire('coroutine').yield()"
1863
    str = str.."\nrequire('coroutine').yield()"
1865
1864
1866
    local modfunc, errmsg = loadstring(str, modfn)
1865
    local modfunc, errmsg = loadstring(str, modfn)
1867
    if (modfunc == nil) then
1866
    if (modfunc == nil) then
1868
        errorf(ERRLEV-1, "Couldn't load \"%s\": %s", modname, errmsg)
1867
        errorf(ERRLEV-1, "Couldn't load \"%s\": %s", modname, errmsg)
1869
    end
1868
    end
1870
1869
1871
    package_loaded[modname] = false  -- 'not yet loaded'
1870
    package_loaded[modname] = false  -- 'not yet loaded'
1872
    table.insert(modname_stack, modname)
1871
    table.insert(modname_stack, modname)
1873
1872
1874
    -- Run the module code in a separate Lua thread!
1873
    -- Run the module code in a separate Lua thread!
1875
    local modthread = coroutine.create(modfunc)
1874
    local modthread = coroutine.create(modfunc)
1876
    local ok, retval = coroutine.resume(modthread, omodname, ...)
1875
    local ok, retval = coroutine.resume(modthread, omodname, ...)
1877
1876
1878
    if (not ok) then
1877
    if (not ok) then
1879
        errorf(ERRLEV-1, "Failed running \"%s\": %s\n%s", modname,
1878
        errorf(ERRLEV-1, "Failed running \"%s\": %s\n%s", modname,
1880
               retval, debug.traceback(modthread))
1879
               retval, debug.traceback(modthread))
1881
    end
1880
    end
1882
1881
1883
    table.remove(modname_stack)
1882
    table.remove(modname_stack)
1884
1883
1885
    local modtab = package_loaded[modname]
1884
    local modtab = package_loaded[modname]
1886
1885
1887
    if (type(modtab) ~= "table") then
1886
    if (type(modtab) ~= "table") then
1888
        -- The module didn't call our 'module'. Check if it returned a table.
1887
        -- 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
1888
        -- In that case, the coroutine has finished its main function and has
1890
        -- not reached our implanted 'yield'.
1889
        -- not reached our implanted 'yield'.
1891
        if (coroutine.status(modthread)=="dead" and type(retval)=="table") then
1890
        if (coroutine.status(modthread)=="dead" and type(retval)=="table") then
1892
            modtab = retval
1891
            modtab = retval
1893
            package_loaded[modname] = modtab
1892
            package_loaded[modname] = modtab
1894
        else
1893
        else
1895
            package_loaded[modname] = true
1894
            package_loaded[modname] = true
1896
        end
1895
        end
1897
    end
1896
    end
1898
1897
1899
    if (type(modtab) == "table") then
1898
    if (type(modtab) == "table") then
1900
        -- Protect module table in any case (i.e. either if the module used our
1899
        -- Protect module table in any case (i.e. either if the module used our
1901
        -- 'module' or if it returned a table).
1900
        -- 'module' or if it returned a table).
1902
        setmetatable(modtab, required_module_mt)
1901
        setmetatable(modtab, required_module_mt)
1903
    end
1902
    end
1904
1903
1905
    local gvmodi = module_gvlocali[modname]
1904
    local gvmodi = module_gvlocali[modname]
1906
1905
1907
    if (gvmodi and gvmodi[2] and gvmodi[2]>=gvmodi[1]) then
1906
    if (gvmodi and gvmodi[2] and gvmodi[2]>=gvmodi[1]) then
1908
        if (coroutine.status(modthread)=="suspended") then
1907
        if (coroutine.status(modthread)=="suspended") then
1909
            -- Save off the suspended thread so that we may get its locals later on.
1908
            -- 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().
1909
            -- It is never resumed, but only ever used for debug.getlocal().
1911
            module_thread[modname] = modthread
1910
            module_thread[modname] = modthread
1912
1911
1913
            if (ffiC._DEBUG_LUNATIC ~= 0) then
1912
            if (ffiC._DEBUG_LUNATIC ~= 0) then
1914
                printf("Keeping coroutine for module \"%s\"", modname)
1913
                printf("Keeping coroutine for module \"%s\"", modname)
1915
            end
1914
            end
1916
        end
1915
        end
1917
    end
1916
    end
1918
1917
1919
    return modtab
1918
    return modtab
1920
end
1919
end
1921
1920
1922
1921
1923
local module_mt = {
1922
local module_mt = {
1924
    __index = error_on_nil_read,
1923
    __index = error_on_nil_read,
1925
}
1924
}
1926
1925
1927
-- Our 'module' replacement doesn't get the module name from the function args
1926
-- 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.
1927
-- since a malicious user could remove other loaded modules this way.
1929
-- Also, our 'module' takes no varargs ("option functions" in Lua).
1928
-- Also, our 'module' takes no varargs ("option functions" in Lua).
1930
-- TODO: make transactional?
1929
-- TODO: make transactional?
1931
local function our_module()
1930
local function our_module()
1932
    if (#modname_stack == 0) then
1931
    if (#modname_stack == 0) then
1933
        error("'module' must be called at the top level of a require'd file", 2)
1932
        error("'module' must be called at the top level of a require'd file", 2)
1934
        -- ... as opposed to "at runtime".
1933
        -- ... as opposed to "at runtime".
1935
    end
1934
    end
1936
1935
1937
    local modname = getcurmodname("module")
1936
    local modname = getcurmodname("module")
1938
1937
1939
    if (package_loaded[modname]) then
1938
    if (package_loaded[modname]) then
1940
        error("'module' must be called at most once per require'd file", 2)
1939
        error("'module' must be called at most once per require'd file", 2)
1941
    end
1940
    end
1942
1941
1943
    local M = setmetatable({}, module_mt)
1942
    local M = setmetatable({}, module_mt)
1944
    package_loaded[modname] = M
1943
    package_loaded[modname] = M
1945
    -- change the environment of the function which called us:
1944
    -- change the environment of the function which called us:
1946
    setfenv(2, M)
1945
    setfenv(2, M)
1947
1946
1948
    module_gvlocali[modname] = { getnumlocals()+1 }
1947
    module_gvlocali[modname] = { getnumlocals()+1 }
1949
end
1948
end
1950
1949
1951
-- overridden 'error' that always passes a string to the base 'error'
1950
-- overridden 'error' that always passes a string to the base 'error'
1952
local function our_error(errmsg, level)
1951
local function our_error(errmsg, level)
1953
    if (type(errmsg) ~= "string") then
1952
    if (type(errmsg) ~= "string") then
1954
        error("error using 'error': error message must be a string", 2)
1953
        error("error using 'error': error message must be a string", 2)
1955
    end
1954
    end
1956
1955
1957
    if (level) then
1956
    if (level) then
1958
        if (type(level) ~= "number") then
1957
        if (type(level) ~= "number") then
1959
            error("error using 'error': error level must be a number", 2)
1958
            error("error using 'error': error level must be a number", 2)
1960
        end
1959
        end
1961
1960
1962
        error(errmsg, level==0 and 0 or level+1)
1961
        error(errmsg, level==0 and 0 or level+1)
1963
    end
1962
    end
1964
1963
1965
    error(errmsg, 2)
1964
    error(errmsg, 2)
1966
end
1965
end
1967
1966
1968
1967
1969
-- _G tweaks -- pull in only 'safe' stuff
1968
-- _G tweaks -- pull in only 'safe' stuff
1970
local G_ = {}  -- our soon-to-be global environment
1969
local G_ = {}  -- our soon-to-be global environment
1971
1970
1972
G_.assert = assert
1971
G_.assert = assert
1973
G_.error = our_error
1972
G_.error = our_error
1974
G_.ipairs = ipairs
1973
G_.ipairs = ipairs
1975
G_.pairs = pairs
1974
G_.pairs = pairs
1976
G_.pcall = pcall
1975
G_.pcall = pcall
1977
G_.print = print
1976
G_.print = print
1978
G_.module = our_module
1977
G_.module = our_module
1979
G_.next = next
1978
G_.next = next
1980
G_.require = our_require
1979
G_.require = our_require
1981
G_.select = select
1980
G_.select = select
1982
G_.tostring = tostring
1981
G_.tostring = tostring
1983
G_.tonumber = tonumber
1982
G_.tonumber = tonumber
1984
G_.type = type
1983
G_.type = type
1985
G_.unpack = unpack
1984
G_.unpack = unpack
1986
G_.xpcall = xpcall
1985
G_.xpcall = xpcall
1987
G_._VERSION = _VERSION
1986
G_._VERSION = _VERSION
1988
1987
1989
-- Available through our 'require':
1988
-- Available through our 'require':
1990
-- bit, coroutine, math, string, table
1989
-- bit, coroutine, math, string, table
1991
1990
1992
-- Not available:
1991
-- Not available:
1993
-- collectgarbage, debug, dofile, gcinfo (DEPRECATED), getfenv, getmetatable,
1992
-- collectgarbage, debug, dofile, gcinfo (DEPRECATED), getfenv, getmetatable,
1994
-- jit, load, loadfile, loadstring, newproxy (NOT STD?), package, rawequal,
1993
-- jit, load, loadfile, loadstring, newproxy (NOT STD?), package, rawequal,
1995
-- rawget, rawset, setfenv, setmetatable
1994
-- rawget, rawset, setfenv, setmetatable
1996
1995
1997
G_._G = G_
1996
G_._G = G_
1998
1997
1999
-- Chain together two functions taking 3 input args.
1998
-- Chain together two functions taking 3 input args.
2000
local function chain_func3(func1, func2)
1999
local function chain_func3(func1, func2)
2001
    if (func1==nil or func2==nil) then
2000
    if (func1==nil or func2==nil) then
2002
        return assert(func1 or func2)
2001
        return assert(func1 or func2)
2003
    end
2002
    end
2004
2003
2005
    -- Return a function that runs <func1> first and then tail-calls <func2>.
2004
    -- Return a function that runs <func1> first and then tail-calls <func2>.
2006
    return function(aci, pli, dist)
2005
    return function(aci, pli, dist)
2007
        func1(aci, pli, dist)
2006
        func1(aci, pli, dist)
2008
        return func2(aci, pli, dist)
2007
        return func2(aci, pli, dist)
2009
    end
2008
    end
2010
end
2009
end
2011
2010
2012
-- Determines the last numeric index of a table using *pairs*, so that in
2011
-- 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
2012
-- arg-lists with "holes" (e.g. {1, 2, nil, function() end}) are handled
2014
-- properly.
2013
-- properly.
2015
local function ourmaxn(tab)
2014
local function ourmaxn(tab)
2016
    local maxi = 0
2015
    local maxi = 0
2017
    for i in pairs(tab) do
2016
    for i in pairs(tab) do
2018
        if (type(i)=="number") then
2017
        if (type(i)=="number") then
2019
            maxi = math.max(i, maxi)
2018
            maxi = math.max(i, maxi)
2020
        end
2019
        end
2021
    end
2020
    end
2022
    assert(tab[maxi] ~= nil)
2021
    assert(tab[maxi] ~= nil)
2023
    return maxi
2022
    return maxi
2024
end
2023
end
2025
2024
2026
-- Running for the very first time?
2025
-- Running for the very first time?
2027
local g_firstRun = (ffiC.g_elCONSize == 0)
2026
local g_firstRun = (ffiC.g_elCONSize == 0)
2028
2027
2029
-- Actor functions, saved for actor chaining
2028
-- Actor functions, saved for actor chaining
2030
local actor_funcs = {}
2029
local actor_funcs = {}
2031
-- Event functions, saved for event chaining
2030
-- Event functions, saved for event chaining
2032
local event_funcs = {}
2031
local event_funcs = {}
2033
2032
2034
-- Per-actor sprite animation callbacks
2033
-- Per-actor sprite animation callbacks
2035
local animsprite_funcs = {}
2034
local animsprite_funcs = {}
2036
2035
2037
local gameactor_internal = gameactor_internal  -- included in lunatic.c
2036
local gameactor_internal = gameactor_internal  -- included in lunatic.c
2038
local gameevent_internal = gameevent_internal  -- included in lunatic.c
2037
local gameevent_internal = gameevent_internal  -- included in lunatic.c
2039
2038
2040
local function animate_all_sprites()
2039
local function animate_all_sprites()
2041
    for i=0,ffiC.spritesortcnt-1 do
2040
    for i=0,ffiC.spritesortcnt-1 do
2042
        local tspr = ffiC.tsprite[i]
2041
        local tspr = ffiC.tsprite[i]
2043
2042
2044
        if (tspr.owner < ffiC.MAXSPRITES+0ULL) then
2043
        if (tspr.owner < ffiC.MAXSPRITES+0ULL) then
2045
            local spr = tspr:getspr()
2044
            local spr = tspr:getspr()
2046
            local animfunc = animsprite_funcs[spr.picnum]
2045
            local animfunc = animsprite_funcs[spr.picnum]
2047
2046
2048
            if (animfunc) then
2047
            if (animfunc) then
2049
                animfunc(tspr)
2048
                animfunc(tspr)
2050
            end
2049
            end
2051
        end
2050
        end
2052
    end
2051
    end
2053
end
2052
end
2054
2053
2055
2054
2056
local function check_arg_number(name, argpos, val)
2055
local function check_arg_number(name, argpos, val)
2057
    if (type(val) ~= "number") then
2056
    if (type(val) ~= "number") then
2058
        errorf(3, "invalid '%s' argument (#%d) to gameactor: must be a number", name, argpos)
2057
        errorf(3, "invalid '%s' argument (#%d) to gameactor: must be a number", name, argpos)
2059
    end
2058
    end
2060
end
2059
end
2061
2060
2062
-- gameactor{tilenum [, flags [, strength [, action [, move [, movflags]]]]], func}
2061
-- gameactor{tilenum [, flags [, strength [, action [, move [, movflags]]]]], func}
2063
-- Every arg may be positional OR key=val (with the name indicated above as key),
2062
-- Every arg may be positional OR key=val (with the name indicated above as key),
2064
-- but not both.
2063
-- but not both.
2065
local function our_gameactor(args)
2064
local function our_gameactor(args)
2066
    bcheck.top_level("gameactor")
2065
    bcheck.top_level("gameactor")
2067
2066
2068
    if (type(args)~="table") then
2067
    if (type(args)~="table") then
2069
        error("invalid gameactor call: must be passed a table")
2068
        error("invalid gameactor call: must be passed a table")
2070
    end
2069
    end
2071
2070
2072
    local tilenum = args[1]
2071
    local tilenum = args[1]
2073
    if (type(tilenum) ~= "number") then
2072
    if (type(tilenum) ~= "number") then
2074
        error("invalid argument #1 to gameactor: must be a number", 2)
2073
        error("invalid argument #1 to gameactor: must be a number", 2)
2075
    end
2074
    end
2076
    if (not (tilenum >= 0 and tilenum < ffiC.MAXTILES)) then
2075
    if (not (tilenum >= 0 and tilenum < ffiC.MAXTILES)) then
2077
        error("invalid argument #1 to gameactor: must be a tile number [0..gv.MAXTILES-1]", 2)
2076
        error("invalid argument #1 to gameactor: must be a tile number [0..gv.MAXTILES-1]", 2)
2078
    end
2077
    end
2079
2078
2080
    local lastargi = ourmaxn(args)
2079
    local lastargi = ourmaxn(args)
2081
    local func = args[lastargi]
2080
    local func = args[lastargi]
2082
    if (type(func) ~= "function") then
2081
    if (type(func) ~= "function") then
2083
        func = args.func
2082
        func = args.func
2084
        lastargi = 1/0
2083
        lastargi = 1/0
2085
    end
2084
    end
2086
    if (type(func) ~= "function") then
2085
    if (type(func) ~= "function") then
2087
        error("invalid gameactor call: must provide a function with last numeric arg or .func", 2)
2086
        error("invalid gameactor call: must provide a function with last numeric arg or .func", 2)
2088
    end
2087
    end
2089
2088
2090
    local flags = (lastargi > 2 and args[2]) or args.flags or 0
2089
    local flags = (lastargi > 2 and args[2]) or args.flags or 0
2091
    check_arg_number("flags", 2, flags)
2090
    check_arg_number("flags", 2, flags)
2092
2091
2093
    local AF = actor.FLAGS
2092
    local AF = actor.FLAGS
2094
    local chainflags = band(flags, AF._CHAIN_MASK_ACTOR)
2093
    local chainflags = band(flags, AF._CHAIN_MASK_ACTOR)
2095
    flags = band(flags, BNOT.CHAIN_MASK_ACTOR)
2094
    flags = band(flags, BNOT.CHAIN_MASK_ACTOR)
2096
2095
2097
    if (chainflags == 0) then
2096
    if (chainflags == 0) then
2098
        -- Default chaining behavior: don't, replace the old actor instead.
2097
        -- Default chaining behavior: don't, replace the old actor instead.
2099
        chainflags = AF.replace
2098
        chainflags = AF.replace
2100
    elseif (band(chainflags, chainflags-1) ~= 0) then
2099
    elseif (band(chainflags, chainflags-1) ~= 0) then
2101
        error("invalid chaining control flags to gameactor", 2)
2100
        error("invalid chaining control flags to gameactor", 2)
2102
    end
2101
    end
2103
2102
2104
    local replacep = (chainflags==AF.replace)
2103
    local replacep = (chainflags==AF.replace)
2105
    if (not replacep and not actor_funcs[tilenum]) then
2104
    if (not replacep and not actor_funcs[tilenum]) then
2106
        error("attempt to chain code to nonexistent actor tile "..tilenum, 2)
2105
        error("attempt to chain code to nonexistent actor tile "..tilenum, 2)
2107
    end
2106
    end
2108
2107
2109
    local flags_rbits = band(flags, BNOT.USER_MASK)
2108
    local flags_rbits = band(flags, BNOT.USER_MASK)
2110
    if (flags_rbits ~= 0) then
2109
    if (flags_rbits ~= 0) then
2111
        error("invalid 'flags' argument (#2) to gameactor: must not set reserved bits (0x"
2110
        error("invalid 'flags' argument (#2) to gameactor: must not set reserved bits (0x"
2112
              ..(bit.tohex(flags_rbits))..")", 2)
2111
              ..(bit.tohex(flags_rbits))..")", 2)
2113
    end
2112
    end
2114
2113
2115
    local strength = ((lastargi > 3 and args[3]) or args.strength) or (replacep and 0 or nil)
2114
    local strength = ((lastargi > 3 and args[3]) or args.strength) or (replacep and 0 or nil)
2116
    if (replacep or strength~=nil) then
2115
    if (replacep or strength~=nil) then
2117
        check_arg_number("strength", 3, strength)
2116
        check_arg_number("strength", 3, strength)
2118
    end
2117
    end
2119
2118
2120
    local act = ((lastargi > 4 and args[4]) or args.action) or (replacep and literal_act[0] or nil)
2119
    local act = ((lastargi > 4 and args[4]) or args.action) or (replacep and literal_act[0] or nil)
2121
    if (replacep or act ~= nil) then
2120
    if (replacep or act ~= nil) then
2122
        if (type(act)=="number" and (act==0 or act==1)) then
2121
        if (type(act)=="number" and (act==0 or act==1)) then
2123
            act = literal_act[act]
2122
            act = literal_act[act]
2124
        elseif (not ffi.istype(con_action_ct, act)) then
2123
        elseif (not ffi.istype(con_action_ct, act)) then
2125
            error("invalid 'action' argument (#4) to gameactor: must be an action", 2)
2124
            error("invalid 'action' argument (#4) to gameactor: must be an action", 2)
2126
        end
2125
        end
2127
    end
2126
    end
2128
2127
2129
    local mov = ((lastargi > 5 and args[5]) or args.move) or (replacep and literal_mov[0] or nil)
2128
    local mov = ((lastargi > 5 and args[5]) or args.move) or (replacep and literal_mov[0] or nil)
2130
    if (replacep or mov ~= nil) then
2129
    if (replacep or mov ~= nil) then
2131
        if (type(mov)=="number" and (mov==0 or mov==1)) then
2130
        if (type(mov)=="number" and (mov==0 or mov==1)) then
2132
            mov = literal_mov[mov]
2131
            mov = literal_mov[mov]
2133
        elseif (not ffi.istype(con_move_ct, mov)) then
2132
        elseif (not ffi.istype(con_move_ct, mov)) then
2134
            error("invalid 'move' argument (#5) to gameactor: must be a move", 2)
2133
            error("invalid 'move' argument (#5) to gameactor: must be a move", 2)
2135
        end
2134
        end
2136
    end
2135
    end
2137
2136
2138
    local movflags = ((lastargi > 6 and args[6]) or args.movflags) or (replacep and 0 or nil)
2137
    local movflags = ((lastargi > 6 and args[6]) or args.movflags) or (replacep and 0 or nil)
2139
    if (replacep or movflags ~= nil) then
2138
    if (replacep or movflags ~= nil) then
2140
        check_arg_number("movflags", 6, movflags)
2139
        check_arg_number("movflags", 6, movflags)
2141
    end
2140
    end
2142
2141
2143
    -- Register a potentially passed drawn sprite animation callback function.
2142
    -- Register a potentially passed drawn sprite animation callback function.
2144
    -- TODO: allow registering without main actor execution callback.
2143
    -- TODO: allow registering without main actor execution callback.
2145
    local animfunc = args.animate
2144
    local animfunc = args.animate
2146
    if (animfunc ~= nil) then
2145
    if (animfunc ~= nil) then
2147
        if (type(animfunc) ~= "function") then
2146
        if (type(animfunc) ~= "function") then
2148
            error("invalid 'animate' argument to gameactor: must be a function", 2)
2147
            error("invalid 'animate' argument to gameactor: must be a function", 2)
2149
        end
2148
        end
2150
2149
2151
        animsprite_funcs[tilenum] = replacep and func
2150
        animsprite_funcs[tilenum] = replacep and func
2152
            or (chainflags==AF.chain_beg) and chain_func3(animfunc, animsprite_funcs[tilenum])
2151
            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)
2152
            or (chainflags==AF.chain_end) and chain_func3(animsprite_funcs[tilenum], animfunc)
2154
            or assert(false)
2153
            or assert(false)
2155
2154
2156
        -- Register our EVENT_ANIMATEALLSPRITES only now so that it is not
2155
        -- Register our EVENT_ANIMATEALLSPRITES only now so that it is not
2157
        -- called if there are no 'animate' definitions.
2156
        -- called if there are no 'animate' definitions.
2158
        gameevent_internal(97, animate_all_sprites)  -- EVENT_ANIMATEALLSPRITES
2157
        gameevent_internal(97, animate_all_sprites)  -- EVENT_ANIMATEALLSPRITES
2159
    end
2158
    end
2160
2159
2161
    -- All good, bitwise-OR the tile bits and register the actor!
2160
    -- 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)
2161
    ffiC.g_tile[tilenum]._flags = bit.bor(ffiC.g_tile[tilenum]._flags, flags)
2163
2162
2164
    local newfunc = replacep and func
2163
    local newfunc = replacep and func
2165
        or (chainflags==AF.chain_beg) and chain_func3(func, actor_funcs[tilenum])
2164
        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)
2165
        or (chainflags==AF.chain_end) and chain_func3(actor_funcs[tilenum], func)
2167
        or assert(false)
2166
        or assert(false)
2168
2167
2169
    gameactor_internal(tilenum, strength, act, mov, movflags, newfunc)
2168
    gameactor_internal(tilenum, strength, act, mov, movflags, newfunc)
2170
    actor_funcs[tilenum] = newfunc
2169
    actor_funcs[tilenum] = newfunc
2171
end
2170
end
2172
2171
2173
2172
2174
-- gameevent{<event idx or string> [, flags], <event function>}
2173
-- gameevent{<event idx or string> [, flags], <event function>}
2175
local function our_gameevent(args)
2174
local function our_gameevent(args)
2176
    bcheck.top_level("gameevent")
2175
    bcheck.top_level("gameevent")
2177
2176
2178
    if (type(args)~="table") then
2177
    if (type(args)~="table") then
2179
        error("invalid gameevent call: must be passed a table")
2178
        error("invalid gameevent call: must be passed a table")
2180
    end
2179
    end
2181
2180
2182
    local event = args[1]
2181
    local event = args[1]
2183
2182
2184
    if (type(event) == "string") then
2183
    if (type(event) == "string") then
2185
        if (event:sub(1,6) ~= "EVENT_") then
2184
        if (event:sub(1,6) ~= "EVENT_") then
2186
            event = "EVENT_"..event
2185
            event = "EVENT_"..event
2187
        end
2186
        end
2188
        local eventidx = con_lang.EVENT[event]
2187
        local eventidx = con_lang.EVENT[event]
2189
        if (eventidx == nil) then
2188
        if (eventidx == nil) then
2190
            errorf(2, "gameevent: invalid event label %q", event)
2189
            errorf(2, "gameevent: invalid event label %q", event)
2191
        end
2190
        end
2192
        event = eventidx
2191
        event = eventidx
2193
    end
2192
    end
2194
    if (type(event) ~= "number") then
2193
    if (type(event) ~= "number") then
2195
        error("invalid argument #1 to gameevent: must be a number or event label", 2)
2194
        error("invalid argument #1 to gameevent: must be a number or event label", 2)
2196
    end
2195
    end
2197
    if (not (event >= 0 and event < con_lang.MAXEVENTS)) then
2196
    if (not (event >= 0 and event < con_lang.MAXEVENTS)) then
2198
        error("invalid argument #1 to gameevent: must be an event number (0 .. MAXEVENTS-1)", 2)
2197
        error("invalid argument #1 to gameevent: must be an event number (0 .. MAXEVENTS-1)", 2)
2199
    end
2198
    end
2200
2199
2201
    local AF = actor.FLAGS
2200
    local AF = actor.FLAGS
2202
2201
2203
    -- Kind of CODEDUP from our_gameactor.
2202
    -- Kind of CODEDUP from our_gameactor.
2204
    local lastargi = ourmaxn(args)
2203
    local lastargi = ourmaxn(args)
2205
    local func = args[lastargi]
2204
    local func = args[lastargi]
2206
    if (type(func) ~= "function") then
2205
    if (type(func) ~= "function") then
2207
        func = args.func
2206
        func = args.func
2208
        lastargi = 1/0
2207
        lastargi = 1/0
2209
    end
2208
    end
2210
    if (type(func) ~= "function") then
2209
    if (type(func) ~= "function") then
2211
        error("invalid gameevent call: must provide a function with last numeric arg or .func", 2)
2210
        error("invalid gameevent call: must provide a function with last numeric arg or .func", 2)
2212
    end
2211
    end
2213
2212
2214
    -- Event chaining: in Lunatic, chaining at the *end* is the default.
2213
    -- Event chaining: in Lunatic, chaining at the *end* is the default.
2215
    local flags = (lastargi > 2 and args[2]) or args.flags or AF.chain_end
2214
    local flags = (lastargi > 2 and args[2]) or args.flags or AF.chain_end
2216
    if (type(flags) ~= "number") then
2215
    if (type(flags) ~= "number") then
2217
        error("invalid 'flags' argument (#2) to gameevent: must be a number", 2)
2216
        error("invalid 'flags' argument (#2) to gameevent: must be a number", 2)
2218
    end
2217
    end
2219
2218
2220
    if (band(flags, BNOT.CHAIN_MASK_EVENT) ~= 0) then
2219
    if (band(flags, BNOT.CHAIN_MASK_EVENT) ~= 0) then
2221
        error("invalid 'flags' argument to gameevent: must not set reserved bits", 2)
2220
        error("invalid 'flags' argument to gameevent: must not set reserved bits", 2)
2222
    end
2221
    end
2223
2222