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