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 "common/scummsys.h"
24 #include "xeen/worldofxeen/worldofxeen_menu.h"
25 #include "xeen/worldofxeen/worldofxeen.h"
26 #include "xeen/dialogs/credits_screen.h"
27 #include "xeen/dialogs/dialogs_difficulty.h"
28 #include "xeen/resources.h"
29
30 namespace Xeen {
31 namespace WorldOfXeen {
32
show()33 void MainMenuContainer::show() {
34 MainMenuContainer *menu;
35
36 switch (g_vm->getGameID()) {
37 case GType_Clouds:
38 menu = new CloudsMainMenuContainer();
39 break;
40 case GType_DarkSide:
41 menu = new DarkSideMainMenuContainer();
42 break;
43 case GType_WorldOfXeen:
44 if (g_vm->getIsCD())
45 menu = new WorldOfXeenCDMainMenuContainer();
46 else
47 menu = new WorldOfXeenMainMenuContainer();
48 break;
49 default:
50 error("Invalid game");
51 }
52
53 menu->execute();
54 delete menu;
55 }
56
MainMenuContainer(const char * spritesName1,const char * spritesName2,const char * spritesName3)57 MainMenuContainer::MainMenuContainer(const char *spritesName1, const char *spritesName2, const char *spritesName3) :
58 _animateCtr(0), _dialog(nullptr) {
59 g_vm->_files->setGameCc(g_vm->getGameID() == GType_Clouds ? 0 : 1);
60
61 _backgroundSprites.resize(1 + (spritesName2 ? 1 : 0) + (spritesName3 ? 1 : 0));
62 _backgroundSprites[0].load(spritesName1);
63 if (spritesName2)
64 _backgroundSprites[1].load(spritesName2);
65 if (spritesName3)
66 _backgroundSprites[2].load(spritesName3);
67
68 _frameCount = 0;
69 for (uint idx = 0; idx < _backgroundSprites.size(); ++idx)
70 _frameCount += _backgroundSprites[idx].size();
71 }
72
~MainMenuContainer()73 MainMenuContainer::~MainMenuContainer() {
74 delete _dialog;
75 g_vm->_windows->closeAll();
76 g_vm->_sound->stopAllAudio();
77 g_vm->_events->clearEvents();
78 }
79
draw()80 void MainMenuContainer::draw() {
81 g_vm->_screen->restoreBackground();
82 _animateCtr = (_animateCtr + 1) % _frameCount;
83
84 // Draw the next background frame
85 uint frameNum = _animateCtr;
86 for (uint idx = 0; idx < _backgroundSprites.size(); ++idx) {
87 if (frameNum < _backgroundSprites[idx].size()) {
88 _backgroundSprites[idx].draw(0, frameNum);
89 return;
90 } else {
91 frameNum -= _backgroundSprites[idx].size();
92 }
93 }
94 }
95
execute()96 void MainMenuContainer::execute() {
97 EventsManager &events = *g_vm->_events;
98 Screen &screen = *g_vm->_screen;
99 bool showFlag = false;
100
101 // Show the cursor
102 events.clearEvents();
103 events.setCursor(0);
104 events.showCursor();
105
106 screen.doScroll(true, false);
107
108 while (!g_vm->shouldExit() && g_vm->_gameMode == GMODE_NONE) {
109 // Draw the menu
110 draw();
111 if (_dialog)
112 _dialog->draw();
113
114 // Fade/scroll in screen if first frame showing screen
115 if (!showFlag) {
116 display();
117 screen.doScroll(false, true);
118 showFlag = true;
119 }
120
121 // Check for events
122 events.updateGameCounter();
123
124 if (events.wait(4, true)) {
125 if (_dialog) {
126 // There's a dialog active, so let it handle the event
127 _dialog->handleEvents();
128
129 // If dialog was removed as a result of the event, flag screen for re-showing,
130 // such as returning to main menu from the Credits screen
131 if (!_dialog)
132 showFlag = false;
133 } else {
134 // No active dialog. If Escape pressed, exit game entirely. Otherwise,
135 // open up the main menu dialog
136 PendingEvent pe;
137 if (events.getEvent(pe) && pe._keyState.keycode == Common::KEYCODE_ESCAPE)
138 g_vm->_gameMode = GMODE_QUIT;
139
140 events.clearEvents();
141 showMenuDialog();
142 }
143 }
144 }
145 }
146
147 /*------------------------------------------------------------------------*/
148
CloudsMainMenuContainer()149 CloudsMainMenuContainer::CloudsMainMenuContainer() : MainMenuContainer("intro.vga") {
150 }
151
display()152 void CloudsMainMenuContainer::display() {
153 FileManager &files = *g_vm->_files;
154 Screen &screen = *g_vm->_screen;
155 Sound &sound = *g_vm->_sound;
156
157 sound._musicSide = 0;
158 files.setGameCc(0);
159
160 screen.loadPalette("mm4.pal");
161 screen.loadBackground("intro.raw");
162 screen.saveBackground();
163
164 if (!sound.isMusicPlaying())
165 sound.playSong("inn.m");
166 }
167
showMenuDialog()168 void CloudsMainMenuContainer::showMenuDialog() {
169 setOwner(new CloudsMenuDialog(this));
170 }
171
172 /*------------------------------------------------------------------------*/
173
DarkSideMainMenuContainer()174 DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("title2a.int") {
175 Screen &screen = *g_vm->_screen;
176 Sound &sound = *g_vm->_sound;
177 screen.loadPalette("dark.pal");
178 screen.fadeIn(0x81);
179
180 sound._musicSide = 1;
181 sound.playSong("newbrigh.m");
182
183 _background.load("title2.int");
184 }
185
display()186 void DarkSideMainMenuContainer::display() {
187 FileManager &files = *g_vm->_files;
188 Screen &screen = *g_vm->_screen;
189 Sound &sound = *g_vm->_sound;
190
191 _background.draw(0, 0, Common::Point(0, 0));
192 _background.draw(0, 1, Common::Point(160, 0));
193
194 sound._musicSide = 1;
195 files.setGameCc(1);
196
197 screen.loadPalette("dark.pal");
198 screen.saveBackground();
199
200 if (!sound.isMusicPlaying())
201 sound.playSong("newbrigh.m");
202 }
203
showMenuDialog()204 void DarkSideMainMenuContainer::showMenuDialog() {
205 setOwner(new DarkSideMenuDialog(this));
206 }
207
208 /*------------------------------------------------------------------------*/
209
WorldOfXeenMainMenuContainer()210 WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("world.int") {
211 }
212
display()213 void WorldOfXeenMainMenuContainer::display() {
214 FileManager &files = *g_vm->_files;
215 Screen &screen = *g_vm->_screen;
216 Sound &sound = *g_vm->_sound;
217
218 sound._musicSide = 1;
219 files.setGameCc(1);
220
221 screen.loadPalette("dark.pal");
222 screen.loadBackground("world.raw");
223 screen.saveBackground();
224
225 if (!sound.isMusicPlaying())
226 sound.playSong("newbrigh.m");
227 }
228
showMenuDialog()229 void WorldOfXeenMainMenuContainer::showMenuDialog() {
230 setOwner(new WorldMenuDialog(this));
231 }
232
233 /*------------------------------------------------------------------------*/
234
WorldOfXeenCDMainMenuContainer()235 WorldOfXeenCDMainMenuContainer::WorldOfXeenCDMainMenuContainer() : MainMenuContainer("world0.int", "world1.int", "world2.int") {
236 }
237
display()238 void WorldOfXeenCDMainMenuContainer::display() {
239 FileManager &files = *g_vm->_files;
240 Screen &screen = *g_vm->_screen;
241 Sound &sound = *g_vm->_sound;
242
243 sound._musicSide = 1;
244 files.setGameCc(1);
245
246 screen.loadPalette("dark.pal");
247 screen.loadBackground("world.raw");
248 screen.saveBackground();
249
250 if (!sound.isMusicPlaying())
251 sound.playSong("newbrigh.m");
252 }
253
showMenuDialog()254 void WorldOfXeenCDMainMenuContainer::showMenuDialog() {
255 setOwner(new WorldMenuDialog(this));
256 }
257
258 /*------------------------------------------------------------------------*/
259
handleEvents()260 bool MainMenuDialog::handleEvents() {
261 FileManager &files = *g_vm->_files;
262 checkEvents(g_vm);
263 int difficulty;
264
265 switch (_buttonValue) {
266 case Common::KEYCODE_s:
267 // Start new game
268 difficulty = DifficultyDialog::show(g_vm);
269 if (difficulty == -1)
270 return true;
271
272 // Load a new game state and set the difficulty
273 g_vm->_saves->newGame();
274 g_vm->_party->_difficulty = (Difficulty)difficulty;
275 g_vm->_gameMode = GMODE_PLAY_GAME;
276 break;
277
278 case Common::KEYCODE_l: {
279 // Load existing game
280 int ccNum = files._ccNum;
281 g_vm->_saves->newGame();
282 if (!g_vm->_saves->loadGame()) {
283 files.setGameCc(ccNum);
284 return true;
285 }
286
287 g_vm->_gameMode = GMODE_PLAY_GAME;
288 break;
289 }
290
291 case Common::KEYCODE_c:
292 case Common::KEYCODE_v:
293 // Show credits
294 CreditsScreen::show(g_vm);
295 break;
296
297 case Common::KEYCODE_ESCAPE:
298 // Exit dialog (returning to just the animated background)
299 break;
300
301 default:
302 return false;
303 }
304
305 // If this point is reached, delete the dialog itself, which will return the main menu
306 // to it's default "No dialog showing" state
307 delete this;
308 return true;
309 }
310
311 /*------------------------------------------------------------------------*/
312
CloudsMenuDialog(MainMenuContainer * owner)313 CloudsMenuDialog::CloudsMenuDialog(MainMenuContainer *owner) : MainMenuDialog(owner) {
314 Windows &windows = *g_vm->_windows;
315 Window &w = windows[GAME_WINDOW];
316 w.setBounds(Common::Rect(72, 25, 248, g_vm->_gameWon[0] ? 175 : 150));
317 w.open();
318
319 loadButtons();
320 }
321
~CloudsMenuDialog()322 CloudsMenuDialog::~CloudsMenuDialog() {
323 Windows &windows = *g_vm->_windows;
324 Window &w = windows[GAME_WINDOW];
325 w.close();
326 }
327
loadButtons()328 void CloudsMenuDialog::loadButtons() {
329 _buttonSprites.load("start.icn");
330 addButton(Common::Rect(93, 53, 227, 73), Common::KEYCODE_s, &_buttonSprites);
331 addButton(Common::Rect(93, 78, 227, 98), Common::KEYCODE_l, &_buttonSprites);
332 addButton(Common::Rect(93, 103, 227, 123), Common::KEYCODE_c, &_buttonSprites);
333 if (g_vm->_gameWon[0])
334 addButton(Common::Rect(93, 128, 227, 148), Common::KEYCODE_e, &_buttonSprites);
335 }
336
draw()337 void CloudsMenuDialog::draw() {
338 Windows &windows = *g_vm->_windows;
339 Window &w = windows[GAME_WINDOW];
340
341 w.frame();
342 w.writeString(Common::String::format(Res.OPTIONS_MENU, Res.GAME_NAMES[0], g_vm->_gameWon[0] ? 117 : 92, 1992));
343 drawButtons(&w);
344 }
345
handleEvents()346 bool CloudsMenuDialog::handleEvents() {
347 if (MainMenuDialog::handleEvents())
348 return true;
349
350 switch (_buttonValue) {
351 case Common::KEYCODE_e:
352 if (g_vm->_gameWon[0]) {
353 // Close the window
354 delete this;
355
356 // Show clouds ending
357 WOX_VM._sound->stopAllAudio();
358 WOX_VM.showCloudsEnding(g_vm->_finalScore);
359 return true;
360 }
361 break;
362
363 default:
364 break;
365 }
366
367 return false;
368 }
369
370 /*------------------------------------------------------------------------*/
371
DarkSideMenuDialog(MainMenuContainer * owner)372 DarkSideMenuDialog::DarkSideMenuDialog(MainMenuContainer *owner) : MainMenuDialog(owner), _firstDraw(true) {
373 Windows &windows = *g_vm->_windows;
374 Window &w = windows[GAME_WINDOW];
375 w.setBounds(Common::Rect(72, 25, 248, 150));
376 w.open();
377
378 loadButtons();
379 }
380
~DarkSideMenuDialog()381 DarkSideMenuDialog::~DarkSideMenuDialog() {
382 Windows &windows = *g_vm->_windows;
383 Window &w = windows[GAME_WINDOW];
384 w.close();
385 }
386
loadButtons()387 void DarkSideMenuDialog::loadButtons() {
388 addButton(Common::Rect(124, 87, 177, 97), Common::KEYCODE_s);
389 addButton(Common::Rect(126, 98, 173, 108), Common::KEYCODE_l);
390 addButton(Common::Rect(91, 110, 209, 120), Common::KEYCODE_c);
391 addButton(Common::Rect(85, 121, 216, 131), Common::KEYCODE_o);
392 }
393
draw()394 void DarkSideMenuDialog::draw() {
395 Screen &screen = *g_vm->_screen;
396 EventsManager &events = *g_vm->_events;
397 Sound &sound = *g_vm->_sound;
398 Windows &windows = *g_vm->_windows;
399
400 if (!_firstDraw)
401 return;
402
403 SpriteResource kludgeSprites("kludge.int");
404 SpriteResource title2Sprites[8] = {
405 SpriteResource("title2b.int"), SpriteResource("title2c.int"),
406 SpriteResource("title2d.int"), SpriteResource("title2e.int"),
407 SpriteResource("title2f.int"), SpriteResource("title2g.int"),
408 SpriteResource("title2h.int"), SpriteResource("title2i.int"),
409 };
410
411 screen.loadBackground("title2b.raw");
412 kludgeSprites.draw(0, 0, Common::Point(85, 86));
413 screen.saveBackground();
414 sound.playSound("elect.voc");
415
416 for (int i = 0; i < 30 && !g_vm->shouldExit(); ++i) {
417 events.updateGameCounter();
418 screen.restoreBackground();
419 title2Sprites[i / 4].draw(0, i % 4);
420 windows[0].update();
421
422 if (i == 19)
423 sound.stopSound();
424
425 if (events.wait(2))
426 break;
427 }
428
429 events.clearEvents();
430 sound.stopSound();
431
432 screen.restoreBackground();
433 windows[0].update();
434 _firstDraw = false;
435 }
436
handleEvents()437 bool DarkSideMenuDialog::handleEvents() {
438 if (MainMenuDialog::handleEvents())
439 return true;
440
441 switch (_buttonValue) {
442 case Common::KEYCODE_o: {
443 // Show other options dialog
444 // Remove this dialog
445 MainMenuContainer *owner = _owner;
446 delete this;
447
448 // Set the new options dialog
449 owner->setOwner(new OtherOptionsDialog(owner));
450 return true;
451 }
452
453 default:
454 break;
455 }
456
457 return false;
458 }
459
460 /*------------------------------------------------------------------------*/
461
WorldMenuDialog(MainMenuContainer * owner)462 WorldMenuDialog::WorldMenuDialog(MainMenuContainer *owner) : MainMenuDialog(owner) {
463 Windows &windows = *g_vm->_windows;
464 Window &w = windows[GAME_WINDOW];
465 w.setBounds(Common::Rect(72, 25, 248, 175));
466 w.open();
467
468 loadButtons();
469 }
470
~WorldMenuDialog()471 WorldMenuDialog::~WorldMenuDialog() {
472 Windows &windows = *g_vm->_windows;
473 Window &w = windows[GAME_WINDOW];
474 w.close();
475 }
476
loadButtons()477 void WorldMenuDialog::loadButtons() {
478 _buttonSprites.load("start.icn");
479 addButton(Common::Rect(93, 53, 227, 73), Common::KEYCODE_s, &_buttonSprites);
480 addButton(Common::Rect(93, 78, 227, 98), Common::KEYCODE_l, &_buttonSprites);
481 addButton(Common::Rect(93, 103, 227, 123), Common::KEYCODE_c, &_buttonSprites);
482 addButton(Common::Rect(93, 128, 227, 148), Common::KEYCODE_o, &_buttonSprites);
483 }
484
draw()485 void WorldMenuDialog::draw() {
486 Windows &windows = *g_vm->_windows;
487 Window &w = windows[GAME_WINDOW];
488
489 w.frame();
490 w.writeString(Common::String::format(Res.OPTIONS_MENU, Res.GAME_NAMES[2], 117, 1993));
491 drawButtons(&w);
492 }
493
handleEvents()494 bool WorldMenuDialog::handleEvents() {
495 if (MainMenuDialog::handleEvents())
496 return true;
497
498 switch (_buttonValue) {
499 case Common::KEYCODE_o: {
500 // Show other options dialog
501 // Remove this dialog
502 MainMenuContainer *owner = _owner;
503 delete this;
504
505 // Set the new options dialog
506 owner->setOwner(new OtherOptionsDialog(owner));
507 return true;
508 }
509
510 default:
511 break;
512 }
513
514 return false;
515 }
516
517 /*------------------------------------------------------------------------*/
518
OtherOptionsDialog(MainMenuContainer * owner)519 OtherOptionsDialog::OtherOptionsDialog(MainMenuContainer *owner) : MenuContainerDialog(owner) {
520 Windows &windows = *g_vm->_windows;
521 Window &w = windows[GAME_WINDOW];
522
523 int height = (g_vm->getGameID() == GType_WorldOfXeen ? 25 : 0)
524 + (g_vm->getGameID() == GType_WorldOfXeen && g_vm->_gameWon[0] ? 25 : 0)
525 + (g_vm->_gameWon[1] ? 25 : 0)
526 + (g_vm->_gameWon[2] ? 25 : 0)
527 + 75;
528
529 w.setBounds(Common::Rect(72, 25, 248, 25 + height));
530 w.open();
531
532 loadButtons();
533 }
534
~OtherOptionsDialog()535 OtherOptionsDialog::~OtherOptionsDialog() {
536 Windows &windows = *g_vm->_windows;
537 Window &w = windows[GAME_WINDOW];
538 w.close();
539 }
540
loadButtons()541 void OtherOptionsDialog::loadButtons() {
542 _buttonSprites.load("special.icn");
543 Common::Rect r(93, 53, 227, 73);
544
545 // View Darkside Intro
546 addButton(r, Common::KEYCODE_d, &_buttonSprites);
547 r.translate(0, 25);
548
549 // View Clouds Intro
550 if (g_vm->getGameID() == GType_WorldOfXeen) {
551 addButton(r, Common::KEYCODE_c, &_buttonSprites);
552 r.translate(0, 25);
553 } else {
554 addButton(Common::Rect(), Common::KEYCODE_INVALID);
555 }
556
557 // View Darkside End
558 if (g_vm->_gameWon[1]) {
559 addButton(r, Common::KEYCODE_e, &_buttonSprites);
560 r.translate(0, 25);
561 } else {
562 addButton(Common::Rect(), Common::KEYCODE_INVALID);
563 }
564
565 // View Clouds End
566 if (g_vm->_gameWon[0]) {
567 addButton(r, Common::KEYCODE_v, &_buttonSprites);
568 r.translate(0, 25);
569 } else {
570 addButton(Common::Rect(), Common::KEYCODE_INVALID);
571 }
572
573 // View World End
574 if (g_vm->_gameWon[2]) {
575 addButton(r, Common::KEYCODE_w, &_buttonSprites);
576 } else {
577 addButton(Common::Rect(), Common::KEYCODE_INVALID);
578 }
579 }
580
draw()581 void OtherOptionsDialog::draw() {
582 Windows &windows = *g_vm->_windows;
583 Window &w = windows[GAME_WINDOW];
584
585 w.frame();
586 w.writeString(Common::String::format(Res.OPTIONS_MENU,
587 Res.GAME_NAMES[g_vm->getGameID() == GType_WorldOfXeen ? 2 : 1],
588 w.getBounds().height() - 33, 1993));
589 drawButtons(&w);
590 }
591
handleEvents()592 bool OtherOptionsDialog::handleEvents() {
593 Sound &sound = *g_vm->_sound;
594 checkEvents(g_vm);
595
596 switch (_buttonValue) {
597 case Common::KEYCODE_d:
598 delete this;
599 sound.stopAllAudio();
600 WOX_VM.showDarkSideIntro(false);
601 break;
602
603 case Common::KEYCODE_c:
604 if (g_vm->getGameID() == GType_WorldOfXeen) {
605 delete this;
606 sound.stopAllAudio();
607 WOX_VM.showCloudsIntro();
608 }
609 break;
610
611 case Common::KEYCODE_e:
612 if (g_vm->_gameWon[1]) {
613 delete this;
614 sound.stopAllAudio();
615 WOX_VM.showDarkSideEnding(g_vm->_finalScore);
616 }
617 break;
618
619 case Common::KEYCODE_v:
620 if (g_vm->_gameWon[0]) {
621 delete this;
622 sound.stopAllAudio();
623 WOX_VM.showCloudsEnding(g_vm->_finalScore);
624 }
625 break;
626
627 case Common::KEYCODE_w:
628 if (g_vm->_gameWon[2]) {
629 delete this;
630 sound.stopAllAudio();
631 WOX_VM.showWorldOfXeenEnding(NON_GOOBER, g_vm->_finalScore);
632 }
633 break;
634
635 case Common::KEYCODE_ESCAPE:
636 // Exit dialog
637 delete this;
638 break;
639
640 default:
641 return false;
642 }
643
644 return true;
645 }
646
647 } // End of namespace WorldOfXeen
648 } // End of namespace Xeen
649