Subversion Repositories eduke32

Rev

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

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