diff --git a/polymer/eduke32/source/lunatic/bcheck.lua b/polymer/eduke32/source/lunatic/bcheck.lua index 5dc3cb68b..4635cc2b9 100644 --- a/polymer/eduke32/source/lunatic/bcheck.lua +++ b/polymer/eduke32/source/lunatic/bcheck.lua @@ -1,6 +1,7 @@ -- Bound-checking functions for engine and game "things". local ffiC = require("ffi").C +local con_lang = require("con_lang") local bcheck = {} @@ -71,5 +72,15 @@ function bcheck.level_idx(level) end end +function bcheck.quote_idx(qnum) + if (qnum >= con_lang.MAXQUOTES+0ULL) then + error("invalid quote number "..qnum, 3) + end + + if (ffiC.ScriptQuotes[qnum] == nil) then + error("null quote "..qnum, 3) + end +end + return bcheck diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index 19bf4cfdb..8978404b5 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -516,9 +516,9 @@ local PlayerLabels = { airleft = PL".airleft", fta = PL".fta", - ftq = PL".ftq", - access_wallnum = PL".access_wallnum", - access_spritenum = PL".access_spritenum", + ftq = { PL".ftq", PL":set_ftq(%%s)" }, + access_wallnum = { PL".access_wallnum" }, + access_spritenum = { PL".access_spritenum" }, got_access = PL".got_access", weapon_ang = PL".weapon_ang", diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 209acb3f6..b7674db34 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -329,6 +329,10 @@ end --- player/actor/sprite searching functions --- +local xmath = require("xmath") +local abs = math.abs +local dist, ldist = xmath.dist, xmath.ldist + local function A_FP_ManhattanDist(ps, spr) return (ps.pos - spr^(28*256)):blen1() end @@ -339,6 +343,48 @@ function _findplayer(ps, spritenum) return 0, A_FP_ManhattanDist(ps, sprite[spritenum]) end +local FN_STATNUMS = { + [false] = { con_lang.STAT.STAT_ACTOR }, + [true] = {}, +} + +-- TODO: Python-like range() and xrange()? +for i=0,ffiC.MAXSTATUS-1 do + FN_STATNUMS[true][i+1] = ffiC.MAXSTATUS-1-i +end + +local FN_DISTFUNC = { + d2 = function(s1, s2, d) + return (xmath.ldist(s1, s2) < d) + end, + + d3 = function(s1, s2, d) + return (xmath.dist(s1, s2) < d) + end, + + z = function(s1, s2, d, zd) + return (xmath.ldist(s1, s2) < d and abs(s1.z-s2.z) < zd) + end, +} + +function _findnear(spritenum, allspritesp, distkind, picnum, maxdist, maxzdist) + local statnums = FN_STATNUMS[allspritesp] + local distfunc = FN_DISTFUNC[distkind] + local spr = sprite[spritenum] + + for st=1,#statnums do + for i in spritesofstat(st) do + if (i ~= spritenum and sprite[i].picnum==picnum) then + if (distfunc(spr, sprite[i], maxdist, maxzdist)) then + return i + end + end + end + end + + return -1 +end + ---=== Weapon stuff ===--- @@ -374,31 +420,21 @@ end local MAXQUOTES = con_lang.MAXQUOTES -local function check_quote_idx(qnum) - if (qnum >= MAXQUOTES+0ULL) then - error("invalid quote number "..qnum, 3) - end - - if (ffiC.ScriptQuotes[qnum] == nil) then - error("null quote "..qnum, 3) - end -end - function _definequote(qnum, quotestr) - check_quote_idx(qnum) + bcheck.quote_idx(qnum) assert(type(quotestr)=="string") ffiC.C_DefineQuote(qnum, quotestr) return (#quotestr >= con_lang.MAXQUOTELEN) end function _quote(pli, qnum) - check_quote_idx(qnum) + bcheck.quote_idx(qnum) check_player_idx(pli) ffiC.P_DoQuote(qnum+MAXQUOTES, ffiC.g_player[pli].ps) end function _echo(qnum) - check_quote_idx(qnum) + bcheck.quote_idx(qnum) -- XXX: ugly round-trip print(ffi.string(ffiC.ScriptQuotes[qnum])) end @@ -771,14 +807,12 @@ function _awayfromwall(spr, d) return true end -local xmath = require("xmath") - local function cossinb(bang) return xmath.cosb(bang), xmath.sinb(bang) end local function manhatdist(v1, v2) - return math.abs(v1.x-v2.x) + math.abs(v1.y-v2.y) + return abs(v1.x-v2.x) + abs(v1.y-v2.y) end -- "otherspr" is either player or holoduke sprite @@ -950,8 +984,8 @@ function _angdiffabs(a1, a2) a1 = bit.band(a1, 2047) a2 = bit.band(a2, 2047) -- a1 and a2 are in [0, 2047] - if (math.abs(a2-a1) < 1024) then - return math.abs(a2-a1) + if (abs(a2-a1) < 1024) then + return abs(a2-a1) end -- |a2-a1| >= 1024 if (a2 > 1024) then a2=a2-2048 end @@ -961,7 +995,7 @@ function _angdiffabs(a1, a2) end function _angdiffabs(a1, a2) - return math.abs(_angdiff(a1, a2)) + return abs(_angdiff(a1, a2)) end function _angtotarget(aci) diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index c9c138a82..d9aecbb9d 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -199,7 +199,8 @@ __attribute__((packed)) struct { int16_t horiz, horizoff, ohoriz, ohorizoff; const int16_t newowner; int16_t jumping_counter, airleft; - int16_t fta, ftq, access_wallnum, access_spritenum; + int16_t fta; + const int16_t ftq, access_wallnum, access_spritenum; int16_t got_access, weapon_ang, visibility; int16_t somethingonplayer, on_crane; const int16_t i; @@ -911,6 +912,11 @@ local player_mt = { p.inv_amount[inv] = amount end, + set_ftq = function(p, ftq) + bcheck.quote_idx(ftq) + ffi.cast(player_ptr_ct, p).ftq = ftq + end, + set_customexitsound = function(p, soundnum) if (soundnum >= con_lang.MAXSOUNDS+0ULL) then error("Invalid sound number "..soundnum, 2) @@ -1047,6 +1053,15 @@ function gv_access._currentMenu() return ffiC.g_currentMenu end +function gv_access._set_guniqhudid(id) + local MAXUNIQHUDID = 256 -- KEEPINSYNC build.h + if (id >= MAXUNIQHUDID+0ULL) then + error("invalid unique HUD ID "..id) + end + ffiC.guniqhudid = id +end + +-- TODO: make return 1-based index function gv_access.currentEpisode() return ffiC.ud.volume_number end diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index f70f91714..ddd5779e2 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -228,6 +228,7 @@ const int32_t windowx1, windowy1, windowx2, windowy2; decl[[ int32_t yxaspect, viewingrange; int32_t spritesortcnt; +int32_t guniqhudid; const int32_t rendmode; const int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1]; const int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES]; @@ -511,6 +512,24 @@ end ---- indirect C array access ---- +-- create a safe indirection for an ffi.C array +function creategtab(ctab, maxidx, name) + local tab = {} + local tmpmt = { + __index = function(tab, key) + if (key>=0 and key < maxidx) then + return ctab[key] + end + error('out-of-bounds '..name..' read access', 2) + end, + __newindex = function() + error('cannot write directly to '..name, 2) + end, + } + + return setmtonce(tab, tmpmt) +end + -- Construct const struct from table function conststruct(tab) local strtab = { "const struct { int32_t " } @@ -554,6 +573,15 @@ static_members.sprite.CSTAT = conststruct TRANSLUCENT_BOTH_BITS = 512+2, } +local sms = static_members.sprite +sms._headspritesect = creategtab(ffiC.headspritesect, ffiC.MAXSECTORS, 'headspritesect[]') +-- NOTE: don't allow freelist access +sms._headspritestat = creategtab(ffiC.headspritestat, ffiC.MAXSTATUS, 'headspritestat[]') +sms._nextspritesect = creategtab(ffiC.nextspritesect, ffiC.MAXSPRITES, 'nextspritesect[]') +sms._nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritestat[]') +sms._prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]') +sms._prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, 'prevspritestat[]') + function static_members.sprite.changesect(spritenum, sectnum) check_sprite_idx(spritenum) check_sector_idx(sectnum) @@ -611,24 +639,6 @@ local atsprite_mt = { __newindex = function() error('cannot write directly to atsprite[]', 2) end, } --- create a safe indirection for an ffi.C array -function creategtab(ctab, maxidx, name) - local tab = {} - local tmpmt = { - __index = function(tab, key) - if (key>=0 and key < maxidx) then - return ctab[key] - end - error('out-of-bounds '..name..' read access', 2) - end, - __newindex = function() - error('cannot write directly to '..name, 2) - end, - } - - return setmtonce(tab, tmpmt) -end - local vars_to_ignore = {} for varname,_ in pairs(getfenv(1)) do @@ -646,14 +656,6 @@ sprite = setmtonce({}, sprite_mt) spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[]') atsprite = setmtonce({}, atsprite_mt) -headspritesect = creategtab(ffiC.headspritesect, ffiC.MAXSECTORS, 'headspritesect[]') --- TODO: allow sprite freelist access via the status list for CON compatibility? -headspritestat = creategtab(ffiC.headspritestat, ffiC.MAXSTATUS, 'headspritestat[]') -nextspritesect = creategtab(ffiC.nextspritesect, ffiC.MAXSPRITES, 'nextspritesect[]') -nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritestat[]') -prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]') -prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, 'prevspritestat[]') - local function iter_wallsofsec(endwall, w) w = w+1 if (w < endwall) then diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index 0a2b82909..76f137abe 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -29,8 +29,6 @@ local ffi, ffiC if (string.dump) then bit = require("bit") - -- For Rio Lua: --- bit = { bor=function() return 0 end } require("strict") else bit = require("bit") @@ -1492,12 +1490,14 @@ local Cinner = { / handle.NYI, -- will never be cmenu = cmd(R) / handle.NYI, - checkavailweapon = cmd(R), - checkavailinven = cmd(R), - guniqhudid = cmd(R), + checkavailweapon = cmd(R) -- THISACTOR + / handle.NYI, + checkavailinven = cmd(R) -- THISACTOR + / handle.NYI, + guniqhudid = cmd(R) + / "_gv._set_guniqhudid(%1)", savegamevar = cmd(R), readgamevar = cmd(R), - userquote = cmd(R), echo = cmd(R) / "_con._echo(%1)", activatecheat = cmd(R) @@ -1579,8 +1579,6 @@ local Cinner = { / "_con._spawnmany(_aci,1233,%1)", -- TODO: dyntile paper = cmd(D) / "_con._spawnmany(_aci,4460,%1)", -- TODO: dyntile - quote = cmd(D) - / "_con._quote(_pli,%1)", savenn = cmd(D), save = cmd(D), sleeptime = cmd(D) @@ -1630,7 +1628,7 @@ local Cinner = { tip = cmd() / PLS".tipincs=26", tossweapon = cmd() - / "", -- TODO + / "", -- TODO_MP wackplayer = cmd() / PLS":wack()", @@ -1638,19 +1636,31 @@ local Cinner = { findplayer = cmd(W) / CSV".RETURN,%1=_con._findplayer(_pli,_aci)", -- player index, distance findotherplayer = cmd(W) - / CSV".RETURN,%1=0,0x7fffffff", -- TODO: MP case - findnearspritezvar = cmd(D,R,R,W), - findnearspritez = cmd(D,D,D,W), - findnearsprite3dvar = cmd(D,R,W), - findnearsprite3d = cmd(D,D,W), - findnearspritevar = cmd(D,R,W), - findnearsprite = cmd(D,D,W), - findnearactorzvar = cmd(D,R,R,W), - findnearactorz = cmd(D,D,D,W), - findnearactor3dvar = cmd(D,R,W), - findnearactor3d = cmd(D,D,W), - findnearactorvar = cmd(D,R,W), - findnearactor = cmd(D,D,W), + / CSV".RETURN,%1=0,0x7fffffff", -- TODO_MP + findnearspritezvar = cmd(D,R,R,W) + / "%4=_con._findnear(_aci,true,'z',%1,%2,%3)", + findnearspritez = cmd(D,D,D,W) + / "%4=_con._findnear(_aci,true,'z',%1,%2,%3)", + findnearsprite3dvar = cmd(D,R,W) + / "%3=_con._findnear(_aci,true,'d3',%1,%2)", + findnearsprite3d = cmd(D,D,W) + / "%3=_con._findnear(_aci,true,'d3',%1,%2)", + findnearspritevar = cmd(D,R,W) + / "%3=_con._findnear(_aci,true,'d2',%1,%2)", + findnearsprite = cmd(D,D,W) + / "%3=_con._findnear(_aci,true,'d2',%1,%2)", + findnearactorzvar = cmd(D,R,R,W) + / "%4=_con._findnear(_aci,false,'z',%1,%2,%3)", + findnearactorz = cmd(D,D,D,W) + / "%4=_con._findnear(_aci,false,'z',%1,%2,%3)", + findnearactor3dvar = cmd(D,R,W) + / "%3=_con._findnear(_aci,false,'d3',%1,%2)", + findnearactor3d = cmd(D,D,W) + / "%3=_con._findnear(_aci,false,'d3',%1,%2)", + findnearactorvar = cmd(D,R,W) + / "%3=_con._findnear(_aci,false,'d2',%1,%2)", + findnearactor = cmd(D,D,W) + / "%3=_con._findnear(_aci,false,'d2',%1,%2)", -- quotes qsprintf = sp1 * tok.rvar * sp1 * tok.rvar * (sp1 * tok.rvar)^-32, @@ -1660,6 +1670,11 @@ local Cinner = { qstrlen = cmd(R,R), qstrncat = cmd(R,R), qsubstr = cmd(R,R), + quote = cmd(D) + / "_con._quote(_pli,%1)", + userquote = cmd(R), + getkeyname = cmd(R,R,R), + getpname = cmd(R,R), -- array stuff copy = sp1 * tok.identifier * arraypat * sp1 * tok.identifier * arraypat * sp1 * tok.rvar, @@ -1751,12 +1766,18 @@ local Cinner = { loadmapstate = cmd(), savemapstate = cmd(), - headspritesect = cmd(W,R), - headspritestat = cmd(W,R), - nextspritesect = cmd(W,R), - nextspritestat = cmd(W,R), - prevspritesect = cmd(W,R), - prevspritestat = cmd(W,R), + headspritesect = cmd(W,R) + / "%1=sprite._headspritesect[%2]", + headspritestat = cmd(W,R) + / "%1=sprite._headspritestat[%2]", + nextspritesect = cmd(W,R) + / "%1=sprite._nextspritesect[%2]", + nextspritestat = cmd(W,R) + / "%1=sprite._nextspritestat[%2]", + prevspritesect = cmd(W,R) + / "%1=sprite._prevspritesect[%2]", + prevspritestat = cmd(W,R) + / "%1=sprite._prevspritestat[%2]", redefinequote = sp1 * tok.define * newline_term_string / function(qnum, qstr) return format("_con._definequote(%d,%q)", qnum, stripws(qstr)) end, @@ -1821,8 +1842,6 @@ local Cinner = { / "%4=sector[%1]:floorzat(%2,%3)", getcurraddress = cmd(W) / handle.NYI, -- will never be - getkeyname = cmd(R,R,R), - getpname = cmd(R,R), getticks = cmd(W) / "%1=_gv.getticks()", gettimedate = cmd(W,W,W,W,W,W,W,W) @@ -1868,7 +1887,7 @@ local Cif = { ifspritepal = cmd(D) / SPS".pal==%1", ifgotweaponce = cmd(D) - / "false", -- TODO? (multiplayer only) + / "false", -- TODO_MP ifangdiffl = cmd(D) / format("_con._angdiffabs(%s,%s)<=%%1", PLS".ang", SPS".ang"), ifsound = cmd(D) @@ -1931,7 +1950,7 @@ local Cif = { ifnosounds = cmd() / "not _con._ianysound()", ifmultiplayer = cmd() - / "false", -- TODO? + / "false", -- TODO_MP ifinwater = cmd() / format("sector[%s].lotag==2", SPS".sectnum"), ifinspace = cmd() diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index e395fa7d0..43f1e816a 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -136,10 +136,10 @@ checkfail('gv.QWE = 4', "write access forbidden") checkfail('sector[4] = sector[6]', "cannot write directly to sector[]") -- that would be horrible... -checkfail('nextspritesect[4] = -666', "cannot write directly to nextspritesect[]") +checkfail('sprite._nextspritesect[4] = -666', "cannot write directly to nextspritesect[]") -- we're indexing a plain array! -checkfail('print(nextspritesect[4].whatfield)', "attempt to index a number value") +checkfail('print(sprite._nextspritesect[4].whatfield)', "attempt to index a number value") -- creating new keys forbidden... handled by LuaJit checkfail('wall[4].QWE = 123', "has no member named 'QWE'") diff --git a/polymer/eduke32/source/player.c b/polymer/eduke32/source/player.c index bf9006aa2..04fba553f 100644 --- a/polymer/eduke32/source/player.c +++ b/polymer/eduke32/source/player.c @@ -2032,12 +2032,6 @@ static int32_t P_DisplayTip(int32_t gs,int32_t snum) p = P_GetHudPal(ps); - /* if(ps->access_spritenum >= 0) - p = sprite[ps->access_spritenum].pal; - else - p = wall[ps->access_wallnum].pal; - */ - tipy = tip_y[ps->tipincs]>>1; G_DrawTileScaled(170+(g_player[snum].sync->avel>>4)-(ps->look_ang>>1), @@ -2069,9 +2063,6 @@ static int32_t P_DisplayAccess(int32_t gs,int32_t snum) if (ps->access_spritenum >= 0) p = sprite[ps->access_spritenum].pal; - // else - // p = wall[ps->access_wallnum].pal; - if ((ps->access_incs-3) > 0 && (ps->access_incs-3)>>3) { guniqhudid = 200;