· 7 years ago · Sep 30, 2018, 07:56 AM
1--##****************************************************
2--##** ZONE CONTROL FOR SUPREME COMMANDER **
3--##** BY SAYA **
4--##** V 1.0 BETA **
5--##****************************************************
6
7-- MAP BY ANGRY ZEALOT
8
9--scenario utilities
10local ScenarioUtils = import('/lua/sim/ScenarioUtilities.lua')
11local ScenarioFramework = import('/lua/ScenarioFramework.lua')
12local Utilities = import('/lua/utilities.lua')
13
14--interface utilities
15local UIUtil = import('/lua/ui/uiutil.lua')
16local gameParent = import('/lua/ui/game/gamemain.lua').GetGameParent()
17
18--TRIGGER TABLES
19local bunkerDeath = {}
20local unitDeath = {}
21
22
23--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~GAME VARIABLES~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24
25
26local executing = false
27local mainBeatTime = 1
28local spawnBeatTime = 5
29
30
31--PLAYERS, CONTAINS USEFUL INFO FOR THE SCRIPT FOR EACH PLAYER
32local playersDATA = {
33 ['player1'] = {
34 name = 'player1',
35 kills = 0,
36 bunkerType = 'ueb2301',
37 zonecontrol = 1,
38 attack = 0,
39 defence = 0,
40 upgrades = 1,
41 level = 0,
42 money = 0,
43 infoUnit = false,
44 attackUnit = false,
45 defenceUnit = false,
46 upgrader = false,
47 kamikazeShop = false,
48 startLocation = {1,4},
49 baseTemplate = {info = {8,42}, attack = {8,20}, defence = {30,42}, upgrader = {20,30},
50 kamikazeShop = {32,18}},
51 defeated = false,
52 },
53 ['player2'] = {
54 name = 'player2',
55 kills = 0,
56 bunkerType = 'ueb2301',
57 zonecontrol = 1,
58 attack = 0,
59 defence = 0,
60 upgrades = 1,
61 level = 0,
62 money = 0,
63 infoUnit = false,
64 attackUnit = false,
65 defenceUnit = false,
66 upgrader = false,
67 kamikazeShop = false,
68 startLocation = {2,1},
69 baseTemplate = {info = {8,8}, attack = {8,30}, defence = {30,8}, upgrader = {20,20},
70 kamikazeShop = {32,32}},
71 defeated = false,
72 },
73 ['player3'] = {
74 name = 'player3',
75 kills = 0,
76 bunkerType = 'ueb2301',
77 zonecontrol = 1,
78 attack = 0,
79 defence = 0,
80 upgrades = 1,
81 level = 0,
82 money = 0,
83 infoUnit = false,
84 attackUnit = false,
85 defenceUnit = false,
86 upgrader = false,
87 kamikazeShop = false,
88 startLocation = {5,2},
89 baseTemplate = {info = {42,8}, attack = {20,8}, defence = {42,30}, upgrader = {30,20},
90 kamikazeShop = {18,32}},
91 defeated = false,
92 },
93 ['player4'] = {
94 name = 'player4',
95 kills = 0,
96 bunkerType = 'ueb2301',
97 zonecontrol = 1,
98 attack = 0,
99 defence = 0,
100 upgrades = 1,
101 level = 0,
102 money = 0,
103 infoUnit = false,
104 attackUnit = false,
105 defenceUnit = false,
106 upgrader = false,
107 kamikazeShop = false,
108 startLocation = {4,5},
109 baseTemplate = {info = {42,42}, attack = {42,20}, defence = {20,42}, upgrader = {30,30},
110 kamikazeShop = {18,18}},
111 defeated = false,
112 },
113 ['neutral'] = {
114 name = 'neutral',
115 kills = 0,
116 bunkerType = 'urb2301',
117 zonecontrol = 0,
118 attack = 0,
119 defence = 0,
120 upgrades = 1,
121 level = 0,
122 money = 0,
123 infoUnit = false,
124 attackUnit = false,
125 defenceUnit = false,
126 kamikazeShop = false,
127 upgrader = false,
128 defeated = false,
129 },
130}
131
132local players = {}
133
134local defeatcount = 0
135local gameEnd = false
136local beat = 0
137
138
139
140local armyTable = {
141 ['ARMY_1'] = 'player1',
142 ['ARMY_2'] = 'player2',
143 ['ARMY_3'] = 'player3',
144 ['ARMY_4'] = 'player4',
145 ['ARMY_5'] = 'player5',
146 ['ARMY_6'] = 'player6',
147 ['ARMY_7'] = 'player7',
148 ['ARMY_8'] = 'player8',
149 ['ARMY_9'] = 'neutral',
150}
151
152
153local upgradeList = {
154 ['LEVEL 1'] = { level = 1, kills = 50, upgrade = 2, description = 'LEVEL 1: TANK 400 HP'},
155 ['LEVEL 2'] = { level = 2, kills = 150, upgrade = 3, description = 'LEVEL 2: PILLAR 600 HP'},
156 ['LEVEL 3'] = { level = 3, kills = 400, upgrade = 7, description = 'LEVEL 3: ASSAULT BOT 1400 HP'},
157 ['LEVEL 4'] = { level = 4, kills = 700, upgrade = 7, description = ''},
158 ['LEVEL 5'] = { level = 5, kills = 1000, upgrade = 7, description = ''},
159}
160
161local unitUpgradeList = {
162 ['LEVEL 0'] = 'UEL0106',--level 0: mech marine
163 ['LEVEL 1'] = 'UEL0201',--level 1: striker
164 ['LEVEL 2'] = 'UEL0202',--level 2: pillar
165 ['LEVEL 3'] = 'UEL0303',--level 3: assault bot
166 ['LEVEL 4'] = 'UEL0303',--level 4: assault bot
167 ['LEVEL 5'] = 'UEL0303',--level 5: assault bot
168}
169
170
171
172--create areas on the map
173local zones = {}
174local xzonesize = 50
175local yzonesize = 50
176local xmapsize = ScenarioInfo.size[1]
177local ymapsize = ScenarioInfo.size[2]
178local x = 0
179local y = 0
180
181--number of zones on the X axis
182local imax = math.floor(xmapsize / xzonesize)
183--number of zones on the Y axis
184local jmax = math.floor(ymapsize / yzonesize)
185
186
187local mainBunkerType = 'ueb2301'
188
189
190
191
192--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~UTILITY FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
193
194--given a player returns an army
195toArmy = function(player)
196 local army = false
197 for i,v in armyTable do
198 if v == player.name then
199 army = i
200 end
201 end
202 return army
203end
204
205
206--given a player returns a proper username
207username = function(player)
208 return GetArmyBrain(toArmy(player)).Nickname
209end
210
211--given a player returns the number of kills
212armyKills = function(player)
213 local kills = 0
214 if player.name != 'neutral' then
215 local army = toArmy(player)
216 kills = GetArmyBrain(army):GetArmyStat('Enemies_Killed',0.0).Value
217 end
218 return kills
219end
220
221--print a text scn way :p
222--first arg is the text to print
223--second arg is what player it concerns
224--third arg is if it has to be printed to that player only or to all players
225scnPrint = function(text,player,playeronly)
226
227 local army = toArmy(player)
228 local colorIndex = ScenarioInfo.ArmySetup[army].PlayerColor
229 local color = import('/lua/GameColors.lua').GameColors.ArmyColors[colorIndex]
230
231 -- WARN(army)
232 -- WARN(GetFocusArmy())
233 -- WARN(color)
234 -- WARN(text)
235
236 if not playeronly then
237 playerspecific = false
238 else
239 playerspecific = playeronly
240 end
241
242
243 if playerspecific == true then
244 if army == indexToArmy(GetFocusArmy()) then
245 PrintText(text,20,color,spawnBeatTime,'center')
246 end
247 else
248 PrintText(text,20,color,spawnBeatTime,'center')
249 end
250end
251
252--given a unit returns the army
253scnArmy = function(unit)
254 local armyIndex = unit:GetArmy()
255 return indexToArmy(armyIndex)
256end
257
258--given an army index returns an army
259--more efficient but does not work yet
260indexToArmy = function(armyIndex)
261 local army = ListArmies()[armyIndex]
262 return army
263end
264
265--get the number of players
266playerCount = function()
267 local i = 0
268 for index, player in players do
269 i = i + 1
270 end
271 return i
272end
273
274
275
276
277
278
279
280
281--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MAIN SCRIPT FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
282
283--populating
284function OnPopulate()
285 InitializeArmies()
286 ScenarioFramework.SetPlayableArea('Playfield', false)
287 import('/lua/SimUtils.lua').GiveUnitsToPlayer = function() end
288end
289
290
291--start of map script
292function OnStart(self)
293 -- force victory condition to sandbox
294 ScenarioInfo.Options.Victory = 'sandbox'
295
296 -- set score calculation to show total kills
297 for index, brain in ArmyBrains do
298 brain.CalculateScore = function(thisBrain)
299 return thisBrain:GetArmyStat("Enemies_Killed", 0.0).Value
300 end
301 end
302
303 --initialise scenario
304 ScenarioFramework.SetPlayableArea('Playfield', false)
305 Utilities.UserConRequest("ui_ForceLifbarsOnEnemy")--show enemy life bars
306 initialiseZones()
307
308 --initialise player zone control
309 for index, player in players do
310 if player.startLocation != nil then
311 changeOwner(zones[player.startLocation[1]][player.startLocation[2]],player.name)
312 end
313 end
314
315 --spawn start bunkers
316 spawnBunkers()
317
318 --spawn start info units
319 spawnUtilityUnits()
320
321 --start the different scenario threads
322 startScenarioThreads()
323end
324
325--creates the different threads
326startScenarioThreads = function()
327 --start main thread
328 local mainThread = ForkThread(function(self)
329 while gameEnd == false do
330 --call main thread beat
331 mainThreadBeat()
332 --wait time between each beat
333 WaitSeconds(mainBeatTime)
334 end
335 KillThread(self)
336 end)
337
338 --check for upgrades in a separate thread for better reaction time
339 local spawnThread = ForkThread(function(self)
340 while gameEnd == false do
341 --call spawn thread beat
342 spawnThreadBeat()
343 --wait time between each beat
344 WaitSeconds(spawnBeatTime)
345 --increment beat count
346 beat = beat + 1
347 end
348 KillThread(self)
349 end)
350end
351
352--MAIN SCENARIO THREAD
353--do map script actions every TICK
354--this thread does all the checking of upgrade requests, zone ownership change and victory conditions?
355mainThreadBeat = function()
356 checkUpgrades()
357 checkZones()
358 checkVictoryConditions()
359 copyPlayerInfo()
360end
361
362--this thread spawns units
363spawnThreadBeat = function()
364 spawnUnits()
365end
366
367--copy the map script variables into the aibrains so that the zone control ai can use them
368copyPlayerInfo = function()
369 for i, player in players do
370 GetArmyBrain(toArmy(player)).ZCInfo = table.copy(players)
371 end
372end
373
374
375
376
377--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MAIN THREAD FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
378
379--check for end game conditions
380checkVictoryConditions = function()
381 --check for defeat
382 for index, player in players do
383 --LOG(player.zonecontrol)
384 if player.zonecontrol == 0 and player.defeated == false then
385 player.defeated = true
386 GetArmyBrain(toArmy(player)):OnDefeat()
387 end
388 end
389 --check for victory
390 if gameEnd == false then
391 local playersUndefeated = {}
392
393 --create a table with all undefeated players
394 for index, player in players do
395 if player.defeated == false and player.name != 'neutral' then
396 table.insert(playersUndefeated,player)
397 end
398 end
399
400 --check the alliances of the undefeated players and the number of undefeated players to determine if they must be victorious or not
401 for index, player in playersUndefeated do
402 if table.getn(playersUndefeated) == 1 then
403 local army1 = toArmy(playersUndefeated[1])
404 GetArmyBrain(army1):OnVictory()
405 gameEnd = true
406 elseif table.getn(playersUndefeated) == 2 then
407 local army1 = toArmy(playersUndefeated[1])
408 local army2 = toArmy(playersUndefeated[2])
409 if IsAlly(army1, army2) == true then
410 GetArmyBrain(army1):OnVictory()
411 GetArmyBrain(army2):OnVictory()
412 gameEnd = true
413 end
414 elseif table.getn(playersUndefeated) == 3 then
415 local army1 = toArmy(playersUndefeated[1])
416 local army2 = toArmy(playersUndefeated[2])
417 local army3 = toArmy(playersUndefeated[3])
418 if IsAlly(army1, army2) == true and IsAlly(army2, army3) == true then
419 GetArmyBrain(army1):OnVictory()
420 GetArmyBrain(army2):OnVictory()
421 GetArmyBrain(army3):OnVictory()
422 gameEnd = true
423 end
424 end
425 end
426
427 end
428end
429
430
431
432
433
434--CHECK IF UPGRADES ARE NECESSARY, APPLY THEM
435checkUpgrades = function()
436
437 --Check for kill triggered upgrades
438 for levelindex,level in upgradeList do
439 for index,player in players do
440 if armyKills(player) >= level.kills then
441 upgrade(player,levelindex)
442 end
443 end
444 end
445
446 --Check for area triggered upgrades
447 checkUpgradeRequests()
448end
449
450
451
452--SPAWN UNITS ON ALL ZONES DEPENDING ON OWNERSHIP
453spawnUnits = function()
454 local i = 1
455 while i <= imax do
456 local j = 1
457 while j <= jmax do
458 if (i > 1 and i < 5) or (j > 1 and j<5) then
459 spawnUnit(zones[i][j])
460 end
461 j = j + 1
462 end
463 i = i + 1
464 end
465end
466
467
468--SPAWN BUNKERS AT START
469spawnBunkers = function()
470 local i = 1
471 while i <= imax do
472 local j = 1
473 while j <= jmax do
474 if (i > 1 and i < 5) or (j > 1 and j<5) then
475 spawnBunker(zones[i][j])
476 end
477 j = j + 1
478 end
479 i = i + 1
480 end
481end
482
483--CHECK OWNERSHIP ON ALL ZONES
484checkZones = function()
485 local i = 1
486 while i <= imax do
487 local j = 1
488 while j <= jmax do
489 if (i > 1 and i < 5) or (j > 1 and j<5) then
490 checkZone(zones[i][j])
491 end
492 j = j + 1
493 end
494 i = i + 1
495 end
496end
497
498--make all zones
499initialiseZones = function()
500 local i = 1
501 while i <= imax do
502 local j = 1
503 zones[i] = {}
504 bunkerDeath[i] = {}
505 while j <= jmax do
506 if (i > 1 and i < 5) or (j > 1 and j<5) then
507 zones[i][j] = createZone(i,j)
508 end
509 j = j + 1
510 end
511 i = i + 1
512
513 end
514end
515
516
517
518
519
520
521
522
523
524
525
526
527--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ZONE MANAGING FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
528--zone constructor
529createZone = function(i,j)
530 --create zone at (i, j) coordonates
531 local zone = {owner = 'neutral', x = i, y = j, Xsize = xzonesize, Ysize = yzonesize, hasBunker = false}
532
533 --create zone rectangle
534 zone.rectangle = {}
535 zone.rectangle.x0 = (zone.x - 1) * zone.Xsize + 1
536 zone.rectangle.y0 = (zone.y - 1) * zone.Ysize + 5
537 zone.rectangle.x1 = zone.rectangle.x0 + zone.Xsize
538 zone.rectangle.y1 = zone.rectangle.y0 + zone.Ysize
539
540 --generate ,bunker death trigger functions
541 bunkerDeath[i][j] = function()
542 --acknowledge bunker destruction and refresh zone count
543 zone.hasBunker = false
544 removeZone(zone.owner)
545 end
546
547 return zone
548end
549
550--given a zone, returns the position of its center
551zoneCenter = function(zone)
552 local center = {}
553 center.x = zone.x * zone.Xsize - ( zone.Xsize / 2) + 1
554 center.y = zone.y * zone.Ysize - ( zone.Ysize / 2) + 5
555 return center
556end
557
558
559--change the owner of a zone
560changeOwner = function(zone,newowner)
561 zone.owner = newowner
562end
563
564--returns the player that owns the zone
565owner = function(zone)
566 return players[zone.owner]
567end
568
569
570--CHECK ZONE OWNERSHIP, CHANGE IT IF NECESSARY
571checkZone = function(zone)
572 --IF ZONE CONTAINS A BUNKER DO NOT CHECK: DONE
573 --IF ZONE CONTAINS ONLY UNITS FROM 1 PLAYER AND PLAYER != OWNER THEN OWNER = PLAYER
574 --CREATE A BUNKER FOR THE NEW OWNER: DONE
575
576 --if zone does not have a bunker
577 if zone.hasBunker == false then --and zone.owner == 'neutral' then
578 --find new owner
579 local ownerfound = refreshOwner(zone)
580 --spawn bunker on zone
581 if zone.owner != 'neutral' and ownerfound == true then
582 spawnBunker(zone)
583 --add zone to owner
584 addZone(zone.owner)
585 end
586
587 end
588
589end
590
591--FIND NEW OWNER FOR ZONE
592refreshOwner = function(zone)
593 local ownerfound = false
594
595 --LOG(repr(zone.rectangle))
596
597 local ally = toArmy(owner(zone))
598 local count = { ['ARMY_1'] = 0, ['ARMY_2'] = 0, ['ARMY_3'] = 0, ['ARMY_4'] = 0, ['ARMY_9'] = 0}
599 local enemyCount = 0
600 local allyCount = 0
601
602 --get units in zone
603 local unitsInZone = GetUnitsInRect(zone.rectangle)
604
605
606
607 --get army counts in zone
608 if unitsInZone then
609 for k,unit in unitsInZone do
610 if not unit:IsDead() then
611 local army = ''
612 if unit:GetArmy() == playerCount() then
613 army = 'ARMY_9'
614 else
615 army = scnArmy(unit)
616 end
617
618 count[army] = count[army] + 1
619 if army != ally and IsAlly(ally, army) == false then
620 enemyCount = enemyCount + 1
621 else
622 allyCount = allyCount + 1
623 end
624 end
625 end
626 end
627
628 --determine new owner depending on army count
629 --zone owner retakes ownership
630 if allyCount >= 10 and enemyCount == 0 then
631 ownerfound = true
632 --attacker captures zones
633 elseif allyCount <= 5 then
634 local maxcountArmy = false
635 local maxvalue = 0
636 local draw = false
637
638 --find army with most troops on zone
639 for army,value in count do
640 if maxcountArmy == false then
641 maxcountArmy = army
642 end
643 if value > maxvalue then
644 maxvalue = value
645 maxcountArmy = army
646 elseif value == maxvalue and value != 0 then
647 draw = true
648 end
649 end
650
651 --if the army with more troops has more than 5 troops then capture the zone
652 if count[maxcountArmy] >= 5 and draw == false then
653 zone.owner = armyTable[maxcountArmy]
654 ownerfound = true
655 end
656
657
658 end
659
660 return ownerfound
661end
662
663
664--add zone to count of player
665addZone = function(playername)
666 players[playername].zonecontrol = players[playername].zonecontrol + 1
667 --instigator:GetAIBrain():GiveResource('MASS', mamount)
668 --armyTable:GetAIBrain():GiveResource('ENERGY', eamount)
669 --GetArmyBrain(toArmy(players[playername])):GiveResource('MASS', 1)
670 --LOG("" .. players[player].name .."ZONE CONTROL: " .. players[player].zonecontrol)
671end
672
673--remove zone from count of player
674removeZone = function(playername)
675 players[playername].zonecontrol = players[playername].zonecontrol - 1
676 --GetArmyBrain(toArmy(players[playername])):TakeResource('MASS', 1)
677 --self:GetAIBrain():TakeResource('Energy', self:GetBlueprint().Economy.StorageEnergy)
678 --LOG("" .. players[player].name .."ZONE CONTROL: " .. players[player].zonecontrol)
679end
680
681--returns a valid spot to spawn a unit for a player in case he doesnt own his start location anymore
682findZone = function(player)
683 local startzone = zones[player.startLocation[1]][player.startLocation[2]]
684 local properzone = startzone
685
686 --if the player does not own his start zone anymore
687 if startzone.owner != player.name then
688 local mindistance = VDist2(1,1,imax,jmax) --initialise the minimum distance with the maximum value
689
690 for i,zoneline in zones do
691 for j,zone in zoneline do --calculate the minimal distance and save the corresponding zone
692 if zone.owner == player.name then
693 zonedistance = VDist2(startzone.x, startzone.y, i, j)--math.sqrt( (i-startzone.x)*(i-startzone.x) + (j - startzone.y)*(j - startzone.y))
694 if zonedistance < mindistance then
695 properzone = zone
696 mindistance = zonedistance
697 --LOG("temp min distance: " .. mindistance .. " for zone(" .. zone.x .. ")(".. zone.y .. ")")
698 end
699 end
700 end
701 end
702 end
703
704 return properzone
705end
706
707
708
709
710
711
712--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~UNIT SPAWNING FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
713
714
715--spawns a bunker on a zone
716spawnBunker = function(zone)
717 --SPAWN UNIT ON ZONE DEPENDING ON PLAYER OWNERSHIP
718 --SPAWN NO UNIT IF ZONE IS NEUTRAL
719 local x = zoneCenter(zone).x
720 local y = zoneCenter(zone).y
721 local player = owner(zone)
722 local army = toArmy(player)
723
724 zone.bunker = false
725
726 --spawn bunker if not population limit
727 if GetArmyUnitCostTotal(GetArmyBrain(army):GetArmyIndex()) < GetArmyUnitCap(GetArmyBrain(army):GetArmyIndex()) then
728 if zone.x == player.startLocation[1] and zone.y == player.startLocation[2] then
729 zone.bunker = CreateUnitHPR( mainBunkerType, toArmy(player), x,y,y, 0,0,0)
730 else
731 zone.bunker = CreateUnitHPR( player.bunkerType, toArmy(player), x,y,y, 0,0,0)
732 end
733 end
734
735 --if bunker exists apply balance changes and upgrades
736 if zone.bunker != false then
737 zone.hasBunker = true
738
739 if zone.owner == 'neutral' then
740 zone.bunker:SetMaxHealth(600)
741 zone.bunker:SetHealth(zone.bunker,600)
742 else
743 zone.bunker:SetMaxHealth(5000 + 1000*player.defence)
744 zone.bunker:SetHealth(nil,5000 + 1000*player.defence)
745 zone.bunker:SetRegenRate(2*player.defence*player.defence)
746
747 for i = 1, zone.bunker:GetWeaponCount() do
748 zone.bunker:GetWeapon(i):ChangeRateOfFire(1 + player.defence/4)
749 zone.bunker:GetWeapon(i):AddDamageMod(10*player.defence + 5*player.defence*player.defence)
750 end
751
752 zone.bunker:SetCustomName(username(player) .. ', level ' .. player.defence)
753
754 addBunkerKillCount(zone.bunker)
755 end
756 zone.bunker:GetWeapon(1):ChangeMaxRadius(30)
757 --disable wreckage
758 zone.bunker:GetBlueprint().Wreckage.WreckageLayers.Land=false
759 --death trigger
760 ScenarioFramework.CreateUnitDeathTrigger(bunkerDeath[zone.x][zone.y],zone.bunker)
761
762 ForkThread(function() playBuildEffect(zone.bunker) end)
763 end
764
765end
766
767--ADD A KILL COUNT TO A BUNKER
768--defender gets more money than attacker, a kill made by a bunker gives 10 instead of 5 for a regular kill
769addBunkerKillCount = function(unit)
770 --kill count
771 unit.OldOnKilledUnit = unit.OnKilledUnit
772 unit.OnKilledUnit = function(self, unitKilled)
773 local player = players[armyTable[scnArmy(self)]]
774 local enemy = players[armyTable[scnArmy(unitKilled)]]
775 --if the unit did not commit suicide
776 if self:GetArmy() != unitKilled:GetArmy() then
777 player.kills = player.kills + 1
778 if enemy.level == 2 then
779 player.money = player.money + 15
780 elseif enemy.level >= 3 then
781 player.money = player.money + 20
782 else
783 player.money = player.money + 10
784 end
785 --update display
786 updateInfo(player)
787 --GetArmyBrain(toArmy(player)):GiveResource('ENERGY', 10000)
788 end
789 unit.OldOnKilledUnit(self, unitKilled)
790 end
791end
792
793
794--SPAWN UNIT ON ZONE
795spawnUnit = function(zone)
796 --SPAWN UNIT ON ZONE DEPENDING ON PLAYER OWNERSHIP
797 --SPAWN NO UNIT IF ZONE IS NEUTRAL
798 local x = zoneCenter(zone).x
799 local y = zoneCenter(zone).y
800 local unit = false
801 local player = owner(zone)
802 local army = toArmy(player)
803 local unitType = unitUpgradeList['LEVEL ' .. player.level]
804
805 local xside = math.random(0,1)
806 local yside = math.random(0,1)
807 local xoff = 0
808 local yoff = 0
809
810 if zone.hasBunker == false then
811 elseif zone.owner != 'neutral' then
812 --check unit cap to avoid bug
813 if GetArmyUnitCostTotal(GetArmyBrain(army):GetArmyIndex()) < GetArmyUnitCap(GetArmyBrain(army):GetArmyIndex()) then
814 --adjust spawn rate depending on level
815 if player.level <= 1 then --low level units spawn every tick
816 --unit = CreateUnitHPR( unitType, army, x,25,y+3, 0,0,0)
817 unit = CreateUnitHPR( unitType, army, x+(-1+xside*2),25,y+(-1+yside*2), 0,0,0)
818 elseif player.level == 2 then -- pillars spawn 1 time out of 2
819 if math.mod(beat,2) == 0 then
820 --unit = CreateUnitHPR( unitType, army, x,25,y+3, 0,0,0)
821 unit = CreateUnitHPR( unitType, army, x+(-1+xside*2),25,y+(-1+yside*2), 0,0,0)
822 end
823 elseif player.level >=3 then -- siege bots spawn 1 time out of 3
824 if math.mod(beat,3) == 0 then
825 --unit = CreateUnitHPR( unitType, army, x,25,y+3, 0,0,0)
826 unit = CreateUnitHPR( unitType, army, x+(-1+xside*2),25,y+(-1+yside*2), 0,0,0)
827 end
828 end
829 end
830 end
831
832 --if unit exists apply unit balance changes and upgrades
833 if unit != false then
834 addKillCount(unit)
835
836 unit:DestroyShield()
837 unit:SetMaxHealth(200*upgrades(zone)+50*player.attack)
838 unit:SetHealth(nil,200*upgrades(zone)+50*player.attack)
839
840 --thanks to UArchitect
841 --disable wreckage as way too many of the stuff appears..decals are enough, (wouldnt be so bad if i could make them slowly sink into the ground after a while)
842 unit:GetBlueprint().Wreckage.WreckageLayers.Land=false
843
844 for i = 1, unit:GetWeaponCount() do
845 unit:GetWeapon(i):AddDamageMod(5*player.attack)
846 end
847
848 unit:SetSpeedMult(2)
849 unit:SetAccMult(3)
850 unit:SetTurnMult(3)
851 --ScenarioFramework.CreateUnitDeathTrigger(unitDeath[zone.owner],unit)
852 --move unit after being created
853
854 --thanks to UArchitect
855 --add randomness stuff to the move order
856 xoff = -8 + xside*16
857 yoff = -8 + yside*16
858
859 xoff = xoff + -2 + math.random(0,1)*4
860 yoff = yoff + -2 + math.random(0,1)*4
861
862 IssueMove( {unit}, {x+xoff,25,y+yoff} )
863 --IssueMove( {unit}, {x,25,y+8} )
864
865 end
866end
867
868--ADD A KILL COUNT TO A UNIT
869addKillCount = function(unit)
870 --kill count
871 unit.OldOnKilledUnit = unit.OnKilledUnit
872 unit.OnKilledUnit = function(self, unitKilled)
873 local player = players[armyTable[scnArmy(self)]]
874 local enemy = players[armyTable[scnArmy(unitKilled)]]
875 --if the unit did not commit suicide
876 if self:GetArmy() != unitKilled:GetArmy() then
877 player.kills = player.kills + 1
878 if enemy.level == 2 then
879 player.money = player.money + 10
880 elseif enemy.level >= 3 then
881 player.money = player.money + 15
882 else
883 player.money = player.money + 5
884 end
885 --update display
886 updateInfo(player)
887 --GetArmyBrain(toArmy(player)):GiveResource('ENERGY', 10000)
888 end
889 unit.OldOnKilledUnit(self, unitKilled)
890 end
891end
892
893
894--UNIT DEATH TRIGGERS
895unitDeath['player1'] = function()
896 --players['player1'].deaths = players['player1'].deaths + 1
897 WARN('player1')
898 WARN('index: ' .. GetArmyBrain(toArmy(players['player1'])):GetArmyIndex())
899end
900
901unitDeath['player2'] = function()
902 --players['player2'].deaths = players['player2'].deaths + 1
903 WARN('player2')
904 WARN('index: ' .. GetArmyBrain(toArmy(players['player2'])):GetArmyIndex())
905end
906
907unitDeath['player3'] = function()
908 --players['player3'].deaths = players['player3'].deaths + 1
909 WARN('player3')
910 WARN('index: ' .. GetArmyBrain(toArmy(players['player3'])):GetArmyIndex())
911end
912
913unitDeath['player4'] = function()
914 --players['player4'].deaths = players['player4'].deaths + 1
915 WARN('player4')
916 WARN('index: ' .. GetArmyBrain(toArmy(players['player4'])):GetArmyIndex())
917end
918
919
920
921
922
923
924
925
926
927--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~UPGRADE SYSTEM FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
928
929--for each player check each shop
930checkUpgradeRequests = function()
931 for index,player in players do
932 local shops = {
933 {unit = player.attackUnit, buy = function(player) upgradeAttack(player) end},
934 {unit = player.defenceUnit, buy = function(player) upgradeDefence(player) end},
935 {unit = player.kamikazeShop, buy = function(player) purchaseKamikaze(player) end},
936 }
937 for index2, shop in shops do
938 checkShop(shop,player)
939 end
940 end
941end
942
943--check upgrade request on a shop
944checkShop = function(shop,player)
945 if shop.unit != false then
946 if player.upgrader then
947 --get target data
948 local v1 = player.upgrader:GetNavigator():GetGoalPos()
949 local v2 = shop.unit:GetPosition()
950 local check = {false,false,false}
951 local tolerance = 10
952
953 --verify if target is inside range
954 for i = 1,3 do
955 if math.abs(v1[i] - v2[i]) <= tolerance then
956 check[i] = true
957 end
958 end
959
960 --if check is ok do shop action
961 if check[1] == true and check[2] == true and check[3] == true then
962 ForkThread(function() playBuildEffect(shop.unit) end)
963 respawnUpgrader(player,player.baseTemplate.upgrader.px,player.baseTemplate.upgrader.py)
964 shop.buy(player)
965 end
966 end
967 end
968end
969
970--return the number of upgrades of the owner of a zone
971upgrades = function(zone)
972 return owner(zone).upgrades
973end
974
975--upgrades a player to a given level
976upgrade = function(player,levelindex)
977 if upgradeList[levelindex].level > player.level then
978 player.level = upgradeList[levelindex].level
979 player.upgrades = upgradeList[levelindex].upgrade
980
981 --level specific actions
982 spawnLevelHero(player,levelindex)
983 end
984end
985
986--spawn hero unit if necessary given a player and a level
987spawnLevelHero = function(player,levelindex)
988 if upgradeList[levelindex].level == 4 then
989 local spawnzone = findZone(player)
990 local x = zoneCenter(spawnzone).x
991 local y = zoneCenter(spawnzone).y
992 local hero = CreateUnitHPR( 'ual0401', toArmy(player), x,25,y, 0,0,0)
993 hero:SetMaxHealth(250000)
994 hero:SetHealth(hero,250000)
995 hero:SetCustomName('Galactic Colossus: ' .. username(player))
996 scnPrint(username(player) .. ": Galactic Colossus Has Arrived",player)
997 elseif upgradeList[levelindex].level == 5 then
998 local spawnzone = findZone(player)
999 local x = zoneCenter(spawnzone).x
1000 local y = zoneCenter(spawnzone).y
1001 local hero = CreateUnitHPR( 'URL0402', toArmy(player), x,25,y, 0,0,0)
1002 hero:SetMaxHealth(500000)
1003 hero:SetHealth(hero,500000)
1004 hero:SetCustomName('Lord of Monkey Lords: ' .. username(player))
1005 scnPrint(username(player) .. ": Lord of Monkey Lords Has Arrived",player)
1006 else
1007 scnPrint(username(player) .. " has reached " .. upgradeList[levelindex].description,player)
1008 end
1009end
1010
1011
1012--upgrade attack level trigger
1013--attack upgrade upgrades unit weapon damage
1014upgradeAttack = function(player)
1015 if player.money >= (player.attack + 1)*50 then
1016 player.money = player.money - (player.attack + 1)*50
1017 player.attack = player.attack + 1
1018 updateInfo(player)
1019 scnPrint(username(player) .. ': upgrading attack to level '..player.attack,player)
1020 else
1021 scnPrint(username(player) .. ': not enough money for attack upgrade',player,true)
1022 end
1023end
1024
1025--upgrade defence level trigger
1026--defence upgrade upgrades unit health as well as tower regen rate
1027upgradeDefence = function(player)
1028 if player.money >= (player.defence + 1)*50 then
1029 player.money = player.money - (player.defence + 1)*50
1030 player.defence = player.defence + 1
1031
1032 -- if player.defence == 8 then
1033 -- player.bunkerType = 'ueb2301'
1034 -- replaceBunkers(player)
1035 --elseif player.defence == 2 then
1036 --player.bunkerType = 'urb2301'
1037 --replaceBunkers(player)
1038 -- end
1039
1040 updateInfo(player)
1041 scnPrint(username(player) .. ': upgrading defence to level '..player.defence,player)
1042 upgradeBunkers(player)
1043 else
1044 scnPrint(username(player) .. ': not enough money for defence upgrade',player,true)
1045 end
1046end
1047
1048--replace all bunkers to refresh bunker type
1049replaceBunkers = function(player)
1050 local i = 1
1051 while i <= imax do
1052 local j = 1
1053 while j <= jmax do
1054 if (i > 1 and i < 5) or (j > 1 and j<5) then
1055 local zone = zones[i][j]
1056 if zone.owner == player.name and zone.bunker != false then
1057 if not zone.bunker:IsDead() then
1058 zone.bunker:Kill()
1059 spawnBunker(zone)
1060 addZone(zone.owner)
1061 end
1062 end
1063 end
1064 j = j + 1
1065 end
1066 i = i + 1
1067 end
1068end
1069
1070
1071--upgrades all alive bunkers for a player
1072upgradeBunkers = function(player)
1073 local i = 1
1074 while i <= imax do
1075 local j = 1
1076 while j <= jmax do
1077 if (i > 1 and i < 5) or (j > 1 and j<5) then
1078 local zone = zones[i][j]
1079 if zone.owner == player.name and zone.bunker != false then
1080 if not zone.bunker:IsDead() then
1081 ForkThread(function() playBuildEffect(zone.bunker) end)
1082 zone.bunker:SetRegenRate(10*(player.defence+1))
1083 zone.bunker:SetMaxHealth(5000 + 1000*player.defence)
1084 zone.bunker:SetHealth(nil,5000 + 1000*player.defence)
1085
1086 for i = 1, zone.bunker:GetWeaponCount() do
1087 zone.bunker:GetWeapon(i):ChangeRateOfFire(1 + player.defence/4)
1088 zone.bunker:GetWeapon(i):AddDamageMod(10*player.defence + 5*player.defence*player.defence)
1089 end
1090
1091 zone.bunker:SetCustomName(username(player) .. ', level ' .. player.defence)
1092 end
1093 end
1094 end
1095 j = j + 1
1096 end
1097 i = i + 1
1098 end
1099end
1100
1101--spawns a kamikaze unit if you have enough money
1102purchaseKamikaze = function(player)
1103 local unitcost = 200
1104 if player.money >= unitcost then
1105 player.money = player.money - unitcost
1106 local spawnzone = findZone(player)
1107 local x = zoneCenter(spawnzone).x
1108 local y = zoneCenter(spawnzone).y
1109 local kamikaze = CreateUnitHPR( 'URL0303', toArmy(player), x,25,y + 5, 0,0,0)
1110 local health = 2000 + 1000*player.attack
1111 kamikaze:SetMaxHealth(health)
1112 kamikaze:SetHealth(nil,health)
1113 kamikaze:SetAllWeaponsEnabled(false)
1114 kamikaze:SetSpeedMult(2)
1115 kamikaze:SetAccMult(3)
1116 kamikaze:SetTurnMult(3)
1117 --addCzarKamikazeAbility(kamikaze)
1118 addKamikazeAbility(kamikaze)
1119 kamikaze:SetCustomName('kamikaze: ' .. username(player))
1120 updateInfo(player)
1121 scnPrint(username(player) .. ': bought a kamikaze',player)
1122 else
1123 scnPrint(username(player) .. ': not enough money to purchase a kamikaze',player,true)
1124 end
1125end
1126
1127--Special ability kamikaze
1128addKamikazeAbility = function(unit)
1129 unit.OldOnKilled = unit.OnKilled
1130 unit.OnKilled = function(self, instigator, type, overkillRatio)
1131 local player = players[armyTable[scnArmy(self)]]
1132 local position = self:GetPosition()
1133 local damage = 5000 + 1000*player.attack
1134 CreateLightParticle( self, -1, -1, 70, 62, 'flare_lens_add_02', 'ramp_red_10' )
1135 local deathThread = ForkThread(function()
1136 WaitSeconds(3)
1137 DamageArea(nil, position, 10, damage, 'Normal', true, true)
1138
1139 end)
1140 unit.OldOnKilled(self, instigator, type, overkillRatio)
1141 end
1142end
1143
1144--SPECIAL ABILITY: DEATH CZAR ATTACK uaa0310
1145addCzarKamikazeAbility = function(unit)
1146 unit.OldOnKilled = unit.OnKilled
1147 unit.OnKilled = function(self, instigator, type, overkillRatio)
1148 local player = players[armyTable[scnArmy(self)]]
1149 czar = CreateUnitHPR( 'uaa0310', scnArmy(self), self:GetPosition()[1],300,self:GetPosition()[3], 0,0,0)
1150 czar:GetBlueprint().Wreckage.WreckageLayers.Land=false
1151 local czardeathThread = ForkThread(function()
1152 WaitSeconds(5)
1153 czar:Kill()
1154 end)
1155 unit.OldOnKilled(self, instigator, type, overkillRatio)
1156 end
1157end
1158
1159--spawns a kamikaze unit if you have enough money
1160purchaseArtillery = function(player)
1161 local unitcost = 200
1162 if player.money >= unitcost then
1163 player.money = player.money - unitcost
1164 local startzone = zones[player.startLocation[1]][player.startLocation[2]]
1165 local x = zoneCenter(startzone).x
1166 local y = zoneCenter(startzone).y
1167 local artillery = CreateUnitHPR( 'UEL0304', toArmy(player), x,25,y + 5, 0,0,0)
1168 artillery:SetMaxHealth(3000)
1169 artillery:SetHealth(nil,3000)
1170 artillery:GetWeapon(1):ChangeMaxRadius(30)
1171 artillery:SetCustomName('artillery: ' .. username(player))
1172 updateInfo(player)
1173 scnPrint(username(player) .. ': bought an artillery',player)
1174 else
1175 scnPrint(username(player) .. ': not enough money to purchase an artillery',player)
1176 end
1177end
1178
1179
1180--kill and respawn player upgrader unit
1181respawnUpgrader = function(player,x,y)
1182 local xPos = 20
1183 local yPos = 20
1184
1185 if x != nil then
1186 xPos = x
1187 end
1188
1189 if y != nil then
1190 yPos = y
1191 end
1192
1193 player.baseTemplate.upgrader.px = x
1194 player.baseTemplate.upgrader.py = y
1195
1196 --destroy upgrader unit if necessary
1197 if player.upgrader != false then
1198 player.upgrader:SetCanBeKilled(true)
1199 player.upgrader:Kill()
1200 player.upgrader = false
1201 end
1202 --spawn upgrader unit
1203 if player.upgrader == false then
1204 player.upgrader = CreateUnitHPR( 'URL0107', toArmy(player), xPos,25,yPos, 0,0,0)
1205 player.upgrader:SetAllWeaponsEnabled(false)
1206 player.upgrader:SetCanBeKilled(false)
1207 player.upgrader:SetDoNotTarget(true)
1208 player.upgrader:SetMaxHealth(1)
1209 player.upgrader:SetHealth(nil,1)
1210 player.upgrader:SetRegenRate(1)
1211 player.upgrader:SetSpeedMult(2)
1212 player.upgrader:SetAccMult(10)
1213 --player.upgrader:SetTurnMult(10)
1214 player.upgrader:SetCustomName(username(player) .. ': Upgrader')
1215 end
1216end
1217
1218--spawn invincible units used to show stats, make upgrades etc
1219spawnUtilityUnits = function()
1220 if players['player1'] then
1221 spawnPlayerUtilityUnits(players['player1'],1,5)
1222 end
1223 if players['player2'] then
1224 spawnPlayerUtilityUnits(players['player2'],1,1)
1225 end
1226 if players['player3'] then
1227 spawnPlayerUtilityUnits(players['player3'],5,1)
1228 end
1229 if players['player4'] then
1230 spawnPlayerUtilityUnits(players['player4'],5,5)
1231 end
1232end
1233
1234--spawn invincible units used to show stats, make upgrades etc for a player at a given zone position
1235spawnPlayerUtilityUnits = function(player,x,y)
1236
1237 local positionX = 50*(x-1)
1238 local positionY = 50*(y-1)
1239 local bt = player.baseTemplate
1240
1241 --info unit
1242 player.infoUnit = CreateUnitHPR( 'uab5202', toArmy(player), positionX+bt.info[1],25,positionY+bt.info[2], 0,0,0)
1243 player.infoUnit:SetAllWeaponsEnabled(false)
1244 player.infoUnit:SetUnSelectable(true)
1245 player.infoUnit:SetCanBeKilled(false)
1246 player.infoUnit:SetDoNotTarget(true)
1247 player.infoUnit:SetMaxHealth(1)
1248 player.infoUnit:SetHealth(nil,1)
1249 player.infoUnit:SetRegenRate(1)
1250
1251 --attack upgrade
1252 player.attackUnit = CreateUnitHPR( 'urb5202', toArmy(player), positionX+bt.attack[1],25,positionY+bt.attack[2], 0,0,0)
1253 player.attackUnit:SetAllWeaponsEnabled(false)
1254 player.attackUnit:SetCanBeKilled(false)
1255 player.attackUnit:SetDoNotTarget(true)
1256 player.attackUnit:SetMaxHealth(1)
1257 player.attackUnit:SetHealth(nil,1)
1258 player.attackUnit:SetRegenRate(1)
1259
1260 --defence upgrade
1261 player.defenceUnit = CreateUnitHPR( 'ueb5202', toArmy(player), positionX+bt.defence[1],25,positionY+bt.defence[2], 0,0,0)
1262 player.defenceUnit:SetAllWeaponsEnabled(false)
1263 player.defenceUnit:SetCanBeKilled(false)
1264 player.defenceUnit:SetDoNotTarget(true)
1265 player.defenceUnit:SetMaxHealth(1)
1266 player.defenceUnit:SetHealth(nil,1)
1267 player.defenceUnit:SetRegenRate(1)
1268
1269 --kamikaze shop
1270 player.kamikazeShop = CreateUnitHPR( 'URB4201', toArmy(player), positionX+bt.kamikazeShop[1],25,positionY+bt.kamikazeShop[2], 0,0,0)
1271 player.kamikazeShop:SetAllWeaponsEnabled(false)
1272 player.kamikazeShop:SetCanBeKilled(false)
1273 player.kamikazeShop:SetDoNotTarget(true)
1274 player.kamikazeShop:SetMaxHealth(1)
1275 player.kamikazeShop:SetHealth(nil,1)
1276 player.kamikazeShop:SetRegenRate(1)
1277 player.kamikazeShop:SetScale(5)
1278
1279 --upgrade selection unit
1280 respawnUpgrader(player,positionX+bt.upgrader[1],positionY+bt.upgrader[2])
1281
1282 --resource storage unit, needed to have resource storage for stats like money and zone control
1283 --spawn resource storage units here
1284
1285 updateInfo(player)
1286end
1287
1288--update player info
1289updateInfo = function(player)
1290 if player.infoUnit != false then
1291 player.infoUnit:SetCustomName('Money ' .. username(player) .. ": " .. player.money)
1292 end
1293 if player.attackUnit != false then
1294 player.attackUnit:SetCustomName('Attack level: ' .. player.attack ..', upgrade for: ' .. (player.attack + 1)*50)
1295 end
1296 if player.defenceUnit != false then
1297 player.defenceUnit:SetCustomName('Defence level: ' .. player.defence ..', upgrade for: ' .. (player.defence + 1)*50)
1298 end
1299 if player.kamikazeShop != false then
1300 player.kamikazeShop:SetCustomName('Shop, purchase kamikaze for: 200')
1301 end
1302end
1303
1304
1305
1306
1307
1308
1309--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MISCALENIOUS FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1310
1311
1312--SPECIAL ARMY INITIALISATION: NO COMMANDER, NEUTRAL ALWAYS ENEMY
1313function InitializeArmies()
1314 local tblGroups = {}
1315 local tblArmy = ListArmies()
1316
1317 --multiplayer lobby game option: chose turret type
1318 local bunkerType = 'uab2301'
1319 if ScenarioInfo.Options.zone_control_turret == 'mixed' then
1320 mainBunkerType = 'ueb2301'
1321 bunkerType = 'uab2301'
1322 elseif ScenarioInfo.Options.zone_control_turret == 'triads' then
1323 mainBunkerType = 'ueb2301'
1324 bunkerType = 'ueb2301'
1325 elseif ScenarioInfo.Options.zone_control_turret == 'oblivions' then
1326 mainBunkerType = 'uab2301'
1327 bunkerType = 'uab2301'
1328 end
1329
1330
1331 --determine the players depending on which slots are occupied
1332 for index,army in tblArmy do
1333 players[armyTable[army]] = playersDATA[armyTable[army]]
1334 players[armyTable[army]].bunkerType = bunkerType
1335 end
1336 players['neutral'].bunkerType = 'urb2301'
1337 players['neutral'].zonecontrol = 21 - playerCount() + 1
1338
1339 for iArmy, strArmy in pairs(tblArmy) do
1340 local tblData = Scenario.Armies[strArmy]
1341
1342 tblGroups[ strArmy ] = {}
1343
1344 if tblData then
1345
1346
1347 for iEnemy, strEnemy in pairs(tblArmy) do
1348
1349 --civilian ARMY_9 is always an enemey
1350 if iArmy != iEnemy and strArmy != 'NEUTRAL_CIVILIAN' and strEnemy != 'NEUTRAL_CIVILIAN' then
1351 SetAlliance( iArmy, iEnemy, 'Enemy')
1352 elseif strArmy == 'NEUTRAL_CIVILIAN' or strEnemy == 'NEUTRAL_CIVILIAN' then
1353 SetAlliance( iArmy, iEnemy, 'Neutral')
1354 end
1355 end
1356
1357
1358 end
1359
1360 end
1361
1362 return tblGroups
1363end
1364
1365playBuildEffect = function(unit,wait)
1366
1367 unit:PlayUnitSound('TeleportStart')
1368 unit:PlayUnitAmbientSound('TeleportLoop')
1369 WaitSeconds( 0.1 )
1370 unit:PlayTeleportInEffects()
1371 WaitSeconds( 0.1 )
1372 unit:StopUnitAmbientSound('TeleportLoop')
1373 unit:PlayUnitSound('TeleportEnd')
1374
1375end