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 }