diff --git a/polymer/eduke32/source/gameexec.c b/polymer/eduke32/source/gameexec.c index 76496a59b..b07a8f0dc 100644 --- a/polymer/eduke32/source/gameexec.c +++ b/polymer/eduke32/source/gameexec.c @@ -203,7 +203,7 @@ GAMEEXEC_STATIC GAMEEXEC_INLINE void P_ForceAngle(DukePlayer_t *p) p->look_ang = p->rotscrnang = n>>1; } -GAMEEXEC_STATIC int32_t A_Dodge(spritetype *s) +int32_t A_Dodge(spritetype *s) { int32_t bx,by,bxvect,byvect,i; int32_t mx = s->x, my = s->y; @@ -434,8 +434,6 @@ int32_t G_GetAngleDelta(int32_t a,int32_t na) if (na > 1024) na -= 2048; if (a > 1024) a -= 2048; - na -= 2048; - a -= 2048; // OSD_Printf("G_GetAngleDelta() returning %d\n",na-a); return (na-a); } diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 92223227a..875644ad4 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -5,6 +5,7 @@ local ffiC = ffi.C local bit = require("bit") local math = require("math") +local geom = require("geom") local setmetatable = setmetatable @@ -12,7 +13,10 @@ local error = error local type = type local player = assert(player) -local cansee = require("defs_common").cansee +local defs_c = require("defs_common") +local cansee = defs_c.cansee +local neartag = defs_c.neartag +local inside = defs_c.inside module(...) @@ -232,23 +236,23 @@ function _VM_ResetPlayer2(snum) return (ffiC.VM_ResetPlayer2(snum)~=0) end -function _addinventory(p, inv, amount, pal) +local PALBITS = { [0]=1, [21]=2, [23]=4 } +local ICONS = { + [ffiC.GET_FIRSTAID] = 1, -- ICON_FIRSTAID + [ffiC.GET_STEROIDS] = 2, + [ffiC.GET_HOLODUKE] = 3, + [ffiC.GET_JETPACK] = 4, + [ffiC.GET_HEATS] = 5, + [ffiC.GET_SCUBA] = 6, + [ffiC.GET_BOOTS] = 7, +} + +function _addinventory(ps, inv, amount, pal) if (inv == ffiC.GET_ACCESS) then - local PALBITS = { [0]=1, [21]=2, [23]=4 } if (PALBITS[pal]) then ps.got_access = bit.bor(ps.got_access, PALBITS[pal]) end else - local ICONS = { - [ffiC.GET_FIRSTAID] = 1, -- ICON_FIRSTAID - [ffiC.GET_STEROIDS] = 2, - [ffiC.GET_HOLODUKE] = 3, - [ffiC.GET_JETPACK] = 4, - [ffiC.GET_HEATS] = 5, - [ffiC.GET_SCUBA] = 6, - [ffiC.GET_BOOTS] = 7, - } - if (ICONS[inv]) then ps.inven_icon = ICONS[inv] end @@ -262,6 +266,19 @@ function _addinventory(p, inv, amount, pal) end end +-- For GET_ACCESS: returns logical: whether player has card given by PAL +-- Else: returns inventory amount +function _getinventory(ps, inv, pal) + if (inv == ffiC.GET_ACCESS) then + if (PALBITS[pal]) then + return (bit.band(ps.got_access, PALBITS[pal])~=0) + end + return false + else + return ps:get_inv_amount(inv) + end +end + -- The return value is true iff the ammo was at the weapon's max. -- In that case, no action is taken. function _addammo(ps, weapon, amount) @@ -282,6 +299,118 @@ function _addweapon(ps, weapon, amount) P_AddWeaponAmmoCommon(ps, weap, amount) end +function _A_RadiusDamage(i, r, hp1, hp2, hp3, hp4) + check_sprite_idx(i) + ffiC.A_RadiusDamage(i, r, hp1, hp2, hp3, hp4) +end + +function _testkey(pli, synckey) + local bound_check = player[pli] + if (synckey >= 32ULL) then + error("Invalid argument #2 to _testkey: must be in [0..31]", 2) + end + local bits = ffiC.player[pli].sync.bits + return (bit.band(bits, bit.lshift(1,synckey)) ~= 0) +end + +function _operate(spritenum) + local NEAROP = { + [9] = true, + [15] = true, + [16] = true, + [17] = true, + [18] = true, + [19] = true, + [20] = true, + [21] = true, + [22] = true, + [23] = true, + [25] = true, + [26] = true, + [29] = true, + } + + local spr = sprite[spritenum] + + if (sector[spr.sectnum].lotag == 0) then + local tag = neartag(spr^(32*256), spr.sectnum, spr.ang, 768, 4+1) + if (tag.sector >= 0) then + local sect = sector[tag.sector] + local lotag = sect.lotag + if (NEAROP[bit.band(lotag, 0xff)]) then + if (lotag==23 or sect.floorz==sect.ceilingz) then + if (bit.band(lotag, 32768+16384) == 0) then + for j in spritesofsect(tag.sector) do + if (sprite[j].picnum==2) then + -- TODO: ^^^ actually ACTIVATOR. Make the + -- dynamic name->tilenum mappings work. + return + end + end + ffiC.G_OperateSectors(tag.sector, spritenum) + end + end + end + end + end +end + +function _endofgame(pli, timebeforeexit) + player[pli].timebeforeexit = timebeforeexit + player[pli].customexitsound = -1 + ffiC.ud.eog = 1 +end + +function _bulletnear(i) + return (ffiC.A_Dodge(sprite[i]) == 1) +end + +-- d is a distance +function _awayfromwall(spr, d) + local vec2 = geom.vec2 + local vecs = { vec2(d,d), vec2(-d,-d), vec2(d,-d), vec2(-d,d) } + for i=1,4 do + if (not inside(vecs[i]+spr, spr.sectnum)) then + return false + end + end + return true +end + +function _canseetarget(spr, ps) + -- NOTE: &41 ? + return cansee(spr^(bit.band(ffiC.krand(),41)), spr.sectnum, + ps.pos, sprite[ps.i].sectnum) +end + +function _getlastpal(spritenum) + local spr = sprite[spritenum] + if (spr.picnum == 1405) then -- TODO: APLAYER + spr.pal = player[spr.yvel].palookup + else + if (spr.pal == 1 and spr.extra == 0) then -- hack for frozen + spr.extra = spr.extra+1 + end + spr.pal = actor[spritenum].tempang + end + actor[spritenum].tempang = 0 +end + +-- abs(G_GetAngleDelta(a1, a2)) +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) + end + -- |a2-a1| >= 1024 + if (a2 > 1024) then a2=a2-2048 end + if (a1 > 1024) then a1=a1-2048 end + -- a1 and a2 is in [-1023, 1024] + return math.abs(a2-a1) +end + --- Exported functions --- diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 94b3a4146..15f280fb7 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -191,8 +191,11 @@ local DUKEPLAYER_STRUCT = [[ const int16_t i; const int16_t one_parallax_sectnum; int16_t random_club_frame, one_eighty_count; - int16_t dummyplayersprite, extra_extra8; - int16_t actorsqu, timebeforeexit, customexitsound, last_pissed_time; + const int16_t dummyplayersprite; + int16_t extra_extra8; + int16_t actorsqu, timebeforeexit; + const int16_t customexitsound; + int16_t last_pissed_time; const int16_t weaprecs[MAX_WEAPONS]; int16_t weapon_sway, crack_time, bobcounter; @@ -432,6 +435,9 @@ int32_t A_IncurDamage(int32_t sn); int32_t A_Spawn(int32_t j, int32_t pn); void VM_FallSprite(int32_t i); int32_t VM_ResetPlayer2(int32_t snum); +void A_RadiusDamage(int32_t i, int32_t r, int32_t, int32_t, int32_t, int32_t); +void G_OperateSectors(int32_t sn, int32_t ii); +int32_t A_Dodge(spritetype *s); ]] -- functions @@ -696,14 +702,30 @@ local player_mt = { ffi.cast(player_ptr_ct, p).inv_amount[inv] = amount end, + set_customexitsound = function(p, soundnum) + if (soundnum >= con_lang.MAXSOUNDS+0ULL) then + error("Invalid sound number "..soundnum, 2) + end + ffi.cast(player_ptr_ct, p).customexitsound = soundnum + end, + -- CON-like addammo/addweapon, but without the non-local control flow -- (returns true if weapon's ammo was at the max. instead). addammo = con._addammo, addweapon = con._addweapon, + addinventory = con._addinventory, pstomp = con._pstomp, + wack = function(p) + p.horiz = p.horiz + 64 + p.return_to_center = 9 + local n = bit.arshift(128-bit.band(ffiC.krand(),255), 1) + p.rotscrnang = n + p.look_ang = n + end, + --- Not fully specified, off-limits to users. Might disappear, change --- signature, etc... _palfrom = function(p, f, r,g,b) diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index e119f4632..a95980df1 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -201,10 +201,14 @@ int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32 hitdata_t *hitinfo, uint32_t cliptype); int32_t cansee(int32_t x1, int32_t y1, int32_t z1, int16_t sect1, int32_t x2, int32_t y2, int32_t z2, int16_t sect2); +void neartag(int32_t xs, int32_t ys, int32_t zs, int16_t sectnum, int16_t ange, int16_t *neartagsector, int16_t *neartagwall, + int16_t *neartagsprite, int32_t *neartaghitdist, int32_t neartagrange, uint8_t tagsearch, + int32_t (*blacklist_sprite_func)(int32_t)); int32_t ldist(const spritetype *s1, const spritetype *s2); int32_t dist(const spritetype *s1, const spritetype *s2); +int32_t inside(int32_t x, int32_t y, int16_t sectnum); void updatesector(int32_t x, int32_t y, int16_t *sectnum); void updatesectorbreadth(int32_t x, int32_t y, int16_t *sectnum); void updatesectorz(int32_t x, int32_t y, int32_t z, int16_t *sectnum); @@ -220,6 +224,7 @@ double gethitickms(void); int32_t krand(void); int32_t ksqrt(uint32_t num); +int32_t __fastcall getangle(int32_t xvect, int32_t yvect); ]] local ivec3_ @@ -317,6 +322,12 @@ nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritesta prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]') prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, 'prevspritestat[]') +local function check_sector_idx(sectnum) + if (sectnum >= ffiC.numsectors+0ULL) then + error("passed out-of-bounds sector number "..sectnum, 3) + end +end + --== Per-sector/per-statnum sprite iterators ==-- local function iter_spritesofsect(sect, i) if (i < 0) then @@ -329,10 +340,7 @@ local function iter_spritesofsect(sect, i) end function spritesofsect(sect) - if (sect < 0 or sect >= ffiC.numsectors) then - error("passed invalid sectnum to spritesofsect iterator", 2) - end - + check_sector_idx(sect) return iter_spritesofsect, sect, -1 end @@ -347,7 +355,7 @@ local function iter_spritesofstat(stat, i) end function spritesofstat(stat) - if (stat < 0 or stat >= ffiC.MAXSTATUS) then + if (stat >= ffiC.MAXSTATUS+0ULL) then error("passed invalid statnum to spritesofstat iterator", 2) end @@ -377,9 +385,7 @@ function sectorsofbunch(bunchnum, cf) end function getbunch(sectnum, cf) - if (sectnum < 0 or sectnum >= ffiC.numsectors) then - error("passed out-of-bounds sector number "..sectnum, 2) - end + check_sector_idx(sectnum) if (cf ~= 0 and cf ~= 1) then error("passed invalid 'cf' to getbunch, must be 0 or 1", 2) end @@ -389,14 +395,12 @@ end ---=== Engine functions, wrapped for Lua convenience ===--- + -- returns a hitdata_ct -- TODO: make v[xyz] be passed as one aggregate, too? -- Additionally, permit different coordinates? (ang&horiz, ...) function hitscan(pos, sectnum, vx,vy,vz, cliptype) - if (sectnum >= ffiC.numsectors+0ULL) then - error("passed out-of-bounds sector number "..sectnum, 2) - end - + check_sector_idx(sectnum) local vec = vec3_ct(pos.x, pos.y, pos.z) local hitdata = hitdata_ct() @@ -417,6 +421,31 @@ function cansee(pos1,sect1, pos2,sect2) return (ret~=0) end +ffi.cdef[[ +typedef struct { + int32_t sector, wall, sprite; + int32_t dist; +} neartag_ret_t; +]] +local neartag_ret_ct = ffi.typeof("const neartag_ret_t") + +-- TODO: make tagsearch something more convenient +function neartag(pos, sectnum, ang, range, tagsearch) + check_sector_idx(sectnum) + local newar = function() return ffi.new("int16_t [1]") end + local a, b, c, d = newar(), newar(), newar(), ffi.new("int32_t [1]") + ffiC.neartag(pos.x, pos.y, pos.z, sectnum, ang, a, b, c, d, range, tagsearch, nil) + return neartag_ret_ct(a[0], b[0], c[0], d[0]) +end + +-- TODO: reimplement in Lua (benefit: no int overflow)? On the engine side, +-- make it take a sectortype pointer, and add as metamethod to our LuaJIT +-- sector type ("contains"?) +function inside(pos, sectnum) + check_sector_idx(sectnum) + return (ffiC.inside(pos.x, pos.y, sectnum)==1) +end + -- TODO: should these rather be one function, and the specific kind of updating -- controlled by an argument? function updatesector(pos, sectnum) diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index c08499598..74eb9ccea 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -29,8 +29,11 @@ nextsectbunch; krand; ksqrt; +inside; +getangle; cansee; hitscan; +neartag; rotatesprite; dist; @@ -77,4 +80,7 @@ A_IncurDamage; A_Spawn; VM_FallSprite; VM_ResetPlayer2; +A_RadiusDamage; +G_OperateSectors; +A_Dodge; }; diff --git a/polymer/eduke32/source/lunatic/dynsymlist_m32 b/polymer/eduke32/source/lunatic/dynsymlist_m32 index 2aaed0f91..0ba224952 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist_m32 +++ b/polymer/eduke32/source/lunatic/dynsymlist_m32 @@ -29,8 +29,11 @@ nextsectbunch; krand; ksqrt; +inside; +getangle; cansee; hitscan; +neartag; rotatesprite; dist; diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index 82c076ca2..fea234543 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -586,8 +586,8 @@ local Co = { music = sp1 * t_define * match_until(sp1 * t_filename, sp1 * conl.keyword * sp1) / cmd_music, --- 3. Game Settings - -- gamestartup has 25/29 fixed defines, depending on 1.3D/1.5 version: - gamestartup = (sp1 * t_define)^25 / cmd_gamestartup, + -- gamestartup has 26/30 fixed defines, depending on 1.3D/1.5 version: + gamestartup = (sp1 * t_define)^26 / cmd_gamestartup, spritenopal = cmd(D), spritenoshade = cmd(D), spritenvg = cmd(D), @@ -766,7 +766,8 @@ local Ci = { / (SPS".cstat=_bit.bor(%1,"..SPS".cstat)"), cstat = cmd(D) / SPS".cstat=%1", - clipdist = cmd(D), + clipdist = cmd(D) + / SPS".clipdist=%1", sizeto = cmd(D,D) / "_con._sizeto(_aci)", -- TODO: see control.lua:_sizeto sizeat = cmd(D,D) @@ -777,7 +778,8 @@ local Ci = { / (SPS".extra="..SPS".extra+%1"), spritepal = cmd(D), - hitradius = cmd(D,D,D,D,D), + hitradius = cmd(D,D,D,D,D) + / "_con._A_RadiusDamage(%1,%2,%3,%4,%5)", hitradiusvar = cmd(R,R,R,R,R), -- some commands taking read vars @@ -821,7 +823,8 @@ local Ci = { / "", -- TODO addinventory = cmd(D,D) / PLS":addinventory(%1,%2)", - guts = cmd(D,D), + guts = cmd(D,D) + / "", -- TODO -- cont'd addkills = cmd(D) @@ -831,20 +834,26 @@ local Ci = { angoff = cmd(D), debug = cmd(D) / "", -- TODO? - endofgame = cmd(D), + endofgame = cmd(D) + / "_con._endofgame(_pli,%1)", eqspawn = cmd(D), espawn = cmd(D), globalsound = cmd(D) / "", lotsofglass = cmd(D), - mail = cmd(D), - money = cmd(D), - paper = cmd(D), + mail = cmd(D) + / "", -- TODO + money = cmd(D) + / "", -- TODO + paper = cmd(D) + / "", -- TODO qspawn = cmd(D), - quote = cmd(D), + quote = cmd(D) + / "", -- TODO savenn = cmd(D), save = cmd(D), - sleeptime = cmd(D), + sleeptime = cmd(D) + / ACS".timetosleep=%1", soundonce = cmd(D), sound = cmd(D) / "", -- TODO: all things audio... @@ -863,13 +872,16 @@ local Ci = { fall = cmd() / "_con._VM_FallSprite(_aci)", flash = cmd(), - getlastpal = cmd(), + getlastpal = cmd() + / "_con._getlastpal(_aci)", insertspriteq = cmd(), killit = cmd() -- NLCF / "_con.killit()", mikesnd = cmd(), - nullop = cmd(), - pkick = cmd(), + nullop = cmd() + / "", -- NOTE: really generate no code + pkick = cmd() + / "", -- TODO pstomp = cmd() / PLS":pstomp(_aci)", resetactioncount = cmd() @@ -878,11 +890,14 @@ local Ci = { / ACS":set_count(0)", resetplayer = cmd() -- NLCF / "if (_con._VM_ResetPlayer2(_pli,_aci)) then _con.longjmp() end", - respawnhitag = cmd(), + respawnhitag = cmd() + / "", -- TODO tip = cmd() / PLS".tipincs=26", - tossweapon = cmd(), - wackplayer = cmd(), + tossweapon = cmd() + / "", -- TODO + wackplayer = cmd() + / PLS":wack()", -- player/sprite searching findplayer = cmd(W), @@ -949,7 +964,8 @@ local Ci = { palfrom = (sp1 * t_define)^-4 / handle_palfrom, - operate = cmd() * #sp1, + operate = cmd() * #sp1 + / "_con._operate(_aci)", myos = cmd(R,R,R,R,R), myosx = cmd(R,R,R,R,R), @@ -1051,11 +1067,17 @@ local Cif = { / format("sprite[%s].extra<%%1", PLS".i"), ifspritepal = cmd(D) / SPS".pal==%1", - ifgotweaponce = cmd(D), - ifangdiffl = cmd(D), + ifgotweaponce = cmd(D) + / "false", -- TODO? (multiplayer only) + ifangdiffl = cmd(D) + / format("_con._angdiffabs(%s,%s)<=%%1", PLS".ang", SPS".ang"), ifsound = cmd(D) / "", - ifpinventory = cmd(D,D), + -- vvv TODO: this is not correct for GET_ACCESS or GET_SHIELD. + -- Additionally, it accesses the current sprite unconditinally + -- (will throw error if invalid). + ifpinventory = cmd(D,D) + / format("_con._getinventory(%s,%%1,%s)~=%%2", PLS"", SPS".pal"), ifvarl = cmd(R,D), ifvarg = cmd(R,D), @@ -1077,36 +1099,45 @@ local Cif = { ifactorsound = cmd(R,R), - ifp = (sp1 * t_define)^1, + ifp = (sp1 * t_define)^1 + / "false", -- TODO ifsquished = cmd() / "false", -- TODO ifserver = cmd(), - ifrespawn = cmd(), + ifrespawn = cmd() + / "false", -- TODO ifoutside = cmd() / format("_bit.band(sector[%s].ceilingstat,1)~=0", SPS".sectnum"), ifonwater = cmd() / format("sectnum[%s].lotag==1 and _math.abs(%s-sector[%s].floorz)<32*256", SPS".sectnum", SPS".z", SPS".sectnum"), - ifnotmoving = cmd(), + ifnotmoving = cmd() + / "_bit.band(actor[_aci].movflag,49152)>16384", ifnosounds = cmd(), ifmultiplayer = cmd() / "false", -- TODO? ifinwater = cmd() / format("sector[%s].lotag==2", SPS".sectnum"), - ifinspace = cmd(), - ifinouterspace = cmd(), + ifinspace = cmd() + / "false", -- TODO + ifinouterspace = cmd() + / "false", -- TODO ifhitweapon = cmd() / "_con._A_IncurDamage(_aci)", - ifhitspace = cmd(), + ifhitspace = cmd() + / "_con._testkey(_pli,29)", -- XXX ifdead = cmd() / SPS".extra<=0", ifclient = cmd(), ifcanshoottarget = cmd() / "false", -- TODO - ifcanseetarget = cmd(), + ifcanseetarget = cmd() -- TODO: maybe set timetosleep afterwards + / format("_con._canseetarget(%s,%s)", SPS"", PLS""), ifcansee = cmd() * #sp1, - ifbulletnear = cmd(), - ifawayfromwall = cmd(), + ifbulletnear = cmd() + / "_con._bulletnear(_aci)", + ifawayfromwall = cmd() + / format("_con._awayfromwall(%s,108)", SPS""), ifactornotstayput = cmd() / ACS".actorstayput==-1", }