1 // Outro sequence for this tutorial.
2
3 #appendto Sequence
4
Outro_Init(int for_plr)5 public func Outro_Init(int for_plr)
6 {
7 this.plr = for_plr;
8 // Store villagers.
9 this.village_head = Dialogue->FindByName("VillageHead")->GetDialogueTarget();
10 this.farmer = Dialogue->FindByName("Farmer")->GetDialogueTarget();
11 this.lookout = Dialogue->FindByName("Lookout")->GetDialogueTarget();
12 this.lumberjack = Dialogue->FindByName("Lumberjack")->GetDialogueTarget();
13 this.fireman = Dialogue->FindByName("Fireman")->GetDialogueTarget();
14 this.builder = Dialogue->FindByName("Builder")->GetDialogueTarget();
15 // Create two airplanes with pilots and let them fly from left to right.
16 this.airplane1 = CreateObject(Airplane, AbsX(40), AbsY(160));
17 this.pilot1 = CreateObject(Clonk);
18 this.pilot1->SetSkin(2);
19 this.pilot1->Enter(this.airplane1);
20 this.pilot1->SetAction("Walk");
21 this.pilot1->SetColor(0xff000000);
22 this.airplane1->PlaneMount(this.pilot1);
23 this.airplane1->FaceRight();
24 this.airplane1->StartInstantFlight(90, 15);
25 this.airplane1->SetXDir(12);
26 this.airplane1->SetYDir(-1);
27 this.airplane1->MakeInvincible();
28 this.airplane1->SetColor(0xff000000);
29 this.airplane1.BorderBound = 0;
30 this.airplane2 = CreateObject(Airplane, AbsX(0), AbsY(190));
31 this.pilot2 = CreateObject(Clonk);
32 this.pilot2->SetSkin(2);
33 this.pilot2->Enter(this.airplane2);
34 this.pilot2->SetAction("Walk");
35 this.pilot2->SetColor(0xff000000);
36 this.airplane2->PlaneMount(this.pilot2);
37 this.airplane2->FaceRight();
38 this.airplane2->StartInstantFlight(90, 15);
39 this.airplane2->SetXDir(12);
40 this.airplane2->SetYDir(-1);
41 this.airplane2->MakeInvincible();
42 this.airplane2->SetColor(0xff000000);
43 this.airplane2.BorderBound = 0;
44 // Each plane has a henchman which will kidnap the wipfs.
45 this.henchman1 = CreateObject(Clonk);
46 this.henchman1->SetAlternativeSkin("Leather");
47 this.henchman1->Enter(this.airplane1);
48 this.henchman1->SetAction("Walk");
49 this.henchman1->SetColor(0xff000000);
50 this.henchman1->CreateContents(Blunderbuss)->CreateContents(LeadBullet);
51 this.henchman2 = CreateObject(Clonk);
52 this.henchman2->SetAlternativeSkin("Leather");
53 this.henchman2->Enter(this.airplane2);
54 this.henchman2->SetAction("Walk");
55 this.henchman2->SetColor(0xff000000);
56 this.henchman2->CreateContents(Blunderbuss)->CreateContents(LeadBullet);
57
58 // Another henchman which will control the lookout.
59 this.henchman3 = CreateObject(Clonk);
60 this.henchman3->SetAlternativeSkin("Leather");
61 this.henchman3->Enter(this.airplane2);
62 this.henchman3->SetAction("Walk");
63 this.henchman3->SetColor(0xff000000);
64 this.henchman3->CreateContents(Blunderbuss)->CreateContents(LeadBullet);
65
66 // The faction leader which will do the talking.
67 this.leader = CreateObject(Clonk);
68 this.leader->SetAlternativeSkin("Doctor");
69 this.leader->SetName("Gotham");
70 this.leader->Enter(this.airplane1);
71 this.leader->SetAction("Walk");
72 this.leader->SetColor(0xff000000);
73 this.leader->CreateContents(Blunderbuss)->CreateContents(LeadBullet);
74
75 // There is also a kidnapper on an airship with a lorry to collect the wipfs.
76 // The third henchman shoots down the balloons.
77 this.airship = CreateObject(Airship, AbsX(20), AbsY(280));
78 this.lorry = CreateObject(Lorry, AbsX(32), AbsY(280));
79 this.kidnapper = CreateObject(Clonk, AbsX(30), AbsY(280));
80 this.kidnapper->SetSkin(3);
81 this.kidnapper->SetAction("Walk");
82 this.kidnapper->SetCommand("Grab", this.airship);
83 this.kidnapper->SetColor(0xff000000);
84 this.airship->ControlRight(this.kidnapper);
85 return true;
86 }
87
Outro_JoinPlayer(int plr)88 public func Outro_JoinPlayer(int plr)
89 {
90 SetPlayerZoomByViewRange(plr, LandscapeWidth(), nil, PLRZOOM_Set | PLRZOOM_LimitMax);
91 return;
92 }
93
Outro_Start()94 public func Outro_Start()
95 {
96 return ScheduleNext(4);
97 }
98
Outro_1()99 public func Outro_1()
100 {
101 MessageBox("$MsgVillageHeadNoise$", GetCrew(this.plr, 0), this.village_head, this.plr, true);
102 return ScheduleNext(72);
103 }
104
Outro_2()105 public func Outro_2()
106 {
107 MessageBox("$MsgFarmerAirplanes$", GetCrew(this.plr, 0), this.farmer, this.plr, true);
108 // Fireman and lumberjack flee into wooden cabin.
109 this.fireman->SetCommand("Enter", this.fireman->FindObject(Find_ID(WoodenCabin), Find_AnyLayer(), Sort_Distance()));
110 this.lumberjack->SetCommand("Enter", this.lumberjack->FindObject(Find_ID(WoodenCabin), Find_AnyLayer(), Sort_Distance()));
111 // Builder flees into the mine.
112 this.builder->SetCommand("MoveTo", this.builder->FindObject(Find_ID(Foundry), Find_AnyLayer(), Sort_Distance()));
113 return ScheduleNext(36);
114 }
115
Outro_3()116 public func Outro_3()
117 {
118 // Exit the leader from the airplane on a balloon.
119 this.leader->Exit();
120 var balloon = this.leader->CreateContents(Balloon);
121 balloon->ControlUseStart(this.leader);
122 this.leader->GetActionTarget()->ControlDown(this.leader);
123 return ScheduleNext(36);
124 }
125
Outro_4()126 public func Outro_4()
127 {
128 // Exit henchman from the airplanes on balloons.
129 this.henchman1->Exit();
130 var balloon = this.henchman1->CreateContents(Balloon);
131 balloon->ControlUseStart(this.henchman1);
132 this.henchman1->GetActionTarget()->ControlDown(this.henchman1);
133 this.henchman2->Exit();
134 var balloon = this.henchman2->CreateContents(Balloon);
135 balloon->ControlUseStart(this.henchman2);
136 this.henchman2->GetActionTarget()->ControlDown(this.henchman2);
137 // Let henchmen aim at the farmer.
138 AddEffect("AimBlunderbussAt", this.henchman1, 100, 1, this, nil, this.farmer, 356);
139 AddEffect("AimBlunderbussAt", this.henchman2, 100, 1, this, nil, this.farmer, 356);
140 // Let leader aim at the village head.
141 AddEffect("AimBlunderbussAt", this.leader, 100, 1, this, nil, this.village_head);
142 return ScheduleNext(78);
143 }
144
Outro_5()145 public func Outro_5()
146 {
147 MessageBox("$MsgEvilLeaderItsUs$", GetCrew(this.plr, 0), this.leader, this.plr, true);
148 // Exit a third henchman from the airplane on a balloon.
149 this.henchman3->Exit();
150 var balloon = this.henchman3->CreateContents(Balloon);
151 balloon->ControlUseStart(this.henchman3);
152 this.henchman3->GetActionTarget()->ControlDown(this.henchman3);
153 return ScheduleNext(20);
154 }
155
Outro_6()156 public func Outro_6()
157 {
158 // Third henchman aims at lookout
159 AddEffect("AimBlunderbussAt", this.henchman3, 100, 1, this, nil, this.lookout, 280);
160 return ScheduleNext(100);
161 }
162
Outro_7()163 public func Outro_7()
164 {
165 return ScheduleNext(36);
166 }
167
Outro_8()168 public func Outro_8()
169 {
170 MessageBox("$MsgVillageHeadWhy$", GetCrew(this.plr, 0), this.village_head, this.plr, true);
171 return ScheduleNext(36);
172 }
173
Outro_9()174 public func Outro_9()
175 {
176 // Third henchman tells lookout to drop the weapon.
177 this.henchman3->Message("$MsgHenchman3DropBlunderbuss$");
178 return ScheduleNext(18);
179 }
180
Outro_10()181 public func Outro_10()
182 {
183 // First and second henchman scare off farmer.
184 this.henchman1->Message("$MsgHenchman1RunGirl$");
185 this.henchman2->Message("$MsgHenchman2Wipfs$");
186 return ScheduleNext(18);
187 }
188
Outro_11()189 public func Outro_11()
190 {
191 // Lookout surrenders.
192 this.lookout->Message("$MsgLookoutSurrender$");
193 this.lookout->SetCommand("Drop", this.lookout->Contents());
194 return ScheduleNext(18);
195 }
196
Outro_12()197 public func Outro_12()
198 {
199 // Farmer runs off into the mines.
200 this.farmer->SetCommand("MoveTo", this.farmer->FindObject(Find_ID(ToolsWorkshop), Find_AnyLayer(), Sort_Distance()));
201 this.farmer->Message("$MsgFarmerComment$");
202 return ScheduleNext(100);
203 }
204
Outro_13()205 public func Outro_13()
206 {
207 MessageBox("$MsgEvilLeaderWipfs$", GetCrew(this.plr, 0), this.leader, this.plr, true);
208 this.airship->ControlStop(this.kidnapper);
209 AddEffect("TieWipfToBalloon", this.henchman1, 100, 5, this);
210 AddEffect("TieWipfToBalloon", this.henchman2, 100, 5, this);
211 return ScheduleNext(108);
212 }
213
Outro_14()214 public func Outro_14()
215 {
216 MessageBox("$MsgVillageHeadManiac$", GetCrew(this.plr, 0), this.village_head, this.plr, true);
217 ScheduleCall(this, "MessageBox", 108, 0, "$MsgEvilLeader$", GetCrew(this.plr, 0), this.leader, this.plr, true);
218 ScheduleCall(this, "MessageBox", 216, 0, "$MsgPlayerDontTakeWipf$", GetCrew(this.plr, 0), GetCrew(this.plr, 0), this.plr, true);
219 ScheduleCall(this, "MessageBox", 356, 0, "$MsgEvilLeaderBegging$", GetCrew(this.plr, 0), this.leader, this.plr, true);
220 return ScheduleNext(4);
221 }
222
Outro_15()223 public func Outro_15()
224 {
225 // Wait until all wipfs are up then move airship.
226 if (!FindObject(Find_ID(Wipf), Find_InRect(AbsX(632), AbsY(280), 216, 112), Find_AnyLayer()))
227 {
228 AddEffect("MoveAirshipToWipf", this.kidnapper, 100, 5, this);
229 return ScheduleNext(10);
230 }
231 return ScheduleSame(10);
232 }
233
Outro_16()234 public func Outro_16()
235 {
236 if (FindObject(Find_ID(Wipf), Find_NoContainer(), Find_InRect(AbsX(632), AbsY(0), 216, 352), Find_Property("tied_up")))
237 return ScheduleSame(10);
238 return ScheduleNext(10);
239 }
240
Outro_17()241 public func Outro_17()
242 {
243 this.airship->ControlRight(this.kidnapper);
244 this.airship->ControlUp(this.kidnapper);
245 this.kidnapper->Message("$MsgKidnapperGotThem$");
246 ScheduleCall(this.kidnapper, "RemoveObject", 300, 0);
247 ScheduleCall(this.airship, "RemoveObject", 300, 0);
248 ScheduleCall(this.lorry, "RemoveObject", 300, 0);
249
250 var boompack = this.henchman3->CreateContents(Boompack);
251 boompack->SetFuel(10000);
252 boompack->ControlUse(this.henchman3, -8, -40);
253 boompack->SetDirectionDeviation();
254 this.henchman3->Message("$MsgHenchman3SeeYa$");
255 RemoveAll(Find_Container(this.henchman3));
256 ScheduleCall(this.henchman3, "RemoveObject", 120, 0);
257 ScheduleCall(boompack, "RemoveObject", 120, 0);
258
259 this.henchman1->SetCommand("MoveTo", nil, 632, 382);
260 this.henchman2->SetCommand("MoveTo", nil, 632, 382);
261 return ScheduleNext(70);
262 }
263
Outro_18()264 public func Outro_18()
265 {
266 var boompack = this.henchman2->CreateContents(Boompack);
267 boompack->SetFuel(10000);
268 boompack->ControlUse(this.henchman2, -10, -40);
269 boompack->SetDirectionDeviation();
270 this.henchman2->Message("$MsgHenchman3SeeYa$");
271 RemoveAll(Find_Container(this.henchman2));
272 ScheduleCall(this.henchman2, "RemoveObject", 100, 0);
273 ScheduleCall(boompack, "RemoveObject", 100, 0);
274 return ScheduleNext(10);
275 }
276
Outro_19()277 public func Outro_19()
278 {
279 MessageBox("$MsgEvilLeaderBye$", GetCrew(this.plr, 0), this.leader, this.plr, true);
280
281 var boompack = this.henchman1->CreateContents(Boompack);
282 boompack->SetFuel(10000);
283 boompack->ControlUse(this.henchman1, -10, -40);
284 boompack->SetDirectionDeviation();
285 this.henchman1->Message("$MsgHenchman3SeeYa$");
286 RemoveAll(Find_Container(this.henchman1));
287 ScheduleCall(this.henchman1, "RemoveObject", 120, 0);
288 ScheduleCall(boompack, "RemoveObject", 120, 0);
289
290 RemoveEffect("AimBlunderbussAt", this.leader);
291 return ScheduleNext(36);
292 }
293
Outro_20()294 public func Outro_20()
295 {
296 var boompack = this.leader->CreateContents(Boompack);
297 boompack->SetFuel(10000);
298 boompack->ControlUse(this.leader, -8, -40);
299 boompack->SetDirectionDeviation();
300 RemoveAll(Find_Container(this.leader));
301 ScheduleCall(this.leader, "RemoveObject", 120, 0);
302 ScheduleCall(boompack, "RemoveObject", 120, 0);
303 return ScheduleNext(188);
304 }
305
Outro_21()306 public func Outro_21()
307 {
308 // Show last guide message and then stop the sequence and fulfill the goal.
309 GameCall("ShowLastGuideMessage");
310 return ScheduleNext(108);
311 }
312
Outro_22()313 public func Outro_22()
314 {
315 return Stop();
316 }
317
Outro_Stop()318 public func Outro_Stop()
319 {
320 // Fulfill the tutorial goal.
321 var goal = FindObject(Find_ID(Goal_Tutorial));
322 if (goal)
323 goal->Fulfill();
324 return true;
325 }
326
327
328 /*-- Effects --*/
329
FxAimBlunderbussAtStart(object target,proplist effect,int temp,object aim,int length)330 public func FxAimBlunderbussAtStart(object target, proplist effect, int temp, object aim, int length)
331 {
332 if (temp)
333 return FX_OK;
334 effect.aim_target = aim;
335 effect.aim_length = length;
336 effect.blunderbuss = FindObject(Find_ID(Blunderbuss), Find_Container(target));
337 effect.blunderbuss.loaded = true;
338 effect.blunderbuss->ControlUseStart(target, effect.aim_target->GetX() - target->GetX(), effect.aim_target->GetY() - target->GetY());
339 return FX_OK;
340 }
341
FxAimBlunderbussAtTimer(object target,proplist effect,int time)342 public func FxAimBlunderbussAtTimer(object target, proplist effect, int time)
343 {
344 effect.blunderbuss->ControlUseHolding(target, effect.aim_target->GetX() - target->GetX(), effect.aim_target->GetY() - target->GetY());
345 if (effect.aim_length != nil && time >= effect.aim_length)
346 return FX_Execute_Kill;
347 return FX_OK;
348 }
349
FxAimBlunderbussAtStop(object target,proplist effect,int reason,bool temp)350 public func FxAimBlunderbussAtStop(object target, proplist effect, int reason, bool temp)
351 {
352 if (temp)
353 return FX_OK;
354 effect.blunderbuss->ControlUseCancel(target, effect.aim_target->GetX() - target->GetX(), effect.aim_target->GetY() - target->GetY());
355 return FX_OK;
356 }
357
358
FxTieWipfToBalloonStart(object target,proplist effect,int temp)359 public func FxTieWipfToBalloonStart(object target, proplist effect, int temp)
360 {
361 if (temp)
362 return FX_OK;
363 effect.wait_time = 0;
364 return FX_OK;
365 }
366
FxTieWipfToBalloonTimer(object target,proplist effect,int time)367 public func FxTieWipfToBalloonTimer(object target, proplist effect, int time)
368 {
369 if (effect.wait_time > 0)
370 {
371 effect.wait_time -= effect.Interval;
372 return FX_OK;
373 }
374
375 if (!effect.wipf)
376 {
377 effect.wipf = target->FindObject(Find_ID(Wipf), Find_InRect(target->AbsX(632), target->AbsY(260), 216, 132), Find_AnyLayer(), Find_Not(Find_Or(Find_Property("tied_up"), Find_Property("tie_target"))), Sort_Distance());
378 if (!effect.wipf)
379 return FX_Execute_Kill;
380 effect.wipf.tie_target = true;
381 }
382
383 if (ObjectDistance(target, effect.wipf) < 10)
384 {
385 effect.wipf->SetObjectLayer();
386 effect.wipf.Collectible = true;
387 var balloon = effect.wipf->CreateContents(Balloon);
388 balloon->HangWipfOnBalloon(effect.wipf);
389 target->Message(Translate(Format("MsgHenchmanGotWipf%d", 1 + Random(3))));
390 effect.wipf.tied_up = true;
391 effect.wipf = nil;
392 effect.wait_time = 36;
393 return FX_OK;
394 }
395
396 target->SetCommand("MoveTo", nil, effect.wipf->GetX(), effect.wipf->GetY());
397 return FX_OK;
398 }
399
FxTieWipfToBalloonStop(object target,proplist effect,int reason,bool temp)400 public func FxTieWipfToBalloonStop(object target, proplist effect, int reason, bool temp)
401 {
402 if (temp)
403 return FX_OK;
404 return FX_OK;
405 }
406
407
FxMoveAirshipToWipfStart(object target,proplist effect,int temp)408 public func FxMoveAirshipToWipfStart(object target, proplist effect, int temp)
409 {
410 if (temp)
411 return FX_OK;
412
413 return FX_OK;
414 }
415
FxMoveAirshipToWipfTimer(object target,proplist effect,int time)416 public func FxMoveAirshipToWipfTimer(object target, proplist effect, int time)
417 {
418 var right_wipf = FindObject(Find_ID(Wipf), Find_NoContainer(), Find_InRect(AbsX(616), AbsY(0), 248, 280), Find_Property("tied_up"), Sort_Reverse(Sort_Func("GetX")));
419 if (!right_wipf)
420 return FX_Execute_Kill;
421 if (Abs(this.airship->GetX() - right_wipf->GetX()) < 8)
422 {
423 this.airship->ControlStop(this.kidnapper);
424 // Shoot blunderbuss.
425 if (!right_wipf.shot)
426 {
427 var blunderbuss = FindObject(Find_ID(Blunderbuss), Find_Container(this.henchman3));
428 blunderbuss.BulletsPerShot = 1;
429 blunderbuss.BulletSpread = 0;
430 blunderbuss.loaded = true;
431 blunderbuss->ControlUseStart(target, right_wipf->GetX() - this.henchman3->GetX(), right_wipf->GetY() - this.henchman3->GetY() - 24);
432 blunderbuss->ControlUseHolding(target, right_wipf->GetX() - this.henchman3->GetX(), right_wipf->GetY() - this.henchman3->GetY() - 24);
433 blunderbuss->ControlUseStop(target, right_wipf->GetX() - this.henchman3->GetX(), right_wipf->GetY() - this.henchman3->GetY() - 24);
434 right_wipf.shot = true;
435 }
436 return FX_OK;
437 }
438 if (this.airship->GetX() > right_wipf->GetX())
439 this.airship->ControlLeft(this.kidnapper);
440 else
441 this.airship->ControlRight(this.kidnapper);
442 return FX_OK;
443 }
444
FxMoveAirshipToWipfStop(object target,proplist effect,int reason,bool temp)445 public func FxMoveAirshipToWipfStop(object target, proplist effect, int reason, bool temp)
446 {
447 if (temp)
448 return FX_OK;
449 return FX_OK;
450 }