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 "mohawk/riven_stacks/aspit.h"
24
25 #include "mohawk/riven.h"
26 #include "mohawk/riven_card.h"
27 #include "mohawk/riven_graphics.h"
28 #include "mohawk/riven_inventory.h"
29 #include "mohawk/riven_sound.h"
30 #include "mohawk/riven_video.h"
31
32 #include "common/translation.h"
33
34 #include "graphics/fonts/ttf.h"
35 #include "graphics/font.h"
36 #include "graphics/fontman.h"
37
38 #include "gui/message.h"
39
40 namespace Mohawk {
41 namespace RivenStacks {
42
ASpit(MohawkEngine_Riven * vm)43 ASpit::ASpit(MohawkEngine_Riven *vm) :
44 RivenStack(vm, kStackAspit) {
45
46 REGISTER_COMMAND(ASpit, xastartupbtnhide);
47 REGISTER_COMMAND(ASpit, xasetupcomplete);
48 REGISTER_COMMAND(ASpit, xaatrusopenbook);
49 REGISTER_COMMAND(ASpit, xaatrusbookback);
50 REGISTER_COMMAND(ASpit, xaatrusbookprevpage);
51 REGISTER_COMMAND(ASpit, xaatrusbooknextpage);
52 REGISTER_COMMAND(ASpit, xacathopenbook);
53 REGISTER_COMMAND(ASpit, xacathbookback);
54 REGISTER_COMMAND(ASpit, xacathbookprevpage);
55 REGISTER_COMMAND(ASpit, xacathbooknextpage);
56 REGISTER_COMMAND(ASpit, xtrapbookback);
57 REGISTER_COMMAND(ASpit, xatrapbookclose);
58 REGISTER_COMMAND(ASpit, xatrapbookopen);
59 REGISTER_COMMAND(ASpit, xarestoregame);
60 REGISTER_COMMAND(ASpit, xadisablemenureturn);
61 REGISTER_COMMAND(ASpit, xaenablemenureturn);
62 REGISTER_COMMAND(ASpit, xalaunchbrowser);
63 REGISTER_COMMAND(ASpit, xadisablemenuintro);
64 REGISTER_COMMAND(ASpit, xaenablemenuintro);
65 REGISTER_COMMAND(ASpit, xademoquit);
66 REGISTER_COMMAND(ASpit, xaexittomain);
67
68 REGISTER_COMMAND(ASpit, xaSaveGame);
69 REGISTER_COMMAND(ASpit, xaResumeGame);
70 REGISTER_COMMAND(ASpit, xaOptions);
71 REGISTER_COMMAND(ASpit, xaNewGame);
72 }
73
74 struct MenuItemText {
75 int language;
76 const char *items[7];
77 } static const menuItems[] = {
78 { Common::EN_ANY, { "SETUP", "START NEW GAME", "START SAVED GAME", "SAVE GAME", "RESUME", "OPTIONS", "QUIT" } },
79 { Common::DE_DEU, { "SETUP", "SPIELEN", "SPIELSTAND LADEN", "SPIEL SPEICHERN", "FORTSETZEN", "OPTIONEN", "BEENDEN" } },
80 { Common::ES_ESP, { "IMAGEN", "IR A RIVEN", "CARGAR JUEGO", "GUARDAR JUEGO", "CONTINUAR", "OPCIONES", "SALIR" } },
81 { Common::FR_FRA, { "CONFIG", "NOUVELLE PARTIE", "CHARGER", "ENREGISTRER", "REPRENDRE", "OPTIONS", "QUITTER" } },
82 { Common::IT_ITA, { "CONF.", "GIOCA", "CARICA GIOCO", "SALVA IL GIOCO", "SEGUITARE", "OPZIONI", "ESCI" } },
83 { Common::RU_RUS, { "УСТАНОВКИ", "СТАРТ", "ПРОДОЛЖИТЬ ИГРУ", "СОХРАНИТЬ ИГРУ", "ПРОДОЛЖИТЬ", "ОПЦИИ", "ВЫЙТИ" } },
84 { Common::JA_JPN, { "セットアップ", "RIVENを演奏する", "保存したゲームを開始する", "ゲームを保存する", "持続する", "オプション","やめる" } },
85 { Common::PL_POL, { "USTAWIENIA", "GRAJ W RIVEN", "ZAŁADUJ GRĘ", "ZAPISZ GRĘ", "POWRÓT", "OPCJE", "WYJŚCIE" } },
86 { -1, { 0 } }
87 };
88
xastartupbtnhide(const ArgumentArray & args)89 void ASpit::xastartupbtnhide(const ArgumentArray &args) {
90 // The original game hides the start/setup buttons depending on an ini entry.
91 // It's safe to ignore this command.
92
93 if (!_vm->isGameVariant(GF_25TH))
94 return;
95
96 int lang = -1;
97 for (int i = 0; menuItems[i].language != -1; i++) {
98 if (menuItems[i].language == _vm->getLanguage()) {
99 lang = i;
100 break;
101 }
102 }
103
104 if (lang == -1) {
105 warning("Unsupported menu language, falling back to English");
106 lang = 0;
107 }
108
109 struct MenuItem {
110 uint16 blstId;
111 bool requiresStartedGame;
112 };
113
114 MenuItem items[] = {
115 { 22, false }, // Setup
116 { 16, false }, // New game
117 { 23, false }, // Load game
118 { 24, true }, // Save game
119 { 25, true }, // Resume
120 { 26, false }, // Options
121 { 27, false } // Quit
122 };
123
124 for (uint i = 0; i < ARRAYSIZE(items); i++) {
125 RivenHotspot *hotspot = _vm->getCard()->getHotspotByBlstId(items[i].blstId);
126
127 if (!hotspot) {
128 warning("Missing hotspot %d", items[i].blstId);
129 continue;
130 }
131
132 bool enabled = !items[i].requiresStartedGame || _vm->isGameStarted();
133 hotspot->enable(enabled);
134
135 Common::U32String str = Common::convertUtf8ToUtf32(menuItems[lang].items[i]);
136 Common::Rect hotspotRect = hotspot->getRect();
137 uint8 greyLevel = enabled ? 164 : 96;
138
139 _vm->_gfx->drawText(str, hotspotRect, greyLevel);
140 }
141 }
142
xasetupcomplete(const ArgumentArray & args)143 void ASpit::xasetupcomplete(const ArgumentArray &args) {
144 // The original game sets an ini entry to disable the setup button and use the
145 // start button only. It's safe to ignore this part of the command.
146 uint16 menuCardId = getCardStackId(0xE2E);
147 RivenScriptPtr goToMenuScript = _vm->_scriptMan->createScriptFromData(1, kRivenCommandChangeCard, 1, menuCardId);
148 _vm->_scriptMan->runScript(goToMenuScript, false);
149 }
150
xaatrusopenbook(const ArgumentArray & args)151 void ASpit::xaatrusopenbook(const ArgumentArray &args) {
152 // Get the variable
153 uint32 &page = _vm->_vars["aatrusbook"];
154
155 // Set hotspots depending on the page
156 RivenHotspot *openBook = _vm->getCard()->getHotspotByName("openBook");
157 RivenHotspot *nextPage = _vm->getCard()->getHotspotByName("nextpage");
158 RivenHotspot *prevPage = _vm->getCard()->getHotspotByName("prevpage");
159 if (page == 1) {
160 prevPage->enable(false);
161 nextPage->enable(false);
162 openBook->enable(true);
163 } else {
164 prevPage->enable(true);
165 nextPage->enable(true);
166 openBook->enable(false);
167 }
168
169 // Draw the image of the page
170 _vm->getCard()->drawPicture(page);
171 }
172
xaatrusbookback(const ArgumentArray & args)173 void ASpit::xaatrusbookback(const ArgumentArray &args) {
174 _vm->_inventory->backFromItemScript();
175 }
176
xaatrusbookprevpage(const ArgumentArray & args)177 void ASpit::xaatrusbookprevpage(const ArgumentArray &args) {
178 // Get the page variable
179 uint32 &page = _vm->_vars["aatrusbook"];
180
181 // Keep turning pages while the mouse is pressed
182 while (keepTurningPages()) {
183 // Check for the first page
184 if (page == 1)
185 return;
186
187 // Update the page number
188 page--;
189
190 pageTurn(kRivenTransitionWipeRight);
191 _vm->getCard()->drawPicture(page);
192 _vm->doFrame();
193
194 waitForPageTurnSound();
195 }
196 }
197
xaatrusbooknextpage(const ArgumentArray & args)198 void ASpit::xaatrusbooknextpage(const ArgumentArray &args) {
199 // Get the page variable
200 uint32 &page = _vm->_vars["aatrusbook"];
201
202 // Keep turning pages while the mouse is pressed
203 while (keepTurningPages()) {
204 // Check for the last page
205 if ((_vm->isGameVariant(GF_DEMO) && page == 6) || page == 10)
206 return;
207
208 // Update the page number
209 page++;
210
211 pageTurn(kRivenTransitionWipeLeft);
212 _vm->getCard()->drawPicture(page);
213 _vm->doFrame();
214
215 // Wait until the previous page turn sound completes
216 waitForPageTurnSound();
217 }
218 }
219
xacathopenbook(const ArgumentArray & args)220 void ASpit::xacathopenbook(const ArgumentArray &args) {
221 // Get the variable
222 uint32 page = _vm->_vars["acathbook"];
223
224 // Set hotspots depending on the page
225 RivenHotspot *openBook = _vm->getCard()->getHotspotByName("openBook");
226 RivenHotspot *nextPage = _vm->getCard()->getHotspotByName("nextpage");
227 RivenHotspot *prevPage = _vm->getCard()->getHotspotByName("prevpage");
228 if (page == 1) {
229 prevPage->enable(false);
230 nextPage->enable(false);
231 openBook->enable(true);
232 } else {
233 prevPage->enable(true);
234 nextPage->enable(true);
235 openBook->enable(false);
236 }
237
238 cathBookDrawPage(page);
239 }
240
cathBookDrawPage(uint32 page)241 void ASpit::cathBookDrawPage(uint32 page) {// Draw the image of the page
242 _vm->getCard()->drawPicture(page);
243
244 // Draw the white page edges
245 if (page > 1 && page < 5)
246 _vm->getCard()->drawPicture(50);
247 else if (page > 5)
248 _vm->getCard()->drawPicture(51);
249
250 if (page == 28) {
251 cathBookDrawTelescopeCombination();
252 }
253 }
254
cathBookDrawTelescopeCombination()255 void ASpit::cathBookDrawTelescopeCombination() {// Draw the telescope combination
256 // The images for the numbers are tBMP's 13 through 17.
257 // The start point is at (156, 247)
258 uint32 teleCombo = _vm->_vars["tcorrectorder"];
259 static const uint16 kNumberWidth = 32;
260 static const uint16 kNumberHeight = 25;
261 static const uint16 kDstX = 156;
262 static const uint16 kDstY = 247;
263
264 for (byte i = 0; i < 5; i++) {
265 uint16 offset = (getComboDigit(teleCombo, i) - 1) * kNumberWidth;
266 Common::Rect srcRect = Common::Rect(offset, 0, offset + kNumberWidth, kNumberHeight);
267 Common::Rect dstRect = Common::Rect(i * kNumberWidth + kDstX, kDstY, (i + 1) * kNumberWidth + kDstX, kDstY + kNumberHeight);
268 _vm->_gfx->drawImageRect(i + 13, srcRect, dstRect);
269 }
270 }
271
xacathbookback(const ArgumentArray & args)272 void ASpit::xacathbookback(const ArgumentArray &args) {
273 _vm->_inventory->backFromItemScript();
274 }
275
xacathbookprevpage(const ArgumentArray & args)276 void ASpit::xacathbookprevpage(const ArgumentArray &args) {
277 // Get the variable
278 uint32 &page = _vm->_vars["acathbook"];
279
280 // Keep turning pages while the mouse is pressed
281 while (keepTurningPages()) {
282 // Check for the first page
283 if (page == 1)
284 return;
285
286 // Update the page number
287 page--;
288
289 pageTurn(kRivenTransitionWipeDown);
290 cathBookDrawPage(page);
291 _vm->doFrame();
292
293 waitForPageTurnSound();
294 }
295 }
296
xacathbooknextpage(const ArgumentArray & args)297 void ASpit::xacathbooknextpage(const ArgumentArray &args) {
298 // Get the variable
299 uint32 &page = _vm->_vars["acathbook"];
300
301 // Keep turning pages while the mouse is pressed
302 while (keepTurningPages()) {
303 // Check for the last page
304 if (page == 49)
305 return;
306
307 // Update the page number
308 page++;
309
310 pageTurn(kRivenTransitionWipeUp);
311 cathBookDrawPage(page);
312 _vm->doFrame();
313
314 waitForPageTurnSound();
315 }
316 }
317
xtrapbookback(const ArgumentArray & args)318 void ASpit::xtrapbookback(const ArgumentArray &args) {
319 // Return to where we were before entering the book
320 _vm->_vars["atrap"] = 0;
321 _vm->_inventory->backFromItemScript();
322 }
323
xatrapbookclose(const ArgumentArray & args)324 void ASpit::xatrapbookclose(const ArgumentArray &args) {
325 // Close the trap book
326 _vm->_vars["atrap"] = 0;
327
328 pageTurn(kRivenTransitionWipeRight);
329
330 // Stop the flyby movie to prevent a glitch where the book does not actually
331 // close because the movie continues to draw over the closed book picture.
332 // This glitch also happened in the original engine with transitions disabled.
333 RivenVideo *flyby = _vm->_video->getSlot(1);
334 flyby->close();
335
336 _vm->getCard()->enter(false);
337 }
338
xatrapbookopen(const ArgumentArray & args)339 void ASpit::xatrapbookopen(const ArgumentArray &args) {
340 // Open the trap book
341 _vm->_vars["atrap"] = 1;
342
343 pageTurn(kRivenTransitionWipeLeft);
344
345 _vm->getCard()->enter(false);
346 }
347
xarestoregame(const ArgumentArray & args)348 void ASpit::xarestoregame(const ArgumentArray &args) {
349 if (!showConfirmationDialog(_("Are you sure you want to load a saved game? All unsaved progress will be lost."),
350 _("Load game"), _("Cancel"))) {
351 return;
352 }
353
354 // Launch the load game dialog
355 _vm->loadGameDialog();
356 }
357
xaSaveGame(const ArgumentArray & args)358 void ASpit::xaSaveGame(const ArgumentArray &args) {
359 _vm->saveGameDialog();
360 }
361
xaResumeGame(const ArgumentArray & args)362 void ASpit::xaResumeGame(const ArgumentArray &args) {
363 _vm->resumeFromMainMenu();
364 }
365
xaOptions(const ArgumentArray & args)366 void ASpit::xaOptions(const ArgumentArray &args) {
367 _vm->runOptionsDialog();
368 }
369
xaNewGame(const ArgumentArray & args)370 void ASpit::xaNewGame(const ArgumentArray &args) {
371 if (!showConfirmationDialog(_("Are you sure you want to start a new game? All unsaved progress will be lost."),
372 _("New game"), _("Cancel"))) {
373 return;
374 }
375
376 _vm->startNewGame();
377
378 RivenScriptPtr script = _vm->_scriptMan->createScriptFromData(2,
379 kRivenCommandTransition, 1, kRivenTransitionBlend,
380 kRivenCommandChangeCard, 1, 2);
381
382 script->addCommand(RivenCommandPtr(new RivenStackChangeCommand(_vm, 0, 0x6E9A, false, false)));
383
384 script += _vm->_scriptMan->createScriptFromData(1,
385 kRivenCommandStopSound, 1, 2);
386
387 _vm->_scriptMan->runScript(script, false);
388 }
389
showConfirmationDialog(const Common::U32String & message,const Common::U32String & confirmButton,const Common::U32String & cancelButton)390 bool ASpit::showConfirmationDialog(const Common::U32String &message, const Common::U32String &confirmButton, const Common::U32String &cancelButton) {
391 if (!_vm->isGameStarted()) {
392 return true;
393 }
394
395 GUI::MessageDialog dialog(message, confirmButton, cancelButton);
396
397 return dialog.runModal() == GUI::kMessageOK;
398 }
399
xadisablemenureturn(const ArgumentArray & args)400 void ASpit::xadisablemenureturn(const ArgumentArray &args) {
401 // This function would normally enable the Windows menu item for
402 // returning to the main menu. Ctrl+r will do this instead.
403 // The original also had this shortcut.
404 }
405
xaenablemenureturn(const ArgumentArray & args)406 void ASpit::xaenablemenureturn(const ArgumentArray &args) {
407 // This function would normally enable the Windows menu item for
408 // returning to the main menu. Ctrl+r will do this instead.
409 // The original also had this shortcut.
410 }
411
xalaunchbrowser(const ArgumentArray & args)412 void ASpit::xalaunchbrowser(const ArgumentArray &args) {
413 // Well, we can't launch a browser for obvious reasons ;)
414 // The original text is as follows (for reference):
415
416 // If you have an auto-dial configured connection to the Internet,
417 // please select YES below.
418 //
419 // America Online and CompuServe users may experience difficulty. If
420 // you find that you are unable to connect, please quit the Riven
421 // Demo, launch your browser and type in the following URL:
422 //
423 // www.redorb.com/buyriven
424 //
425 // Would you like to attempt to make the connection?
426 //
427 // [YES] [NO]
428
429 GUI::MessageDialog dialog(_("At this point, the Riven Demo would\n"
430 "ask if you would like to open a web browser\n"
431 "to bring you to the Red Orb store to buy\n"
432 "the game. ScummVM cannot do that and\n"
433 "the site no longer exists."));
434 dialog.runModal();
435 }
436
xadisablemenuintro(const ArgumentArray & args)437 void ASpit::xadisablemenuintro(const ArgumentArray &args) {
438 // This function would normally enable the Windows menu item for
439 // playing the intro. Ctrl+p will play the intro movies instead.
440 // The original also had this shortcut.
441
442 _vm->_inventory->forceHidden(true);
443 }
444
xaenablemenuintro(const ArgumentArray & args)445 void ASpit::xaenablemenuintro(const ArgumentArray &args) {
446 // This function would normally enable the Windows menu item for
447 // playing the intro. Ctrl+p will play the intro movies instead.
448 // The original also had this shortcut.
449
450 // Show the "exit" button here
451 _vm->_inventory->forceHidden(false);
452 }
453
xademoquit(const ArgumentArray & args)454 void ASpit::xademoquit(const ArgumentArray &args) {
455 if (!showConfirmationDialog(_("Are you sure you want to quit? All unsaved progress will be lost."), _("Quit"),
456 _("Cancel"))) {
457 return;
458 }
459
460 // Exactly as it says on the tin. In the demo, this function quits.
461 _vm->setGameEnded();
462 }
463
xaexittomain(const ArgumentArray & args)464 void ASpit::xaexittomain(const ArgumentArray &args) {
465 // One could potentially implement this function, but there would be no
466 // point. This function is only used in the demo's aspit card 9 update
467 // screen script. However, card 9 is not accessible from the game without
468 // jumping to the card and there's nothing going on in the card so it
469 // never gets called. There's also no card 9 in the full game, so the
470 // functionality of this card was likely removed before release. The
471 // demo executable references some other external commands relating to
472 // setting and getting the volume, as well as drawing the volume. I'd
473 // venture to guess that this would have been some sort of options card
474 // replaced with the Windows/Mac API in the final product.
475 //
476 // Yeah, this function is just dummied and holds a big comment ;)
477 }
478
479 } // End of namespace RivenStacks
480 } // End of namespace Mohawk
481