1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "xeen/sound.h"
24 #include "xeen/xeen.h"
25 #include "xeen/worldofxeen/darkside_cutscenes.h"
26 #include "xeen/worldofxeen/worldofxeen.h"
27
28 #define WAIT(TIME) if (_subtitles.wait(TIME)) return false
29
30 namespace Xeen {
31 namespace WorldOfXeen {
32
33 #define WAIT_SUBTITLES(time) \
34 _subtitles.show(); \
35 WAIT(time)
36
37 static const int PHAROAH_FRAMES[32] = {
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 2, 1,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
40 };
41 const int PHAROAH_YLIST[32] = {
42 -3, -3, -3, -3, -3, -3, -3, -3, -1, 0, 0, 0, 0, 0, 0, 0,
43 -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3
44 };
45 const int LEFT_CLAW_RUB_X[32] = {
46 223, 208, 187, 158, 129, 104, 85, 70, 61, 53, 49,
47 46, 46, 49, 53, 56, 61, 67, 72, 82, 91, 103,
48 117, 130, 142, 156, 170, 184, 199, 210, 221, 227
49 };
50 const int LEFT_CLAW_RUB_Y[32] = {
51 116, 111, 105, 103, 101, 96, 93, 92, 92, 95, 98,
52 100, 104, 107, 107, 105, 102, 100, 98, 99, 101, 104,
53 107, 109, 110, 111, 114, 115, 115, 116, 116, 118
54 };
55 static const int RIGHT_CLAW_IDLE_X[32] = {
56 146, 145, 143, 141, 141, 141, 141, 141, 141, 141, 141, 142, 143, 144, 145, 146,
57 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146
58 };
59 static const int RIGHT_CLAW_IDLE_Y[32] = {
60 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
61 143, 143, 144, 145, 145, 145, 145, 145, 145, 145, 145, 144, 143, 143, 143, 143
62 };
63 const int LEFT_CLAW_IDLE_X[32] = {
64 223, 222, 220, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
65 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 221
66 };
67 const int LEFT_CLAW_IDLE_Y[32] = {
68 116, 116, 116, 117, 117, 117, 117, 117, 118, 118, 118, 118, 118, 118, 118, 118,
69 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118
70 };
71
72
showDarkSideTitle(bool seenIntro)73 bool DarkSideCutscenes::showDarkSideTitle(bool seenIntro) {
74 Screen &screen = *g_vm->_screen;
75 Sound &sound = *g_vm->_sound;
76 g_vm->_files->_ccNum = true;
77 _subtitles.reset();
78
79 screen.loadPalette("dark.pal");
80 SpriteResource nwc[4] = {
81 SpriteResource("nwc1.int"), SpriteResource("nwc2.int"),
82 SpriteResource("nwc3.int"), SpriteResource("nwc4.int")
83 };
84 File voc[3];
85 voc[0].open("dragon1.voc");
86 voc[1].open("dragon2.voc");
87 voc[2].open("dragon3.voc");
88
89 // Load backgrounds
90 screen.loadBackground("nwc1.raw");
91 screen.loadPage(0);
92 screen.loadBackground("nwc2.raw");
93 screen.loadPage(1);
94
95 // Draw the screen and fade it in
96 screen.horizMerge(0);
97 screen.fadeIn();
98
99 sound.setMusicPercent(75);
100 sound.playFX(1);
101
102 // Initial loop for dragon roaring
103 int nwcIndex = 0, nwcFrame = 0;
104 for (int idx = 0; idx < 55 && !g_vm->shouldExit(); ++idx) {
105 // Render the next frame
106 screen.vertMerge(0);
107 nwc[nwcIndex].draw(0, nwcFrame);
108
109 switch (idx) {
110 case 17:
111 sound.playSound(voc[0]);
112 break;
113 case 34:
114 case 44:
115 ++nwcIndex;
116 nwcFrame = 0;
117 break;
118 case 35:
119 sound.playSound(voc[1]);
120 break;
121 default:
122 ++nwcFrame;
123 }
124
125 WAIT(2);
126 }
127
128 // Loop for dragon using flyspray
129 for (int idx = 0; idx < 42 && !g_vm->shouldExit(); ++idx) {
130 screen.vertMerge(SCREEN_HEIGHT);
131 nwc[3].draw(0, idx);
132
133 switch (idx) {
134 case 3:
135 sound.playFX(40);
136 break;
137 case 11:
138 sound.playFX(0);
139 break;
140 case 27:
141 case 30:
142 sound.playFX(3);
143 break;
144 case 31:
145 sound.playSound(voc[2]);
146 break;
147 case 33:
148 sound.playFX(2);
149 break;
150 default:
151 break;
152 }
153
154 WAIT(2);
155 }
156 if (g_vm->shouldExit())
157 return false;
158
159 // Pause for a bit
160 WAIT(10);
161 screen.fadeOut(8);
162
163 return true;
164 }
165
showDarkSideIntro(bool seenIntro)166 bool DarkSideCutscenes::showDarkSideIntro(bool seenIntro) {
167 FileManager &files = *g_vm->_files;
168 Screen &screen = *g_vm->_screen;
169 Sound &sound = *g_vm->_sound;
170
171 files._ccNum = true;
172 files.setGameCc(1);
173 _subtitles.reset();
174
175 if (showDarkSideTitle(seenIntro)) {
176 if (seenIntro) {
177 if (g_vm->getGameID() == GType_WorldOfXeen)
178 seenIntro = showWorldOfXeenLogo();
179 } else {
180 _ball.load("ball.int");
181 _dragon1.load("dragon1.int");
182 _claw.load("claw.int");
183
184 seenIntro = showDarkSideIntro1() && showDarkSideIntro2() && showDarkSideIntro3();
185
186 _ball.clear();
187 _dragon1.clear();
188 _claw.clear();
189
190 if (seenIntro && g_vm->getGameID() == GType_WorldOfXeen)
191 seenIntro = showWorldOfXeenLogo();
192 }
193 }
194
195 sound.stopAllAudio();
196 screen.freePages();
197
198 return seenIntro;
199 }
200
rubCrystalBall(bool fadeIn)201 bool DarkSideCutscenes::rubCrystalBall(bool fadeIn) {
202 Screen &screen = *g_vm->_screen;
203
204 for (int frame = 0; frame < 32; ++frame) {
205 screen.restoreBackground();
206
207 if (frame)
208 _ball.draw(0, frame - 1);
209 _claw.draw(0, 5, Common::Point(RIGHT_CLAW_IDLE_X[frame], RIGHT_CLAW_IDLE_Y[frame]), SPRFLAG_800);
210 _claw.draw(0, 6, Common::Point(149, 184));
211
212 _dragon1.draw(0, PHAROAH_FRAMES[frame], Common::Point(139, PHAROAH_YLIST[frame]), SPRFLAG_800);
213 _claw.draw(0, frame % 5, Common::Point(LEFT_CLAW_RUB_X[frame], LEFT_CLAW_RUB_Y[frame]), SPRFLAG_800);
214
215 if (_subtitles.active())
216 _subtitles.show();
217
218 if (fadeIn && frame == 0)
219 screen.fadeIn();
220 WAIT(3);
221 }
222
223 return true;
224 }
225
animatePharoah(int frame,bool showBall)226 void DarkSideCutscenes::animatePharoah(int frame, bool showBall) {
227 if (showBall && frame)
228 _ball.draw(0, frame - 1);
229 _claw.draw(0, 5, Common::Point(RIGHT_CLAW_IDLE_X[frame], RIGHT_CLAW_IDLE_Y[frame]), SPRFLAG_800);
230 _claw.draw(0, 6, Common::Point(149, 184));
231 _dragon1.draw(0, PHAROAH_FRAMES[frame], Common::Point(139, PHAROAH_YLIST[frame]), SPRFLAG_800);
232 _claw.draw(0, frame % 5, Common::Point(LEFT_CLAW_IDLE_X[frame], LEFT_CLAW_IDLE_Y[frame]), SPRFLAG_800);
233 }
234
showDarkSideIntro1()235 bool DarkSideCutscenes::showDarkSideIntro1() {
236 EventsManager &events = *g_vm->_events;
237 Screen &screen = *g_vm->_screen;
238 Sound &sound = *g_vm->_sound;
239 const int XLIST1[] = {
240 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 58, 60, 62
241 };
242 const int YLIST1[] = {
243 0, 5, 10, 15, 20, 25, 30, 35, 40, 40, 39, 37, 35, 33, 31
244 };
245 const int XLIST2[] = {
246 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 98, 90, 82
247 };
248
249 // Play the intro music
250 sound.setMusicPercent(75);
251 sound.playSong("bigtheme.m");
252
253 screen.loadBackground("jvc.raw");
254 screen.loadPalette("dark.pal");
255 screen.fadeIn();
256
257 WAIT(60);
258 screen.fadeOut(8);
259
260 screen.loadBackground("pyramid2.raw");
261 screen.loadPage(0);
262 screen.loadPage(1);
263 screen.loadBackground("pyramid3.raw");
264 screen.saveBackground();
265
266 SpriteResource title("title.int");
267 SpriteResource pyraTop("pyratop.int");
268 SpriteResource pyramid("pyramid.int");
269
270 screen.vertMerge(SCREEN_HEIGHT);
271 screen.loadPage(0);
272 screen.restoreBackground();
273 screen.loadPage(1);
274
275 // Show Might and Magic Darkside of Xeen title, and gradualy scroll
276 // the background vertically down to show the Pharoah's base
277 bool fadeFlag = true;
278 for (int yp = 0, frameNum = 0, idx1 = 0; yp < SCREEN_HEIGHT && !g_vm->shouldExit(); ++yp) {
279 screen.vertMerge(yp);
280
281 title.draw(0, 0);
282 if (frameNum)
283 title.draw(0, frameNum);
284
285 idx1 = (idx1 + 1) % 4;
286 if (!idx1)
287 frameNum = (frameNum + 1) % 10;
288
289 WAIT(1);
290
291 if (fadeFlag) {
292 screen.fadeIn();
293 fadeFlag = false;
294 }
295 }
296
297 screen.vertMerge(SCREEN_HEIGHT);
298 screen.saveBackground();
299 screen.freePages();
300
301 WAIT(20);
302
303 // Zoom into the Pharoah's base closeup view
304 sound.setMusicPercent(38);
305 for (int idx = 14; idx >= 0 && !g_vm->shouldExit(); --idx) {
306 pyraTop.draw(0, 0, Common::Point(XLIST1[idx], YLIST1[idx]), 0, idx);
307 pyraTop.draw(0, 1, Common::Point(XLIST2[idx], YLIST1[idx]), 0, idx);
308
309 WAIT(2);
310 }
311
312 // Inconceivable, the royal pyramid besieged
313 screen.saveBackground();
314 sound.playVoice("pharoh1a.voc");
315
316 _subtitles.setLine(0);
317
318 bool phar2 = false;
319 for (int idx = 0; idx < 19 && !g_vm->shouldExit(); ++idx) {
320 screen.restoreBackground();
321 pyramid.draw(0, idx, Common::Point(132, 62));
322 _subtitles.show();
323
324 if (!sound.isSoundPlaying() && !phar2)
325 sound.playVoice("pharoh1b.voc");
326
327 WAIT_SUBTITLES(4);
328 }
329
330 if (!_subtitles.waitForLineOrSound())
331 return false;
332 screen.fadeOut();
333
334 const int XLIST3[10] = { 102, 103, 104, 104, 104, 103, 102, 101, 101, 101 };
335 const int YLIST3[10] = { 30, 29, 28, 27, 26, 25, 24, 25, 26, 28 };
336 const int FRAMES3[70] = {
337 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 9, 9, 9, 0,
338 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8, 8,
339 8, 8, 9, 9, 9, 9, 165, 149, 126, 106, 92, 80, 66, 55, 42,
340 29, 10, -6, -26, -40, -56, -72, -83, 154, 141, 125, 105, 94, 83, 74,
341 69, 68, 70, 73, 77, 83, 89, 94, 99, 109
342 };
343 const char *const PHAR_VOC[5] = {
344 "pharoh2a.voc", "pharoh2b.voc", "pharoh2c.voc", "pharoh2d.voc", "pharoh2e.voc"
345 };
346
347 SpriteResource dragon("dragon.int");
348 _subtitles.setLine(1);
349
350 screen.loadBackground("2room.raw");
351 screen.loadPage(1);
352 screen.loadBackground("3room.raw");
353 screen.loadPage(0);
354 screen.loadBackground("1room.raw");
355 screen.saveBackground();
356 screen.horizMerge(SCREEN_WIDTH);
357 dragon.draw(0, 9, Common::Point(XLIST3[0], YLIST3[0]), SPRFLAG_800);
358
359 _subtitles.show();
360 screen.fadeIn();
361
362 int posNum = 0, phar2Index = 0, ctr = 0;
363 for (int idx = SCREEN_WIDTH, frameNum = 0; idx >= 0; --idx) {
364 events.updateGameCounter();
365 screen.horizMerge(idx);
366 dragon.draw(0, FRAMES3[frameNum], Common::Point(XLIST3[posNum], YLIST3[posNum]), SPRFLAG_800);
367 _subtitles.show();
368
369 if (idx == SCREEN_WIDTH)
370 sound.playVoice(PHAR_VOC[0]);
371 if (!sound.isSoundPlaying() && phar2Index < 4)
372 sound.playVoice(PHAR_VOC[1 + phar2Index++]);
373
374 if (phar2Index == 4) {
375 if (!sound.isSoundPlaying() && !_subtitles.active())
376 break;
377 }
378
379 if (++ctr > 2) {
380 if (posNum == 5)
381 sound.playFX(7);
382 else if (posNum == 0)
383 sound.playFX(8);
384
385 posNum = (posNum + 1) % 10;
386 frameNum = (frameNum + 1) % 36;
387 }
388
389 WAIT(1);
390 }
391
392 sound.stopSound();
393 screen.fadeOut();
394 screen.freePages();
395 return true;
396 }
397
398 #define ANIMATE_PHAROAH \
399 screen.restoreBackground(); \
400 animatePharoah(clawCtr); \
401 clawCtr = (clawCtr + 1) % 32
402
showDarkSideIntro2()403 bool DarkSideCutscenes::showDarkSideIntro2() {
404 Screen &screen = *g_vm->_screen;
405 Sound &sound = *g_vm->_sound;
406 SpriteResource goon("goon.int"), darkLord("darklord.int"), queen("queen.int"),
407 wizard("wizard.int"), fizzle("fizzle.int"), wizMth("wizmth.int");
408 int idx, clawCtr;
409
410 screen.loadPalette("dark.pal");
411 screen.loadBackground("ball.raw");
412 screen.saveBackground();
413
414 if (!rubCrystalBall(true))
415 return false;
416
417 // Queen Kalindra?
418 _subtitles.setLine(9);
419 sound.playFX(42);
420
421 for (idx = 0, clawCtr = 0; idx < 11; ++idx) {
422 ANIMATE_PHAROAH;
423 if (idx > 3)
424 queen.draw(0, 0, Common::Point(9, 57));
425 fizzle.draw(0, idx, Common::Point(9, 57));
426
427 if (idx == 6) {
428 sound.playVoice("pharoh3.voc");
429 sound.playFX(0);
430 }
431
432 if (idx > 6)
433 _subtitles.show();
434 WAIT(3);
435 }
436
437 const char *const VOC_NAMES[4] = { "queen1.voc", "queen2.voc", "queenhis.voc", "pharoh4.voc" };
438 int nwcIndex = 0, vocIndex = 0;
439 do {
440 ANIMATE_PHAROAH;
441
442 if (!sound.isSoundPlaying() && vocIndex < 3) {
443 if (!_subtitles.active()) {
444 if (!vocIndex)
445 _subtitles.setLine(10);
446
447 sound.playVoice(VOC_NAMES[vocIndex++]);
448 if (vocIndex == 3)
449 nwcIndex = 7;
450 }
451 }
452
453 if (nwcIndex) {
454 queen.draw(0, (nwcIndex >= 17) ? 0 : nwcIndex,
455 Common::Point(9, 57));
456 if (nwcIndex < 17)
457 ++nwcIndex;
458 } else {
459 queen.draw(0, (vocIndex == 0) ? 0 : getSpeakingFrame(0, 5),
460 Common::Point(9, 57));
461 }
462
463 _subtitles.show();
464 WAIT(3);
465 } while (vocIndex < 3 || sound.isSoundPlaying() || _subtitles.active());
466
467 sound.playVoice(VOC_NAMES[3]);
468 _subtitles.setLine(11);
469
470 idx = 34;
471 do {
472 ANIMATE_PHAROAH;
473 queen.draw(0, 0, Common::Point(9, 57));
474
475 if (++idx <= 37)
476 idx = 34;
477
478 _subtitles.show();
479 WAIT(3);
480 } while (sound.isSoundPlaying() || _subtitles.active());
481
482 _subtitles.setLine(12);
483 sound.playVoice("dark3.voc");
484
485 const char *const VOC_NAMES2[2] = { "pharoh5a.voc", "pharoh5b.voc" };
486 vocIndex = 0;
487
488 do {
489 ANIMATE_PHAROAH;
490 darkLord.draw(0, vocIndex == 0 ? getSpeakingFrame(0, 3) : 0, Common::Point(9, 57));
491
492 _subtitles.show();
493 WAIT(3);
494 if (!sound.isSoundPlaying() && vocIndex < 2) {
495 if (vocIndex)
496 _subtitles.setLine(13);
497 sound.playVoice(VOC_NAMES2[vocIndex++]);
498 }
499 } while (vocIndex < 2 || sound.isSoundPlaying() || _subtitles.active());
500
501 sound.playFX(42);
502 vocIndex = 0;
503
504 for (idx = 10; idx >= 0; --idx) {
505 ANIMATE_PHAROAH;
506
507 if (!sound.isSoundPlaying() && !vocIndex) {
508 sound.playVoice("laff1.voc");
509 vocIndex = 1;
510 }
511
512 if (idx > 3)
513 darkLord.draw(0, getSpeakingFrame(0, 3), Common::Point(9, 57));
514 fizzle.draw(0, idx, Common::Point(9, 57));
515
516 _subtitles.show();
517 WAIT(3);
518 }
519
520 sound.playFX(0);
521
522 do {
523 ANIMATE_PHAROAH;
524
525 _subtitles.show();
526 WAIT(3);
527 } while (sound.isSoundPlaying() || _subtitles.active());
528
529 if (!rubCrystalBall())
530 return false;
531
532 for (idx = 0, clawCtr = 0; idx < 11; ++idx) {
533 ANIMATE_PHAROAH;
534
535 if (idx > 3)
536 goon.draw(0, 0, Common::Point(9, 57));
537 fizzle.draw(0, idx, Common::Point(9, 57));
538
539 if (idx == 6)
540 sound.playVoice("pharoh6w.voc");
541 if (idx > 6)
542 _subtitles.show();
543 WAIT(3);
544 }
545
546 const char *const VOC_NAMES3[2] = { "alamar1.voc", "pharoh7t.voc" };
547 vocIndex = nwcIndex = 0;
548 _subtitles.setLine(14);
549
550 do {
551 ANIMATE_PHAROAH;
552 goon.draw(0, (vocIndex == 0) ? 0 : nwcIndex, Common::Point(9, 57));
553
554 if (!sound.isSoundPlaying() && !vocIndex && !_subtitles.active()) {
555 _subtitles.setLine(15);
556 sound.playVoice(VOC_NAMES3[vocIndex++]);
557 sound.playFX(0);
558 }
559
560 nwcIndex = (nwcIndex + 1) % 17;
561 _subtitles.show();
562 WAIT(3);
563 } while (!vocIndex || sound.isSoundPlaying() || _subtitles.active());
564
565 _subtitles.setLine(16);
566 sound.playFX(42);
567
568 for (idx = 10, vocIndex = 0; idx >= 0; --idx) {
569 ANIMATE_PHAROAH;
570 if (idx > 4)
571 goon.draw(0, 0, Common::Point(9, 57));
572 fizzle.draw(0, idx, Common::Point(9, 57));
573
574 if (!sound.isSoundPlaying() && !vocIndex) {
575 sound.playVoice("pharoh7t.voc");
576 vocIndex = 1;
577 }
578
579 _subtitles.show();
580 WAIT(3);
581 }
582
583 sound.playFX(0);
584
585 if (!rubCrystalBall())
586 return false;
587
588 _subtitles.setLine(17);
589
590 for (idx = 0, clawCtr = 0; idx < 11; ++idx) {
591 ANIMATE_PHAROAH;
592
593 if (idx > 3)
594 wizard.draw(0, 0, Common::Point(9, 57));
595 fizzle.draw(0, idx, Common::Point(9, 57));
596
597 if (idx == 5)
598 sound.playVoice("pharoh8.voc");
599 if (idx > 6)
600 _subtitles.show();
601
602 WAIT(3);
603 }
604
605 const char *const VOC_NAMES4[3] = { "ellinger.voc", "pharoh9a.voc", "pharoh9b.voc" };
606 vocIndex = 0;
607
608 do {
609 ANIMATE_PHAROAH;
610 wizard.draw(0, (vocIndex == 1) ? getSpeakingFrame(0, 3) : 0, Common::Point(9, 57));
611
612 if (!sound.isSoundPlaying() && vocIndex < 2 && !_subtitles.active()) {
613 _subtitles.setLine((vocIndex == 0) ? 18 : 19);
614 sound.playVoice(VOC_NAMES4[vocIndex++]);
615 sound.playFX(0);
616 }
617
618 _subtitles.show();
619 WAIT(3);
620 } while (vocIndex < 2 || sound.isSoundPlaying() || _subtitles.active());
621
622 sound.playFX(42);
623
624 for (idx = 10; idx >= 0; --idx) {
625 ANIMATE_PHAROAH;
626 if (idx > 4)
627 wizard.draw(0, 0, Common::Point(9, 57));
628 fizzle.draw(0, idx, Common::Point(9, 57));
629
630 _subtitles.show();
631 WAIT(3);
632 }
633
634 _subtitles.setLine(20);
635 vocIndex = 0;
636
637 do {
638 ANIMATE_PHAROAH;
639
640 if (!sound.isSoundPlaying() && !vocIndex) {
641 sound.playVoice("pharoh9b.voc");
642 vocIndex = 1;
643 }
644
645 _subtitles.show();
646 WAIT(3);
647 } while (sound.isSoundPlaying() || !vocIndex || _subtitles.active());
648
649 sound.playFX(0);
650 screen.fadeOut();
651
652 return true;
653 }
654
showDarkSideIntro3()655 bool DarkSideCutscenes::showDarkSideIntro3() {
656 Screen &screen = *g_vm->_screen;
657 Sound &sound = *g_vm->_sound;
658 SpriteResource fly("fly.int");
659 SpriteResource bird[11];
660 SpriteResource drop[4];
661 for (int idx = 0; idx < 11; ++idx)
662 bird[idx].load(Common::String::format("bird%02d.int", idx + 1));
663 for (int idx = 0; idx < 4; ++idx)
664 drop[idx].load(Common::String::format("drop%d.int", idx + 1));
665
666 screen.loadPalette("fly.pal");
667 screen.loadBackground("fly.raw");
668 screen.saveBackground();
669
670 _subtitles.setLine(6);
671 _subtitles.show();
672
673 screen.fadeIn();
674 sound.playVoice("pharoh11.voc", 2);
675
676 for (int idx = 0; idx < 35; ++idx) {
677 screen.restoreBackground();
678 fly.draw(0, idx);
679
680 if (idx == 16 || idx == 28)
681 sound.playFX(43);
682 WAIT(2);
683 }
684
685 sound.playFX(0);
686 screen.fadeOut();
687 sound.setMusicPercent(75);
688 screen.loadBackground("bird.raw");
689 screen.saveBackground();
690 screen.fadeIn();
691
692 for (int idx = 0; idx < 81; ++idx) {
693 screen.restoreBackground();
694 bird[idx / 8].draw(0, idx % 8);
695
696 switch (idx) {
697 case 1:
698 sound.playSound("comet.voc");
699 sound.playFX(43);
700 break;
701 case 16:
702 case 39:
703 sound.playFX(43);
704 break;
705 case 21:
706 sound.playSound("comet.voc");
707 break;
708 case 56:
709 sound.playSound("screech.voc");
710 break;
711 case 61:
712 sound.playSound("disint.voc");
713 break;
714 case 73:
715 sound.playSound("laff1.voc");
716 break;
717 default:
718 break;
719 }
720
721 WAIT(2);
722 }
723
724 sound.playFX(0);
725 screen.loadBackground("drop.raw");
726 screen.saveBackground();
727
728 for (int idx = 0; idx < 39; ++idx) {
729 screen.restoreBackground();
730 drop[idx / 12].draw(0, idx % 12);
731
732 if (idx == 9)
733 sound.playSound("branch.voc");
734 else if (idx == 22)
735 sound.playSound("vine.voc");
736
737 WAIT(2);
738 }
739
740 sound.playSound("thud.voc");
741 screen.fadeOut(24);
742
743 SpriteResource end[3] = {
744 SpriteResource("end1.int"), SpriteResource("end2.int"), SpriteResource("end3.int")
745 };
746 screen.loadBackground("end.raw");
747 screen.saveBackground();
748 screen.fadeIn();
749 //sound.playSong(16);
750
751 for (int idx = 0; idx < 19; ++idx) {
752 screen.restoreBackground();
753 end[idx / 8].draw(0, idx % 8);
754 WAIT(4);
755 }
756
757 SpriteResource title2("title2.int");
758 const byte TITLE_XLIST1[] = { 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55 };
759 const byte TITLE_XLIST2[] = { 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105 };
760 const byte TITLE_YLIST[] = { 0, 5, 10, 15, 20, 25, 30, 36, 44, 51, 57, 62 };
761
762 screen.saveBackground();
763 WAIT(20);
764
765 for (int idx = 11; idx >= 0; --idx) {
766 screen.restoreBackground();
767 title2.draw(0, 0, Common::Point(TITLE_XLIST1[idx], TITLE_YLIST[idx]), 0, idx);
768 title2.draw(0, 1, Common::Point(TITLE_XLIST2[idx], TITLE_YLIST[idx]), 0, idx);
769
770 WAIT(2);
771 }
772
773 screen.fadeOut();
774 return true;
775 }
776
showWorldOfXeenLogo()777 bool DarkSideCutscenes::showWorldOfXeenLogo() {
778 Screen &screen = *g_vm->_screen;
779 Sound &sound = *g_vm->_sound;
780 SpriteResource fizzle("fizzle.int");
781 SpriteResource wfire[7];
782 for (uint idx = 0; idx < 7; ++idx)
783 wfire[idx].load(Common::String::format("wfire%u.int", idx + 1));
784
785 screen.loadBackground("firemain.raw");
786 screen.loadPalette("firemain.pal");
787 screen.saveBackground();
788 screen.fadeIn();
789 WAIT(10);
790
791 for (int idx = 0; idx < 28; ++idx) {
792 if (idx == 17)
793 sound.playSound("explosio.voc");
794 if (!sound.isSoundPlaying() && idx < 17)
795 sound.playSound("rumble.voc");
796
797 screen.restoreBackground();
798 wfire[idx / 5].draw(0, idx % 5, Common::Point(0, 45));
799 WAIT(2);
800 }
801
802 screen.saveBackground();
803
804 for (int loopCtr = 0; loopCtr < 2; ++loopCtr) {
805 for (int idx = 0; idx < 21; ++idx) {
806 screen.restoreBackground();
807 wfire[6].draw(0, idx, Common::Point(0, 45));
808
809 switch (idx) {
810 case 0:
811 case 11:
812 sound.playSound("thud.voc");
813 break;
814 case 3:
815 sound.playFX(60);
816 break;
817 default:
818 break;
819 }
820
821 WAIT(2);
822 }
823 }
824
825 WAIT(10);
826 screen.fadeOut();
827 return true;
828 }
829
showDarkSideEnding(uint endingScore)830 void DarkSideCutscenes::showDarkSideEnding(uint endingScore) {
831 FileManager &files = *g_vm->_files;
832 Screen &screen = *g_vm->_screen;
833 Sound &sound = *g_vm->_sound;
834
835 files.setGameCc(1);
836 _subtitles.reset();
837 sound._musicSide = 1;
838 screen.fadeOut();
839
840 if (showDarkSideEnding1())
841 if (showDarkSideEnding2())
842 if (showDarkSideEnding3())
843 showDarkSideEnding4();
844
845 showDarkSideScore(endingScore);
846
847 _claw.clear();
848 _dragon1.clear();
849 screen.fadeOut();
850 }
851
showDarkSideEnding1()852 bool DarkSideCutscenes::showDarkSideEnding1() {
853 EventsManager &events = *g_vm->_events;
854 Screen &screen = *g_vm->_screen;
855 Sound &sound = *g_vm->_sound;
856
857 sound.playSong("dngon3.m");
858 screen.loadBackground("scene1.raw");
859 screen.loadPalette("endgame.pal");
860 screen.update();
861
862 screen.fadeIn();
863 WAIT(30);
864
865 screen.fadeOut();
866 screen.loadBackground("scene2-b.raw");
867 screen.update();
868 screen.saveBackground();
869 SpriteResource::setClippedBottom(171);
870
871 SpriteResource faceEnd("face.end");
872 screen.restoreBackground();
873 faceEnd.draw(0, 0, Common::Point(29, 76), SPRFLAG_BOTTOM_CLIPPED);
874 screen.update();
875
876 screen.fadeIn();
877 WAIT(1);
878
879 // Alamar stands up
880 for (int yp = 74; yp > 20; yp -= 2) {
881 if (yp == 60)
882 sound.songCommand(207);
883 else if (yp == 22)
884 sound.stopSong();
885
886 screen.restoreBackground();
887 faceEnd.draw(0, 0, Common::Point(29, yp), SPRFLAG_BOTTOM_CLIPPED);
888 screen.update();
889
890 WAIT(2);
891 }
892 faceEnd.clear();
893
894 // Alamar says "Come to me"
895 sound.playVoice("come2.voc");
896 _subtitles.setLine(21);
897 WAIT(27);
898
899 // Show the entire throne room
900 screen.loadBackground("mainback.raw");
901 SpriteResource sc03a("sc03a.end"), sc03b("sc03b.end"), sc03c("sc03c.end");
902 sc03a.draw(0, 0, Common::Point(250, 0));
903
904 screen.saveBackground();
905 screen.update();
906 WAIT(30);
907
908 // Silhouette of door opening
909 sound.playSound("door.voc");
910 for (int idx = 0; idx < 6; ++idx) {
911 screen.restoreBackground();
912 sc03b.draw(0, idx, Common::Point(72, 125));
913 screen.update();
914
915 WAIT(4);
916 }
917
918 // Silhouette of playing entering
919 for (int idx = 0; idx < 19; ++idx) {
920 screen.restoreBackground();
921 sc03c.draw(0, idx, Common::Point(72, 125));
922 screen.update();
923
924 if (idx == 3 || idx == 11)
925 sound.playFX(7);
926 if (idx == 7 || idx == 16)
927 sound.playFX(8);
928
929 WAIT(4);
930 }
931
932 sc03a.clear();
933 sc03b.clear();
934 sc03c.clear();
935
936 // Box throwing
937 screen.loadBackground("scene4.raw");
938 screen.loadPage(0);
939 screen.loadBackground("scene4-1.raw");
940 screen.loadPage(1);
941 SpriteResource disk("disk.end");
942 File whoosh("whoosh.voc");
943
944 screen.horizMerge();
945 int yp = 101, tCtr = 0, frameNum = 0;
946 for (int xp = 0; xp < 320; xp += 2) {
947 screen.horizMerge(xp);
948
949 disk.draw(0, frameNum, Common::Point(xp / 2, yp));
950 if (xp < 44)
951 disk.draw(0, 11, Common::Point(-xp, 22), SPRFLAG_800);
952 disk.draw(0, 10, Common::Point(0, 134));
953
954 if (!(xp % 22))
955 sound.playSound(whoosh);
956 WAIT(1);
957
958 if (++tCtr % 2)
959 frameNum = (frameNum + 1) % 10;
960
961 if (xp < 100)
962 --yp;
963 else if (xp > 150)
964 ++yp;
965 }
966
967 whoosh.close();
968 WAIT(10);
969
970 // Play landing thud
971 sound.playSound("thud.voc");
972 while (!g_vm->shouldExit() && !events.isKeyMousePressed()
973 && sound.isSoundPlaying()) {
974 events.pollEventsAndWait();
975 }
976
977 // Fade over to box opening background
978 events.updateGameCounter();
979 screen.freePages();
980 screen.fadeOut();
981 screen.loadBackground("sc050001.raw");
982 screen.update();
983 screen.saveBackground();
984 screen.fadeIn();
985 events.updateGameCounter();
986
987 // Box opening
988 SpriteResource diskOpen[5] = {
989 SpriteResource("diska.end"), SpriteResource("diskb.end"),
990 SpriteResource("diskc.end"), SpriteResource("diskd.end"),
991 SpriteResource("diske.end")
992 };
993 File click("click.voc");
994
995 for (int idx = 0; idx < 34; ++idx) {
996 screen.restoreBackground();
997 diskOpen[idx / 8].draw(0, idx % 8, Common::Point(28, 11));
998
999 WAIT(3);
1000 if (idx == 0 || idx == 2 || idx == 4 || idx == 6)
1001 sound.playSound(click);
1002 else if (idx == 18)
1003 sound.playSound("explosio.voc");
1004 else if (idx == 9 || idx == 10 || idx == 11 || idx == 12)
1005 sound.playFX(30);
1006 else if (idx == 13)
1007 sound.playFX(14);
1008 }
1009 click.close();
1010 for (int idx = 0; idx < 5; ++idx)
1011 diskOpen[idx].clear();
1012
1013 SpriteResource sc06[2] = {
1014 SpriteResource("sc06a.end"), SpriteResource("sc06b.end")
1015 };
1016 screen.loadBackground("mainback.raw");
1017 screen.saveBackground();
1018 sc06[0].draw(0, 0);
1019 screen.update();
1020 sound.playSound("alien2.voc");
1021
1022 // Zoomed out throneroom view of beam coming out of box
1023 for (int idx = 0; idx < 20; ++idx) {
1024 if (idx == 6 || idx == 8 || idx == 9 || idx == 10
1025 || idx == 13 || idx == 15 || idx == 16)
1026 sound.playFX(3);
1027
1028 screen.restoreBackground();
1029 sc06[idx / 10].draw(0, idx % 10);
1030 screen.update();
1031
1032 WAIT(3);
1033 }
1034
1035 screen.fadeOut();
1036 sc06[0].clear();
1037 sc06[1].clear();
1038
1039 // Corak appearing
1040 SpriteResource sc07[8] = {
1041 SpriteResource("sc07a.end"), SpriteResource("sc07b.end"),
1042 SpriteResource("sc07c.end"), SpriteResource("sc07d.end"),
1043 SpriteResource("sc07e.end"), SpriteResource("sc07f.end"),
1044 SpriteResource("sc07g.end"), SpriteResource("sc07h.end")
1045 };
1046
1047 screen.loadBackground("sc070001.raw");
1048 screen.saveBackground();
1049 screen.update();
1050 screen.fadeIn();
1051 WAIT(2);
1052
1053 for (int idx = 0; idx < 45; ++idx) {
1054 screen.restoreBackground();
1055 sc07[idx / 6].draw(0, idx % 6, Common::Point(61, 12));
1056
1057 if (_subtitles.active() == 0)
1058 screen.update();
1059 else
1060 _subtitles.show();
1061
1062 WAIT(2);
1063 if (idx == 40)
1064 _subtitles.setLine(22);
1065 else if (idx == 1 || idx == 19)
1066 // Wind storm
1067 sound.playSound("windstor.voc");
1068 }
1069
1070 return true;
1071 }
1072
showDarkSideEnding2()1073 bool DarkSideCutscenes::showDarkSideEnding2() {
1074 EventsManager &events = *g_vm->_events;
1075 Screen &screen = *g_vm->_screen;
1076 Sound &sound = *g_vm->_sound;
1077
1078 // Corak?!
1079 sound.playVoice("corak2.voc");
1080
1081 // Yep, that's my name, don't wear it out
1082 SpriteResource sc08("sc08.end");
1083 sound.playFX(0);
1084
1085 for (int idx = 0; idx < 15; ++idx) {
1086 if (idx == 2) {
1087 if (!_subtitles.waitForLineOrSound())
1088 return false;
1089 sound.playVoice("yes1.voc");
1090 _subtitles.setLine(23);
1091 }
1092
1093 // Animate Corak speaking
1094 sc08.draw(0, sound.isSoundPlaying() ? getSpeakingFrame(0, 2) : 0);
1095 _subtitles.show();
1096 WAIT(3);
1097 }
1098
1099 if (!_subtitles.waitForLineOrSound())
1100 return false;
1101 sc08.clear();
1102
1103 // Nowhere to run to
1104 SpriteResource sc09("sc09.end");
1105
1106 screen.loadBackground("sc090001.raw");
1107 screen.saveBackground();
1108 screen.update();
1109
1110 _subtitles.setLine(24);
1111
1112 for (int idx = 0; idx < 15; ++idx) {
1113 if (idx == 2)
1114 sound.playVoice("nowre1.voc");
1115
1116 screen.restoreBackground();
1117 sc09.draw(0, getSpeakingFrame(0, 8));
1118 _subtitles.show();
1119 WAIT(3);
1120 }
1121
1122 if (!_subtitles.waitForLineOrSound())
1123 return false;
1124 sc09.clear();
1125
1126 // Nor do you!
1127 SpriteResource sc10("sc10.end");
1128 _subtitles.setLine(25);
1129
1130 for (int idx = 0; idx < 15; ++idx) {
1131 if (idx == 3)
1132 sound.playVoice("nordo2.voc");
1133
1134 screen.restoreBackground();
1135 sc10.draw(0, getSpeakingFrame(0, 1));
1136 _subtitles.show();
1137 WAIT(3);
1138 }
1139
1140 if (!_subtitles.waitForLineOrSound())
1141 return false;
1142 sc10.clear();
1143
1144 // Closeup of side of Alamar's helmet
1145 SpriteResource sc11("sc11.end");
1146 sound.setMusicPercent(75);
1147 sound.playSong("dngon2.m");
1148 screen.fadeOut();
1149 screen.loadBackground("blank.raw");
1150 screen.saveBackground();
1151
1152 for (int idx = 0; idx < 15; ++idx) {
1153 screen.restoreBackground();
1154 sc11.draw(0, idx, Common::Point(100, 44));
1155
1156 if (idx == 0)
1157 screen.fadeIn();
1158 WAIT(3);
1159
1160 if (idx == 3)
1161 sound.playSound("click.voc");
1162 else if (idx == 5)
1163 sound.playSound("airmon.voc");
1164 }
1165
1166 screen.fadeOut();
1167
1168 // Helmet raises, we see the face appear
1169 for (int idx = 80; idx > 20; idx -= 2) {
1170 screen.restoreBackground();
1171 sc11.draw(0, 15, Common::Point(60, 80));
1172 sc11.draw(0, 16, Common::Point(61, idx));
1173 sc11.draw(0, 17);
1174 screen.update();
1175
1176 if (idx == 80)
1177 screen.fadeIn();
1178
1179 WAIT(3);
1180 }
1181
1182 // Sheltem is revealed
1183 sc11.clear();
1184 screen.fadeOut();
1185 screen.loadBackground("scene12.raw");
1186 screen.update();
1187 screen.fadeIn();
1188 WAIT(30);
1189 screen.fadeOut();
1190
1191 // I'm ready for you this time
1192 SpriteResource sc13("sc13.end");
1193 _subtitles.setLine(26);
1194 sound.setMusicPercent(38);
1195
1196 for (int idx = 0; idx < 16; ++idx) {
1197 if (idx == 1)
1198 sound.playVoice("ready2.voc");
1199
1200 sc13.draw(0, getSpeakingFrame(0, 3));
1201 _subtitles.show();
1202
1203 if (idx == 0)
1204 screen.fadeIn();
1205 WAIT(3);
1206 }
1207
1208 do {
1209 sc13.draw(0, 0);
1210 _subtitles.show();
1211 events.pollEventsAndWait();
1212 } while (_subtitles.active() && !g_vm->shouldExit());
1213
1214 sc13.clear();
1215
1216 // This fight will be your last
1217 SpriteResource sc14("sc14.end");
1218 _subtitles.setLine(27);
1219
1220 screen.fadeOut();
1221 screen.loadBackground("blank.raw");
1222 screen.saveBackground();
1223
1224 sc14.draw(0, 0, Common::Point(37, 37));
1225 screen.update();
1226 screen.fadeIn();
1227
1228 for (int waveNum = 0; waveNum < 2; ++waveNum) {
1229 for (int idx = 0; idx < 10; ++idx) {
1230 if (waveNum == 0 && idx == 3)
1231 sound.playSound("fight2.voc");
1232
1233 screen.restoreBackground();
1234 sc14.draw(0, idx, Common::Point(37, 37));
1235 _subtitles.show();
1236 WAIT(3);
1237 }
1238 }
1239
1240 if (!_subtitles.waitForLineOrSound())
1241 return false;
1242
1243 return true;
1244 }
1245
showDarkSideEnding3()1246 bool DarkSideCutscenes::showDarkSideEnding3() {
1247 Screen &screen = *g_vm->_screen;
1248 Sound &sound = *g_vm->_sound;
1249
1250 // Fighting start
1251 SpriteResource sc15("sc15.end");
1252 screen.loadBackground("mainback.raw");
1253 screen.saveBackground();
1254 sc15.draw(0, 0, Common::Point(52, 84));
1255 screen.update();
1256
1257 for (int idx = 0; idx < 21; ++idx) {
1258 screen.restoreBackground();
1259 sc15.draw(0, idx, Common::Point(52, 84));
1260 screen.update();
1261 WAIT(3);
1262
1263 if (idx == 4)
1264 sound.playSound("disint.voc");
1265 else if (idx == 12)
1266 sound.playSound("explosio.voc");
1267 }
1268
1269 sc15.clear();
1270 sound.stopSound();
1271
1272 // I can not fail
1273 SpriteResource sc16("sc16.end");
1274 _subtitles.setLine(28);
1275
1276 screen.loadBackground("scene4.raw");
1277 screen.loadPage(0);
1278 screen.loadBackground("scene4-1.raw");
1279 screen.loadPage(1);
1280 screen.loadBackground("sc170001.raw");
1281 screen.saveBackground();
1282 screen.horizMerge(0);
1283 sc16.draw(0, 0, Common::Point(7, 29));
1284 _subtitles.show();
1285 sound.playVoice("fail1.voc", 2);
1286
1287 for (int idx = 0; idx < 5; ++idx) {
1288 screen.horizMerge(0);
1289 sc16.draw(0, idx, Common::Point(7, 29));
1290 _subtitles.show();
1291 WAIT(4);
1292 }
1293
1294 // Force sphere goes horizontally
1295 int val = 5;
1296 for (int idx = 0; idx < 320; idx += 16) {
1297 screen.horizMerge(idx);
1298 sc16.draw(0, (val >= 12) ? 11 : val++,
1299 Common::Point(idx * -1 + 7, 29));
1300
1301 if (val > 10)
1302 sc16.draw(0, 12, Common::Point(273, 70));
1303
1304 _subtitles.show();
1305 WAIT(2);
1306
1307 if (idx == 48)
1308 sound.playSound("alien2.voc");
1309 }
1310
1311 screen.freePages();
1312 sc16.clear();
1313
1314 // Sheltem protects himself with cloak
1315 SpriteResource sc17[2] = {
1316 SpriteResource("sc17xa.end"), SpriteResource("sc17xb.end")
1317 };
1318 screen.restoreBackground();
1319 screen.update();
1320
1321 for (int idx = 0; idx < 16; ++idx) {
1322 screen.restoreBackground();
1323 sc17[idx / 8].draw(0, idx % 8, Common::Point(44, 19));
1324 screen.update();
1325 WAIT(3);
1326
1327 if (idx == 9)
1328 sound.playSound("thud1.voc");
1329 }
1330
1331 screen.fadeOut();
1332 sc17[0].clear();
1333 sc17[1].clear();
1334
1335 // Sheltem fires on Corak
1336 SpriteResource sc18[4] = {
1337 SpriteResource("sc18a.end"), SpriteResource("sc18b.end"),
1338 SpriteResource("sc18c.end"), SpriteResource("sc18d.end")
1339 };
1340 screen.loadBackground("sc180001.raw");
1341 screen.saveBackground();
1342 screen.update();
1343 screen.fadeIn();
1344
1345 for (int idx = 0; idx < 31; ++idx) {
1346 screen.restoreBackground();
1347 sc18[idx / 8].draw(0, idx % 8, Common::Point(29, 12));
1348 screen.update();
1349 WAIT(3);
1350
1351 if (idx == 2)
1352 sound.playSound("gascompr.voc");
1353 }
1354
1355 for (int idx = 0; idx < 4; ++idx)
1356 sc18[idx].clear();
1357
1358 // Closeup of Corak bleeding
1359 SpriteResource sc19("sc19.end");
1360 screen.loadBackground("sc190001.raw");
1361 screen.saveBackground();
1362 screen.update();
1363
1364 for (int idx = 0; idx < 28; ++idx) {
1365 if (idx == 20)
1366 sound.songCommand(207);
1367
1368 screen.restoreBackground();
1369 sc19.draw(0, idx, Common::Point(33, 10));
1370 WAIT(3);
1371 }
1372
1373 sc19.clear();
1374 sound.stopSong();
1375 screen.fadeOut();
1376
1377 // Corak waving his hands
1378 SpriteResource sc20("sc20.end");
1379 sound.setMusicPercent(75);
1380 sound.playSong("sf17.m");
1381 screen.loadBackground("blank.raw");
1382 screen.saveBackground();
1383 screen.update();
1384 screen.fadeIn();
1385
1386 for (int waveNum = 0; waveNum < 2; ++waveNum) {
1387 sound.playSound("cast.voc");
1388
1389 for (int idx = 0; idx < 9; ++idx) {
1390 screen.restoreBackground();
1391 sc20.draw(0, idx, Common::Point(80, 18));
1392 screen.update();
1393 WAIT(3);
1394 }
1395 }
1396
1397 sc20.clear();
1398
1399 // Sheltem bounces back bolts that Corak fires
1400 SpriteResource sc21("sc21.end");
1401 File alien2("alien2.voc");
1402 screen.loadBackground("mainback.raw");
1403 screen.saveBackground();
1404 sc21.draw(0, 0, Common::Point(133, 81));
1405 screen.update();
1406
1407 for (int boltNum = 0; boltNum < 4; ++boltNum) {
1408 sound.playSound(alien2);
1409
1410 for (int idx = (boltNum == 0) ? 0 : 3; idx < 13; ++idx) {
1411 screen.restoreBackground();
1412 sc21.draw(0, idx, Common::Point(133, 81));
1413 WAIT(2);
1414 }
1415 }
1416
1417 screen.restoreBackground();
1418 sc21.draw(0, 0, Common::Point(133, 81));
1419 screen.update();
1420
1421 sc21.clear();
1422 alien2.close();
1423
1424 // Sheltem fires force sphere at Corak
1425 SpriteResource sc22("sc22.end");
1426 screen.loadBackground("scene4.raw");
1427 screen.loadPage(0);
1428 screen.loadBackground("scene4-1.raw");
1429 screen.loadPage(1);
1430 screen.loadBackground("sc230001.raw");
1431 screen.saveBackground();
1432 screen.horizMerge(SCREEN_WIDTH);
1433
1434 while (sound.isSoundPlaying()) {
1435 WAIT(1);
1436 }
1437
1438 sc22.draw(0, 0, Common::Point(156, 28));
1439 screen.update();
1440 sound.playSound("cast.voc");
1441
1442 for (int idx = 0; idx < 5; ++idx) {
1443 screen.horizMerge(SCREEN_WIDTH);
1444 sc22.draw(0, idx, Common::Point(156, 28));
1445 screen.update();
1446 WAIT(3);
1447 }
1448
1449 // The sphere travels horizontally
1450 sound.playSound("gascompr.voc");
1451
1452 int ctr = 5;
1453 for (int idx = SCREEN_WIDTH, xOffset = 0; idx >= 0; idx -= 16, xOffset += 16) {
1454 screen.horizMerge(idx);
1455 sc22.draw(0, (ctr >= 8) ? 7 : ctr++,
1456 Common::Point(xOffset + 156, 28), SPRFLAG_800);
1457 if (ctr > 7)
1458 sc22.draw(0, 8, Common::Point(136, 64));
1459 screen.update();
1460
1461 WAIT(2);
1462 }
1463
1464 screen.freePages();
1465 sc22.clear();
1466
1467 // Corak raises shield and blocks sphere
1468 SpriteResource sc23[2] = {
1469 SpriteResource("sc23a.end"), SpriteResource("sc23b.end")
1470 };
1471
1472 screen.restoreBackground();
1473 screen.update();
1474 sound.playSound("cast.voc");
1475
1476 for (int idx = 0; idx < 19; ++idx) {
1477 screen.restoreBackground();
1478 sc23[idx / 12].draw(0, idx % 12, Common::Point(72, 4));
1479 screen.update();
1480 WAIT(3);
1481
1482 if (idx == 5)
1483 sound.playSound("padspell.voc");
1484 else if (idx == 11)
1485 sound.playFX(9);
1486 }
1487
1488 screen.restoreBackground();
1489 sc23[0].draw(0, 0, Common::Point(72, 4));
1490 screen.update();
1491 screen.fadeOut();
1492
1493 return true;
1494 }
1495
showDarkSideEnding4()1496 bool DarkSideCutscenes::showDarkSideEnding4() {
1497 EventsManager &events = *g_vm->_events;
1498 FileManager &files = *g_vm->_files;
1499 Screen &screen = *g_vm->_screen;
1500 Sound &sound = *g_vm->_sound;
1501
1502 // Corak does a ricochet shot on Sheltem
1503 SpriteResource sc24[2] = {
1504 SpriteResource("sc24a.end"), SpriteResource("sc24b.end")
1505 };
1506
1507 screen.loadBackground("mainback.raw");
1508 screen.saveBackground();
1509 sc24[0].draw(0, 0, Common::Point(148, 0));
1510 screen.update();
1511 screen.fadeIn(4);
1512 sound.playSound("cast.voc");
1513
1514 for (int idx = 0; idx < 30; ++idx) {
1515 screen.restoreBackground();
1516 sc24[idx / 15].draw(0, idx % 15, Common::Point(148, 0));
1517 screen.update();
1518 WAIT(3);
1519
1520 if (idx == 6)
1521 sound.playSound("padspell.voc");
1522 else if (idx == 11 || idx == 14)
1523 sound.playSound("click.voc");
1524 else if (idx == 17)
1525 sound.playSound("thud1.voc");
1526 }
1527
1528 sc24[0].clear();
1529 sc24[1].clear();
1530
1531 // Admit your defeat Corak
1532 // Interestingly, the original also has a sc25b.end here, which was of
1533 // Corak speaking here. It seems this was ditched in favor of the
1534 // following closeup of him speaking "I do"
1535 SpriteResource sc25("sc25a.end");
1536 _subtitles.setLine(29);
1537
1538 screen.loadBackground("sc250001.raw");
1539 screen.saveBackground();
1540 sc25.draw(0, 0, Common::Point(27, 30));
1541 screen.update();
1542
1543 for (int struggleNum = 0; struggleNum < 2; ++struggleNum) {
1544 for (int idx = 0; idx < 9; ++idx) {
1545 if (struggleNum == 0 && idx == 2)
1546 sound.playVoice("admit2.voc");
1547
1548 sc25.draw(0, idx, Common::Point(27, 30));
1549 _subtitles.show();
1550 WAIT(3);
1551 }
1552 }
1553
1554 sc25.clear();
1555
1556 // I do. Kamakazi time
1557 SpriteResource sc26[4] = {
1558 SpriteResource("sc26a.end"), SpriteResource("sc26b.end"),
1559 SpriteResource("sc26c.end"), SpriteResource("sc26d.end")
1560 };
1561 _subtitles.setLine(30);
1562
1563 screen.loadBackground("sc260001.raw");
1564 screen.saveBackground();
1565 _subtitles.show();
1566 sound.playVoice("ido2.voc");
1567
1568 for (int idx = 0; sound.isSoundPlaying() || _subtitles.active(); ) {
1569 screen.restoreBackground();
1570 sc26[idx / 8].draw(0, idx % 8, Common::Point(58, 25));
1571 WAIT(2);
1572
1573 idx = (idx == 31) ? 22 : idx + 1;
1574 }
1575
1576 screen.loadBackground("sc270001.raw");
1577 screen.saveBackground();
1578
1579 while (sound.isSoundPlaying() && !g_vm->shouldExit()) {
1580 events.pollEventsAndWait();
1581 if (events.isKeyMousePressed())
1582 return false;
1583 }
1584
1585 for (int idx = 0; idx < 4; ++idx)
1586 sc26[idx].clear();
1587
1588 // What? No!
1589 SpriteResource sc27("sc27.end");
1590 _subtitles.setLine(31);
1591 _subtitles.show();
1592
1593 for (int idx = 0; idx < 12; ++idx) {
1594 if (idx == 1)
1595 sound.playVoice("what3.voc");
1596
1597 screen.restoreBackground();
1598 sc27.draw(0, idx, Common::Point(65, 22));
1599 _subtitles.show();
1600 WAIT(3);
1601 }
1602
1603 sc27.clear();
1604
1605 // Vortex is opened and the two are sucked in, obliterating them
1606 files.setGameCc(2);
1607 SpriteResource sc28[11] = {
1608 SpriteResource("sca28.end"), SpriteResource("scb28.end"),
1609 SpriteResource("scc28.end"), SpriteResource("scd28.end"),
1610 SpriteResource("sce28.end"), SpriteResource("scf28.end"),
1611 SpriteResource("scg28.end"), SpriteResource("sch28.end"),
1612 SpriteResource("sci28.end"), SpriteResource("sck28.end"),
1613 SpriteResource("sck28.end")
1614 };
1615
1616 sound.playSong("dungeon2.m");
1617 screen.fadeOut();
1618 screen.loadBackground("mainback.raw");
1619 screen.saveBackground();
1620
1621 sc28[0].draw(0, 0, Common::Point(74, 0));
1622 screen.update();
1623 screen.fadeIn();
1624 files.setGameCc(1);
1625
1626 for (int idx = 0; idx < 44; ++idx) {
1627 screen.restoreBackground();
1628 sc28[idx / 4].draw(0, idx % 4, Common::Point(74, 0));
1629 screen.update();
1630 WAIT(3);
1631
1632 if (idx == 0 || idx == 10 || idx == 18)
1633 sound.playSound("rumble.voc");
1634 else if (idx == 27)
1635 sound.playSound("airmon.voc");
1636 else if (idx == 38)
1637 sound.playSound("explosio.voc");
1638 }
1639
1640 screen.fadeOut();
1641 for (int idx = 0; idx < 11; ++idx)
1642 sc28[idx].clear();
1643
1644 // Longshot of castle blowing up
1645 SpriteResource sc29[6] = {
1646 SpriteResource("sc29a.end"), SpriteResource("sc29b.end"),
1647 SpriteResource("sc29c.end"), SpriteResource("sc29d.end"),
1648 SpriteResource("sc29e.end"), SpriteResource("sc29f.end")
1649 };
1650
1651 screen.loadBackground("sc290001.raw");
1652 screen.saveBackground();
1653 screen.fadeIn();
1654
1655 for (int idx = 0; idx < 54; ++idx) {
1656 screen.restoreBackground();
1657 if (idx == 40)
1658 sound.songCommand(207);
1659
1660 sc29[idx / 10].draw(0, idx % 10, Common::Point(92, 10));
1661 screen.update();
1662 WAIT(3);
1663
1664 if (idx == 1 || idx == 5 || idx == 11 || idx == 19 || idx == 34 || idx == 35)
1665 sound.playSound("explosio.voc");
1666 }
1667
1668 // Final bit of smoke from destroyed castle
1669 for (int loopNum = 0; loopNum < 4; ++loopNum) {
1670 for (int idx = 49; idx < 54; ++idx) {
1671 screen.restoreBackground();
1672 sc29[idx / 10].draw(0, idx % 10, Common::Point(92, 10));
1673 screen.update();
1674 WAIT(3);
1675 }
1676 }
1677
1678 screen.fadeOut();
1679 sound.stopSong();
1680 return true;
1681 }
1682
showDarkSideScore(uint endingScore)1683 void DarkSideCutscenes::showDarkSideScore(uint endingScore) {
1684 SavesManager &saves = *g_vm->_saves;
1685 Sound &sound = *g_vm->_sound;
1686
1687 sound.stopAllAudio();
1688
1689 if (!g_vm->shouldExit()) {
1690 sound.playSong("outday3.m");
1691
1692 Common::String str = Common::String::format(Res.DARKSIDE_ENDING1, endingScore);
1693 showPharaohEndText(str.c_str(), Res.DARKSIDE_ENDING2);
1694
1695 g_vm->_mode = MODE_INTERACTIVE;
1696 if (!g_vm->shouldExit())
1697 saves.saveGame();
1698 }
1699 }
1700
showPharaohEndText(const char * msg1,const char * msg2,const char * msg3)1701 bool DarkSideCutscenes::showPharaohEndText(const char *msg1, const char *msg2, const char *msg3) {
1702 Windows &windows = *g_vm->_windows;
1703 _ball.load("ball.int");
1704 _claw.load("claw.int");
1705 _dragon1.load("dragon1.int");
1706
1707 windows[39].setBounds(Common::Rect(12, 8, 162, 198));
1708 bool result = showPharaohEndTextInner(msg1, msg2, msg3);
1709
1710 _ball.clear();
1711 _claw.clear();
1712 _dragon1.clear();
1713 return result;
1714 }
1715
showPharaohEndTextInner(const char * msg1,const char * msg2,const char * msg3)1716 bool DarkSideCutscenes::showPharaohEndTextInner(const char *msg1, const char *msg2, const char *msg3) {
1717 Screen &screen = *g_vm->_screen;
1718 EventsManager &events = *g_vm->_events;
1719 Windows &windows = *g_vm->_windows;
1720 int numPages = 0 + (msg1 ? 1 : 0) + (msg2 ? 1 : 0) + (msg3 ? 1 : 0);
1721 const char *const text[3] = { msg1, msg2, msg3 };
1722
1723 screen.loadBackground("3room.raw");
1724 screen.saveBackground();
1725 screen.loadPalette("dark.pal");
1726
1727 int clawCtr = 0;
1728 ANIMATE_PHAROAH;
1729 screen.fadeIn();
1730 events.clearEvents();
1731
1732 // Iterate through showing the pages
1733 for (int pageNum = 0; !g_vm->shouldExit() && pageNum < numPages; ++pageNum) {
1734 // Show each page until a key is pressed
1735 do {
1736 events.updateGameCounter();
1737 screen.restoreBackground();
1738 animatePharoah(clawCtr, false);
1739 clawCtr = (clawCtr + 1) % 32;
1740
1741 // Form the text string to display the text
1742 Common::String str1 = Common::String::format(Res.PHAROAH_ENDING_TEXT1,
1743 text[pageNum]);
1744 windows[39].writeString(str1);
1745
1746 Common::String str2 = Common::String::format(Res.PHAROAH_ENDING_TEXT2,
1747 text[pageNum]);
1748 windows[39].writeString(str2);
1749
1750 windows[0].update();
1751 events.wait(1);
1752 } while (!g_vm->shouldExit() && !events.isKeyMousePressed());
1753
1754 events.clearEvents();
1755 }
1756
1757 return true;
1758 }
1759
1760 } // End of namespace WorldOfXeen
1761 } // End of namespace Xeen
1762