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