1
2-- A spawner (NUKEBUTTON+3) of colored TRANSPORTERSTAR+4 sprites in a helical
3-- arrangement.
4
5local require = require
6local math = require("math")
7
8local con = require("con")
9local xmath = require("xmath")
10
11local gv = gv
12local actor = actor
13local player = player
14local sprite = sprite
15
16local gameactor = gameactor
17
18
19module(...)
20
21-- Dual-typed per-actor array: false if a broken nuke switch is not enabled,
22-- start game tic of when it was enabled otherwise.
23-- NOTE: for objects that are not supposed to be deleted such as this one, it
24-- would also be OK to use a plain table.
25local nukeswStart = con.actorvar(false)
26
27-- This one should be a per-actor variable because it holds info about
28-- "volatile" actors.
29local starPal = con.actorvar(0)
30
31-- Color per decasecond, can be changed from outside.
32COLOR = { 1, 2, 6, 7, 8 }
33
34require("end_gamevars")
35
36
37local bangvec = xmath.bangvec
38local angvec = xmath.angvec
39
40
41local D = require("CON.DEFS")
42local GTICSPERSEC = gv.GTICSPERSEC
43
44gameactor
45{
46    D.TRANSPORTERSTAR+4,
47
48    flags = actor.FLAGS.NOCLIP,
49
50    move = con.move{100},
51    movflags = actor.MOVFLAGS.geth,
52
53    func = function(aci)
54        local spr = sprite[aci]
55        -- NOTE: this is prettier than calling it 'a', even if 'act' is used to
56        -- denote an action in other places:
57        local act = actor[aci]
58
59        if (act:has_action(0)) then
60            act:set_action(1)  -- TODO: actor constructors, i.e. 'init' callbacks
61
62            local decasec = math.floor((gv.gametic - nukeswStart[spr.owner])/(GTICSPERSEC*10)) % 12
63
64            local pal = COLOR[decasec+1]
65            if (pal ~= nil) then
66                starPal[aci] = pal
67            end
68
69            -- Every 2nd minute, we stop coloring the spawned stars. This tests
70            -- per-actor variable resetting to the default value.
71            spr.pal = starPal[aci]
72        end
73
74        if (act:checkbump()) then
75            con.killit()
76        end
77
78        -- Test spr:changesect() vs. sprite.changesect()
79        local sectnum = spr.sectnum
80
81        for i=0,gv.numsectors-1 do
82            if (spr.pal ~= 2 and spr.pal ~= 7) then
83                sprite.changesect(aci, i)  -- noticeably faster...
84            else
85                spr:changesect(i)  -- ...than this
86            end
87        end
88
89        sprite.changesect(aci, sectnum)
90    end
91}
92
93local CS = sprite.CSTAT
94local SPAWNSPERTIC = 10  --> 300/second --> 18000 per minute
95local TWOPI = 2*math.pi
96
97gameactor
98{
99    D.NUKEBUTTON+3,  -- destroyed end-of-level nuke switch
100
101    function(aci)
102        local spr = sprite[aci]
103
104        for pi in player.all() do
105            -- XXX: how to emulate "use switch" distance checking code, but in
106            -- an actor-centric fashion?
107            if (not nukeswStart[aci] and player.holdskey(pi, "OPEN")
108                    and (player[pi].pos - spr):len2sq() < 256^2) then
109                -- Enable us.
110                nukeswStart[aci] = gv.gametic
111                spr.cstatbits:clear(CS.TRANS_BITMASK)
112                spr.cstatbits:set(CS.TRANS1)
113                break
114            end
115        end
116
117        local startgtic = nukeswStart[aci]
118        if (not startgtic) then
119            return
120        end
121
122        local hei, zofs = spr:getheightofs()
123        local radius = hei/2
124
125        for i=0,SPAWNSPERTIC-1 do
126            -- Make one second go once round the circle, spawning
127            -- SPAWNSPERTIC*GTICSPERSEC stars.
128            local ii = ((gv.gametic*SPAWNSPERTIC)%(GTICSPERSEC*SPAWNSPERTIC)) + i
129            local v = (radius/16)*angvec(ii*TWOPI/(GTICSPERSEC*SPAWNSPERTIC))
130            local circvec = xmath.vec3(0, v.x, 16*v.y):rotate(spr.ang)
131            local pos = spr^(zofs + radius) + 256*bangvec(spr.ang) + circvec
132
133            con.insertsprite{D.TRANSPORTERSTAR+4, pos, spr.sectnum, actor.STAT.ACTOR, aci,
134                             xrepeat=3, yrepeat=3, ang=spr.ang}
135        end
136    end
137}
138