aboutsummaryrefslogtreecommitdiff
path: root/engines/sky/intro.cpp
blob: 00b1e51248ff8bc5cfa6045fbe3284724ab2218d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */


#include "common/endian.h"
#include "common/util.h"
#include "common/events.h"
#include "common/system.h"
#include "common/textconsole.h"

#include "sky/disk.h"
#include "sky/intro.h"
#include "sky/music/musicbase.h"
#include "sky/screen.h"
#include "sky/sky.h"
#include "sky/sound.h"
#include "sky/struc.h"
#include "sky/text.h"

#include "audio/audiostream.h"
#include "audio/decoders/raw.h"

namespace Sky {

#define SHOWSCREEN		 0
#define COMMANDEND		 0 // end of COMMANDFLIRT block
#define FADEUP			 1 // fade up palette
#define FADEDOWN		 2
#define DELAY			 3
#define DOFLIRT			 4 // start flirt sequence (and wait for it to finish)
#define SCROLLFLIRT		 5 // start special floppy intro flirt sequence (and wait for it)
#define COMMANDFLIRT	 6 // start flirt sequence and wait for it, while processing command block
#define BGFLIRT			 7 // start flirt sequence without waiting for it
#define WAITFLIRT		 8 // wait for sequence started by BGFLIRT
#define STOPFLIRT		 9
#define STARTMUSIC		10
#define WAITMUSIC		11
#define PLAYVOICE		12
#define WAITVOICE		13
#define LOADBG			14 // load new background sound
#define PLAYBG			15 // play background sound
#define LOOPBG			16 // loop background sound
#define STOPBG			17 // stop background sound
#define CLEARBOTTOM		18 // clear the screen
#define SEQEND		 65535 // end of intro sequence

// Modifier flag for SHOWSCREEN when we want the image to cover the entire
// screen.
#define FULLSCREEN		0x8000

#define IC_PREPARE_TEXT 20 // commands used in COMMANDFLIRT block
#define IC_SHOW_TEXT    21
#define IC_REMOVE_TEXT  22
#define IC_MAKE_SOUND   23
#define IC_FX_VOLUME    24

#define FRAME_SIZE (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT)
#define INTRO_TEXT_WIDTH 128
//CD intro file defines
#define CDV_00	59500
#define CD_PAL	59501
#define CD_1_LOG	59502
#define CD_1	59503
#define CDV_01	59504
#define CDV_02	59505
#define CD_2	59506
#define CDV_03	59507
#define CDV_04	59508
#define CD_3	59509
#define CDV_05	59510
#define CDV_06	59511
#define CD_5	59512
#define CDV_07	59513
#define CDV_08	59514
#define CDV_09	59515
#define CD_7	59516
#define CDV_10	59518
#define CD_11	59519
#define CDV_11	59520
#define CD_11_PAL	59521
#define CD_11_LOG	59522
#define CDV_12	59523
#define CD_13	59524
#define CDV_13	59525
#define CDV_14	59527
#define CDV_15	59528
#define CD_15_PAL	59529
#define CD_15_LOG	59530
#define CDV_16	59531
#define CD_17_LOG	59532
#define CD_17	59533
#define CDV_17	59534
#define CDV_18	59535
#define CDV_19	59536
#define CD_19_PAL	59537
#define CD_19_LOG	59538
#define CDV_20	59539
#define CD_20_LOG	59540
#define CDV_21	59541
#define CD_21_LOG	59542
#define CDV_22	59545
#define CDV_23	59546
#define CD_23_PAL	59547
#define CD_24_LOG	59550
#define CDV_24	59551
#define CDV_25	59554
#define CDV_26	59556
#define CD_27	59557
#define CDV_27	59558
#define CD_27_PAL	59559
#define CD_27_LOG	59560
#define CDV_28	59561
#define CDV_29	59562
#define CDV_30	59563
#define CDV_31	59565
#define CDV_32	59566
#define CDV_33	59567
#define CDV_34	59568
#define CD_35	59569
#define CDV_35	59570
#define CD_35_PAL	59571
#define CD_35_LOG	59572
#define CDV_36	59574
#define CD_37	59575
#define CDV_37	59576
#define CD_37_PAL	59577
#define CD_37_LOG	59578
#define CDV_38	59579
#define CDV_39	59581
#define CDV_40	59583
#define CD_40_PAL	59584
#define CD_40_LOG	59585
#define CDV_41	59587
#define CDV_42	59588
#define CD_43	59589
#define CDV_43	59590
#define CD_43_PAL	59591
#define CD_43_LOG	59592
#define CDV_44	59594
#define CD_45	59595
#define CDV_45	59596
#define CD_45_PAL	59597
#define CD_45_LOG	59598
#define CDV_46	59600
#define CDV_47	59602
#define CD_47_PAL	59603
#define CD_47_LOG	59604
#define CD_48	59605
#define CDV_48	59606
#define CD_48_PAL	59607
#define CD_48_LOG	59608
#define CD_49	59609
#define CDV_49	59610
#define CD_50	59611
#define CDV_50	59612
#define CDV_51	59613
#define CDV_52	59614
#define CDV_53	59615
#define CDV_54	59616
#define CDV_55	59618
#define CD_55_PAL	59619
#define CD_55_LOG	59620
#define CDV_56	59621
#define CDV_57	59622
#define CD_58	59623
#define CDV_58	59624
#define CD_58_PAL	59625
#define CD_58_LOG	59626
#define CDV_59	59627
#define CDV_60	59628
#define CDV_61	59629
#define CDV_62	59630
#define CDV_63	59631
#define CDV_64	59632
#define CDV_65	59633
#define CDV_66	59635
#define CD_66_PAL	59636
#define CD_66_LOG	59637
#define CDV_67	59639
#define CD_67_PAL	59640
#define CD_67_LOG	59641
#define CDV_68	59642
#define CD_69	59643
#define CDV_69	59644
#define CD_69_PAL	59645
#define CD_69_LOG	59646
#define CDV_70	59647
#define CDV_71	59648
#define CDV_72	59649
#define CD_72_PAL	59650
#define CD_72_LOG	59651
#define CD_73_PAL	59652
#define CD_73_LOG	59653
#define CDV_73	59654
#define CDV_74	59655
#define CDV_75	59656
#define CD_76_PAL	59657
#define CD_76_LOG	59658
#define CDV_76	59659
#define CDV_77	59660
#define CD_78_PAL	59661
#define CD_78_LOG	59662
#define CDV_78	59663
#define CDV_79	59664
#define CDV_80	59665
#define CDV_81	59666
#define CDV_82	59667
#define CDV_83	59668
#define CDV_84	59669
#define CDV_85	59670
#define CDV_86	59671
#define CDV_87	59672
#define CD_100	60087
#define CD_101_LOG	60088
#define CD_101	60099
#define CD_102_LOG	60090
#define CD_102	60091
#define CD_103_PAL	60092
#define CD_103_LOG	60093
#define CD_103	60094
#define CD_104_PAL	60095
#define CD_104_LOG	60096
#define CD_104	60097
#define CD_105	60098


uint16 Intro::_mainIntroSeq[] = {
	DELAY,       3000, // keep virgin screen up
	FADEDOWN,
	SHOWSCREEN, 60112, // revo screen + palette
	FADEUP,     60113,
	DELAY,       8000,
	FADEDOWN,
	SHOWSCREEN, 60114, // gibbo screen + palette
	FADEUP,     60115,
	DELAY,       2000,
	FADEDOWN,
	SEQEND
};

uint16 Intro::_cdIntroSeq[] = {
	/* black screen */
	PLAYVOICE,	CDV_00,	// Foster: "The old man was trying to tell the future. Looking for pictures in the campfire..."
	LOADBG,		59499,	// Fire crackle
	LOOPBG,
	WAITVOICE,
	PLAYVOICE,	CDV_01,	// Shaman: "ohhh, I see evil..."
	/* Fade up shaman image while he says his line... */
	SHOWSCREEN,	CD_1_LOG,
	FADEUP,		CD_PAL,
	/* And then play the animation showing the shadows of the fire on his face */
	BGFLIRT,	CD_1,
		WAITVOICE,
		PLAYVOICE,	CDV_02,	// Shaman: "Evil born deep beneath the city... far from the light of day."
		WAITVOICE,
	STOPFLIRT,
	BGFLIRT,	CD_2,
		PLAYVOICE,	CDV_03, // Shaman: "I see it growing, safe beneath a sky of steel..."
		WAITVOICE,
		PLAYVOICE,	CDV_04, // Shaman: "Scheming in the dark... gathering strength."
	WAITFLIRT,
	WAITVOICE,
	PLAYVOICE,	CDV_05,		// Shaman: "And now... ohhh.... now the evil spreads..."
	DELAY,		2000,
	BGFLIRT,	CD_3,
		WAITVOICE,
		PLAYVOICE,	CDV_06,	// Shaman: "It sends deadly feelers over the land above..."
	WAITFLIRT,
	WAITVOICE,
	PLAYVOICE,	CDV_07,		// Shaman: "Across the gap... reaching towards this very place!"
	BGFLIRT,	CD_5,
		WAITVOICE,
		PLAYVOICE,	CDV_08,	// Foster: "I'd seen him do this a hundred times, but I humoured him."
		WAITVOICE,
		PLAYVOICE,	CDV_09,	// Foster: "After all, he'd been like a father to me."
	WAITFLIRT,
	WAITVOICE,
	PLAYVOICE,	CDV_10,		// Foster: "And what does this evil want here?"
	BGFLIRT,	CD_7,
		WAITVOICE,
		PLAYVOICE,	CDV_11, // Shaman: "Oh, my son. I fear..."
	WAITFLIRT,
	FADEDOWN,
	SHOWSCREEN,	CD_11_LOG,
	FADEUP,		CD_11_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_12,		// Shaman: "I fear the evil wants you!"
	DELAY,		1600,
	BGFLIRT,	CD_11,
		WAITVOICE,
		PLAYVOICE,	CDV_13,	// Foster: "That was when Joey piped up..."
		WAITVOICE,
	WAITFLIRT,
	WAITVOICE,
	PLAYVOICE,	CDV_14,		// Joey: "Foster! Sensors detect incoming audio source!"
	LOADBG,		59498, // fire crackle to heli start
	PLAYBG,
	DOFLIRT,	CD_13,
	WAITVOICE,
	PLAYVOICE,	CDV_15,		// Shaman: "The evil! The evil is nearly here...!"
	FADEDOWN,
	SHOWSCREEN,	CD_15_LOG,
	FADEUP,		CD_15_PAL,
	WAITVOICE,
	LOADBG,		59496, // quiet heli
	LOOPBG,
	PLAYVOICE,	CDV_16,		// Foster: "It sounded more like a 'copter than a demon."
	WAITVOICE,
	PLAYVOICE,	CDV_17,		// Foster: "But next thing, all hell let loose anyway..."
	DELAY,		2000,
	SHOWSCREEN,	CD_17_LOG,
	WAITVOICE,
	BGFLIRT,	CD_17,
		PLAYVOICE,	CDV_18,	// Shaman: "Run, Foster! Run! Hide from the evil!"
	LOADBG,		59497, // loud heli
	LOOPBG,
	WAITFLIRT,
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_19_LOG,
	FADEUP,		CD_19_PAL,
	PLAYVOICE,	CDV_19,		// Joey: "Foster! (zzzt) H-Help!"
	WAITVOICE,
	PLAYVOICE,	CDV_20,		// Joey: "Better make my next body move faster, Foster..."
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_20_LOG,
	FADEUP,		CD_19_PAL,
	WAITVOICE,
	LOADBG,		59496, // quiet heli
	LOOPBG,
	PLAYVOICE,	CDV_21,		// Foster: "He was only a robot, but, well, I loved the little guy."
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_21_LOG,
	FADEUP,		CD_19_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_22,		// Foster: "Then, as suddenly as it started, the shooting stopped."
	LOADBG,		59494, // heli whine
	PLAYBG,
	WAITVOICE,
	PLAYVOICE,	CDV_23,		// Foster: "There was a moment's silence as the copter cut its rotors, then..."
	/* fade down while Foster's saying his line */
	FADEDOWN,
	WAITVOICE,
	SHOWSCREEN | FULLSCREEN,	CD_24_LOG,
	FADEUP,		CD_23_PAL,
	PLAYVOICE,	CDV_24,		// Reich: "Whoever is in charge here, come forward..."
	WAITVOICE,
	PLAYVOICE,	CDV_25,		// Reich: "Now!!"
	WAITVOICE,
	PLAYVOICE,	CDV_26,		// Foster: "Only a fool would have argued with that firepower."
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_27_LOG,
	FADEUP,		CD_27_PAL,
	PLAYVOICE,	CDV_27,		// Shaman: "... I am the leader of these people... We are peaceful..."
	WAITVOICE,
	PLAYVOICE,	CDV_29,		// Reich: "Bring him here."
	WAITVOICE,
	PLAYVOICE,	CDV_30,		// Guard: "At once, Commander Reich."
	WAITVOICE,
	BGFLIRT,	CD_27,
		PLAYVOICE,	CDV_31,	// Reich: "We're looking for someone..."
		WAITFLIRT,
		CLEARBOTTOM,
		WAITVOICE,
		PLAYVOICE,	CDV_32,	// Reich: "Someone who doesn't belong here..."
		WAITVOICE,
		PLAYVOICE,	CDV_33,	// Reich: "Who wasn't born in this garbage dump..."
		WAITVOICE,
		PLAYVOICE,	CDV_34,	// Reich: "Who came from the city as a child..."
	WAITVOICE,
	PLAYVOICE,	CDV_35,		// Reich: "We want to take him home again."
	WAITVOICE,
	PLAYVOICE,	CDV_36,		// Foster: "My mind racing, I remembered where I'd seen that symbol before..."
		FADEDOWN,
		SHOWSCREEN | FULLSCREEN,	CD_35_LOG,
		FADEUP,		CD_35_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_37,		// Foster: "It was the day the tribe found me..."
		DOFLIRT,	CD_35,
	CLEARBOTTOM,
	WAITVOICE,
	PLAYVOICE,	CDV_38,		// Foster: "The day of the crash..."
		DOFLIRT,	CD_37,
	WAITVOICE,
	PLAYVOICE,	CDV_39,		// Foster: "The day my mother died."
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_40_LOG,
	FADEUP,		CD_40_PAL,
	PLAYVOICE,	CDV_40,		// Shaman: "You alright, city boy?"
	WAITVOICE,
	PLAYVOICE,	CDV_41,		// Shaman: "Got a name, son?"
	WAITVOICE,
	PLAYVOICE,	CDV_42,		// Foster: "R-Robert."
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_43_LOG,
	FADEUP,		CD_43_PAL,
	PLAYVOICE,	CDV_43,		// Shaman: "Hah! Welcome to the Gap, Robert!"
	WAITVOICE,
	DOFLIRT,	CD_43,
	PLAYVOICE,	CDV_45,		// Foster: "As he patched me up, the old man had gently explained that there was no way back into the City..."
	FADEDOWN,
	SHOWSCREEN,	CD_45_LOG,
	FADEUP,		CD_45_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_46,		// Foster: "And I already knew there was nothing he could do for mother."
	DOFLIRT,	CD_45,
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_47_LOG,
	FADEUP,		CD_47_PAL,
	PLAYVOICE,	CDV_47,		// Foster: "His tribe was poor, but they treated me like one of their own..."
	WAITVOICE,
	PLAYVOICE,	CDV_48,		// Foster: "I learned how to survive in the wasteland they called the Gap..."
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_48_LOG,
	FADEUP,		CD_48_PAL,
	WAITVOICE,
	BGFLIRT,	CD_48,
		PLAYVOICE,	CDV_49,	// Foster: "And scavenging from the City dumps."
		WAITVOICE,
		PLAYVOICE,	CDV_50,	// Foster: "As the years passed, I forgot my life in the City."
	WAITFLIRT,
	WAITVOICE,
	PLAYVOICE,	CDV_51,		// Foster: "Discovered new talents..."
	BGFLIRT,	CD_49,
		WAITVOICE,
		PLAYVOICE,	CDV_52,	// Foster: "Hah!"
		WAITVOICE,
		PLAYVOICE,	CDV_53,	// Joey: "I'm your (zzzt) friend... call me (zzzt) Joey."
		WAITVOICE,
	WAITFLIRT,
	PLAYVOICE,	CDV_54,		// Foster: "And got a second name."
	DOFLIRT,	CD_50,
	WAITVOICE,
	PLAYVOICE,	CDV_55,		// Shaman: "This is what we'll call you now you've come of age, son."
	WAITVOICE,
	PLAYVOICE,	CDV_56,		// Shaman: "We found you... we fostered you..."
		FADEDOWN,
		SHOWSCREEN,	CD_55_LOG,
		FADEUP,		CD_55_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_57,		// Shaman: "So that makes you Robert Foster."
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN,	CD_58_LOG,
	FADEUP,		CD_58_PAL,
	PLAYVOICE,	CDV_58,		// Reich: "...Wasted enough time!"
	WAITVOICE,
	PLAYVOICE,	CDV_59,		// Reich: "Give us the runaway or we'll shoot everyone..."
	WAITVOICE,
	PLAYVOICE,	CDV_60,		// Reich: "Starting with you, grandad!"
	WAITVOICE,
	PLAYVOICE,	CDV_61,		// Foster: "The old man had been right, for once..."
	WAITVOICE,
	PLAYVOICE,	CDV_62,		// Foster: "It was me they wanted."
	BGFLIRT,	CD_58,
		WAITVOICE,
		PLAYVOICE,	CDV_63,	// Shaman: "No, my son! Don't let the evil take you! Run!"
		WAITVOICE,
		PLAYVOICE,	CDV_64,	// Guard: "DNA scan confirms it's him, sir."
	WAITFLIRT,
	WAITVOICE,
	PLAYVOICE,	CDV_65,		// Foster: "Evil had come to the Gap, just as he said."
	FADEDOWN,
	WAITVOICE,
	SHOWSCREEN,	CD_66_LOG,
	FADEUP,		CD_66_PAL,
	PLAYVOICE,	CDV_66,		// Reich: "Take him."
	WAITVOICE,
	PLAYVOICE,	CDV_67,		// Foster: "But had the old man seen why it wanted me?"
		FADEDOWN,
		SHOWSCREEN,	CD_67_LOG,
		FADEUP,		CD_67_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_68,		// Foster: "Or what it would do next?"
	WAITVOICE,
	PLAYVOICE,	CDV_69,		// Foster: "It was too late to ask him now."
		FADEDOWN,
		SHOWSCREEN,	CD_69_LOG,
		FADEUP,		CD_69_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_70,		// Guard: "Leaving destruction zone, Commander Reich."
	DOFLIRT,	CD_69,
	WAITVOICE,
	FADEDOWN,
	PLAYVOICE,	CDV_71,		// Reich: "Good. Detonate."
	WAITVOICE,
	SHOWSCREEN | FULLSCREEN,	CD_72_LOG,
	FADEUP,		CD_72_PAL,
	PLAYVOICE,	CDV_72,		// Foster: "Much too late."
	WAITVOICE,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_73_LOG,
	FADEUP,		CD_73_PAL,
	PLAYVOICE,	CDV_73,		// Foster: "Why, you murdering..."
	WAITVOICE,
	PLAYVOICE,	CDV_74,		// Reich: "Keep him quiet."
	WAITVOICE,
	PLAYVOICE,	CDV_75,		// Foster: "All I could do was wait."
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_76_LOG,
	FADEUP,		CD_76_PAL,
	WAITVOICE,
	PLAYVOICE,	CDV_76,		// Foster: "Just like on a hunt. Just like the old man taught me."
	WAITVOICE,
	PLAYVOICE,	CDV_77,		// Foster: "Wait... and be ready."
	WAITVOICE,
	FADEDOWN,
	CLEARBOTTOM,
	SHOWSCREEN,	CD_78_LOG,
	FADEUP,		CD_78_PAL,
	PLAYVOICE,	CDV_78,		// Foster: "It was dawn when we reached the City."
	WAITVOICE,
	PLAYVOICE,	CDV_79,		// Reich: "Land in the central Security compound."
	WAITVOICE,
	PLAYVOICE,	CDV_80,		// Foster: "A dawn my tribe would never see."
	BGFLIRT,	CD_100,
		WAITVOICE,
		PLAYVOICE,	CDV_81,	// Foster: "They were no more than a note in Reich's book now."
		WAITVOICE,
		PLAYVOICE,	CDV_82,	// Guard: "Yes, sir. Locking on automatic landing beacon."
		WAITVOICE,
	WAITFLIRT,
	SHOWSCREEN,	CD_101_LOG,
	BGFLIRT,	CD_101,
		PLAYVOICE,	CDV_83,	// Foster: "But what was I? Why did..."
		WAITVOICE,
		PLAYVOICE,	CDV_84,	// Guard: "Sir! The guidance system! It's gone crazy!"
		WAITVOICE,
		PLAYVOICE,	CDV_85,	// Guard: "We're going to HIT!"
		WAITVOICE,
	WAITFLIRT,
	CLEARBOTTOM,
	SHOWSCREEN,	CD_102_LOG,
	PLAYVOICE,	CDV_86,		// Foster: "Maybe I'd get some answers now."
	DOFLIRT,	CD_102,
	FADEDOWN,
	// This one could be fullscreen, but that causes animation glitches.
	SHOWSCREEN,	CD_103_LOG,
	FADEUP,		CD_103_PAL,
	BGFLIRT,	CD_103,
	WAITVOICE,
	PLAYVOICE,	CDV_87,		// Foster: "If I survived another 'copter crash."
	WAITFLIRT,
	WAITVOICE,
	STARTMUSIC,	2,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,	CD_104_LOG,
	FADEUP,		CD_104_PAL,
	DOFLIRT,	CD_104,
	DOFLIRT,	CD_105,
	SEQEND
};

uint16 Intro::_floppyIntroSeq[] = {
	// This one could be fullscreen, but that causes animation glitches.
	SHOWSCREEN,   60081,
	FADEUP,       60080,
	DOFLIRT,      60082,
	DOFLIRT,      60083,
	DOFLIRT,      60084, // Beneath a Steel Sky
	DOFLIRT,      60085,
	DOFLIRT,      60086,
	SCROLLFLIRT,
	COMMANDFLIRT, 60087, // => command list 4a
		136, IC_MAKE_SOUND,  1, 70,
		 90, IC_FX_VOLUME,  80,
		 50, IC_FX_VOLUME,  90,
		  5, IC_FX_VOLUME, 100,
	COMMANDEND,
	SHOWSCREEN,   60088,
	COMMANDFLIRT, 60089, // => command list 4b (cockpit)
		1000, IC_PREPARE_TEXT,  77,
		 220, IC_SHOW_TEXT,     20, 160, // radar detects jamming signal
		 105, IC_REMOVE_TEXT,
		 105, IC_PREPARE_TEXT,  81,
		 105, IC_SHOW_TEXT,    170,  86, // well switch to override you fool
		  35, IC_REMOVE_TEXT,
		  35, IC_PREPARE_TEXT, 477,
		  35, IC_SHOW_TEXT,     30, 160,
		   3, IC_REMOVE_TEXT,
	COMMANDEND,
	CLEARBOTTOM,
	SHOWSCREEN,   60090,
	COMMANDFLIRT, 60091, // => command list 4c
		1000, IC_FX_VOLUME, 100,
		  25, IC_FX_VOLUME, 110,
		  15, IC_FX_VOLUME, 120,
		   4, IC_FX_VOLUME, 127,
	COMMANDEND,
	FADEDOWN,
	// This one could be fullscreen, but that causes animation glitches.
	SHOWSCREEN,  60093,
	FADEUP,       60092,
	COMMANDFLIRT, 60094, // => command list 5
		31, IC_MAKE_SOUND, 2, 127,
	COMMANDEND,
	WAITMUSIC,
	FADEDOWN,
	SHOWSCREEN | FULLSCREEN,   60096,
	STARTMUSIC,       2,
	FADEUP,       60095,
	COMMANDFLIRT, 60097, // => command list 6a
		1000, IC_PREPARE_TEXT, 478,
		  13, IC_SHOW_TEXT,    175, 155,
	COMMANDEND,
	COMMANDFLIRT, 60098, // => command list 6b
		131, IC_REMOVE_TEXT,
		131, IC_PREPARE_TEXT, 479,
		 74, IC_SHOW_TEXT,    175, 155,
		 45, IC_REMOVE_TEXT,
		 45, IC_PREPARE_TEXT, 162,
		 44, IC_SHOW_TEXT,    175, 155,
		  4, IC_REMOVE_TEXT,
	COMMANDEND,
	SEQEND
};

Intro::Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *text, Audio::Mixer *mixer, OSystem *system) {
	_skyDisk = disk;
	_skyScreen = screen;
	_skyMusic = music;
	_skySound = sound;
	_skyText = text;
	_mixer = mixer;
	_system = system;
	_textBuf = (uint8 *)malloc(10000);
	_saveBuf = (uint8 *)malloc(10000);
	_bgBuf = NULL;
	_relDelay = 0;
}

Intro::~Intro() {
	if (_skyScreen->sequenceRunning())
		_skyScreen->stopSequence();

	free(_textBuf);
	free(_saveBuf);
	_mixer->stopID(SOUND_BG);
	free(_bgBuf);
}

bool Intro::doIntro(bool floppyIntro) {
	if (!SkyEngine::isCDVersion())
		floppyIntro = true;

	_skyMusic->loadSection(0);
	_skySound->loadSection(0);

	if (!escDelay(3000))
		return false;

	if (floppyIntro)
		_skyMusic->startMusic(1);

	uint16 *seqData = _mainIntroSeq;
	while (*seqData != SEQEND) {
		if (!nextPart(seqData))
			return false;
	}
	if (floppyIntro)
		seqData = _floppyIntroSeq;
	else
		seqData = _cdIntroSeq;

	while (*seqData != SEQEND) {
		if (!nextPart(seqData))
			return false;
	}
	return true;
}

bool Intro::nextPart(uint16 *&data) {
	uint8 *vData = NULL;
	Audio::RewindableAudioStream *stream = 0;

	// return false means cancel intro
	uint16 command = *data++;
	switch (command & 0x7fff) {
	case SHOWSCREEN:
		_skyScreen->showScreen(*data++, (command & FULLSCREEN) ? true : false);
		return true;
	case FADEUP:
		_skyScreen->paletteFadeUp(*data++);
		_relDelay += 32 * 20; // hack: the screen uses a seperate delay function for the
							  // blocking fadeups. So add 32*20 msecs to out delay counter.
		return true;
	case FADEDOWN:
		_skyScreen->fnFadeDown(0);
		_relDelay += 32 * 20; // hack: see above.
		return true;
	case DELAY:
		if (!escDelay(*data++))
			return false;
		return true;
	case DOFLIRT:
		_skyScreen->startSequence(*data++);
		while (_skyScreen->sequenceRunning())
			if (!escDelay(50))
				return false;
		return true;
	case SCROLLFLIRT:
		return floppyScrollFlirt();
	case COMMANDFLIRT:
		return commandFlirt(data);
	case STOPFLIRT:
		_skyScreen->stopSequence();
		return true;
	case STARTMUSIC:
		_skyMusic->startMusic(*data++);
		return true;
	case WAITMUSIC:
		while (_skyMusic->musicIsPlaying())
			if (!escDelay(50))
				return false;
		return true;
	case BGFLIRT:
		_skyScreen->startSequence(*data++);
		return true;
	case WAITFLIRT:
		while (_skyScreen->sequenceRunning())
			if (!escDelay(50))
				return false;
		return true;
	case PLAYVOICE:
		if (!escDelay(200))
			return false;
		vData = _skyDisk->loadFile(*data++);
		// HACK: Fill the header with silence. We should
		// probably use _skySound instead of calling playStream()
		// directly, but this will have to do for now.
		memset(vData, 127, sizeof(DataFileHeader));

		stream = Audio::makeRawStream(vData, _skyDisk->_lastLoadedFileSize, 11025, Audio::FLAG_UNSIGNED);
		_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_voice, stream, SOUND_VOICE);
		return true;
	case WAITVOICE:
		while (_mixer->isSoundHandleActive(_voice))
			if (!escDelay(50))
				return false;
		return true;
	case LOADBG:
		_mixer->stopID(SOUND_BG);
		free(_bgBuf);
		_bgBuf = _skyDisk->loadFile(*data++);
		_bgSize = _skyDisk->_lastLoadedFileSize;
		return true;
	case LOOPBG:
		_mixer->stopID(SOUND_BG);
		stream = Audio::makeRawStream(_bgBuf + 256, _bgSize - 768, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
		_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSfx, Audio::makeLoopingAudioStream(stream, 0), SOUND_BG);
		return true;
	case PLAYBG:
		_mixer->stopID(SOUND_BG);
		stream = Audio::makeRawStream(_bgBuf + 256, _bgSize - 768, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
		_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSfx, stream, SOUND_BG);
		return true;
	case STOPBG:
		_mixer->stopID(SOUND_BG);
		return true;
	case CLEARBOTTOM:
		{
			byte *screenBuf = _skyScreen->giveCurrent() + GAME_SCREEN_HEIGHT * GAME_SCREEN_WIDTH;
			memset(screenBuf, 0, GAME_SCREEN_WIDTH * (FULL_SCREEN_HEIGHT - GAME_SCREEN_HEIGHT));
			_system->copyRectToScreen(screenBuf, GAME_SCREEN_WIDTH, 0, GAME_SCREEN_HEIGHT, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT - GAME_SCREEN_HEIGHT);
			_system->updateScreen();
		}
		return true;
	default:
		error("Unknown intro command %X", command);
	}
	return true;
}

bool Intro::floppyScrollFlirt() {
	uint8 *scrollScreen = (uint8 *)malloc(FRAME_SIZE * 2);
	memset(scrollScreen, 0, FRAME_SIZE);
	memcpy(scrollScreen + FRAME_SIZE, _skyScreen->giveCurrent(), FRAME_SIZE);
	uint8 *scrollPos = scrollScreen + FRAME_SIZE;
	uint8 *vgaData = _skyDisk->loadFile(60100);
	uint8 *diffData = _skyDisk->loadFile(60101);
	uint16 frameNum = READ_LE_UINT16(diffData);
	uint8 *diffPtr = diffData + 2;
	uint8 *vgaPtr = vgaData;
	bool doContinue = true;

	for (uint16 frameCnt = 1; (frameCnt < frameNum) && doContinue; frameCnt++) {
		uint8 scrollVal = *diffPtr++;
		if (scrollVal)
			scrollPos -= scrollVal * GAME_SCREEN_WIDTH;

		uint16 scrPos = 0;
		while (scrPos < FRAME_SIZE) {
			uint8 nrToDo, nrToSkip;
			do {
				nrToSkip = *diffPtr++;
				scrPos += nrToSkip;
			} while (nrToSkip == 255);
			do {
				nrToDo = *diffPtr++;
				memcpy(scrollPos + scrPos, vgaPtr, nrToDo);
				scrPos += nrToDo;
				vgaPtr += nrToDo;
			} while (nrToDo == 255);
		}
		_system->copyRectToScreen(scrollPos, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
		_system->updateScreen();
		if (!escDelay(60))
			doContinue = false;
	}
	memcpy(_skyScreen->giveCurrent(), scrollPos, FRAME_SIZE);
	free(diffData);
	free(vgaData);
	free(scrollScreen);
	return doContinue;
}

bool Intro::commandFlirt(uint16 *&data) {
	_skyScreen->startSequence(*data++);

	while ((*data != COMMANDEND) || _skyScreen->sequenceRunning()) {
		while ((_skyScreen->seqFramesLeft() < *data)) {
			data++;
			uint16 command = *data++;
			switch (command) {
			case IC_PREPARE_TEXT:
				_skyText->displayText(*data++, _textBuf, true, INTRO_TEXT_WIDTH, 255);
				break;
			case IC_SHOW_TEXT:
				((DataFileHeader *)_textBuf)->s_x = *data++;
				((DataFileHeader *)_textBuf)->s_y = *data++;
				showTextBuf();
				break;
			case IC_REMOVE_TEXT:
				restoreScreen();
				break;
			case IC_MAKE_SOUND:
				_skySound->playSound(data[0], data[1], 0);
				data += 2;
				break;
			case IC_FX_VOLUME:
				_skySound->playSound(1, *data++, 0);
				break;
			default:
				error("Unknown FLIRT command %X", command);
			}
		}

		if (!escDelay(50)) {
			_skyScreen->stopSequence();
			return false;
		}
	}

	data++; // move pointer over "COMMANDEND"
	return true;
}

void Intro::showTextBuf() {
	uint16 x = ((DataFileHeader *)_textBuf)->s_x;
	uint16 y = ((DataFileHeader *)_textBuf)->s_y;
	uint16 width = ((DataFileHeader *)_textBuf)->s_width;
	uint16 height = ((DataFileHeader *)_textBuf)->s_height;
	uint8 *screenBuf = _skyScreen->giveCurrent() + y * GAME_SCREEN_WIDTH + x;
	memcpy(_saveBuf, _textBuf, sizeof(DataFileHeader));
	uint8 *saveBuf = _saveBuf + sizeof(DataFileHeader);
	uint8 *textBuf = _textBuf + sizeof(DataFileHeader);
	for (uint16 cnty = 0; cnty < height; cnty++) {
		memcpy(saveBuf, screenBuf, width);
		for (uint16 cntx = 0; cntx < width; cntx++)
			if (textBuf[cntx])
				screenBuf[cntx] = textBuf[cntx];
		screenBuf += GAME_SCREEN_WIDTH;
		textBuf += width;
		saveBuf += width;
	}
	screenBuf = _skyScreen->giveCurrent() + y * GAME_SCREEN_WIDTH + x;
	_system->copyRectToScreen(screenBuf, GAME_SCREEN_WIDTH, x, y, width, height);
}

void Intro::restoreScreen() {
	uint16 x = ((DataFileHeader *)_saveBuf)->s_x;
	uint16 y = ((DataFileHeader *)_saveBuf)->s_y;
	uint16 width = ((DataFileHeader *)_saveBuf)->s_width;
	uint16 height = ((DataFileHeader *)_saveBuf)->s_height;
	uint8 *screenBuf = _skyScreen->giveCurrent() + y * GAME_SCREEN_WIDTH + x;
	uint8 *saveBuf = _saveBuf + sizeof(DataFileHeader);
	for (uint16 cnt = 0; cnt < height; cnt++) {
		memcpy(screenBuf, saveBuf, width);
		screenBuf += GAME_SCREEN_WIDTH;
		saveBuf += width;
	}
	_system->copyRectToScreen(_saveBuf + sizeof(DataFileHeader), width, x, y, width, height);
}

bool Intro::escDelay(uint32 msecs) {
	Common::EventManager *eventMan = _system->getEventManager();
	Common::Event event;

	if (_relDelay == 0) // first call, init with system time
		_relDelay = (int32)_system->getMillis();

	_relDelay += msecs; // now wait until _system->getMillis() >= _relDelay

	int32 nDelay = 0;
	do {
		while (eventMan->pollEvent(event)) {
			if (event.type == Common::EVENT_KEYDOWN) {
				if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
					return false;
			} else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL) {
				return false;
			}
		}
		nDelay = _relDelay - _system->getMillis();
		if (nDelay < 0)
			nDelay = 0;
		else if (nDelay > 20)
			nDelay = 20;

		_system->delayMillis(nDelay);

		_skyScreen->processSequence();
		_system->updateScreen();
	} while (nDelay == 20);

	return true;
}

} // End of namespace Sky