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