source: trunk/luarules/gadgets/mo_armageddon.lua @ 5877

Revision 2586, 7.0 KB checked in by Bluestone, 5 years ago (diff)

tweak armageddon

Line 
1
2function gadget:GetInfo()
3    return {
4        name      = 'Armageddon',
5        desc      = 'Implements armageddon modoption',
6        author    = 'Niobium, Bluestone',
7        version   = 'v1.0',
8        date      = '11/2013',
9        license   = 'GNU GPL, v2 or later',
10        layer     = 0,
11        enabled   = true
12    }
13end
14
15----------------------------------------------------------------
16-- Synced only
17----------------------------------------------------------------
18if not gadgetHandler:IsSyncedCode() then
19    return false
20end
21
22----------------------------------------------------------------
23-- Load?
24----------------------------------------------------------------
25local armageddonFrame = 60 * 30 * (tonumber((Spring.GetModOptions() or {}).mo_armageddontime) or 0) --mo_armageddontime is in minutes
26local armageddonDuration = 12
27
28if armageddonFrame <= 0 then
29    return false
30end
31
32----------------------------------------------------------------
33-- Callins
34----------------------------------------------------------------
35
36local toKillUnits = {}
37local toKillFrame = {}
38local toKill = {}
39
40local isArmageddon = false
41local hadArmageddon = false
42
43local gaiaTeamID = Spring.GetGaiaTeamID()
44 
45local spGetUnitDefID    = Spring.GetUnitDefID
46local spValidUnitID             = Spring.ValidUnitID
47local spDestroyUnit             = Spring.DestroyUnit
48local spGetGameFrame    = Spring.GetGameFrame
49
50local numX = Game.mapX-1
51local numZ = Game.mapY-1
52local nSquares = numX*numZ
53
54local meteorDefID = UnitDefNames["meteor"].id
55local METEOR_EXPLOSION = WeaponDefNames["meteor_weapon"].id
56local nextStrike = armageddonFrame
57local meteorStrike = math.max(10,math.sqrt(15*math.floor(numX*numZ)))
58local pStrike = meteorStrike / (armageddonDuration * 30)
59
60
61local meteorCount = {}
62for x=1,numX do
63meteorCount[x] = {}
64for z=1,numZ do
65meteorCount[x][z] = 1 -- start with all at 1, so as not to divide by 0
66end
67end
68
69function RandomCoordInSquare(sx,sz)
70        local x = 512 * sx + math.random(512)
71        local z = 512 * sz + math.random(512)
72        return x,z
73end
74 
75function FireMeteor()
76    -- sample square, with a bias towards squares that haven't been hit much
77    local nMost = 0
78    local nTotal = 0
79    local chanceOfSquare = {}
80    for x=1,numX do
81    for z=1,numZ do
82        if nMost < meteorCount[x][z] then
83            nMost = meteorCount[x][z]
84        end
85    end
86    end
87    local id = 1
88    local N = 0
89    for x=1,numX do
90    for z=1,numZ do
91        chanceOfSquare[id] = {p=nMost+1-meteorCount[x][z], x=x, z=z}
92        N = N + chanceOfSquare[id].p
93        id = id + 1
94    end
95    end
96    local sq = math.random(1,N)
97    local c = 1
98    for i,v in ipairs(chanceOfSquare) do
99        c = c + v.p
100        if sq <= c then
101            id = i --found the winning square, (distribution v -> v.p/N)
102            break
103        end
104    end
105    local sx = chanceOfSquare[id].x
106    local sz = chanceOfSquare[id].z
107   
108    -- fire
109    local x,z = RandomCoordInSquare(sx,sz)
110    local y = Spring.GetGroundHeight(x,z)
111    Spring.CreateUnit(meteorDefID, x, y, z, "north", gaiaTeamID)
112end
113 
114function gadget:GameFrame(n)
115        -- cause the armageddon; kill everything immobile
116    if n == armageddonFrame - 1 then
117                isArmageddon = true
118                hadArmageddon = true
119        local allUnits = Spring.GetAllUnits()
120        local unitID,unitDefID
121                for i = 1, #allUnits do
122                        unitID = allUnits[i]
123                        unitDefID = spGetUnitDefID(unitID)
124                        if UnitDefs[unitDefID].isImmobile then
125                                toKillUnits[#toKillUnits+1] = unitID
126                                toKillFrame[#toKillFrame+1] = armageddonFrame + math.floor(armageddonDuration * 30 * math.random())
127                        end
128        end
129    elseif n >= armageddonFrame and n <= armageddonFrame + armageddonDuration * 30 + 1 then
130        -- explode immobile units
131                for i = 1, #toKillUnits do
132                        if n == toKillFrame[i] then
133                                if spValidUnitID(toKillUnits[i]) then
134                                        spDestroyUnit(toKillUnits[i],true) --boom!
135                                end
136                        end
137        end 
138        elseif n == armageddonFrame + (armageddonDuration + 1) * 30 then
139                isArmageddon = false
140        end
141       
142    -- meteor shower
143    if n>=armageddonFrame then
144        if n==argmageddonFrame then
145            FireMeteor()   
146        elseif n > armageddonFrame and n <= armageddonFrame + 6*30 then
147            if math.random() < pStrike/4 then
148                FireMeteor()
149            end
150        elseif n > armageddonFrame + 6*30 and  n <= armageddonFrame + 10*30 then
151            if math.random() < pStrike/2 then
152                FireMeteor()
153            end
154        elseif n > armageddonFrame + 10*30 and n <= armageddonFrame + 14*30 then
155            if math.random() < pStrike then
156                FireMeteor()
157            end
158        elseif n > armageddonFrame + 14*30 and n <= armageddonFrame + 18*30 then
159            if math.random() < pStrike/3 then
160                FireMeteor()
161            end
162        end
163    end
164   
165    -- keep firing meteors, slower rate
166    if n == nextStrike then
167        FireMeteor()
168        nextStrike = nextStrike + 5 * math.random(25) --about twice every second
169    end
170   
171        -- kill anything that is created (as instructed by UnitFinished)
172        if toKill[n] then
173                for i=1,#(toKill[n]) do
174                        if spValidUnitID(toKill[n][i]) then
175                                spDestroyUnit(toKill[n][i],true)
176                        end
177                end
178                toKill[n] = nil
179        end
180end
181
182function gadget:UnitPreDamaged(unitID, unitDefID, unitTeam, damage, paralyzer, weaponDefID, projectileID, attackerID, attackerDefID, attackerTeam)
183        if isArmageddon then
184        --coms must survive & need protecting until the explosions are over
185        if UnitDefs[unitDefID].customParams.iscommander == "1" then
186            local h, mh = Spring.GetUnitHealth(unitID)
187            if h <= mh/4 then
188                return 0
189            else
190                return h/4
191            end
192        end
193        --anything immobile that gets hit by a meteor explodes
194        if UnitDefs[unitDefID].isImmobile and weaponDefID == METEOR_EXPLOSION then
195            if spValidUnitID(unitID) then
196                spDestroyUnit(unitID,true)
197            end
198        end
199    end
200end
201
202
203function gadget:UnitFinished(unitID, unitDefID, teamID, builderID)
204        if hadArmageddon and unitDefID~=meteorDefID then
205                local n = spGetGameFrame()
206                if not toKill[n+1] then toKill[n+1] = {} end
207                local k = #(toKill[n+1])+1
208                toKill[n+1][k] = unitID --destroying units on the same simframe as they are created is a bad idea
209        end
210end
211
212function gadget:UnitCreated(unitID, unitDefID, teamID, builderID)
213    -- make sure meteors die & make sure they don't show up as "proper" units
214    if unitDefID==meteorDefID then
215        n = spGetGameFrame()
216        local m = n+3*30+2
217        if not toKill[m] then toKill[m] = {} end
218        local k = #(toKill[n+3*30+2])+1
219        toKill[n+3*30+2][k] = unitID --just to make sure, although its own explosion should kill it on the frame before
220       
221        Spring.SetUnitNoDraw(unitID, true)
222                Spring.SetUnitStealth(unitID, true)
223                Spring.SetUnitSonarStealth(unitID, true)
224        Spring.SetUnitNeutral(unitID, true)
225    end
226end
Note: See TracBrowser for help on using the repository browser.