Lunatic: drowning in code.

git-svn-id: https://svn.eduke32.com/eduke32@3259 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-12-09 13:24:39 +00:00
parent 5c06ef08bf
commit 1588a80442
8 changed files with 340 additions and 32 deletions

View file

@ -9910,10 +9910,12 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
#ifdef LUNATIC
const char *g_sizes_of_what[] = {
"sectortype", "walltype", "spritetype",
"actor_t", "DukePlayer_t", "playerdata_t", "user_defs" };
"actor_t", "DukePlayer_t", "playerdata_t",
"user_defs", "tiledata_t" };
int32_t g_sizes_of[] = {
sizeof(sectortype), sizeof(walltype), sizeof(spritetype),
sizeof(actor_t), sizeof(DukePlayer_t), sizeof(playerdata_t), sizeof(user_defs) };
sizeof(actor_t), sizeof(DukePlayer_t), sizeof(playerdata_t),
sizeof(user_defs), sizeof(tiledata_t) };
#endif
int32_t app_main(int32_t argc, const char **argv)

View file

@ -19,8 +19,6 @@ MAXSKILLS = 7
MAXSOUNDS = 4096
SLEEPTIME = 1536
-- KEEPINSYNC with gamedef.c:C_AddDefaultDefinitions() and the respective
-- defines. These are exported to the ffi.C namespace and as literal defines

View file

@ -171,6 +171,20 @@ end
--- expose the functionality in a better fashion than merely giving access to
--- the C functions.)
local D = {
-- TODO: dynamic tile remapping
ACTIVATOR = 2,
APLAYER = 1405,
FIRSTAID = 53,
STEROIDS = 55,
AIRTANK = 56,
JETPACK = 57,
HEATSENSOR = 59,
BOOTS = 61,
HOLODUKE = 1348,
}
local function check_sprite_idx(i)
if (i >= ffiC.MAXSPRITES+0ULL) then
error("invalid argument: must be a valid sprite index", 3)
@ -186,7 +200,6 @@ end
function _A_Shoot(i, atwith)
check_sprite_idx(i)
check_tile_idx(atwith)
return ffiC.A_Shoot(i, atwith)
end
@ -235,6 +248,13 @@ function _pstomp(ps, i)
end
end
function _pkick(ps, spr)
-- TODO: multiplayer branch
if (spr.picnum~=D.APLAYER and ps.quick_kick==0) then
ps.quick_kick = 14
end
end
function _VM_ResetPlayer2(snum)
local bound_check = player[snum]
return (ffiC.VM_ResetPlayer2(snum)~=0)
@ -272,10 +292,10 @@ end
-- For GET_ACCESS: returns logical: whether player has card given by PAL
-- Else: returns inventory amount
function _getinventory(ps, inv, pal)
function _getinventory(ps, inv, i)
if (inv == ffiC.GET_ACCESS) then
if (PALBITS[pal]) then
return (bit.band(ps.got_access, PALBITS[pal])~=0)
if (PALBITS[sprite[i].pal]) then
return (bit.band(ps.got_access, PALBITS[sprite[i].pal])~=0)
end
return false
else
@ -345,9 +365,7 @@ function _operate(spritenum)
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.
if (sprite[j].picnum==D.ACTIVATOR) then
return
end
end
@ -381,15 +399,144 @@ function _awayfromwall(spr, d)
return true
end
local function krandand(mask)
return bit.band(ffiC.krand(), mask)
end
local BANG2RAD = math.pi/1024
local function cossinb(bang)
-- XXX: better use the precalc'd arrays instead?
local ang = BANG2RAD*(bang)
return 16384*math.cos(ang), 16384*math.sin(ang)
end
local function manhatdist(v1, v2)
return math.abs(v1.x-v2.x) + math.abs(v1.y-v2.y)
end
-- "otherspr" is either player or holoduke sprite
local function A_GetFurthestVisiblePoint(aci, otherspr)
if (bit.band(actor[aci].get_t_data(0), 63) ~= 0) then
return
end
local angincs = (ud.player_skill < 3) and 1024 or 2048/(1+krandand(1))
local j = 0
repeat
local c, s = cossinb(otherspr.ang + j)
local hit = hitscan(otherspr^(16*256), otherspr.sectnum,
c, s, 16384-krandand(32767), ffiC.CLIPMASK1)
local dother = manhatdist(hit.pos, otherspr)
local dactor = manhatdist(hit.pos, spr)
if (dother < dactor and hit.sect >= 0) then
if (cansee(hit.pos, hit.sect, otherspr^(16*256), otherspr.sectnum)) then
return hit
end
end
j = j + (angincs - krandand(511))
until (j >= 2048)
end
local SLEEPTIME = 1536
function _cansee(aci, ps)
-- Select sprite for monster to target.
local spr = sprite[aci]
local s = sprite[ps.i]
if (ps.holoduke_on) then
-- If holoduke is on, let them target holoduke first.
local hs = sprite[ps.holoduke_on]
if (cansee(spr^krandand(8191), spr.sectnum, s, s.sectnum)) then
s = hs
end
end
-- Can they see player (or player's holoduke)?
local can = cansee(spr^krandand(47*256), spr.sectnum, s^(24*256), s.sectnum)
if (not can) then
-- Search around for target player.
local hit = A_GetFurthestVisiblePoint(aci, s)
if (hit ~= nil) then
can = true
actor[aci].lastvx = hit.pos.x
actor[aci].lastvy = hit.pos.y
end
else
-- Else, they did see it. Save where we were looking...
actor[aci].lastvx = s.x
actor[aci].lastvy = s.y
end
if (can and (spr.statnum==ffiC.STAT_ACTOR or spr.statnum==ffiC.STAT_STANDABLE)) then
actor[aci].timetosleep = SLEEPTIME
end
return can
end
function _canseetarget(spr, ps)
-- NOTE: &41 ?
return cansee(spr^(bit.band(ffiC.krand(),41)), spr.sectnum,
return cansee(spr^krandand(41), spr.sectnum,
ps.pos, sprite[ps.i].sectnum)
end
local function A_CheckHitSprite(spr, angadd)
local zoff = (spr:isenemy() and 42*256) or (spr.picnum==D.APLAYER and 39*256) or 0
local c, s = cossinb(spr.ang+angadd)
local hit = hitscan(spr^zoff, spr.sectnum, c, s, 0, ffiC.CLIPMASK1)
if (hit.wall >= 0 and wall[hit.wall]:ismasked() and spr:isenemy()) then
return -1, nil
end
local dx = hit.pos.x-spr.x
local dy = hit.pos.y-spr.y
return hit.sprite, math.sqrt(dx*dx+dy*dy) -- TODO: use "ldist" approximation for authenticity
end
function _canshoottarget(dist, aci)
if (dist > 1024) then
local spr = sprite[aci]
local hitspr, hitdist = A_CheckHitSprite(spr, 0)
if (hitdist == nil) then
return true
end
local bigenemy = (spr:isenemy() and spr.xrepeat > 56)
local sclip = bigenemy and 3084 or 768
local angdif = bigenemy and 48 or 16
local sclips = { sclip, sclip, 768 }
local angdifs = { 0, angdif, -angdif }
for i=1,3 do
if (i > 1) then
hitspr, hitdist = A_CheckHitSprite(aci, angdifs[i])
end
if (hitspr >= 0 and sprite[hitspr].picnum == spr.picnum) then
if (hitdist > sclips[i]) then
return false
end
end
end
end
return true
end
function _getlastpal(spritenum)
local spr = sprite[spritenum]
if (spr.picnum == 1405) then -- TODO: APLAYER
if (spr.picnum == D.APLAYER) then
spr.pal = player[spr.yvel].palookup
else
if (spr.pal == 1 and spr.extra == 0) then -- hack for frozen
@ -415,6 +562,94 @@ function _angdiffabs(a1, a2)
return math.abs(a2-a1)
end
local SK = {
CROUCH = 1,
RUN = 5,
}
local function _ifp(flags, pli, aci)
local l = flags
local ps = player[pli]
local vel = sprite[ps.i].xvel
local band = bit.band
local j = false
if (band(l,8)~=0 and ps.on_ground and _testkey(pli, SK.CROUCH)) then
j = true
elseif (band(l,16)~=0 and ps.jumping_counter == 0 and not ps.on_ground and ps.vel.z > 2048) then
j = true
elseif (band(l,32)~=0 and ps.jumping_counter > 348) then
j = true
elseif (band(l,1)~=0 and vel >= 0 and vel < 8) then
j = true
elseif (band(l,2)~=0 and vel >= 8 and not _testkey(pli, SK.RUN)) then
j = true
elseif (band(l,4)~=0 and vel >= 8 and _testkey(pli, SK.RUN)) then
j = true
elseif (band(l,64)~=0 and ps.pos.z < (sprite[_aci].z-(48*256))) then
j = true
elseif (band(l,128)~=0 and vel <= -8 and not _testkey(pli, SK.RUN)) then
j = true
elseif (band(l,256)~=0 and vel <= -8 and _testkey(pli, SK.RUN)) then
j = true
elseif (band(l,512)~=0 and (ps.quick_kick > 0 or (ps.curr_weapon == ffiC.KNEE_WEAPON and ps.kickback_pic > 0))) then
j = true
elseif (band(l,1024)~=0 and sprite[ps.i].xrepeat < 32) then
j = true
elseif (band(l,2048)~=0 and ps.jetpack_on) then
j = true
elseif (band(l,4096)~=0 and ps:get_inv_amount(ffiC.GET_STEROIDS) > 0 and ps:get_inv_amount(ffiC.GET_STEROIDS) < 400) then
j = true
elseif (band(l,8192)~=0 and ps.on_ground) then
j = true
elseif (band(l,16384)~=0 and sprite[ps.i].xrepeat > 32 and sprite[ps.i].extra > 0 and ps.timebeforeexit == 0) then
j = true
elseif (band(l,32768)~=0 and sprite[ps.i].extra <= 0) then
j = true
elseif (band(l,65536)~=0) then
-- TODO: multiplayer branch
if (_angdiffabs(ps.ang, ffiC.getangle(sprite[_aci].x-ps.pos.x, sprite[_aci].y-ps.pos.y)) < 128) then
j = true
end
end
return j
end
function _checkspace(sectnum, floorp)
local sect = sector[sectnum]
local picnum = floorp and sect.floorpicnum or sect.ceilingpicnum
local stat = floorp and sect.floorstat or sect.ceilingstat
return bit.band(stat,1)~=0 and sect.ceilingpal == 0 and
(picnum==D.MOONSKY1 or picnum==D.BIGORBIT1)
end
function _flash(spr, ps)
spr.shade = -127
ps.visibility = -127
ffiC.lastvisinc = ffiC.totalclock+32
end
local INVENTILE = {
[D.FIRSTAID] = true,
[D.STEROIDS] = true,
[D.AIRTANK] = true,
[D.JETPACK] = true,
[D.HEATSENSOR] = true,
[D.BOOTS] = true,
[D.HOLODUKE] = true,
}
function _checkrespawn(spr)
if (spr:isenemy()) then
return (ud.respawn_monsters~=0)
end
if (INVENTILE[spr.picnum]) then
return (ud.respawn_inventory~=0)
end
return (ud.respawn_items~=0)
end
--- Exported functions ---

View file

@ -305,6 +305,32 @@ typedef struct {
char user_name[32];
uint32_t revision;
} playerdata_t;
typedef struct {
int32_t workslike, cstat; // 8b
int32_t hitradius, range, flashcolor; // 12b
int16_t spawns, sound, isound, vel; // 8b
int16_t decal, trail, tnum, drop; // 8b
int16_t offset, bounces, bsound; // 6b
int16_t toffset; // 2b
int16_t extra, extra_rand; // 4b
int8_t sxrepeat, syrepeat, txrepeat, tyrepeat; // 4b
int8_t shade, xrepeat, yrepeat, pal; // 4b
int8_t movecnt; // 1b
uint8_t clipdist; // 1b
int8_t filler[6]; // 6b
} projectile_t;
typedef struct {
intptr_t *execPtr;
intptr_t *loadPtr;
uint32_t flags;
int16_t cacherange;
projectile_t defproj;
} tiledata_t;
#pragma pack(pop)
enum
@ -425,6 +451,7 @@ user_defs ud;
playerdata_t g_player[MAXPLAYERS];
const int32_t playerswhenstarted;
int32_t lastvisinc;
int32_t A_IncurDamage(int32_t sn); // not bound-checked!
void P_AddWeaponMaybeSwitch(DukePlayer_t *ps, int32_t weap);
@ -455,7 +482,7 @@ string.dump = nil
-- sanity-check struct type sizes
local good = true
for i=0,6 do
for i=0,7 do
local what = ffi.string(ffiC.g_sizes_of_what[i])
local fsz = ffi.sizeof(what)
local csz = ffiC.g_sizes_of[i]
@ -469,6 +496,12 @@ if (not good) then
error("Some sizes don't match between C and LuaJIT/FFI.")
end
-- Add game-side metamethods to "spritetype" and register it with "metatype"
defs_c.spritetype_mt.__index.isenemy = function(s)
return (bit.band(ffiC.g_tile[s.picnum], ffiC.SFLAG_BADGUY)~=0)
end
ffi.metatype("spritetype", defs_c.spritetype_mt)
-- "player" global, needed by the "control" module
local tmpmt = {
__index = function(tab, key)
@ -631,6 +664,14 @@ local actor_mt = {
return (a.t_data[5]==ai)
end
end,
-- Getters/setters.
get_t_data = function(a, idx)
if (idx >= 10ULL) then
error("Invalid t_data index "..idx, 2)
end
return ffi.cast(actor_ptr_ct, a).t_data[idx]
end,
},
}
ffi.metatype("actor_t", actor_mt)

View file

@ -6,6 +6,7 @@
local ffi = require("ffi")
local ffiC = ffi.C
local bit = require("bit")
local string = require("string")
local error = error
@ -236,9 +237,30 @@ local ivec3_mt = {
}
ivec3_ = ffi.metatype("vec3_t", ivec3_mt)
local walltype_mt = {
__index = {
isblocking = function(w)
return (bit.band(w.cstat, 1)~=0)
end,
ismasked = function(w)
return (bit.band(w.cstat, 16)~=0)
end,
isoneway = function(w)
return (bit.band(w.cstat, 32)~=0)
end,
ishittable = function(w)
return (bit.band(w.cstat, 64)~=0)
end,
}
}
ffi.metatype("walltype", walltype_mt)
local spritetype_ptr_ct = ffi.typeof("spritetype_u_t *")
local spritetype_mt = {
spritetype_mt = {
__pow = function(s, zofs)
return ivec3_(s.x, s.y, s.z-zofs)
end,
@ -252,7 +274,8 @@ local spritetype_mt = {
end
},
}
ffi.metatype("spritetype", spritetype_mt)
-- The user of this module can insert additional "spritetype" metamethods and
-- register them with "ffi.metatype".
---=== Restricted access to C variables from Lunatic ===---

View file

@ -7,6 +7,7 @@ local ffiC = ffi.C
--== First, load the definitions common to the game's and editor's Lua interface.
decl = ffi.cdef
local defs_c = require("defs_common")
ffi.metatype("spritetype", defs_c.spritetype_mt)
defs_c.create_globals(_G)

View file

@ -60,6 +60,7 @@ ud;
g_player;
playerswhenstarted;
lastvisinc;
luaJIT_BC_lunacon;
luaJIT_BC_con_lang;

View file

@ -9,6 +9,7 @@ local math = require("math")
local string = require("string")
local table = require("table")
local arg = arg
local assert = assert
@ -612,7 +613,8 @@ local Co = {
setgamename = newline_term_string,
precache = cmd(D,D,D),
scriptsize = cmd(D), -- unused
scriptsize = cmd(D)
/ "", -- no-op
cheatkeys = cmd(D,D),
definecheat = newline_term_string, -- XXX: actually tricker syntax (TS)
@ -713,6 +715,11 @@ local function handle_palfrom(...)
v[1] or 0, v[2] or 0, v[3] or 0, v[4] or 0)
end
local function handle_move(mv, ...)
local flags = {...}
return format(ACS":set_move(%s,%d)", mv, (flags[1] and bit.bor(...)) or 0)
end
-- NOTE about prefixes: most is handled by all_alt_pattern(), however commands
-- that have no arguments and that are prefixes of other commands MUST be
-- suffixed with a "* #sp1" pattern.
@ -799,9 +806,8 @@ local Ci = {
/ ACS":set_action(%1)",
ai = cmd(AI)
/ ACS":set_ai(%1)",
-- TODO: move's flags
move = sp1 * t_move * (sp1 * t_define)^0
/ ACS":set_move(%1)",
/ handle_move,
cactor = cmd(D)
/ SPS":set_picnum(%1)",
@ -876,7 +882,8 @@ local Ci = {
/ (PLS".actors_killed="..PLS".actors_killed+%1;"..ACS".actorstayput=-1"),
addphealth = cmd(D)
/ "", -- TODO
angoff = cmd(D),
angoff = cmd(D)
/ "spritext[_aci].angoff=%1",
debug = cmd(D)
/ "", -- TODO?
endofgame = cmd(D)
@ -916,7 +923,8 @@ local Ci = {
fall = cmd()
/ "_con._VM_FallSprite(_aci)",
flash = cmd(),
flash = cmd()
/ format("_con._flash(%s,%s)", ACS"", SPS""),
getlastpal = cmd()
/ "_con._getlastpal(_aci)",
insertspriteq = cmd(),
@ -926,7 +934,7 @@ local Ci = {
nullop = cmd()
/ "", -- NOTE: really generate no code
pkick = cmd()
/ "", -- TODO
/ format("_con._pkick(%s,%s)", PLS"", ACS""),
pstomp = cmd()
/ PLS":pstomp(_aci)",
resetactioncount = cmd()
@ -1119,10 +1127,8 @@ local Cif = {
ifsound = cmd(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"),
/ format("_con._getinventory(%s,%%1,_aci)~=%%2", PLS""),
ifvarl = cmd(R,D),
ifvarg = cmd(R,D),
@ -1145,12 +1151,12 @@ local Cif = {
ifactorsound = cmd(R,R),
ifp = (sp1 * t_define)^1
/ "false", -- TODO
/ function (...) return format("_con._ifp(%d,_pli,_aci)", bit.bor(...)) end,
ifsquished = cmd()
/ "false", -- TODO
ifserver = cmd(),
ifrespawn = cmd()
/ "false", -- TODO
/ format("_con._checkrespawn(%s)", SPS""),
ifoutside = cmd()
/ format("_bit.band(sector[%s].ceilingstat,1)~=0", SPS".sectnum"),
ifonwater = cmd()
@ -1164,9 +1170,9 @@ local Cif = {
ifinwater = cmd()
/ format("sector[%s].lotag==2", SPS".sectnum"),
ifinspace = cmd()
/ "false", -- TODO
/ format("_con._checkspace(%s,false)", SPS".sectnum"),
ifinouterspace = cmd()
/ "false", -- TODO
/ format("_con._checkspace(%s,true)", SPS".sectnum"),
ifhitweapon = cmd()
/ "_con._A_IncurDamage(_aci)",
ifhitspace = cmd()
@ -1175,10 +1181,11 @@ local Cif = {
/ SPS".extra<=0",
ifclient = cmd(),
ifcanshoottarget = cmd()
/ "false", -- TODO
/ "_con._canshoottarget(_dist,_aci)",
ifcanseetarget = cmd() -- TODO: maybe set timetosleep afterwards
/ format("_con._canseetarget(%s,%s)", SPS"", PLS""),
ifcansee = cmd() * #sp1,
ifcansee = cmd() * #sp1
/ format("_con._cansee(_aci,%s)", PLS""),
ifbulletnear = cmd()
/ "_con._bulletnear(_aci)",
ifawayfromwall = cmd()
@ -1706,7 +1713,7 @@ if (string.dump) then
end
--[[
local file = io.stdout
local file = require("io").stdout
for filename,codetab in pairs(g_file_code) do
file:write(format("-- GENERATED CODE for \"%s\":\n", filename))
file:write(table.concat(flatten_codetab(codetab), "\n"))