Subversion Repositories eduke32

Rev

Rev 4515 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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