1/*
2 *
3 *  Copyright (C) 2006  The Exult Team
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 *
20 *	This source file contains some functions specific to a cutscene
21 *	from the Keyring Quest.
22 *
23 *	Author: Marzo Junior
24 *	Last Modified: 2006-02-27
25 */
26
27//Cutscene levels:
28enum MageAndGoons_levels
29{
30	BEGIN_CUTSCENE						= 1,
31	FADE_SCREEN							= 2,
32	CENTER_VIEW							= 3,
33	UNFADE_SCREEN						= 4,
34	DISPLAY_REGION						= 5,
35	MAKE_VISIBLE						= 6,
36	GENERATE_SCRIPTS					= 7,
37	FIREWORKS_LAURIANNA					= 8,
38	GARGOYLE_WARNS						= 9,
39	LAUNDO_SPEAKS						= 10,
40	BEGIN_COMBAT						= 11,
41	PREPARE_NPC							= 12
42};
43
44void beginCutsceneMageAndGoons object#() ()
45{
46	var mage;
47	var gargoyle;
48	var cyclops;
49	var troll;
50	var fighter;
51	var pos;
52	var dir;
53
54	if (event == BEGIN_CUTSCENE)
55	{
56		//Cutscene begins HERE, with item == AVATAR
57
58		//Play music:
59		UI_play_music(21, 0);
60
61		//Cutscene mode :-)
62		AVATAR->trueFreeze();
63		//Create magical effect:
64		pos = get_object_position();
65		UI_sprite_effect(ANIMATION_BLUE_BEADS, pos[X], pos[Y], 0, 0, 0, -1);
66
67		//Screen fader:
68		script item after 5 ticks call beginCutsceneMageAndGoons, FADE_SCREEN;
69
70		//Find Laundo:
71		mage = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
72										SHAPE_MAGE_MALE, 80, ID_MAGE_OR_GOON);
73		//Use him to unfade screen and kick-start the rest of the scene:
74		script mage after 10 ticks
75		{	nohalt;						call beginCutsceneMageAndGoons, CENTER_VIEW;
76			wait 2;						call beginCutsceneMageAndGoons, UNFADE_SCREEN;
77			wait 5;						call beginCutsceneMageAndGoons, DISPLAY_REGION;}
78	}
79
80	else if (event == FADE_SCREEN)
81	{
82		//Fade screen to black:
83		UI_fade_palette(12, 1, 0);
84	}
85
86	else if (event == CENTER_VIEW)
87	{
88		//center around item:
89		center_view();
90	}
91
92	else if (event == UNFADE_SCREEN)
93	{
94		//Unfade screen:
95		UI_fade_palette(12, 1, 1);
96	}
97
98	else if (event == DISPLAY_REGION)
99	{
100		//The magical effect of the Gem of Dispelling
101
102		//item == mage
103
104		//Play a sound effect:
105		UI_play_sound_effect2(SOUND_MOONGATE, item);
106
107		//Get each of the mage's goons:
108		gargoyle = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
109										SHAPE_GARGOYLE_WARRIOR, 80, ID_MAGE_OR_GOON);
110		cyclops = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
111										SHAPE_CYCLOPS, 80, ID_MAGE_OR_GOON);
112		troll = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
113										SHAPE_TROLL, 80, ID_MAGE_OR_GOON);
114		fighter = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
115										SHAPE_FIGHTER_MALE, 80, ID_MAGE_OR_GOON);
116
117		//Make Laurianna visible and generate the scripts for the mage and goons:
118		script LAURIANNA after 6 ticks
119		{	nohalt;						call trueFreeze;
120			call beginCutsceneMageAndGoons, MAKE_VISIBLE;
121			wait 4;
122			call beginCutsceneMageAndGoons, GENERATE_SCRIPTS;}
123
124		//Make the mage and his goons visible:
125		script item after 6 ticks		{nohalt;	call beginCutsceneMageAndGoons, MAKE_VISIBLE;};
126		script gargoyle after 6 ticks	{nohalt;	call beginCutsceneMageAndGoons, MAKE_VISIBLE;};
127		script cyclops after 6 ticks	{nohalt;	call beginCutsceneMageAndGoons, MAKE_VISIBLE;};
128		script troll after 6 ticks		{nohalt;	call beginCutsceneMageAndGoons, MAKE_VISIBLE;};
129		script fighter after 6 ticks	{nohalt;	call beginCutsceneMageAndGoons, MAKE_VISIBLE;};
130	}
131
132	else if (event == MAKE_VISIBLE)
133	{
134		//item varies
135		//Clears DONT_RENDER flag:
136		clear_item_flag(DONT_RENDER);
137		//Play sound effect:
138		UI_play_sound_effect2(110, item);
139		//Show magic bubbles:
140		pos = get_object_position();
141		UI_sprite_effect(ANIMATION_PURPLE_BUBBLES, pos[X], pos[Y], 0, 0, 0, -1);
142	}
143
144	else if (event == GENERATE_SCRIPTS)
145	{
146		//item = LAURIANNA
147
148		//Make Laurianna have fireworks around her:
149		script LAURIANNA call beginCutsceneMageAndGoons, FIREWORKS_LAURIANNA;
150
151		//Get references for the mage and his goons:
152		mage = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
153										SHAPE_MAGE_MALE, 80, ID_MAGE_OR_GOON);
154		gargoyle = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
155										SHAPE_GARGOYLE_WARRIOR, 80, ID_MAGE_OR_GOON);
156		cyclops = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
157										SHAPE_CYCLOPS, 80, ID_MAGE_OR_GOON);
158		troll = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
159										SHAPE_TROLL, 80, ID_MAGE_OR_GOON);
160		fighter = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
161										SHAPE_FIGHTER_MALE, 80, ID_MAGE_OR_GOON);
162
163		//Laundo's script; he casts a couple spells and wonders why they failed; then,
164		//he turns to the Avatar and begins to talk:
165		script mage
166		{	wait 2;						actor frame cast_up;			wait 2;
167			actor frame cast_out;			wait 2;						actor frame cast_up;
168			wait 2;						actor frame cast_out;			wait 2;
169			say "@An Sanct Ort!@";		wait 2;						actor frame standing;
170			wait 2;						actor frame cast_up;			wait 2;
171			actor frame cast_out;			wait 2;						actor frame cast_up;
172			wait 2;						actor frame cast_out;			wait 2;
173			say "@An Ort Sanct!@";
174			wait 2;						actor frame standing;			wait 2;
175			face east;					say "@Damn! Why doesn't it work?@";
176			wait 18;					say "@The spell is correct!@";
177			wait 18;					say "@It -should- work!@";
178			wait 18;					say "@Something -must- protect her!@";
179			wait 34;					say "@What?!@";
180			wait 18;					say "@Intruders?!?@";
181			wait 20;					say "@I'll talk to them!@";
182			wait 12;					call beginCutsceneMageAndGoons, LAUNDO_SPEAKS;}
183
184		//Agra-Lem's script. He patrols around until he sees the Avatar and gang;
185		//then he sounds the alarm:
186		script gargoyle
187		{	repeat 4 {step west;		wait 2;};
188			actor frame standing;			wait 1;						face north;
189			wait 1;						face east;					wait 1;
190			repeat 5 {step east;		wait 2;};
191			actor frame standing;			wait 1;						face north;
192			wait 1;						face west;					wait 1;
193			repeat 2 {step west;		wait 2;};
194			actor frame standing;			wait 1;						face north;
195			wait 1;						actor frame standing;
196			repeat 3 {step north;		wait 2;};
197			actor frame standing;			wait 1;						face east;
198			wait 1;						face south;					wait 1;
199			repeat 4 {step south;		wait 2;};
200			wait 2;						say "@!!!@";				wait 6;
201			say "@To see intruders!@";
202			repeat 2 {step west;		wait 2;};
203			call beginCutsceneMageAndGoons, GARGOYLE_WARNS;}
204
205		//The cyclop's script. He just plays a game of Dragon, Sword, Gold
206		//with the troll:
207		script cyclops
208		{	actor frame raise_1h;		wait 4;						say "@Dragon...@";
209			actor frame ready;			wait 4;
210			actor frame raise_1h;		wait 4;						say "@... sword...@";
211			actor frame ready;			wait 4;
212			actor frame raise_1h;		wait 4;						say "@... gold!@";
213			actor frame strike_1h;		wait 4;
214			actor frame standing;			wait 8;						say "@Damn!@";
215			wait 56;					say "@Yer cheatin'!@";
216			wait 18;					say "@Yer winnin' always!@";
217			wait 22;					say "@Huh?@";}
218
219		//The troll's script. He just plays a game of Dragon, Sword, Gold
220		//with the cyclops:
221		script troll
222		{	wait 5;
223			actor frame raise_1h;		wait 4;						say "@Dragon...@";
224			actor frame ready;			wait 4;
225			actor frame raise_1h;		wait 4;						say "@... sword...@";
226			actor frame ready;			wait 4;
227			actor frame raise_1h;		wait 4;						say "@... gold!@";
228			actor frame strike_1h;		wait 4;
229			actor frame standing;			wait 6;						say "@Haha! My sword...@";
230			wait 18;					say "@... kills yer dragon!@";
231			wait 18;					say "@I win again!@";
232			wait 22;					say "@Am not!@";
233			wait 18;					say "@Yer too dumb!@";
234			wait 14;					face east;
235			say "@Intruders? Kill!@";}
236
237		//The human is having second doubts, but he is there for
238		//the money anyway...
239		script fighter
240		{	wait 4;						say "@What am I doing here?@";
241			wait 10;					say "@I mean, look who is around...@";
242			face north;
243			wait 16;					say "@One dumb troll...@";
244			wait 16;					say "@... a dumber cyclops...@";
245			wait 16;					say "@... one pissed-off gargoyle...@";
246			face east;
247			wait 16;					say "@... and a mad mage.@";
248			wait 20;					say "@The only good thing...@";
249			wait 16;					say "@... is the gold I get.@";
250			wait 24;					say "@Intruders? Where?@";}
251	}
252	else if (event == FIREWORKS_LAURIANNA)
253	{
254		//item = LAURIANNA
255		//This portion of the function is looped over and over
256		//again until Laundo's death halts it.
257		//Creates fireworks around Laurianna:
258		pos = LAURIANNA->get_object_position();
259		UI_sprite_effect(ANIMATION_FIREWORKS, pos[X], pos[Y], 0, 0, 0, -1);
260		//Loop:
261		script item after 10 ticks call beginCutsceneMageAndGoons, FIREWORKS_LAURIANNA;
262	}
263	else if (event == GARGOYLE_WARNS)
264	{
265		//item = gargoyle
266		//Gargoyle sounds the alarm:
267		script item
268		{	say "@To see intruders!@";
269			wait 12;					say "@To believe intruders...@";
270			wait 12;					say "@... to see us too!@";}
271
272		//A party member reacts to it:
273		script randomPartyMember() after 20 ticks say "@Ooops...@";
274	}
275	else if (event == LAUNDO_SPEAKS)
276	{
277		//Laundo begins talking to Avatar:
278		KEYRING_ENEMY->show_npc_face(LAUNDO_FACE);
279		say("@Hey! Thou there! Who art thou?@");
280		//Laundo demands Avatar's name...
281		var choice = askForResponse([getAvatarName(), "Avatar", "None of thy business"]);
282		if (choice == "Avatar")
283			say("The mage whispers to his companions. @I think we are safe. This one seems mad.@");
284
285		else if (choice == "None of thy business")
286			say("@A fiery spirit! I like that! No, wait -- I don't.@ He adds menacingly.");
287		else
288			say("@Bah, thy name is not really important and means nothing to me.@");
289
290		//...rapid-fires a lot of questions without giving time for answers...
291		say("@-I- am the archmage Laundo. Now, who art thou?");
292		say("@No, wait -- I have already asked that. What did I want to ask again?");
293		say("@Ah, yes! How didst thou -- a mere mortal -- dispel my warding spells?");
294		say("@And what art thou doing in my tower?");
295		say("@Wait -- I am -not- in my tower! Regardless, what art thou doing here?");
296		say("@Come now, speak quickly! Shouldst thou speak not, I shall kill thee where thou standest!");
297		say("@Won't thou say anything? Hast thou a death wish?");
298		say("@I am in the middle of an experiment! I don't have time for this! Speak or die!@");
299		//...and is warned by Agra-Lem of his behaviour:
300		const int GARGOYLE_FACE = -262;
301		GARGOYLE_FACE.say("The gargoyle interrupts. @Master! To not be letting intruder speak!@");
302		GARGOYLE_FACE.hide();
303		say("@Ah, thou art correct, Agra-lem. Go on, peasant! Speak! I shall listen.");
304		say("@Perhaps thou shalt amuse me before dying...@ he adds, sounding hopeful.");
305		add(["name", "job", "bye", "dispel", "tower", "Doing here", "rescue", "experiment", "Laurianna", "Rooted woman"]);
306
307		converse (0)
308		{
309			case "name" (remove):
310				say("@-I- am the archmage Laundo. Now, who art thou?");
311				say("@No, wait -- I have already asked that. Never mind.@");
312
313			case "job" (remove):
314				say("He looks at you with impatience. @I am a mage! An -arch-mage!@");
315				add("archmage");
316
317			case "archmage" (remove):
318				say("He gives you an exasperated look. @A mage so powerful he transcends other mages!");
319				say("@And I am one! Hahaha! Behold my powers and beware!@");
320
321			case "bye" (remove):
322				say("@Not so fast, peasant! Thou didst not tell me what thou art doing here!@");
323
324			case "dispel" (remove):
325				say("@Yes, I want to know how a nothing like thee dispelled my protection spells!");
326				say("@Wilt thou tell me or wilt thou die?@");
327				if (chooseFromMenu2(["tell", "die"]) == 2)
328					//Quickest way to end the talk:
329					break;
330
331				AVATAR.say("You quickly explain about the Gem of Dispelling to Laundo.");
332				AVATAR.hide();
333				say("@Gems of Dispelling? Never heard of them. It doesn't matter anyway.@");
334
335			case "tower" (remove):
336				say("@Yes, I have a tower. All wizards have one. But I want a -castle- instead.@");
337				add("castle");
338
339			case "castle" (remove):
340				say("@I mean castle British, of course. None others are worthy!");
341				say("@But alas, I must first slay that tyrant British to have his castle...@");
342				add("Tyrant British");
343
344			case "Doing here" (remove):
345				say("@Wilt thou tell me what art doing here?@");
346				if (chooseFromMenu2(["rescue", "lie"]) == 1)
347					say("@I am sorry to say thou hast wasted thy time. That mad mage sent thee on a wild goose chase.");
348				else
349					say("@I am sorry to say thou art wasting my time. I can feel the touch of that mad mage upon thee!");
350				say("@In any case, thou wilt fail to rescue this mageling! She is mine!@");
351				add("fail", "mad mage");
352				remove("rescue");
353
354			case "rescue" (remove):
355				say("@I am sorry to say thou hast wasted thy time. That mad mage sent thee on a wild goose chase.");
356				say("@In any case, thou wilt fail to rescue this mageling! She is mine!@");
357				add("fail", "mad mage");
358				remove("Doing here");
359
360			case "fail" (remove):
361				say("@Yes, thou wilt fail. By which I mean thou shalt die if thou dost try to rescue her.");
362				say("@And even if thou survivest, she will not be going anywhere...");
363				say("@Seest thou the necklace she wears? It is -my- handiwork.@");
364				add("necklace");
365
366			case "mad mage" (remove):
367				say("@Yes, that mage that wants to keep this menace alive!@ he points towards Laurianna.");
368				say("@He wants to keep that -beast- alive! And he helps people! He is -mad-!");
369				say("@With all the power he has, he could -- I mean, -should- -- kill the tyrant British!@");
370				add("Tyrant British");
371
372			case "Laurianna" (remove):
373				say("@Who? Never heard of her.@");
374				AVATAR.say("You explain that Laurianna is the woman with roots just nearby.");
375				AVATAR.hide();
376				say("@Ah, so -that- is her name? Well, it doesn't matter. She won't be going anywhere.");
377				say("@Seest thou the necklace she wears? It is -my- handiwork.@");
378				add("necklace");
379
380			case "necklace" (remove):
381				say("@It is lovely, is it not? It is a mighty artifact!");
382				say("@The person wearing it -- in this case, this dangerous lady here -- cannot move at all from where she is!");
383				say("@Not even magic can move her! And the necklace also cannot be removed! Hah! She shall be here forever!");
384				say("@And the best part is that the necklace will simply -explode- should someone powerful enough to dispel its magic");
385				say("@come even -near- it. That keeps that mad mage from trying to rescue her! Isn't it brilliant?");
386
387			case "experiment" (remove):
388				say("@Since thou wilt die anyway, I don't see why not explain the greatness of my plans to thee!");
389				say("@This woman is a menace. She wields enormous power, and has no control over them.");
390				say("@So I intend to give her powers to a worthy receptacle -- -me-!");
391				say("@I can then do what I want with them, and she won't be a menace anymore! Haha!");
392				say("@Of course, then I can remove other menaces from the face of Britannia.");
393				say("@One that comes to mind is that tyrant British. He -must- die!@");
394				add("Tyrant British");
395
396			case "Tyrant British" (remove):
397				say("@Thou knowest, that bloke with a crown which calls himself 'king'");
398				say("@That miserable excuse of a tyrant must perish for his misdeeds!@");
399
400			case "Rooted woman" (remove):
401				say("@Yes, that is an effect of the necklace I made for her. Isn't it lovely?@");
402				add("necklace");
403		}
404
405		//When all options are exhausted (or the player chose the quick rout),
406		//we get to this point:
407		say("@Well, it was interesting. But thou art boring me. So now it is time to die!@");
408
409		//Return view to avatar:
410		script AVATAR
411		{	nohalt;						call beginCutsceneMageAndGoons, FADE_SCREEN;
412			wait 2;						call beginCutsceneMageAndGoons, CENTER_VIEW;
413			wait 3;						call beginCutsceneMageAndGoons, UNFADE_SCREEN;
414			wait 3;						call beginCutsceneMageAndGoons, BEGIN_COMBAT;
415			wait 3;						call trueUnfreeze;
416};
417	}
418	else if (event == BEGIN_COMBAT)
419	{
420		//item = AVATAR
421		//Get references to the mage and his goons:
422		mage = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
423										SHAPE_MAGE_MALE, 80, ID_MAGE_OR_GOON);
424		gargoyle = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
425										SHAPE_GARGOYLE_WARRIOR, 80, ID_MAGE_OR_GOON);
426		cyclops = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
427										SHAPE_CYCLOPS, 80, ID_MAGE_OR_GOON);
428		troll = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
429										SHAPE_TROLL, 80, ID_MAGE_OR_GOON);
430		fighter = findNearbyMonsterWithID(LAURIANNA->get_object_position(),
431										SHAPE_FIGHTER_MALE, 80, ID_MAGE_OR_GOON);
432
433		//Make them hostile and in combat:
434		script mage		{nohalt;	call beginCutsceneMageAndGoons, PREPARE_NPC;};
435		script gargoyle	{nohalt;	call beginCutsceneMageAndGoons, PREPARE_NPC;};
436		script cyclops	{nohalt;	call beginCutsceneMageAndGoons, PREPARE_NPC;};
437		script troll	{nohalt;	call beginCutsceneMageAndGoons, PREPARE_NPC;};
438		script fighter	{nohalt;	call beginCutsceneMageAndGoons, PREPARE_NPC;};
439
440		//Release the Avatar from cutscene mode:
441	}
442
443	else if (event == PREPARE_NPC)
444	{
445		//item varies
446		//Make npc hostile:
447		set_alignment(2);
448		//Puts him in combat mode:
449		set_schedule_type(IN_COMBAT);
450		//Just to be sure:
451		clear_item_flag(DONT_RENDER);
452	}
453
454}
455
456void registerDeathOfMageOrGoon object#() ()
457{
458	if ((event == DEATH) &&  (get_npc_id() == ID_MAGE_OR_GOON))
459	{
460		if (get_item_shape() == SHAPE_MAGE_MALE)
461		{
462			//Laundo has died
463			//Set flag:
464			gflags[MAGE_KILLED] = true;
465			//Halt the fireworks around Laurianna:
466			LAURIANNA->halt_scheduled();
467		}
468		//This is called whenever the mage or one of his goons die
469		//Removes the mage/goon from tournament mode:
470		clear_item_flag(SI_TOURNAMENT);
471		//Kill them:
472		reduce_health(50, MAGIC_DAMAGE);
473		//Increase Laurianna's NPC ID:
474		var new_id = 1 + LAURIANNA->get_npc_id();
475		LAURIANNA->set_npc_id(new_id);
476
477		if (new_id == 5)
478		{
479			LAURIANNA->set_npc_id(5);
480			//Everyone is dead; halt scripts for Laurianna:
481			LAURIANNA->halt_scheduled();
482			//Prepare the next portion of the quest:
483			script LAURIANNA after 20 ticks call Laurianna, CLEAR_FLAGS;
484		}
485	}
486}
487