raze-gles/polymer/eduke32/source/lunatic/test/helixspawner.lua

138 lines
3.8 KiB
Lua

-- 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 bangvec = xmath.bangvec
local angvec = xmath.angvec
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)
local spr = sprite[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 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
-- Test spr:changesect() vs. sprite.changesect()
local sectnum = spr.sectnum
for i=0,gv.numsectors-1 do
if (spr.pal ~= 2 and spr.pal ~= 7) then
sprite.changesect(aci, i) -- noticeably faster...
else
spr:changesect(i) -- ...than this
end
end
sprite.changesect(aci, sectnum)
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.vec3(0, v.x, 16*v.y):rotate(spr.ang)
local pos = spr^(zofs + radius) + 256*bangvec(spr.ang) + circvec
con.insertsprite{D.TRANSPORTERSTAR+4, pos, spr.sectnum, actor.STAT.ACTOR, aci,
xrepeat=3, yrepeat=3, ang=spr.ang}
end
end
}