1 /*
2 Guardians of the Windmills
3 Authors: Randrian, Newton, Clonkonaut
4
5 Defend the windmills against waves of enemies
6 */
7
8
9 static g_wave; // index of current wave
10 static g_spawned_enemies;
11 static g_relaunchs; // array of relaunch counts
12 static g_scores; // array of player scores
13 static g_ai; // derived from AI; contains changes for this scenario
14 static g_lost; // True if all windmills are destroyed
15 static const ENEMY = 10; // player number of enemy
16 static const ALLOW_DEBUG_COMMANDS = true;
17
18 static const MAX_RELAUNCH = 10;
19
20 static shared_wealth_remainder;
21
22 //======================================================================
23 /* Initialization */
24
Initialize()25 func Initialize()
26 {
27 // dev stuff (we will forget to turn this off for release)
28 //AddMsgBoardCmd("waveinfo", "GameCall(\"ShowWaveInfo\")");
29 //AddMsgBoardCmd("next", "GameCall(\"SetNextWave\", \"%s\")");
30 //AddMsgBoardCmd("nextwait", "GameCall(\"SetNextWave\", \"%s\", true)");
31 //AddMsgBoardCmd("scrooge", "GameCall(\"DoWealthForAll\", 1000000000)");
32 // Wealth shown at all time
33 GUI_Controller->ShowWealth();
34 // static variable init
35 g_homebases = [];
36 InitWaveData();
37 }
38
InitializePlayer(int plr,int iX,int iY,object pBase,int iTeam)39 func InitializePlayer(int plr, int iX, int iY, object pBase, int iTeam)
40 {
41 if (GetPlayerType(plr) != C4PT_User) return;
42
43 if (g_lost) { EliminatePlayer(plr); return; } // no post-elimination join
44 if (!g_relaunchs)
45 {
46 g_relaunchs = [];
47 g_scores = [];
48 Scoreboard->Init([{key = "relaunchs", title = Rule_Relaunch, sorted = true, desc = true, default = "", priority = 75},
49 {key = "score", title = Nugget, sorted = true, desc = true, default = "0", priority = 100}]);
50 }
51 g_relaunchs[plr] = MAX_RELAUNCH;
52 g_scores[plr] = 0;
53 Scoreboard->NewPlayerEntry(plr);
54 Scoreboard->SetPlayerData(plr, "relaunchs", g_relaunchs[plr]);
55 Scoreboard->SetPlayerData(plr, "score", g_scores[plr]);
56
57 CreateObject(Homebase, 0,0, plr);
58
59 SetPlayerZoomByViewRange(plr, 1200, 0, PLRZOOM_LimitMax);
60
61 //DoWealth(plr, 10000000);
62
63 JoinPlayer(plr);
64 if (!g_wave) StartGame();
65 }
66
RemovePlayer(int plr)67 func RemovePlayer(int plr)
68 {
69 Scoreboard->SetPlayerData(plr, "relaunchs", Icon_Cancel);
70 // Split player's wealth among the remaining players
71 ScheduleCall(nil, Scenario.DoSharedWealth, 50, 1, GetWealth(plr));
72 }
73
TransferInventory(object from,object to)74 private func TransferInventory(object from, object to)
75 {
76 // Drop some items that cannot be transferred (such as connected pipes and dynamite igniters)
77 var i = from->ContentsCount(), contents;
78 while (i--)
79 if (contents = from->Contents(i))
80 if (contents->~IsDroppedOnDeath(from))
81 contents->Exit();
82 return to->GrabContents(from);
83 }
84
JoinPlayer(plr,prev_clonk)85 func JoinPlayer(plr, prev_clonk)
86 {
87 var x=991,y = 970;
88 var clonk = GetCrew(plr);
89 if (clonk)
90 {
91 clonk->SetPosition(x,y-10);
92 }
93 else
94 {
95 clonk = CreateObjectAbove(Clonk, x,y, plr);
96 clonk->MakeCrewMember(plr);
97 }
98 SetCursor(plr, clonk);
99 clonk->DoEnergy(1000);
100 // contents
101 clonk.MaxContentsCount = 1;
102 if (prev_clonk) TransferInventory(prev_clonk, clonk);
103 if (!clonk->ContentsCount())
104 {
105 clonk->CreateContents(Bow);
106 var arrow = CreateObjectAbove(Arrow);
107 clonk->Collect(arrow);
108 arrow->SetInfiniteStackCount();
109 }
110 clonk->~CrewSelection(); // force update HUD
111 // Make this work under the friendly fire rule.
112 for (var obj in [g_windgen1, g_windgen2, g_windgen3, g_windmill])
113 if (obj)
114 obj->SetOwner(plr);
115 }
116
117 // Enter all buyable things into the homebase
FillHomebase(object homebase)118 func FillHomebase(object homebase)
119 {
120 // Quick buy items on hotkeys
121 homebase->SetQuickbuyItems([WindBag, Bow, Javelin, Blunderbuss, GrenadeLauncher, nil, nil, nil, nil, nil]);
122
123 // Buy menu entries
124 homebase->AddCaption("$HomebaseWeapons$");
125 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Weapon { item = Bow, ammo = Arrow, desc = "$HomebaseDescBow$" });
126 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Weapon { item = Javelin, cost = 10, desc = "$HomebaseDescJavelin$" , infinite = true});
127 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Weapon { item = Blunderbuss, cost = 50, ammo = LeadBullet, desc = "$HomebaseDescBlunderbuss$", requirements = ["AdvancedWeapons"] });
128 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Weapon { item = GrenadeLauncher, ammo = IronBomb, desc = "$HomebaseDescGrenadeLauncher$", requirements = ["MasterWeapons"] });
129 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Weapon { item = WindBag, cost = 500, desc = "$HomebaseDescWindBag$", requirements = ["MasterWeapons"] });
130
131 homebase->AddCaption("$HomebaseItems$");
132 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Consumable { item = Bread, cost = 5 });
133 // homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Weapon { item = Hammer, cost = 1000, desc = "$HomebaseDescHammer$", extra_width = 1 });
134
135 homebase->AddCaption("$HomebaseTechnology$");
136 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Technology { name="$HomebaseAdvancedWeapons$", item = Icon_World,cost = 100, desc="$HomebaseDescAdvancedWeapons$", tech = "AdvancedWeapons" });
137 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Technology { name="$HomebaseMasterWeapons$", item = Icon_World,cost = 1000, desc = "$HomebaseDescMasterWeapons$", tech = "MasterWeapons", requirements = ["AdvancedWeapons"] });
138
139 homebase->AddCaption("$HomebaseUpgrades$");
140 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Technology { name="$HomebaseLoadSpeed$", item = Homebase_Icon, graphics="LoadSpeed%d", costs = [100, 500, 1000], desc = "$HomebaseDescLoadSpeed$", tech = "LoadSpeed", tiers=3 });
141 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Technology { name="$HomebaseShootingStrength$", item = Homebase_Icon, graphics="ShootingStrength%d", costs = [50, 150, 350], desc = "$HomebaseDescShootingStrength$", tech = "ShootingStrength", tiers=3 });
142 homebase->AddHomebaseItem(new Homebase.ITEMTYPE_Technology { name="$HomebaseLife$", item = Homebase_Icon, graphics="Life%d", costs = [10, 50, 100], desc = "$HomebaseDescLife$", tech = "Life", tiers=3 });
143 homebase->AddCaption("$HomebaseArtifacts$");
144 }
145
146 // Clonk death callback
OnClonkDeath(clonk,killed_by)147 func OnClonkDeath(clonk, killed_by)
148 {
149 // Player died?
150 if (!clonk) return;
151 var plr = clonk->GetOwner();
152 if (GetPlayerType(plr) == C4PT_User)
153 {
154 // Relaunch count
155 if (!g_relaunchs[plr])
156 {
157 Log("$MsgOutOfRelaunchs$", GetTaggedPlayerName(plr));
158 Scoreboard->SetPlayerData(plr, "relaunchs", Icon_Cancel);
159 EliminatePlayer(plr);
160 return false;
161 }
162 // Relaunch count
163 --g_relaunchs[plr];
164 Scoreboard->SetPlayerData(plr, "relaunchs", g_relaunchs[plr]);
165 Log("$MsgRelaunch$", GetTaggedPlayerName(plr));
166 JoinPlayer(plr, clonk);
167 }
168 else
169 {
170 // Enemy clonk death
171 // Remove inventory
172 var i = clonk->ContentsCount(), obj;
173 while (i--) if (obj=clonk->Contents(i))
174 if (!obj->~OnContainerDeath())
175 obj->RemoveObject();
176 // Clear enemies from list
177 i = GetIndexOf(g_spawned_enemies, clonk);
178 if (i>=0)
179 {
180 g_spawned_enemies[i] = nil;
181 // Kill bounty
182 if (killed_by>=0)
183 {
184 Scoreboard->SetPlayerData(killed_by, "score", ++g_scores[killed_by]);
185 DoWealth(killed_by, clonk.Bounty);
186 }
187 else
188 {
189 // Killer could not be determined. Just give gold to everyone.
190 DoSharedWealth(clonk.Bounty);
191 }
192 }
193 }
194 return;
195 }
196
197 //======================================================================
198 /* The Game */
199
StartGame()200 func StartGame()
201 {
202 // Init objects to defend
203 var obj;
204 for (obj in [g_windgen1, g_windgen2, g_windgen3, g_windmill]) if (obj)
205 {
206 obj->SetCategory(C4D_Living);
207 obj->SetAlive(true);
208 obj.MaxEnergy = 800000;
209 obj->DoEnergy(obj.MaxEnergy/1000);
210 obj->AddEnergyBar();
211 GameCallEx("OnCreationRuleNoFF", obj);
212 }
213 // Launch first wave!
214 g_wave = 1;
215 ScheduleCall(nil, Scenario.LaunchWave, 50, 1, g_wave);
216 return true;
217 }
218
WindmillDown(object windmill)219 public func WindmillDown(object windmill)
220 {
221 if (g_windgen1 == windmill) g_windgen1 = nil;
222 if (g_windgen2 == windmill) g_windgen2 = nil;
223 if (g_windgen3 == windmill) g_windgen3 = nil;
224 if (g_windmill == windmill) g_windmill = nil;
225
226 Sound("Objects::Plane::PlaneCrash", true);
227
228 // Nothing left to defend?
229 if (!g_windgen1 && !g_windgen2 && !g_windgen3 && !g_windmill)
230 {
231 // Fail!
232 var i=GetPlayerCount(C4PT_User);
233 while (i--) EliminatePlayer(GetPlayerByIndex(i, C4PT_User));
234 g_lost = true;
235 ScheduleCall(nil, Global.GameOver, 50, 1);
236 }
237 }
238
DoSharedWealth(int amount)239 public func DoSharedWealth(int amount)
240 {
241 // Split gold among all players. Keep track of remainder and use it next time
242 shared_wealth_remainder += amount;
243 var cnt = GetPlayerCount(C4PT_User);
244 if (cnt)
245 {
246 var wealth_add = shared_wealth_remainder / cnt;
247 if (wealth_add)
248 {
249 shared_wealth_remainder -= wealth_add * cnt;
250 DoWealthForAll(wealth_add);
251 }
252 }
253 return true;
254 }
255
DoWealthForAll(int amount)256 public func DoWealthForAll(int amount)
257 {
258 // Add wealth to all players
259 for (var iplr = 0; iplr < GetPlayerCount(C4PT_User); ++iplr)
260 DoWealth(GetPlayerByIndex(iplr, C4PT_User), amount);
261 return true;
262 }
263
264 //======================================================================
265 /* Enemy waves */
266
LaunchWave(int wave)267 func LaunchWave(int wave)
268 {
269 // * Schedules spawning of all enemies
270 // * Schedules call to LaunchWaveDone() after last enemy has been spawned
271 var wave_data = ENEMY_WAVE_DATA[g_wave];
272 g_spawned_enemies = [];
273 if (wave_data)
274 {
275 var wave_spawn_time = 0;
276 CustomMessage(Format("$MsgWave$: %s", wave, wave_data.Name));
277 Sound("UI::Ding");
278 if (wave_data.Chest != nil && g_chest)
279 {
280 var item = g_chest->CreateContents(wave_data.Chest.Item);
281 if (item)
282 {
283 if (item->GetID() == GoldBar)
284 {
285 item->SetValue(wave_data.Chest.Value);
286 g_chest->SetMeshMaterial("GoldenChest", 0);
287 }
288 }
289 }
290 for (var enemy in ForceVal2Array(wave_data.Enemies)) if (enemy)
291 {
292 if (enemy.Delay)
293 ScheduleCall(nil, Scenario.ScheduleLaunchEnemy, enemy.Delay, 1, enemy);
294 else
295 ScheduleLaunchEnemy(enemy);
296 wave_spawn_time = Max(wave_spawn_time, enemy.Delay + enemy.Interval * enemy.Num);
297 }
298 for (var arrow in ForceVal2Array(wave_data.Arrows))
299 {
300 CreateArrowForPlayers(arrow.X, arrow.Y);
301 }
302 ScheduleCall(nil, Scenario.LaunchWaveDone, wave_spawn_time+5, 1, wave);
303 return true;
304 }
305 return false;
306 }
307
CreateArrowForPlayers(int x,int y)308 func CreateArrowForPlayers(int x, int y)
309 {
310 for (var i = 0; i < GetPlayerCount(C4PT_User); i++)
311 {
312 var plr = GetPlayerByIndex(i, C4PT_User);
313 var cursor = GetCursor(plr);
314 if (!cursor) continue;
315 var arrow = CreateObject(GUI_GoalArrow, cursor->GetX(), cursor->GetY(), plr);
316 if (!arrow) continue;
317 arrow->SetAction("Show", cursor);
318 arrow->SetR(Angle(cursor->GetX(), cursor->GetY(), x, y));
319 arrow->SetClrModulation(RGBa(255, 50, 0, 128));
320 Schedule(arrow, "RemoveObject()", 100);
321 }
322 }
323
ScheduleLaunchEnemy(proplist enemy)324 func ScheduleLaunchEnemy(proplist enemy)
325 {
326 // Schedules spawning of enemy definition
327 // Spawn on ground or in air?
328 var xmin, xmax, ymin, ymax;
329 var def = enemy.Type ?? enemy.Vehicle;
330 if (!def) def = Clonk;
331 var width = def->GetDefWidth();
332 var height = def->GetDefWidth();
333
334 xmin = BoundBy(enemy.PosX - 100, 0 + width/2, LandscapeWidth() - width/2);
335 xmax = BoundBy(enemy.PosX + 100, 0 + width/2, LandscapeWidth() - width/2);
336 ymin = BoundBy(enemy.PosY - 100, 0 + height/2, LandscapeHeight() - height/2);
337 ymax = BoundBy(enemy.PosY + 100, 0 + height/2, LandscapeHeight() - height/2);
338
339 ScheduleCall(nil, CustomAI.LaunchEnemy, Max(enemy.Interval,1), Max(enemy.Num,1), enemy, xmin, xmax - xmin, ymin, ymax - ymin);
340 return true;
341 }
342
LaunchWaveDone(int wave)343 func LaunchWaveDone(int wave)
344 {
345 // All enemies spawned! Now start timer to check whether they are all dead
346 ScheduleCall(nil, Scenario.CheckWaveCleared, 20, 9999999, wave);
347 return true;
348 }
349
CheckWaveCleared(int wave)350 func CheckWaveCleared(int wave)
351 {
352 // Check timer to determine if enemy wave has been cleared.
353 // Enemies nil themselves when they're dead. So clear out nils and we're done when the list is empty
354 var nil_idx;
355 while ( (nil_idx=GetIndexOf(g_spawned_enemies))>=0 )
356 {
357 var l = GetLength(g_spawned_enemies) - 1;
358 if (nil_idx<l) g_spawned_enemies[nil_idx] = g_spawned_enemies[l];
359 SetLength(g_spawned_enemies, l);
360 }
361 if (!GetLength(g_spawned_enemies))
362 {
363 // All enemies dead!
364 ClearScheduleCall(nil, Scenario.CheckWaveCleared);
365 OnWaveCleared(wave);
366 }
367 }
368
OnWaveCleared(int wave)369 func OnWaveCleared(int wave)
370 {
371 var bounty = ENEMY_WAVE_DATA[g_wave].Bounty, bounty_msg = "";
372 if (bounty)
373 {
374 bounty = bounty * 4 / BoundBy(GetPlayerCount(C4PT_User), 1, 4); // Carefully tested balancing
375 bounty_msg = Format("|<c ffff00>+%d</c>{{Icon_Wealth}}", bounty);
376 DoWealthForAll(bounty);
377 }
378 CustomMessage(Format("$MsgWaveCleared$%s| ", wave, bounty_msg));
379 Sound("UI::NextWave");
380 // Fade out stuff
381 Airship->AllStop();
382 if (g_object_fade)
383 for (var obj in FindObjects(Find_Or(Find_And(Find_ID(Clonk), Find_Not(Find_OCF(OCF_Alive))), Find_ID(Catapult), Find_ID(Airship))))
384 obj->AddEffect("IntFadeOut", obj, 100, 1, g_object_fade, Rule_ObjectFade);
385 // Next wave!
386 ++g_wave;
387 if (ENEMY_WAVE_DATA[g_wave])
388 ScheduleCall(nil, Scenario.LaunchWave, 500, 1, g_wave);
389 else
390 {
391 // There is no next wave? Game done D:
392 ScheduleCall(nil, Scenario.OnAllWavesCleared, 50, 1);
393 }
394 }
395
GiveRandomAttackTarget(object attacker)396 public func GiveRandomAttackTarget(object attacker)
397 {
398 return GetRandomWindmill();
399 }
400
401 //======================================================================
402 /* Game end */
403
OnAllWavesCleared()404 func OnAllWavesCleared()
405 {
406 // Success!
407 if (g_goal) g_goal.is_fulfilled = true;
408 if (GetPlayerType(ENEMY) == C4PT_Script) EliminatePlayer(ENEMY);
409 GainScenarioAchievement("Done");
410 GameOver();
411 return true;
412 }
413
414 //======================================================================
415 /* Wave and enemy definitions */
416
417 static ENEMY_WAVE_DATA;
418
419 static const g_respawning_weapons = [Firestone, Rock];
420
InitWaveData()421 func InitWaveData()
422 {
423 // Define different enemy types
424 var pilot = { Name="$EnemyPilot$", Inventory=Rock, Energy=30, Bounty=20, Color=0xff0000ff, Skin=CSKIN_Alchemist, Backpack=0, Vehicle=Airship };
425 var swordman = { Name="$EnemyCrewman$", Inventory=Sword, Energy=50, Bounty=15, Color=0xffff0000, Skin=CSKIN_Default, Backpack=0, IsCrew=true };
426 var defender = { Name="$EnemyDefender$", Inventory=[Shield, Axe], Energy=50, Bounty=10, Color=0xff00ff00, Skin=CSKIN_Farmer, Backpack=0, IsCrew=true };
427 var bowman = { Name="$EnemyBow$", Inventory=[Bow, Arrow], Energy=30, Bounty=10, Color=0xff80ff80, Skin=CSKIN_Steampunk, Backpack=0, IsCrew=true };
428 var artillery = { Name="$EnemyArtillery$", Inventory=Firestone, Energy=10, Bounty=25, Color=0xffffff80, Skin=CSKIN_Steampunk, Backpack=0, Vehicle=Catapult, IsCrew=true };
429 var ballooner = { Name="$EnemyBalloon$", Inventory=Sword, Energy=30, Bounty=15, Color=0xff008000, Skin=CSKIN_Default, Vehicle=Balloon };
430 var rocketeer = { Name="$EnemyRocket$", Inventory=[Bow, Arrow], Energy=15, Bounty=15, Color=0xffffffff, Skin=CSKIN_Steampunk, Vehicle=DefenseBoomAttack };
431 var boomattack = { Type=DefenseBoomAttack, Bounty=2 };
432 var boomattackf = { Type=DefenseBoomAttack, Bounty=15, Speed=300 };
433
434 // Define composition of waves
435 ENEMY_WAVE_DATA = [nil,
436 { Name = "$WaveFirst$", Bounty = 1, Enemies =
437 new boomattack { Num= 1, Interval=10, PosX = 0, PosY = 500 },
438 Arrows = { X = 0, Y = 500 },
439 Chest = { Item = GoldBar, Value = 25 }
440 }, { Name = "$WaveSecond$", Bounty = 30, Enemies =
441 [new boomattack { Num= 3, Interval=10, PosX = 0, PosY = 500 },
442 new boomattack { Num= 3, Interval=10, PosX = 2000, PosY = 500 },],
443 Arrows = [{ X = 0, Y = 500 },{ X = 2000, Y = 500 }]
444 }, { Name = "$WaveThird$", Bounty = 10, Enemies =
445 new rocketeer { Num= 8, PosX = 0, PosY = 500 },
446 Arrows = { X = 0, Y = 500 }
447 }, { Name = "$WaveFourth$", Bounty = 15, Enemies =
448 [new rocketeer { Num= 8, Interval=10, PosX = 0, PosY = 500 },
449 new rocketeer { Num= 8, Interval=10, PosX = 2000, PosY = 500 },],
450 Arrows = [{ X = 0, Y = 500 },{ X = 2000, Y = 500 }]
451 }, { Name = "$WaveFifth$", Bounty = 20, Enemies =
452 [new boomattack { Num= 10, PosX = 1000, PosY = 2000 },
453 new pilot { Num= 1, Delay = 1, PosX = 2000, PosY = 750 },
454 new defender { Num= 1, Delay = 2, PosX = 2000, PosY = 750 },
455 new pilot { Num= 1, Delay = 3, PosX = 0, PosY = 750 },
456 new defender { Num= 1, Delay = 4, PosX = 0, PosY = 750 },],
457 Arrows = [{ X = 0, Y = 750 },{ X = 2000, Y = 750 },{ X = 1000, Y = 2000 }]
458 }, { Name = "$WaveSixth$", Bounty = 20, Enemies =
459 [new pilot { Num= 1, Delay = 1, PosX = 2000, PosY = 1250 },
460 new defender { Num= 2, Delay = 2, PosX = 2000, PosY = 1250 },
461 new bowman { Num= 2, Delay = 2, PosX = 2000, PosY = 1250 },
462 new swordman { Num= 1, Delay = 2, PosX = 2000, PosY = 1250 },
463 new pilot { Num= 1, Delay = 3, PosX = 0, PosY = 1250 },
464 new defender { Num= 2, Delay = 4, PosX = 0, PosY = 1250 },
465 new bowman { Num= 2, Delay = 4, PosX = 0, PosY = 1250 },
466 new swordman { Num= 1, Delay = 4, PosX = 0, PosY = 1250 },],
467 Arrows = [{ X = 0, Y = 1250 },{ X = 2000, Y = 1250 }],
468 Chest = { Item = GoldBar, Value = 100 }
469 }, { Name = "$WaveSeventh$", Bounty = 50, Enemies =
470 new ballooner { Num= 10, PosX = 1000, PosY = 0 },
471 Arrows = { X = 1000, Y = 0 }
472 }, { Name = "$WaveEighth$", Bounty = 50, Enemies =
473 [new boomattack { Num= 15, Interval = 5, PosX = 500, PosY = 0 },
474 new pilot { Num= 1, Delay = 80, PosX = 0, PosY = 1250 },
475 new defender { Num= 3, Delay = 81, PosX = 0, PosY = 1250 },
476 new bowman { Num= 3, Delay = 81, PosX = 0, PosY = 1250 },
477 new pilot { Num= 1, Delay = 82, PosX = 2000, PosY = 1250 },
478 new defender { Num= 3, Delay = 83, PosX = 2000, PosY = 1250 },
479 new bowman { Num= 3, Delay = 83, PosX = 2000, PosY = 1250 },
480 new pilot { Num= 1, Delay = 84, PosX = 200, PosY = 2000 },
481 new defender { Num= 3, Delay = 85, PosX = 200, PosY = 2000 },
482 new swordman { Num= 3, Delay = 85, PosX = 200, PosY = 2000 },
483 new pilot { Num= 1, Delay = 86, PosX = 1800, PosY = 2000 },
484 new defender { Num= 3, Delay = 87, PosX = 1800, PosY = 2000 },
485 new swordman { Num= 3, Delay = 87, PosX = 1800, PosY = 2000 },],
486 Arrows = [{ X = 500, Y = 0 },{ X = 0, Y = 1250 },{ X = 2000, Y = 1250 },{ X = 200, Y = 2000 },{ X = 1800, Y = 2000 }]
487 }, { Name = "$WaveNinth$", Bounty = 100, Enemies =
488 [new ballooner { Num= 10, Interval = 10, Delay = 350, PosX = 1000, PosY = 0 },
489 new boomattackf { Num= 8, Interval = 1, PosX = 0, PosY = 300 },
490 new boomattackf { Num= 8, Interval = 1, PosX = 2000, PosY = 300 },],
491 Arrows = [{ X = 1000, Y = 0 },{ X = 0, Y = 300 },{ X = 2000, Y = 300 }]
492 }, { Name = "$WaveTenth$", Bounty = 1000, Enemies =
493 [new boomattack { Num= 7, Interval = 1, PosX = 0, PosY = 0 },
494 new boomattack { Num= 7, Interval = 1, PosX = 2000, PosY = 0 },
495 new rocketeer { Num= 4, Interval = 10, PosX = 0, PosY = 300 },
496 new rocketeer { Num= 4, Interval = 10, PosX = 2000, PosY = 300 },
497 new ballooner { Num= 10, Interval = 5, Delay = 100, PosX = 1000, PosY = 0 },
498 new pilot { Num= 1, Delay = 80, PosX = 0, PosY = 1250 },
499 new defender { Num= 3, Delay = 81, PosX = 0, PosY = 1250 },
500 new bowman { Num= 4, Delay = 81, PosX = 0, PosY = 1250 },
501 new pilot { Num= 1, Delay = 82, PosX = 2000, PosY = 1250 },
502 new defender { Num= 3, Delay = 83, PosX = 2000, PosY = 1250 },
503 new bowman { Num= 4, Delay = 83, PosX = 2000, PosY = 1250 },
504 new pilot { Num= 1, Delay = 84, PosX = 200, PosY = 2000 },
505 new defender { Num= 3, Delay = 85, PosX = 200, PosY = 2000 },
506 new swordman { Num= 4, Delay = 85, PosX = 200, PosY = 2000 },
507 new pilot { Num= 1, Delay = 86, PosX = 1800, PosY = 2000 },
508 new defender { Num= 3, Delay = 87, PosX = 1800, PosY = 2000 },
509 new swordman { Num= 4, Delay = 87, PosX = 1800, PosY = 2000 },
510 new pilot { Num= 1, Delay = 88, PosX = 880, PosY = 2000 },
511 new bowman { Num= 3, Delay = 89, PosX = 880, PosY = 2000 },
512 new swordman { Num= 3, Delay = 89, PosX = 880, PosY = 2000 },
513 new pilot { Num= 1, Delay = 88, PosX = 1120, PosY = 2000 },
514 new bowman { Num= 3, Delay = 89, PosX = 1120, PosY = 2000 },
515 new swordman { Num= 3, Delay = 89, PosX = 1120, PosY = 2000 },],
516 Arrows = [{ X = 0, Y = 0 },{ X = 2000, Y = 0 },{ X = 0, Y = 300 },{ X = 2000, Y = 300 },{ X = 1000, Y = 0 },{ X = 0, Y = 1250 },{ X = 2000, Y = 1250 },{ X = 200, Y = 2000 },{ X = 1800, Y = 2000 },{ X = 880, Y = 2000 },{ X = 1120, Y = 2000 }]
517 }];
518 return true;
519 }