mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
Lunatic: many changes, motivated by writing test "helixspawner".
- some renames of functions/methods - con.actorvar: explicitly allow (for now) boolean and number values - added gv.gametic, player.holdskey(), player.all(), actor.check*()/hit*(), gv.rendmode, gv.REND, <bitint>:mask(), spr:getheightofs() - make read of nil var in "finalized" (live) module produce error, too - add test/helixspawner.lua git-svn-id: https://svn.eduke32.com/eduke32@3928 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
44f71d313f
commit
d580c1e998
9 changed files with 311 additions and 72 deletions
|
@ -474,7 +474,7 @@ local PlayerLabels = {
|
|||
|
||||
-- NOTE the special case; "%%s" is used to mark settable members
|
||||
-- with METHOD_MEMBER syntax, it's the value to be set.
|
||||
gotweapon = { "("..PL":have_weapon(%s) and 1 or 0)", PL":_gt_weapon(%s,%%s)" },
|
||||
gotweapon = { "("..PL":has_weapon(%s) and 1 or 0)", PL":_gt_weapon(%s,%%s)" },
|
||||
zoom = PL".zoom",
|
||||
|
||||
loogiex = {},
|
||||
|
|
|
@ -537,7 +537,7 @@ end
|
|||
local function P_AddWeaponAmmoCommon(ps, weap, amount)
|
||||
P_AddAmmo(ps, weap, amount)
|
||||
|
||||
if (ps.curr_weapon==ffiC.KNEE_WEAPON and ps:have_weapon(weap)) then
|
||||
if (ps.curr_weapon==ffiC.KNEE_WEAPON and ps:has_weapon(weap)) then
|
||||
CF.P_AddWeaponMaybeSwitchI(ps.weapon._p, weap);
|
||||
end
|
||||
end
|
||||
|
@ -1167,11 +1167,9 @@ function _addammo(ps, weap, amount)
|
|||
end
|
||||
|
||||
function _addweapon(ps, weap, amount)
|
||||
if (weap >= ffiC.MAX_WEAPONS+0ULL) then
|
||||
error("Invalid weapon ID "..weap, 2)
|
||||
end
|
||||
bcheck.weapon_idx(weap)
|
||||
|
||||
if (not ps:have_weapon(weap)) then
|
||||
if (not ps:has_weapon(weap)) then
|
||||
CF.P_AddWeaponMaybeSwitchI(ps.weapon._p, weap);
|
||||
elseif (have_ammo_at_max(ps, weap)) then
|
||||
return true
|
||||
|
@ -1186,32 +1184,23 @@ function _A_RadiusDamage(i, r, hp1, hp2, hp3, hp4)
|
|||
CF.A_RadiusDamage(i, r, hp1, hp2, hp3, hp4)
|
||||
end
|
||||
|
||||
function _testkey(pli, synckey)
|
||||
check_player_idx(pli)
|
||||
if (synckey >= 32ULL) then
|
||||
error("Invalid argument #2 to _testkey: must be in [0..31]", 2)
|
||||
end
|
||||
local bits = ffiC.g_player[pli].sync.bits
|
||||
return (bit.band(bits, bit.lshift(1,synckey)) ~= 0)
|
||||
end
|
||||
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,
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1527,10 +1516,7 @@ function _rotatepoint(pivotx, pivoty, posx, posy, ang)
|
|||
return pos.x, pos.y
|
||||
end
|
||||
|
||||
local SK = {
|
||||
CROUCH = 1,
|
||||
RUN = 5,
|
||||
}
|
||||
local holdskey = player.holdskey
|
||||
|
||||
function _ifp(flags, pli, aci)
|
||||
local l = flags
|
||||
|
@ -1538,7 +1524,7 @@ function _ifp(flags, pli, aci)
|
|||
local vel = sprite[ps.i].xvel
|
||||
local band = bit.band
|
||||
|
||||
if (band(l,8)~=0 and ps.on_ground and _testkey(pli, SK.CROUCH)) then
|
||||
if (band(l,8)~=0 and ps.on_ground and holdskey(pli, "CROUCH")) then
|
||||
return true
|
||||
elseif (band(l,16)~=0 and ps.jumping_counter == 0 and not ps.on_ground and ps.vel.z > 2048) then
|
||||
return true
|
||||
|
@ -1546,15 +1532,15 @@ function _ifp(flags, pli, aci)
|
|||
return true
|
||||
elseif (band(l,1)~=0 and vel >= 0 and vel < 8) then
|
||||
return true
|
||||
elseif (band(l,2)~=0 and vel >= 8 and not _testkey(pli, SK.RUN)) then
|
||||
elseif (band(l,2)~=0 and vel >= 8 and not holdskey(pli, "RUN")) then
|
||||
return true
|
||||
elseif (band(l,4)~=0 and vel >= 8 and _testkey(pli, SK.RUN)) then
|
||||
elseif (band(l,4)~=0 and vel >= 8 and holdskey(pli, "RUN")) then
|
||||
return true
|
||||
elseif (band(l,64)~=0 and ps.pos.z < (sprite[aci].z-(48*256))) then
|
||||
return true
|
||||
elseif (band(l,128)~=0 and vel <= -8 and not _testkey(pli, SK.RUN)) then
|
||||
elseif (band(l,128)~=0 and vel <= -8 and not holdskey(pli, "RUN")) then
|
||||
return true
|
||||
elseif (band(l,256)~=0 and vel <= -8 and _testkey(pli, SK.RUN)) then
|
||||
elseif (band(l,256)~=0 and vel <= -8 and holdskey(pli, "RUN")) then
|
||||
return true
|
||||
elseif (band(l,512)~=0 and (ps.quick_kick > 0 or (ps.curr_weapon == ffiC.KNEE_WEAPON and ps.kickback_pic > 0))) then
|
||||
return true
|
||||
|
@ -2123,6 +2109,16 @@ end
|
|||
|
||||
|
||||
--== Per-actor variable ==--
|
||||
local perxvar_allowed_types = {
|
||||
["boolean"]=true, ["number"]=true,
|
||||
}
|
||||
|
||||
local function check_perxval_type(val)
|
||||
if (perxvar_allowed_types[type(val)] == nil) then
|
||||
error("type forbidden as per-* variable value: "..type(val), 3)
|
||||
end
|
||||
end
|
||||
|
||||
local actorvar_methods = {
|
||||
--- Internal routines ---
|
||||
|
||||
|
@ -2153,7 +2149,6 @@ local actorvar_methods = {
|
|||
end,
|
||||
}
|
||||
|
||||
-- XXX: How about types other than numbers?
|
||||
local actorvar_mt = {
|
||||
__index = function(acv, idx)
|
||||
if (type(idx)=="number") then
|
||||
|
@ -2166,7 +2161,7 @@ local actorvar_mt = {
|
|||
|
||||
__newindex = function(acv, idx, val)
|
||||
check_sprite_idx(idx)
|
||||
check_number(val)
|
||||
check_perxval_type(val)
|
||||
rawset(acv, idx, val)
|
||||
end,
|
||||
|
||||
|
@ -2176,6 +2171,7 @@ local actorvar_mt = {
|
|||
-- <initval>: default value for per-actor variable.
|
||||
-- <values>: optional, a table of <spritenum>=value
|
||||
function actorvar(initval, values)
|
||||
check_perxval_type(initval)
|
||||
local acv = setmetatable({ _defval=initval }, actorvar_mt)
|
||||
g_actorvar[acv] = true
|
||||
return set_values_from_table(acv, values)
|
||||
|
@ -2193,7 +2189,6 @@ local playervar_methods = {
|
|||
end,
|
||||
}
|
||||
|
||||
-- XXX: How about types other than numbers?
|
||||
local playervar_mt = {
|
||||
__index = function(plv, idx)
|
||||
if (type(idx)=="number") then
|
||||
|
@ -2206,7 +2201,7 @@ local playervar_mt = {
|
|||
|
||||
__newindex = function(plv, idx, val)
|
||||
check_player_idx(idx)
|
||||
check_number(val)
|
||||
check_perxval_type(val)
|
||||
rawset(plv, idx, val)
|
||||
end,
|
||||
|
||||
|
@ -2216,6 +2211,7 @@ local playervar_mt = {
|
|||
-- <initval>: default value for per-player variable.
|
||||
-- <values>: optional, a table of <playeridx>=value
|
||||
function playervar(initval, values)
|
||||
check_perxval_type(initval)
|
||||
local plv = setmetatable({ _defval=initval }, playervar_mt)
|
||||
return set_values_from_table(plv, values)
|
||||
end
|
||||
|
|
|
@ -119,6 +119,7 @@ enum dukeweapon_t {
|
|||
|
||||
enum {
|
||||
MAXPLAYERS = 16,
|
||||
GTICSPERSEC = 30, // The real number of movement updates per second
|
||||
};
|
||||
]])
|
||||
|
||||
|
@ -145,7 +146,9 @@ typedef struct {
|
|||
} con_ai_t;
|
||||
]]
|
||||
|
||||
defs_c.bitint_new_struct_type("int16_t", "SBit16")
|
||||
defs_c.bitint_new_struct_type("int32_t", "SBit32")
|
||||
defs_c.bitint_new_struct_type("uint32_t", "UBit32")
|
||||
|
||||
-- Struct template for actor_t. It already has 'const' fields (TODO: might need
|
||||
-- to make more 'const'), but still has array members exposed, so is unsuited
|
||||
|
@ -165,7 +168,9 @@ __attribute__((packed)) struct {
|
|||
const int16_t picnum;
|
||||
int16_t ang, extra;
|
||||
const int16_t owner;
|
||||
int16_t _movflag,tempang,timetosleep; //6b
|
||||
// NOTE: not to be confused with .movflags:
|
||||
]]..defs_c.bitint_member("SBit16", "_movflag")..[[
|
||||
int16_t tempang, timetosleep;
|
||||
|
||||
int16_t stayputsect;
|
||||
const int16_t dispicnum;
|
||||
|
@ -402,7 +407,7 @@ ffi.cdef([[
|
|||
typedef struct { int32_t _p; } weaponaccess_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t bits; // 4b
|
||||
]]..defs_c.bitint_member("UBit32", "bits")..[[
|
||||
int16_t fvel, svel; // 4b
|
||||
int8_t avel, horz; // 2b
|
||||
int8_t extbits, filler; // 2b
|
||||
|
@ -632,6 +637,7 @@ int32_t g_scriptVersion;
|
|||
const int32_t g_currentFrameRate;
|
||||
const int32_t g_currentMenu;
|
||||
uint16_t g_earthquakeTime;
|
||||
uint32_t g_moveThingsCount;
|
||||
char CheatKeys[2];
|
||||
|
||||
// Must not have functions here that may call events directly or
|
||||
|
@ -788,6 +794,40 @@ player_static_members._INPUT_EXT_BITS = defs_c.conststruct
|
|||
TURN_RIGHT = 32,
|
||||
}
|
||||
|
||||
local band = bit.band
|
||||
local lsh = bit.lshift
|
||||
|
||||
do
|
||||
-- player.all() iterator
|
||||
local function iter_allplayers(_nil, pli)
|
||||
if (pli+1 < ffiC.playerswhenstarted) then
|
||||
return pli+1
|
||||
end
|
||||
end
|
||||
|
||||
function player_static_members.all()
|
||||
return iter_allplayers, nil, -1
|
||||
end
|
||||
|
||||
-- player.holdskey(pli, keyname)
|
||||
local KEYS = { -- SK_CROUCH etc. -- "sync keys"
|
||||
CROUCH = lsh(1,1),
|
||||
RUN = lsh(1,5),
|
||||
OPEN = lsh(1,29),
|
||||
}
|
||||
|
||||
function player_static_members.holdskey(pli, keyname)
|
||||
bcheck.player_idx(pli)
|
||||
if (KEYS[keyname] == nil) then
|
||||
error("invalid key name: "..tostring(keyname), 2)
|
||||
end
|
||||
|
||||
return ffiC.g_player[pli].sync.bitsbits:test(KEYS[keyname])
|
||||
end
|
||||
end
|
||||
|
||||
local player_holdskey = player_static_members.holdskey
|
||||
|
||||
-- Actor flags
|
||||
local actor_static_members = {}
|
||||
do
|
||||
|
@ -1100,6 +1140,36 @@ local actor_mt = {
|
|||
check_sprite_idx(owner)
|
||||
ffi.cast(actor_ptr_ct, a).owner = owner
|
||||
end,
|
||||
|
||||
--- Custom methods ---
|
||||
|
||||
-- Checkers for whether the movement update made the actor hit
|
||||
-- something.
|
||||
|
||||
checkhit = function(a)
|
||||
-- Check whether we hit *anything*, including ceiling/floor.
|
||||
return a._movflagbits:test(49152)
|
||||
end,
|
||||
|
||||
checkbump = function(a)
|
||||
-- Check whether we bumped into a wall or sprite.
|
||||
return (a._movflagbits:mask(49152) >= 32768)
|
||||
end,
|
||||
|
||||
hitwall = function(a)
|
||||
if (a._movflagbits:mask(49152) == 32768) then
|
||||
return a._movflagbits:mask(32767)
|
||||
end
|
||||
end,
|
||||
|
||||
hitsprite = function(a)
|
||||
if (a._movflagbits:mask(49152) == 49152) then
|
||||
return a._movflagbits:mask(32767)
|
||||
end
|
||||
end,
|
||||
|
||||
-- NOTE: no 'hitsector' or 'hitceiling' / 'hitfloor' for now because
|
||||
-- more research is needed as to what the best way of checking c/f is.
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1200,16 +1270,21 @@ local player_mt = {
|
|||
|
||||
stomp = con._pstomp,
|
||||
|
||||
have_weapon = function(p, weap)
|
||||
return (bit.band(p.gotweapon, bit.lshift(1, weap)) ~= 0)
|
||||
holdskey = function(p, keyname)
|
||||
-- XXX: on invalid <keyname>, error will point to this next line:
|
||||
return player_holdskey(p.weapon._p, keyname)
|
||||
end,
|
||||
|
||||
has_weapon = function(p, weap)
|
||||
return (band(p.gotweapon, lsh(1, weap)) ~= 0)
|
||||
end,
|
||||
|
||||
give_weapon = function(p, weap)
|
||||
p.gotweapon = bit.bor(p.gotweapon, bit.lshift(1, weap))
|
||||
p.gotweapon = bit.bor(p.gotweapon, lsh(1, weap))
|
||||
end,
|
||||
|
||||
take_weapon = function(p, weap)
|
||||
p.gotweapon = bit.band(p.gotweapon, bit.bnot(bit.lshift(1, weap)))
|
||||
p.gotweapon = band(p.gotweapon, bit.bnot(lsh(1, weap)))
|
||||
end,
|
||||
|
||||
-- Give or take weapon, for implementation of CON's .gotweapon access.
|
||||
|
@ -1226,7 +1301,7 @@ local player_mt = {
|
|||
if (not no_return_to_center) then
|
||||
p.return_to_center = 9
|
||||
end
|
||||
local n = bit.arshift(128-bit.band(ffiC.krand(),255), 1)
|
||||
local n = bit.arshift(128-band(ffiC.krand(),255), 1)
|
||||
p.rotscrnang = n
|
||||
p.look_ang = n
|
||||
end,
|
||||
|
@ -1388,6 +1463,13 @@ gv_access._ud = ffiC.ud
|
|||
-- Support for some CON global system gamevars. RETURN handled separately.
|
||||
gv_access._csv = ffi.new "struct { int32_t LOTAG, HITAG, TEXTURE; }"
|
||||
|
||||
gv_access.REND = defs_c.conststruct
|
||||
{
|
||||
CLASSIC = 0,
|
||||
POLYMOST = 3,
|
||||
POLYMER = 4,
|
||||
}
|
||||
|
||||
function gv_access._get_yxaspect()
|
||||
return ffiC.yxaspect
|
||||
end
|
||||
|
@ -1425,11 +1507,6 @@ function gv_access.currentLevel()
|
|||
return ffiC.ud.level_number
|
||||
end
|
||||
|
||||
function gv_access.currentRenderMode()
|
||||
-- TODO: USE_OPENGL=0 build
|
||||
return ffiC.rendmode
|
||||
end
|
||||
|
||||
function gv_access.doQuake(gametics, snd)
|
||||
ffiC.g_earthquakeTime = gametics
|
||||
if (snd ~= nil) then
|
||||
|
@ -1556,11 +1633,17 @@ local function getnumlocals(l)
|
|||
end
|
||||
end
|
||||
|
||||
local function error_on_nil_read(_, varname)
|
||||
error("attempt to read nil variable '"..varname.."'", 2)
|
||||
end
|
||||
|
||||
local required_module_mt = {
|
||||
__index = error_on_nil_read,
|
||||
|
||||
__newindex = function()
|
||||
-- TODO: allow gamevars to be nil?
|
||||
error("modifying module table forbidden", 2)
|
||||
end,
|
||||
|
||||
__metatable = true,
|
||||
}
|
||||
|
||||
|
@ -1737,9 +1820,7 @@ end
|
|||
|
||||
|
||||
local module_mt = {
|
||||
__index = function (_, n)
|
||||
error("attempt to read undeclared variable '"..n.."'", 2)
|
||||
end,
|
||||
__index = error_on_nil_read,
|
||||
}
|
||||
|
||||
-- Our 'module' replacement doesn't get the module name from the function args
|
||||
|
@ -1872,7 +1953,7 @@ local function our_gameactor(args)
|
|||
lastargi = 1/0
|
||||
end
|
||||
if (type(func) ~= "function") then
|
||||
error("invalid gameactor call: must provide a function with last numeric arg or .func".." "..type(func), 2)
|
||||
error("invalid gameactor call: must provide a function with last numeric arg or .func", 2)
|
||||
end
|
||||
|
||||
local flags = (lastargi > 2 and args[2]) or args.flags or 0
|
||||
|
@ -1881,14 +1962,14 @@ local function our_gameactor(args)
|
|||
end
|
||||
|
||||
local AF = actor.FLAGS
|
||||
local chainflags = bit.band(flags, AF._CHAIN_MASK_ACTOR)
|
||||
flags = bit.band(flags, BNOT.CHAIN_MASK_ACTOR)
|
||||
local chainflags = band(flags, AF._CHAIN_MASK_ACTOR)
|
||||
flags = band(flags, BNOT.CHAIN_MASK_ACTOR)
|
||||
|
||||
-- Default chaining behavior: don't, replace the old actor instead, but
|
||||
-- unlike CON, also replace its flags. (CON ORs them instead.)
|
||||
if (chainflags == 0) then
|
||||
chainflags = AF.replace_hard
|
||||
elseif (bit.band(chainflags, chainflags-1) ~= 0) then
|
||||
elseif (band(chainflags, chainflags-1) ~= 0) then
|
||||
error("invalid chaining control flags to gameactor", 2)
|
||||
end
|
||||
|
||||
|
@ -1897,7 +1978,7 @@ local function our_gameactor(args)
|
|||
error("attempt to chain code to nonexistent actor tile "..tilenum, 2)
|
||||
end
|
||||
|
||||
local flags_rbits = bit.band(flags, BNOT.USER_MASK)
|
||||
local flags_rbits = band(flags, BNOT.USER_MASK)
|
||||
if (flags_rbits ~= 0) then
|
||||
error("invalid 'flags' argument (#2) to gameactor: must not set reserved bits (0x"
|
||||
..(bit.tohex(flags_rbits))..")", 2)
|
||||
|
@ -2007,7 +2088,7 @@ local function our_gameevent(args)
|
|||
error("invalid 'flags' argument (#2) to gameevent: must be a number", 2)
|
||||
end
|
||||
|
||||
if (bit.band(flags, BNOT.CHAIN_MASK_EVENT) ~= 0) then
|
||||
if (band(flags, BNOT.CHAIN_MASK_EVENT) ~= 0) then
|
||||
error("invalid 'flags' argument to gameevent: must not set reserved bits", 2)
|
||||
end
|
||||
|
||||
|
@ -2194,14 +2275,24 @@ end
|
|||
|
||||
-- error(..., 2) is to blame the caller and get its line numbers
|
||||
|
||||
-- Map of 'gv' variable names to C ones.
|
||||
local varnameMap = {
|
||||
gametic = "g_moveThingsCount",
|
||||
}
|
||||
|
||||
gv_access.gametic = true
|
||||
|
||||
local tmpmt = {
|
||||
__index = function(_, key)
|
||||
if (gv_access[key] == nil) then
|
||||
-- Read access allowed.
|
||||
return ffiC[key]
|
||||
end
|
||||
if (type(gv_access[key])~="boolean") then
|
||||
-- overridden...
|
||||
elseif (type(gv_access[key])~="boolean") then
|
||||
-- Overridden 'gv' pseudo-member...
|
||||
return gv_access[key]
|
||||
elseif (varnameMap[key]) then
|
||||
-- Variable known under a different name on the C side.
|
||||
return ffiC[varnameMap[key]]
|
||||
end
|
||||
error("access forbidden", 2)
|
||||
end,
|
||||
|
|
|
@ -90,6 +90,10 @@ local bitint_mt = {
|
|||
test = function(self, bits)
|
||||
return (band(self._v, bits) ~= 0)
|
||||
end,
|
||||
|
||||
mask = function(self, bits)
|
||||
return band(self._v, bits)
|
||||
end,
|
||||
},
|
||||
|
||||
__metatable = true,
|
||||
|
@ -379,13 +383,13 @@ if (_LUNATIC_AUX) then
|
|||
return
|
||||
end
|
||||
|
||||
ffi.cdef "const int32_t rendmode;"
|
||||
|
||||
decl[[
|
||||
int32_t yxaspect;
|
||||
int32_t 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];
|
||||
const int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
|
||||
|
@ -401,6 +405,7 @@ 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 spriteheightofsptr(const spritetype *spr, int32_t *height, int32_t alsotileyofs);
|
||||
|
||||
int32_t changespritesect(int16_t spritenum, int16_t newsectnum);
|
||||
int32_t changespritestat(int16_t spritenum, int16_t newstatnum);
|
||||
|
@ -603,6 +608,8 @@ local spritetype_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(SPRITE_STRUCT
|
|||
-- NOTE: this is the *protected* tspritetype pointer.
|
||||
local tspritetype_ptr_ct = ffi.typeof("$ *", ffi.typeof("tspritetype"))
|
||||
|
||||
local intarg = ffi.new("int32_t[1]")
|
||||
|
||||
local spritetype_mt = {
|
||||
__pow = function(s, zofs)
|
||||
return vec3_ct(s.x, s.y, s.z-zofs)
|
||||
|
@ -630,6 +637,14 @@ local spritetype_mt = {
|
|||
check_sprite_idx(owner)
|
||||
ffi.cast(spritetype_ptr_ct, s).owner = owner
|
||||
end,
|
||||
|
||||
--- Custom methods ---
|
||||
|
||||
getheightofs = function(s)
|
||||
-- XXX: better reimplement in Lua?
|
||||
local zofs = ffiC.spriteheightofsptr(s, intarg, 0)
|
||||
return intarg[0], zofs
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ sectorofwall_noquick;
|
|||
getceilzofslopeptr;
|
||||
getflorzofslopeptr;
|
||||
getzsofslopeptr;
|
||||
spriteheightofsptr;
|
||||
|
||||
changespritesect;
|
||||
changespritestat;
|
||||
|
@ -160,6 +161,7 @@ g_scriptVersion;
|
|||
g_currentFrameRate;
|
||||
g_currentMenu;
|
||||
g_earthquakeTime;
|
||||
g_moveThingsCount;
|
||||
CheatKeys;
|
||||
g_logoFlags;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ sectorofwall_noquick;
|
|||
getceilzofslopeptr;
|
||||
getflorzofslopeptr;
|
||||
getzsofslopeptr;
|
||||
spriteheightofsptr;
|
||||
|
||||
changespritesect;
|
||||
changespritestat;
|
||||
|
|
|
@ -265,7 +265,7 @@ local function new_initial_gvartab()
|
|||
totalclock = RO "_gv.totalclock",
|
||||
framerate = RO "_gv._currentFramerate()",
|
||||
current_menu = RO "_gv._currentMenu()",
|
||||
rendmode = RO "_gv.currentRenderMode()",
|
||||
rendmode = RO "_gv.rendmode",
|
||||
|
||||
screenpeek = RO "_gv.screenpeek",
|
||||
|
||||
|
@ -2689,7 +2689,7 @@ local Cif = {
|
|||
ifhitweapon = cmd()
|
||||
/ "_con._A_IncurDamage(_aci)>=0",
|
||||
ifhitspace = cmd()
|
||||
/ "_con._testkey(_pli,29)", -- XXX
|
||||
/ "player.holdskey(_pli,'OPEN')",
|
||||
ifdead = cmd()
|
||||
/ SPS".extra<=0",
|
||||
ifclient = cmd()
|
||||
|
|
|
@ -111,7 +111,11 @@ local savebuffer_mt = {
|
|||
-- We have a serializeable object from Lunatic
|
||||
-- (e.g. actorvar).
|
||||
self:getRequire(value)
|
||||
self:emitT(refcode, value:_serialize(), value)
|
||||
local restoreCode = value:_serialize()
|
||||
if (restoreCode == nil) then -- XXX: check UNUSED?
|
||||
return true
|
||||
end
|
||||
self:emitT(refcode, restoreCode, value)
|
||||
valcode = refcode
|
||||
|
||||
elseif (type(value)=="table") then
|
||||
|
|
130
polymer/eduke32/source/lunatic/test/helixspawner.lua
Normal file
130
polymer/eduke32/source/lunatic/test/helixspawner.lua
Normal file
|
@ -0,0 +1,130 @@
|
|||
|
||||
-- A spawner (NUKEBUTTON+3) of colored TRANSPORTERSTAR+4 sprites in a helical
|
||||
-- arrangement.
|
||||
|
||||
local require = require
|
||||
local math = require("math")
|
||||
|
||||
local con = require("con")
|
||||
local xmath = require("xmath")
|
||||
|
||||
local gv = gv
|
||||
local actor = actor
|
||||
local player = player
|
||||
local sprite = sprite
|
||||
|
||||
local gameactor = gameactor
|
||||
|
||||
|
||||
module(...)
|
||||
|
||||
-- Dual-typed per-actor array: <false> if a broken nuke switch is not enabled,
|
||||
-- start game tic of when it was enabled otherwise.
|
||||
-- NOTE: for objects that are not supposed to be deleted such as this one, it
|
||||
-- would also be OK to use a plain table.
|
||||
local nukeswStart = con.actorvar(false)
|
||||
|
||||
-- This one should be a per-actor variable because it holds info about
|
||||
-- "volatile" actors.
|
||||
local starPal = con.actorvar(0)
|
||||
|
||||
require("end_gamevars")
|
||||
|
||||
|
||||
local function bangvec(bang)
|
||||
bang = math.floor(bang)
|
||||
return xmath.vec3(xmath.cosb(bang), xmath.sinb(bang))
|
||||
end
|
||||
|
||||
local function angvec(ang)
|
||||
return xmath.vec3(math.cos(ang), math.sin(ang))
|
||||
end
|
||||
|
||||
|
||||
local D = require("CON.DEFS")
|
||||
local GTICSPERSEC = gv.GTICSPERSEC
|
||||
|
||||
-- color per decasecond
|
||||
local COLOR = { 1, 2, 6, 7, 8 }
|
||||
|
||||
gameactor
|
||||
{
|
||||
D.TRANSPORTERSTAR+4,
|
||||
|
||||
flags = actor.FLAGS.NOCLIP,
|
||||
|
||||
move = con.move{100},
|
||||
movflags = actor.MOVFLAGS.geth,
|
||||
|
||||
func = function(aci)
|
||||
-- NOTE: this is prettier than calling it 'a', even if 'act' is used to
|
||||
-- denote an action in other places:
|
||||
local act = actor[aci]
|
||||
|
||||
if (act:has_action(0)) then
|
||||
act:set_action(1) -- TODO: actor constructors, i.e. 'init' callbacks
|
||||
|
||||
local spr = sprite[aci]
|
||||
local decasec = math.floor((gv.gametic - nukeswStart[spr.owner])/(GTICSPERSEC*10))
|
||||
|
||||
local pal = COLOR[decasec+1]
|
||||
if (pal ~= nil) then
|
||||
starPal[aci] = pal
|
||||
end
|
||||
|
||||
-- At one point, we stop coloring the spawned stars. This tests
|
||||
-- per-actor variable resetting to the default value.
|
||||
spr.pal = starPal[aci]
|
||||
end
|
||||
|
||||
if (act:checkbump()) then
|
||||
con.killit()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
local CS = sprite.CSTAT
|
||||
local SPAWNSPERTIC = 10 --> 300/second --> 18000 per minute
|
||||
local TWOPI = 2*math.pi
|
||||
|
||||
gameactor
|
||||
{
|
||||
D.NUKEBUTTON+3, -- destroyed end-of-level nuke switch
|
||||
|
||||
function(aci)
|
||||
local spr = sprite[aci]
|
||||
|
||||
for pi in player.all() do
|
||||
-- XXX: how to emulate "use switch" distance checking code, but in
|
||||
-- an actor-centric fashion?
|
||||
if (not nukeswStart[aci] and player.holdskey(pi, "OPEN")
|
||||
and (player[pi].pos - spr):len2sq() < 256^2) then
|
||||
-- Enable us.
|
||||
nukeswStart[aci] = gv.gametic
|
||||
spr.cstatbits:clear(CS.TRANS_BITMASK)
|
||||
spr.cstatbits:set(CS.TRANS1)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local startgtic = nukeswStart[aci]
|
||||
if (not startgtic) then
|
||||
return
|
||||
end
|
||||
|
||||
local hei, zofs = spr:getheightofs()
|
||||
local radius = hei/2
|
||||
|
||||
for i=0,SPAWNSPERTIC-1 do
|
||||
-- Make one second go once round the circle, spawning
|
||||
-- SPAWNSPERTIC*GTICSPERSEC stars.
|
||||
local ii = ((gv.gametic*SPAWNSPERTIC)%(GTICSPERSEC*SPAWNSPERTIC)) + i
|
||||
local v = (radius/16)*angvec(ii*TWOPI/(GTICSPERSEC*SPAWNSPERTIC))
|
||||
local circvec = xmath.rotate(xmath.vec3(0, v.x, 16*v.y), xmath.vec3(), spr.ang) -- XXX
|
||||
local pos = spr^(zofs + radius) + 256*bangvec(spr.ang) + circvec
|
||||
|
||||
con.insertsprite{D.TRANSPORTERSTAR+4, pos, spr.sectnum, statnum=actor.STAT.ACTOR,
|
||||
xrepeat=3, yrepeat=3, ang=spr.ang, owner=aci}
|
||||
end
|
||||
end
|
||||
}
|
Loading…
Reference in a new issue