diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index 90b920ba5..22795e7d7 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -309,6 +309,8 @@ end wdata_members = { -- NOTE: they are lowercased for Lunatic + -- NOTE: members _*sound*, _spawn and _shoots assume *zero* to mean "none" + -- (-1 would be more logical). "const int32_t _workslike", "int32_t clip", "int32_t reload", diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index ddd9005bb..72ffeb3e4 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -194,6 +194,7 @@ local check_sprite_idx = bcheck.sprite_idx local check_weapon_idx, check_inventory_idx = bcheck.weapon_idx, bcheck.inventory_idx local check_sound_idx = bcheck.sound_idx local check_number = bcheck.number +local check_type = bcheck.type bcarray.new("int16_t", 64, "loogie", "int16_x_64") -- TODO: randomize member names bcarray.new("int16_t", ffiC.MAX_WEAPONS, "weapon", "int16_x_MAX_WEAPONS", WEAPON_NAMES) @@ -967,6 +968,8 @@ end local actor_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(ACTOR_STRUCT))) local player_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(DUKEPLAYER_STRUCT))) local projectile_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(PROJECTILE_STRUCT))) +-- An unrestricted weapondata_t pointer, but with the member names stripped of +-- the leading underscore, too: local weapondata_ptr_ct = ffi.typeof("$ *", ffi.typeof((strip_const(WEAPONDATA_STRUCT):gsub(" _"," ")))) local con_action_ct = ffi.typeof("const con_action_t") @@ -1185,6 +1188,17 @@ ffi.metatype("actor_t", actor_mt) --- PER-PLAYER WEAPON SETTINGS +local wd_sound_member = {} +for _, declstr in pairs(con_lang.wdata_members) do + local member = declstr:match("const int32_t _(.*sound)$") + if (member) then + wd_sound_member[member] = true + if (ffiC._DEBUG_LUNATIC ~= 0) then + printf("weapondata_t member %s denotes a sound", member) + end + end +end + local weapondata_mt = { __index = function(wd, member) -- Handle protected members that are renamed (e.g. shoots/_shoots). @@ -1195,11 +1209,12 @@ local weapondata_mt = { -- Set to 'true' if we set a tile or sound member. local didit = false + check_type(member, "string") -- MEMBER_IS_STRING check_number(val) - if (string.match(member, "sound")) then + if (wd_sound_member[member]) then -- XXX: sound2time is a time, not a sound if (val < 0) then - val = 0 -- Set to 0 if oob (e.g. CrackDown). + val = 0 -- Set to 0 if negative (e.g. CrackDown). else check_sound_idx(val) end @@ -1218,7 +1233,13 @@ local weapondata_mt = { didit = true end - ffi.cast(weapondata_ptr_ct, wd)[0][member] = val + -- DEBUG: +-- printf("assigning %s to weapon's %s", tostring(val), member) + + -- NOTE: we're indexing a *pointer* with the user-supplied 'member', + -- which could be dangerouns if it could be a number. However, we have + -- assured that is is not in MEMBER_IS_STRING above. + ffi.cast(weapondata_ptr_ct, wd)[member] = val if (didit and ffiC.g_elCallDepth==0) then -- Signal that we overrode this member at CON translation time. diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 8a55b25e9..ddeb4aee2 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -1,7 +1,5 @@ -- test script for ELua/Lunatic Interpreter ---do return end - -- error=nil -- must not affect "require" local string = require("string") local bit = require("bit") @@ -31,14 +29,6 @@ local function checkfail(funcstr, expectedmsg) end end ---[[ ----- check serialization ---- --- test nans, infs, precision, subnorms, booleans -ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314, true } -ourvar = { ourvar2; 1, 2, 3, "qwe"; [true]=0, [false]=1 } -ourvar[#ourvar+1] = ourvar; ---]] - gameevent { "ENTERLEVEL", @@ -47,13 +37,8 @@ gameevent local vol, lev = gv.currentEpisode()+1, gv.currentLevel()+1 printf('volume=%d, level=%d', vol, lev) - ---[[ if (vol ~= 4) then -- Tweak some sector pals. - -- NOTE: you're not really supposed to modify game state from Lua file - -- scope! This is for testing only! E.g. it will fail if a savegame is - -- loaded from the menu when no other level is loaded. - print('tweaking sector pals') print('numsectors: ' .. gv.numsectors .. ' of ' .. gv.MAXSECTORS) @@ -109,7 +94,6 @@ gameevent local unsafe = pcall(function() string.UNSAFE=true; end) ---]] --tostring = nil -- REMEMBER --DBG_.printkv('_G in test.elua', _G) @@ -195,9 +179,25 @@ checkfail("gv.g_sizes_of=nil; print(gv.g_sizes_of[0])", "write access forbidden" checkfail("gv.cam.sect=-1", "invalid sector number") checkfail("local flag=gv.SFLAG_NULL", "missing declaration") +-- NOTE: player[0] is forbidden at file scope, this is just for testing purposes. player[0].wackedbyactor = -1 -- should succeed checkfail("player[0].curr_weapon = -1", "Invalid weapon ID") player[0].curr_weapon = 1 +checkfail("local w = player[0].weapon[-1]", "out-of-bounds weapon read access") + +-- XXX: This gives a very strange error message: "attempt to write to constant location". Why? +-- (note how I forgot to index weapon with a weapon index or name) +--player[0].weapon.firesound = 1e5 +checkfail("player[0].weapon.SHOTGUN.firesound = 1e5", "invalid sound number") +checkfail("player[0].weapon.SHOTGUN.firesound = 0/0", "must be a non-NaN number") +-- XXX XXX XXX: FAILS! +-- inf=1/0; inf >= 1ull <- yields FALSE on x86_64 (inf->uint64_t conversion: undefined!) +-- Related (Mike used 0ULL here): http://www.freelists.org/post/luajit/Stack-trace-on-SIGSEGV,4 +checkfail("player[0].weapon.SHOTGUN.firesound = 1/0", "invalid sound number") +-- NOTE: It should only be relied on that setting e.g. .firesound to -1 sets it +-- to 0, not other negative values. +player[0].weapon.SHOTGUN.firesound = -1/0 +assert(player[0].weapon.SHOTGUN.firesound == 0) gameevent{gv.EVENT_JUMP, function(actori, playeri, dist) @@ -246,6 +246,10 @@ gameevent end ps.weapon[gv.PISTOL_WEAPON].firesound = D.LIGHTNING_SLAP + -- This succeeds, because sound2time is a time, not a sound. + ps.weapon.SHOTGUN.sound2time = 5000 + printf("set shotgun's sound2time to %d", ps.weapon.SHOTGUN.sound2time) + -- Set pipebomb and tripbomb to timed mode. -- XXX: Provide either named constants or methods? -- XXX: These are probably reset to default on new game.