Lunatic: sinking in code.

git-svn-id: https://svn.eduke32.com/eduke32@3324 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-12-28 17:18:02 +00:00
parent d7cfde9d3d
commit cc090a2ea8
7 changed files with 228 additions and 27 deletions

View file

@ -11,6 +11,7 @@ local setmetatable = setmetatable
local error = error
local type = type
local unpack = unpack
local player = assert(player)
local defs_c = require("defs_common")
@ -73,6 +74,8 @@ local function action_or_move(what, numargs, tab, name, ...)
tab[name] = ffi.new("const con_"..what.."_t", lastid[what], args)
end
---=== ACTION / MOVE / AI ===---
function action(name, ...)
action_or_move("action", 5, def.action, name, ...)
end
@ -124,9 +127,116 @@ end
---=== RUNTIME CON FUNCTIONS ===---
-- TODO: also check whether sprite exists in the game world (statnum != MAXSTATUS)
local function check_sprite_idx(i)
if (i >= ffiC.MAXSPRITES+0ULL) then
error("invalid argument: must be a valid sprite index", 3)
end
end
local function check_tile_idx(tilenum)
if (tilenum >= ffiC.MAXTILES+0ULL) then
error("invalid argument: must be a valid tile number", 3)
end
end
local function krandand(mask)
return bit.band(ffiC.krand(), mask)
end
-- Lunatic's "insertsprite" is a wrapper around the game "A_InsertSprite", not
-- the engine "insertsprite".
--
-- Forms:
-- 1. table-call: insertsprite{tilenum, pos, sectnum [, owner [, statnum]] [, key=val...]}
-- valid keys are: owner, statnum, shade, xrepeat, yrepeat, xvel, zvel
-- 2. position-call: insertsprite(tilenum, pos, sectnum [, owner [, statnum]])
function insertsprite(tab_or_tilenum, ...)
local tilenum, pos, sectnum -- mandatory
-- optional with defaults:
local owner, statnum
local shade, xrepeat, yrepeat, xvel, zvel = 0, 48, 48, 0, 0
if (type(tab_or_sectnum)=="table") then
local tab = tab_or_tilenum
tilenum, pos, sectnum = unpack(tab, 1, 3)
owner = tab[4] or tab.owner or -1
statnum = tab[5] or tab.statnum or 0
shade = shade and tab.shade
xrepeat = xrepeat and tab.xrepeat
yrepeat = yrepeat and tab.yrepeat
xvel = xvel and tab.xvel
zvel = zvel and tab.zvel
else
tilenum = table_or_tilenum
local args = {...}
pos, sectnum = unpack(args, 1, 2)
owner = args[3] or -1
statnum = args[4] or 0
end
if (type(sectnum)~="number" or type(tilenum) ~= "number") then
error("invalid insertsprite call: 'sectnum' and 'tilenum' must be numbers", 2)
end
check_tile_idx(tilenum)
defs_c.check_sector_idx(sectnum)
if (statnum >= ffiC.MAXSTATUS) then
error("invalid 'statnum' argument to insertsprite: must be a status number (0 .. MAXSTATUS-1)", 2)
end
return ffiC.A_InsertSprite(sectnum, pos.x, pos.y, pos.z, tilenum,
shade, xrepeat, yrepeat, ang, xvel, zvel,
owner, statnum)
end
-- INTERNAL USE ONLY.
function _addtodelqueue(spritenum)
check_sprite_idx(spritenum)
ffiC.A_AddToDeleteQueue(spritenum)
end
-- This corresponds to the first (spawn from parent sprite) form of A_Spawn().
function spawn(parentspritenum, tilenum, addtodelqueue)
check_sprite_idx(parentspritenum)
check_tile_idx(tilenum)
if (addtodelqueue and ffiC.g_spriteDeleteQueueSize == 0) then
return -1
end
local i = ffiC.A_Spawn(parentspritenum, tilenum)
if (addtodelqueue) then
ffiC.A_AddToDeleteQueue(i)
end
return i
end
-- This is the second A_Spawn() form. INTERNAL USE ONLY.
function _spawnexisting(spritenum)
check_sprite_idx(spritenum)
return ffiC.A_Spawn(-1, spritenum)
end
-- A_SpawnMultiple clone
-- ow: parent sprite number
function _spawnmany(ow, tilenum, n)
local spr = sprite[ow]
for i=n,1, -1 do
local j = insertsprite{ tilenum, spr^(ffiC.krand()%(47*256)), spr.sectnum, ow, 5,
shade=-32, xrepeat=8, yrepeat=8, ang=krandand(2047) }
_spawnexisting(j)
sprite[j].cstat = krandand(8+4)
end
end
function isenemytile(tilenum)
return (bit.band(ffiC.g_tile[tilenum], ffiC.SFLAG_BADGUY)~=0)
end
function rotatesprite(x, y, zoom, ang, tilenum, shade, pal, orientation,
cx1, cy1, cx2, cy2)
if (type(tilenum) ~= "number" or not (tilenum >= 0 and tilenum < ffiC.MAXTILES)) then
if (type(tilenum) ~= "number" or tilenum >= ffiC.MAXTILES+0ULL) then
error("bad argument #5 to rotatesprite: must be number in [0.."..ffiC.MAXTILES.."]", 2)
end
@ -187,17 +297,68 @@ local D = {
HEATSENSOR = 59,
BOOTS = 61,
HOLODUKE = 1348,
GLASSPIECES = 1031,
COMMANDER = 1920,
JIBS2 = 2250,
SCRAP1 = 2400,
BLIMP = 3400,
}
local function check_sprite_idx(i)
if (i >= ffiC.MAXSPRITES+0ULL) then
error("invalid argument: must be a valid sprite index", 3)
function _A_DoGuts(i, gutstile, n)
check_tile_idx(gutstile)
local spr = sprite[i]
local smallguts = spr.xrepeat < 16 and spr:isenemy()
local xsz = smallguts and 8 or 32
local ysz = xsz
local z = math.min(spr, sector[spr.sectnum]:floorzat(spr)) - 8*256
if (spr.picnum == D.COMMANDER) then
z = z - (24*256)
end
for i=n,1, -1 do
local pos = geom.vec3(spr.x+krandand(255)-128, spr.y+krandand(255)-128, z-krandand(8191))
local j = insertsprite{ gutstile, pos, spr.sectnum, i, 5, shade=-32, xrepeat=xsz, yrepeat=ysz,
ang=krandand(2047), xvel=48+krandand(31), zvel=-512-krandand(2047) }
local newspr = sprite[j]
if (newspr.picnum==D.JIBS2) then
-- This looks silly, but EVENT_EGS code could have changed the size
-- between the insertion and here.
newspr.xrepeat = newspr.xrepeat/4
newspr.yrepeat = newspr.yrepeat/4
end
newspr.pal = spr.pal
end
end
local function check_tile_idx(tilenum)
if (tilenum >= ffiC.MAXTILES+0ULL) then
error("invalid argument: must be a valid tile number", 3)
function _debris(i, dtile, n)
local spr = sprite[i]
if (spr.sectnum >= ffiC.numsectors+0ULL) then
return
end
for j=n-1,0, -1 do
local isblimpscrap = (spr.picnum==D.BLIMP and dtile==D.SCRAP1)
local picofs = isblimpscrap and 0 or krandand(3)
local pos = spr + geom.vec3(krandand(255)-128, krandand(255)-128, -(8*256)-krandand(8191))
local jj = insertsprite{ dtile+picofs, pos, spr.sectnum, i, 5,
shade=spr.shade, xrepeat=32+krandand(15), yrepeat=32+krandand(15),
ang=krandand(2047), xvel=32+krandand(127), zvel=-krandand(2047) }
-- NOTE: BlimpSpawnSprites[14] (its array size if 15) will never be chosen
sprite[jj].yvel = isblimpscrap and ffiC.BlimpSpawnSprites[math.mod(jj, 14)] or -1
sprite[jj].pal = spr.pal
end
end
function _A_SpawnGlass(i, n)
local spr = sprite[i]
for j=n,1, -1 do
local k = insertsprite{ D.GLASSPIECES+n%3, spr^(256*krandand(16)), spr.sectnum, i, 5,
shade=krandand(15), xrepeat=36, yrepeat=36, ang=krandand(2047),
xvel=32+krandand(63), zvel=-512-krandand(2047) }
sprite[k].pal = spr.pal
end
end
@ -403,10 +564,6 @@ 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)

View file

@ -454,6 +454,8 @@ playerdata_t g_player[MAXPLAYERS];
const int32_t playerswhenstarted;
int32_t lastvisinc;
int16_t g_spriteDeleteQueueSize;
int16_t BlimpSpawnSprites[15];
int32_t A_IncurDamage(int32_t sn); // not bound-checked!
void P_AddWeaponMaybeSwitch(DukePlayer_t *ps, int32_t weap);
@ -465,6 +467,10 @@ 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);
int32_t A_InsertSprite(int32_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int32_t s_pn,int32_t s_s,
int32_t s_xr,int32_t s_yr,int32_t s_a,int32_t s_ve,int32_t s_zv,int32_t s_ow,int32_t s_ss);
int32_t A_Spawn(int32_t j, int32_t pn);
void A_AddToDeleteQueue(int32_t i);
]]
-- functions

View file

@ -209,6 +209,11 @@ const int16_t headsectbunch[2][MAXBUNCHES], nextsectbunch[2][MAXSECTORS];
int16_t yax_getbunch(int16_t i, int16_t cf);
int32_t getceilzofslopeptr(const sectortype *sec, int32_t dax, int32_t day);
int32_t getflorzofslopeptr(const sectortype *sec, int32_t dax, int32_t day);
void getzsofslopeptr(const sectortype *sec, int32_t dax, int32_t day,
int32_t *ceilz, int32_t *florz);
int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
hitdata_t *hitinfo, uint32_t cliptype);
int32_t cansee(int32_t x1, int32_t y1, int32_t z1, int16_t sect1,
@ -248,6 +253,19 @@ local ivec3_mt = {
}
ivec3_ = ffi.metatype("vec3_t", ivec3_mt)
local sectortype_mt = {
__index = {
ceilingzat = function(s, pos)
return ffiC.getceilzofslope(s, pos.x, pos.y)
end,
floorzat = function(s, pos)
return ffiC.getflorzofslope(s, pos.x, pos.y)
end,
}
}
ffi.metatype("sectortype", sectortype_mt)
local walltype_mt = {
__index = {
isblocking = function(w)
@ -356,7 +374,7 @@ 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)
function check_sector_idx(sectnum)
if (sectnum >= ffiC.numsectors+0ULL) then
error("passed out-of-bounds sector number "..sectnum, 3)
end

View file

@ -17,6 +17,10 @@ ydim;
yax_getbunch;
getceilzofslopeptr;
getflorzofslopeptr;
getzsofslopeptr;
headspritesect;
headspritestat;
prevspritesect;
@ -63,6 +67,8 @@ g_player;
playerswhenstarted;
lastvisinc;
g_spriteDeleteQueueSize;
BlimpSpawnSprites;
luaJIT_BC_lunacon;
luaJIT_BC_con_lang;
@ -86,4 +92,7 @@ VM_ResetPlayer2;
A_RadiusDamage;
G_OperateSectors;
A_Dodge;
A_InsertSprite;
A_Spawn;
A_AddToDeleteQueue;
};

View file

@ -17,6 +17,10 @@ ydim;
yax_getbunch;
getceilzofslopeptr;
getflorzofslopeptr;
getzsofslopeptr;
headspritesect;
headspritestat;
prevspritesect;

View file

@ -19,6 +19,7 @@ local print = print
local tonumber = tonumber
local tostring = tostring
local type = type
local unpack = unpack
if (string.dump) then
require("strict")
@ -119,10 +120,7 @@ local function on_actor_end(usertype, tsamm, codetab)
str = str .. tostring(tsamm[i])..","
end
if (#tsamm==5) then
local flags = 0
for i=5,#tsamm do
flags = bit.bor(flags, tsamm[i])
end
local flags = bit.bor(unpack(tsamm, 5))
str = str .. flags..","
end
@ -690,7 +688,7 @@ local varvarop = cmd(W,R)
-- Allow nesting... stuff like
-- ifvarl actorvar[sprite[THISACTOR].owner].burning 0
-- is kinda breaking the classic "no array nesting" rules
-- (if there ever were any) and making our life harder else.
-- (if there ever were any) but making our life harder else.
local arraypat = sp0 * "[" * sp0 * t_rvar * sp0 * "]"
-- Have to bite the bullet here and list actor/player members with second parameters,
@ -887,11 +885,11 @@ local Ci = {
addweapon = cmd(D,D) -- NLCF
/ format("if (%s) then _con.longjmp() end", PLS":addweapon(%1,%2)"),
debris = cmd(D,D)
/ "", -- TODO
/ "_con._debris(_aci, %1, %2)",
addinventory = cmd(D,D)
/ PLS":addinventory(%1,%2)",
guts = cmd(D,D)
/ "", -- TODO
/ "_con._A_DoGuts(_aci,%1,%2)",
-- cont'd
addkills = cmd(D)
@ -908,14 +906,16 @@ local Ci = {
espawn = cmd(D),
globalsound = cmd(D)
/ "",
lotsofglass = cmd(D),
lotsofglass = cmd(D)
/ "_con._A_SpawnGlass(_aci,%1)",
mail = cmd(D)
/ "", -- TODO
/ "_con._spawnmany(_aci,4410,%1)", -- TODO: dyntile
money = cmd(D)
/ "", -- TODO
/ "_con._spawnmany(_aci,1233,%1)", -- TODO: dyntile
paper = cmd(D)
/ "", -- TODO
qspawn = cmd(D),
/ "_con._spawnmany(_aci,4460,%1)", -- TODO: dyntile
qspawn = cmd(D)
/ "_con.spawn(_aci,%1,true)",
quote = cmd(D)
/ "", -- TODO
savenn = cmd(D),
@ -925,7 +925,8 @@ local Ci = {
soundonce = cmd(D),
sound = cmd(D)
/ "", -- TODO: all things audio...
spawn = cmd(D),
spawn = cmd(D)
/ "_con.spawn(_aci, %1)",
stopsound = cmd(D)
/ "",
@ -943,7 +944,8 @@ local Ci = {
/ format("_con._flash(%s,%s)", ACS"", SPS""),
getlastpal = cmd()
/ "_con._getlastpal(_aci)",
insertspriteq = cmd(),
insertspriteq = cmd()
/ "_con._addtodelqueue(_aci)",
killit = cmd() -- NLCF
/ "_con.killit()",
mikesnd = cmd()
@ -1483,8 +1485,8 @@ local Grammar = Pat{
-- Some often-used terminals follow. These appear here because we're
-- hitting a limit with LPeg else.
-- http://lua-users.org/lists/lua-l/2008-11/msg00462.html
-- NOTE: NW demo (NWSNOW.CON) contains a Ctrl-Z char (decimal 26)
whitespace = Set(" \t\r\26") + newline + Set("(),;") + comment + linecomment,

View file

@ -303,6 +303,11 @@ require("test/test_rotspr")
print('---=== END TEST SCRIPT ===---')
function check_sector_idx()
error("bla")
end
spritesofsect(0)
-- This will complain about wrong usage of 'error'. In particular,
-- the nil must not propagate to C!
error(nil)