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 "neverhood/gamemodule.h"
24 
25 #include "neverhood/graphics.h"
26 #include "neverhood/menumodule.h"
27 #include "neverhood/modules/module1000.h"
28 #include "neverhood/modules/module1100.h"
29 #include "neverhood/modules/module1200.h"
30 #include "neverhood/modules/module1300.h"
31 #include "neverhood/modules/module1400.h"
32 #include "neverhood/modules/module1500.h"
33 #include "neverhood/modules/module1600.h"
34 #include "neverhood/modules/module1700.h"
35 #include "neverhood/modules/module1800.h"
36 #include "neverhood/modules/module1900.h"
37 #include "neverhood/modules/module2000.h"
38 #include "neverhood/modules/module2100.h"
39 #include "neverhood/modules/module2200.h"
40 #include "neverhood/modules/module2300.h"
41 #include "neverhood/modules/module2400.h"
42 #include "neverhood/modules/module2500.h"
43 #include "neverhood/modules/module2600.h"
44 #include "neverhood/modules/module2700.h"
45 #include "neverhood/modules/module2800.h"
46 #include "neverhood/modules/module2900.h"
47 #include "neverhood/modules/module3000.h"
48 
49 namespace Neverhood {
50 
51 static const uint32 kRadioMusicFileHashes[] = {
52 	0x82B22000,
53 	0x02B22004,
54 	0x42B22000,
55 	0x03322008,
56 	0x02B22001,
57 	0x02B22008,
58 	0x02B22020,
59 	0x03322001,
60 	0x03322002,
61 	0x03322004,
62 	0x03322040,
63 	0x02B22002,
64 	0x02B22010,
65 	0x03322010,
66 	0x02B22040,
67 	0x43322000,
68 	0x83322000,
69 	0x03322020
70 };
71 
72 enum {
73 	MENU_MODULE			= 9999
74 };
75 
GameModule(NeverhoodEngine * vm)76 GameModule::GameModule(NeverhoodEngine *vm)
77 	: Module(vm, NULL), _moduleNum(-1), _prevChildObject(NULL), _prevModuleNum(-1),
78 	_restoreGameRequested(false), _restartGameRequested(false), _canRequestMainMenu(true),
79 	_mainMenuRequested(false) {
80 
81 	// Other initializations moved to actual engine class
82 	_vm->_soundMan->playSoundThree(0x002D0031, 0x08861079);
83 	SetMessageHandler(&GameModule::handleMessage);
84 }
85 
~GameModule()86 GameModule::~GameModule() {
87 	_vm->_soundMan->deleteSoundGroup(0x002D0031);
88 	delete _childObject;
89 	_childObject = NULL;
90 }
91 
handleMouseMove(int16 x,int16 y)92 void GameModule::handleMouseMove(int16 x, int16 y) {
93 	if (_childObject) {
94 		NPoint mousePos;
95 		mousePos.x = x;
96 		mousePos.y = y;
97 		debug(2, "GameModule::handleMouseMove(%d, %d)", x, y);
98 		sendPointMessage(_childObject, NM_MOUSE_MOVE, mousePos);
99 	}
100 }
101 
handleMouseDown(int16 x,int16 y)102 void GameModule::handleMouseDown(int16 x, int16 y) {
103 	if (_childObject) {
104 		NPoint mousePos;
105 		mousePos.x = x;
106 		mousePos.y = y;
107 		debug(2, "GameModule::handleMouseDown(%d, %d)", x, y);
108 		sendPointMessage(_childObject, NM_MOUSE_CLICK, mousePos);
109 	}
110 }
111 
handleMouseUp(int16 x,int16 y)112 void GameModule::handleMouseUp(int16 x, int16 y) {
113 	if (_childObject) {
114 		NPoint mousePos;
115 		mousePos.x = x;
116 		mousePos.y = y;
117 		debug(2, "GameModule::handleMouseUp(%d, %d)", x, y);
118 		sendPointMessage(_childObject, NM_MOUSE_RELEASE, mousePos);
119 	}
120 }
121 
handleWheelUp()122 void GameModule::handleWheelUp() {
123 	if (_childObject) {
124 		sendMessage(_childObject, NM_MOUSE_WHEELUP, 0);
125 	}
126 }
127 
handleWheelDown()128 void GameModule::handleWheelDown() {
129 	if (_childObject) {
130 		sendMessage(_childObject, NM_MOUSE_WHEELDOWN, 0);
131 	}
132 }
133 
handleSpaceKey()134 void GameModule::handleSpaceKey() {
135 	if (_childObject) {
136 		debug(2, "GameModule::handleSpaceKey()");
137 		sendMessage(_childObject, NM_KEYPRESS_SPACE, 0);
138 	}
139 }
140 
handleAsciiKey(char key)141 void GameModule::handleAsciiKey(char key) {
142 	if (_childObject) {
143 		debug(2, "GameModule::handleAsciiKey()");
144 		sendMessage(_childObject, 0x000A, (uint32)key);
145 	}
146 }
147 
handleKeyDown(Common::KeyCode keyCode)148 void GameModule::handleKeyDown(Common::KeyCode keyCode) {
149 	if (_childObject) {
150 		if (keyCode == Common::KEYCODE_ESCAPE)
151 			handleEscapeKey();
152 		else if (keyCode == Common::KEYCODE_SPACE)
153 			handleSpaceKey();
154 		debug(2, "GameModule::handleKeyDown()");
155 		sendMessage(_childObject, 0x000B, keyCode);
156 	}
157 }
158 
handleEscapeKey()159 void GameModule::handleEscapeKey() {
160 	if (_vm->isDemo())
161 		_vm->quitGame();
162 	else if (!_prevChildObject && _canRequestMainMenu)
163 		_mainMenuRequested = true;
164 	else if (_childObject)
165 		sendMessage(_childObject, NM_KEYPRESS_ESC, 0);
166 }
167 
initKeySlotsPuzzle()168 void GameModule::initKeySlotsPuzzle() {
169 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x25400B10)) {
170 		NonRepeatingRandomNumbers keySlots(_vm->_rnd, 16);
171 		for (uint i = 0; i < 3; i++) {
172 			setSubVar(VA_GOOD_KEY_SLOT_NUMBERS, i, keySlots.getNumber());
173 			setSubVar(VA_CURR_KEY_SLOT_NUMBERS, i, keySlots.getNumber());
174 		}
175 		setSubVar(VA_IS_PUZZLE_INIT, 0x25400B10, 1);
176 	}
177 }
178 
initMemoryPuzzle()179 void GameModule::initMemoryPuzzle() {
180 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0xC8606803)) {
181 		NonRepeatingRandomNumbers diceIndices(_vm->_rnd, 3);
182 		NonRepeatingRandomNumbers availableTiles(_vm->_rnd, 48);
183 		NonRepeatingRandomNumbers tileSymbols(_vm->_rnd, 10);
184 		for (uint32 i = 0; i < 3; i++)
185 			setSubVar(VA_CURR_DICE_NUMBERS, i, 1);
186 		// Set special symbols
187 		// Symbol 5 is always one of the three special symbols
188 		setSubVar(VA_DICE_MEMORY_SYMBOLS, diceIndices.getNumber(), 5);
189 		tileSymbols.removeNumber(5);
190 		for (int i = 0; i < 2; i++)
191 			setSubVar(VA_DICE_MEMORY_SYMBOLS, diceIndices.getNumber(), tileSymbols.getNumber());
192 		// Insert special symbols tiles
193 		for (uint32 i = 0; i < 3; ++i) {
194 			int tileSymbolOccurence = _vm->_rnd->getRandomNumber(4 - 1) * 2 + 2;
195 			setSubVar(VA_GOOD_DICE_NUMBERS, i, tileSymbolOccurence);
196 			while (tileSymbolOccurence--)
197 				setSubVar(VA_TILE_SYMBOLS, availableTiles.getNumber(), getSubVar(VA_DICE_MEMORY_SYMBOLS, i));
198 		}
199 		// Fill the remaining tiles
200 		uint32 tileSymbolIndex = 0;
201 		while (!availableTiles.empty()) {
202 			setSubVar(VA_TILE_SYMBOLS, availableTiles.getNumber(), tileSymbols[tileSymbolIndex]);
203 			setSubVar(VA_TILE_SYMBOLS, availableTiles.getNumber(), tileSymbols[tileSymbolIndex]);
204 			tileSymbolIndex++;
205 			if (tileSymbolIndex >= tileSymbols.size())
206 				tileSymbolIndex = 0;
207 		}
208 		setSubVar(VA_IS_PUZZLE_INIT, 0xC8606803, 1);
209 	}
210 }
211 
initWaterPipesPuzzle()212 void GameModule::initWaterPipesPuzzle() {
213 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x40520234)) {
214 		setSubVar(VA_GOOD_WATER_PIPES_LEVEL, 0, 3);
215 		setSubVar(VA_GOOD_WATER_PIPES_LEVEL, 1, 1);
216 		setSubVar(VA_GOOD_WATER_PIPES_LEVEL, 2, 2);
217 		setSubVar(VA_GOOD_WATER_PIPES_LEVEL, 3, 0);
218 		setSubVar(VA_GOOD_WATER_PIPES_LEVEL, 4, 4);
219 		setSubVar(VA_IS_PUZZLE_INIT, 0x40520234, 1);
220 	}
221 }
222 
initRadioPuzzle()223 void GameModule::initRadioPuzzle() {
224 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x08C80800)) {
225 		int currMusicIndex = _vm->_rnd->getRandomNumber(5 - 1) + 3;
226 		setGlobalVar(V_GOOD_RADIO_MUSIC_INDEX, 5 * currMusicIndex);
227 		setGlobalVar(V_GOOD_RADIO_MUSIC_NAME, kRadioMusicFileHashes[currMusicIndex]);
228 		setGlobalVar(V_RADIO_ROOM_LEFT_DOOR, 1);
229 		setGlobalVar(V_RADIO_ROOM_RIGHT_DOOR, 0);
230 		setSubVar(VA_IS_PUZZLE_INIT, 0x08C80800, 1);
231 	}
232 }
233 
initTestTubes1Puzzle()234 void GameModule::initTestTubes1Puzzle() {
235 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x20479010)) {
236 		for (uint i = 0; i < 3; i++)
237 			setSubVar(VA_GOOD_TEST_TUBES_LEVEL_1, i, _vm->_rnd->getRandomNumber(3 - 1) + 1);
238 		setSubVar(VA_IS_PUZZLE_INIT, 0x20479010, 1);
239 	}
240 }
241 
initTestTubes2Puzzle()242 void GameModule::initTestTubes2Puzzle() {
243 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x66059818)) {
244 		for (uint i = 0; i < 3; i++)
245 			setSubVar(VA_GOOD_TEST_TUBES_LEVEL_2, i, _vm->_rnd->getRandomNumber(6 - 1) + 1);
246 		setSubVar(VA_IS_PUZZLE_INIT, 0x66059818, 1);
247 	}
248 }
249 
initCannonSymbolsPuzzle()250 void GameModule::initCannonSymbolsPuzzle() {
251 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x8C9819C2)) {
252 		for (int i = 0; i < 3; i++) {
253 			setSubVar(VA_GOOD_CANNON_SYMBOLS_1, i, _vm->_rnd->getRandomNumber(12 - 1));
254 			setSubVar(VA_GOOD_CANNON_SYMBOLS_2, i, _vm->_rnd->getRandomNumber(12 - 1));
255 		}
256 		setSubVar(VA_IS_PUZZLE_INIT, 0x8C9819C2, 1);
257 	}
258 }
259 
initCodeSymbolsPuzzle()260 void GameModule::initCodeSymbolsPuzzle() {
261 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x0CD09B50)) {
262 		for (int i = 0; i < 12; ++i)
263 			setSubVar(VA_CODE_SYMBOLS, i, i);
264 		for (int i = 0; i < 12; ++i) {
265 			uint32 index1 = _vm->_rnd->getRandomNumber(12 - 1);
266 			uint32 index2 = _vm->_rnd->getRandomNumber(12 - 1);
267 			uint32 temp = getSubVar(VA_CODE_SYMBOLS, index1);
268 			setSubVar(VA_CODE_SYMBOLS, index1, getSubVar(VA_CODE_SYMBOLS, index2));
269 			setSubVar(VA_CODE_SYMBOLS, index2, temp);
270 		}
271 		setGlobalVar(V_NOISY_SYMBOL_INDEX, _vm->_rnd->getRandomNumber(11 - 1) + 1);
272 		setSubVar(VA_IS_PUZZLE_INIT, 0x0CD09B50, 1);
273 	}
274 }
275 
initCubeSymbolsPuzzle()276 void GameModule::initCubeSymbolsPuzzle() {
277 	if (!getSubVar(VA_IS_PUZZLE_INIT, 0x60400854)) {
278 		NonRepeatingRandomNumbers cubeSymbols(_vm->_rnd, 9);
279 		for (uint32 cubePosition = 0; cubePosition < 9; ++cubePosition)
280 			setSubVar(VA_CUBE_POSITIONS, cubePosition, (uint32)(cubeSymbols.getNumber() - 1));
281 		setSubVar(VA_IS_PUZZLE_INIT, 0x60400854, 1);
282 	}
283 }
284 
initCrystalColorsPuzzle()285 void GameModule::initCrystalColorsPuzzle() {
286 	if (!getGlobalVar(V_CRYSTAL_COLORS_INIT)) {
287 		TextResource textResource(_vm);
288 		const char *textStart, *textEnd;
289 		textResource.load(0x46691611);
290 		textStart = textResource.getString(0, textEnd);
291 		for (uint index = 0; index < 5; index++) {
292 			char colorLetter = (byte)textStart[index];
293 			byte correctColorNum = 0, misalignedColorNum;
294 			switch (colorLetter) {
295 			case 'B':
296 				correctColorNum = 4;
297 				break;
298 			case 'G':
299 				correctColorNum = 3;
300 				break;
301 			case 'O':
302 				correctColorNum = 1;
303 				break;
304 			case 'R':
305 				correctColorNum = 0;
306 				break;
307 			case 'V':
308 				correctColorNum = 5;
309 				break;
310 			case 'Y':
311 				correctColorNum = 2;
312 				break;
313 			default:
314 				break;
315 			}
316 			do {
317 				misalignedColorNum = _vm->_rnd->getRandomNumber(6 - 1);
318 			} while (misalignedColorNum == correctColorNum);
319 			setSubVar(VA_GOOD_CRYSTAL_COLORS, index, correctColorNum);
320 			setSubVar(VA_CURR_CRYSTAL_COLORS, index, misalignedColorNum);
321 		}
322 		setGlobalVar(V_CRYSTAL_COLORS_INIT, 1);
323 	}
324 }
325 
getCurrRadioMusicFileHash()326 uint32 GameModule::getCurrRadioMusicFileHash() {
327 	uint musicIndex = getGlobalVar(V_CURR_RADIO_MUSIC_INDEX);
328 	return (musicIndex % 5 != 0) ? 0 : kRadioMusicFileHashes[CLIP<uint>(musicIndex / 5, 0, 17)];
329 }
330 
331 
handleMessage(int messageNum,const MessageParam & param,Entity * sender)332 uint32 GameModule::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
333 	uint32 messageResult = Module::handleMessage(messageNum, param, sender);
334 	switch (messageNum) {
335 	case 0x0800:
336 		_canRequestMainMenu = true;
337 		break;
338 	case 0x1009:
339 		_moduleResult = param.asInteger();
340 		_done = true;
341 		break;
342 	default:
343 		break;
344 	}
345 	return messageResult;
346 }
347 
startup()348 void GameModule::startup() {
349 #if 1
350 	// Logos and intro video // Real game start
351 	createModule(1500, 0);
352 #else
353 	// DEBUG>>>
354 	/*
355 	setGlobalVar(V_SEEN_MUSIC_BOX, 1);
356 	setGlobalVar(V_CREATURE_EXPLODED, 0);
357 	setGlobalVar(V_MATCH_STATUS, 0);
358 	setGlobalVar(V_PROJECTOR_LOCATION, 2);
359 	*/
360 	//setGlobalVar(V_ENTRANCE_OPEN, 0);
361 	//setGlobalVar(V_DOOR_SPIKES_OPEN, 1);
362 	//setGlobalVar(V_CREATURE_ANGRY, 1);
363 	setGlobalVar(V_RADIO_ENABLED, 1);
364 	//setGlobalVar(V_TNT_DUMMY_BUILT, 1);
365 	setGlobalVar(V_FLYTRAP_RING_DOOR, 1);
366 	setGlobalVar(V_TV_JOKE_TOLD, 1);
367 	/*
368 	// Give all disks
369 	for (int i = 0; i < 20; i++)
370 		setSubVar(VA_IS_TAPE_INSERTED, i, 1);
371 	*/
372 	setSubVar(VA_IS_KEY_INSERTED, 0, 1);
373 	setSubVar(VA_IS_KEY_INSERTED, 1, 1);
374 	setSubVar(VA_IS_KEY_INSERTED, 2, 1);
375 	for (uint32 index = 0; index < 9; index++)
376 		setSubVar(VA_CUBE_POSITIONS, index, 7 - index);
377 	setGlobalVar(V_WALL_BROKEN, 0);
378 	setGlobalVar(V_WORLDS_JOINED, 1);
379 	setGlobalVar(V_RADIO_MOVE_DISH_VIDEO, 0);
380 	// Enable all locations
381 	for (int i = 0; i < 6; i++)
382 		setSubVar(V_TELEPORTER_DEST_AVAILABLE, i, 1);
383 	//setGlobalVar(V_PROJECTOR_LOCATION, 4);
384 	setGlobalVar(V_KEYDOOR_UNLOCKED, 1);
385 	setGlobalVar(V_LIGHTS_ON, 1);
386 	setGlobalVar(V_WATER_RUNNING, 1);
387 	setGlobalVar(V_HAS_TEST_TUBE, 1);
388 	setSubVar(VA_CURR_WATER_PIPES_LEVEL, 0, 3);
389 	setSubVar(VA_CURR_WATER_PIPES_LEVEL, 1, 1);
390 	setSubVar(VA_CURR_WATER_PIPES_LEVEL, 2, 2);
391 	setSubVar(VA_CURR_WATER_PIPES_LEVEL, 3, 0);
392 	setSubVar(VA_CURR_WATER_PIPES_LEVEL, 4, 4);
393 	setGlobalVar(V_KLAYMEN_SMALL, 1);
394 	setGlobalVar(V_SHRINK_LIGHTS_ON, 0);
395 	// <<<DEBUG
396 
397 #if 1
398 	_vm->gameState().which = 0;
399 	_vm->gameState().sceneNum = 0;
400 	createModule(2400, 0);
401 #endif
402 
403 #endif
404 }
405 
requestRestoreGame()406 void GameModule::requestRestoreGame() {
407 	_restoreGameRequested = true;
408 }
409 
requestRestartGame(bool requestMainMenu)410 void GameModule::requestRestartGame(bool requestMainMenu) {
411 	_restartGameRequested = true;
412 	_mainMenuRequested = requestMainMenu;
413 }
414 
redrawPrevChildObject()415 void GameModule::redrawPrevChildObject() {
416 	if (_prevChildObject) {
417 		_prevChildObject->draw();
418 		_vm->_screen->update();
419 	}
420 }
421 
checkRequests()422 void GameModule::checkRequests() {
423 	if (_restartGameRequested) {
424 		_restartGameRequested = false;
425 		_vm->_gameVars->clear();
426 		requestRestoreGame();
427 	}
428 	if (_restoreGameRequested) {
429 		_restoreGameRequested = false;
430 		_vm->_audioResourceMan->stopAllMusic();
431 		_vm->_audioResourceMan->stopAllSounds();
432 		_vm->_soundMan->stopAllMusic();
433 		_vm->_soundMan->stopAllSounds();
434 		// Reinsert turning sound because SoundMan::stopAllSounds() removes it
435 		_vm->_soundMan->playSoundThree(0x002D0031, 0x08861079);
436 		delete _childObject;
437 		delete _prevChildObject;
438 		_childObject = NULL;
439 		_prevChildObject = NULL;
440 		_prevModuleNum = 0;
441 		createModuleByHash(getGlobalVar(V_MODULE_NAME));
442 	}
443 	if (_mainMenuRequested)
444 		openMainMenu();
445 }
446 
createModule(int moduleNum,int which)447 void GameModule::createModule(int moduleNum, int which) {
448 	debug(1, "GameModule::createModule(%d, %d)", moduleNum, which);
449 	_moduleNum = moduleNum;
450 
451 	delete _childObject;
452 
453 	switch (_moduleNum) {
454 	case 1000:
455 		setGlobalVar(V_MODULE_NAME, 0x03294419);
456 		_childObject = new Module1000(_vm, this, which);
457 		break;
458 	case 1100:
459 		setGlobalVar(V_MODULE_NAME, 0x0002C818);
460 		_childObject = new Module1100(_vm, this, which);
461 		break;
462 	case 1200:
463 		setGlobalVar(V_MODULE_NAME, 0x00478311);
464 		_childObject = new Module1200(_vm, this, which);
465 		break;
466 	case 1300:
467 		setGlobalVar(V_MODULE_NAME, 0x0061C090);
468 		_childObject = new Module1300(_vm, this, which);
469 		break;
470 	case 1400:
471 		setGlobalVar(V_MODULE_NAME, 0x00AD0012);
472 		_childObject = new Module1400(_vm, this, which);
473 		break;
474 	case 1500:
475 		_canRequestMainMenu = false;
476 		setGlobalVar(V_MODULE_NAME, 0x00F10114);
477 		_childObject = new Module1500(_vm, this, which);
478 		break;
479 	case 1600:
480 		setGlobalVar(V_MODULE_NAME, 0x01A008D8);
481 		_childObject = new Module1600(_vm, this, which);
482 		break;
483 	case 1700:
484 		setGlobalVar(V_MODULE_NAME, 0x04212331);
485 		_childObject = new Module1700(_vm, this, which);
486 		break;
487 	case 1800:
488 		setGlobalVar(V_MODULE_NAME, 0x04A14718);
489 		_childObject = new Module1800(_vm, this, which);
490 		break;
491 	case 1900:
492 		setGlobalVar(V_MODULE_NAME, 0x04E1C09C);
493 		_childObject = new Module1900(_vm, this, which);
494 		break;
495 	case 2000:
496 		setGlobalVar(V_MODULE_NAME, 0x08250000);
497 		_childObject = new Module2000(_vm, this, which);
498 		break;
499 	case 2100:
500 		setGlobalVar(V_MODULE_NAME, 0x10A10C14);
501 		_childObject = new Module2100(_vm, this, which);
502 		break;
503 	case 2200:
504 		setGlobalVar(V_MODULE_NAME, 0x11391412);
505 		_childObject = new Module2200(_vm, this, which);
506 		break;
507 	case 2300:
508 		setGlobalVar(V_MODULE_NAME, 0x1A214010);
509 		_childObject = new Module2300(_vm, this, which);
510 		break;
511 	case 2400:
512 		setGlobalVar(V_MODULE_NAME, 0x202D1010);
513 		_childObject = new Module2400(_vm, this, which);
514 		break;
515 	case 2500:
516 		setGlobalVar(V_MODULE_NAME, 0x29220120);
517 		_childObject = new Module2500(_vm, this, which);
518 		break;
519 	case 2600:
520 		setGlobalVar(V_MODULE_NAME, 0x40271018);
521 		_childObject = new Module2600(_vm, this, which);
522 		break;
523 	case 2700:
524 		setGlobalVar(V_MODULE_NAME, 0x42212411);
525 		_childObject = new Module2700(_vm, this, which);
526 		break;
527 	case 2800:
528 		setGlobalVar(V_MODULE_NAME, 0x64210814);
529 		_childObject = new Module2800(_vm, this, which);
530 		break;
531 	case 2900:
532 		setGlobalVar(V_MODULE_NAME, 0x81100020);
533 		if (which >= 0)
534 			setGlobalVar(V_TELEPORTER_CURR_LOCATION, which);
535 		_childObject = new Module2900(_vm, this, which);
536 		break;
537 	case 3000:
538 		setGlobalVar(V_MODULE_NAME, 0x81293110);
539 		_childObject = new Module3000(_vm, this, which);
540 		break;
541 	case 9999:
542 		createDemoScene();
543 		break;
544 	default:
545 		error("GameModule::createModule() Could not create module %d", moduleNum);
546 	}
547 	SetUpdateHandler(&GameModule::updateModule);
548 	_childObject->handleUpdate();
549 }
550 
createModuleByHash(uint32 nameHash)551 void GameModule::createModuleByHash(uint32 nameHash) {
552 	debug(1, "GameModule::createModuleByHash(%08X)", nameHash);
553 	switch (nameHash) {
554 	case 0x03294419:
555 		createModule(1000, -1);
556 		break;
557 	case 0x0002C818:
558 		createModule(1100, -1);
559 		break;
560 	case 0x00478311:
561 		createModule(1200, -1);
562 		break;
563 	case 0x0061C090:
564 		createModule(1300, -1);
565 		break;
566 	case 0x00AD0012:
567 		createModule(1400, -1);
568 		break;
569 	case 0x00F10114:
570 		createModule(1500, -1);
571 		break;
572 	case 0x01A008D8:
573 		createModule(1600, -1);
574 		break;
575 	case 0x04212331:
576 		createModule(1700, -1);
577 		break;
578 	case 0x04A14718:
579 		createModule(1800, -1);
580 		break;
581 	case 0x04E1C09C:
582 		createModule(1900, -1);
583 		break;
584 	case 0x08250000:
585 		createModule(2000, -1);
586 		break;
587 	case 0x10A10C14:
588 		createModule(2100, -1);
589 		break;
590 	case 0x11391412:
591 		createModule(2200, -1);
592 		break;
593 	case 0x1A214010:
594 		createModule(2300, -1);
595 		break;
596 	case 0x202D1010:
597 		createModule(2400, -1);
598 		break;
599 	case 0x29220120:
600 		createModule(2500, -1);
601 		break;
602 	case 0x40271018:
603 		createModule(2600, -1);
604 		break;
605 	case 0x42212411:
606 		createModule(2700, -1);
607 		break;
608 	case 0x64210814:
609 		createModule(2800, -1);
610 		break;
611 	case 0x81100020:
612 		createModule(2900, -1);
613 		break;
614 	case 0x81293110:
615 		createModule(3000, -1);
616 		break;
617 	default:
618 		createModule(1000, 0);
619 		break;
620 	}
621 }
622 
updateModule()623 void GameModule::updateModule() {
624 	if (!updateChild()) {
625 		switch (_moduleNum) {
626 		case 1000:
627 			createModule(2300, 0);
628 			break;
629 		case 1200:
630 			if (_moduleResult == 1)
631 				createModule(2600, 0);
632 			else
633 				createModule(2300, 2);
634 			break;
635 		case 1100:
636 			if (_moduleResult == 0)
637 				createModule(2900, 2);
638 			else {
639 				setGlobalVar(V_ENTRANCE_OPEN, 1);
640 				createModule(1300, 0);
641 			}
642 			break;
643 		case 1300:
644 			if (_moduleResult == 1) {
645 				// The game was successfully finished
646 				requestRestartGame(true);
647 			} else
648 				createModule(2900, 0);
649 			break;
650 		case 1400:
651 			createModule(1600, 1);
652 			break;
653 		case 1500:
654 			createModule(1000, 0);
655 			break;
656 		case 1600:
657 			if (_moduleResult == 1)
658 				createModule(1400, 0);
659 			else if (_moduleResult == 2)
660 				createModule(1700, 0);
661 			else
662 				createModule(2100, 0);
663 			break;
664 		case 1700:
665 			if (_moduleResult == 1)
666 				createModule(2900, 3);
667 			else
668 				createModule(1600, 2);
669 			break;
670 		case 1800:
671 			if (_moduleResult == 1) {
672 				// Game over, Klaymen jumped into the hole
673 				requestRestartGame(true);
674 			} else if (_moduleResult == 2)
675 				createModule(2700, 0);
676 			else if (_moduleResult == 3)
677 				createModule(3000, 3);
678 			else
679 				createModule(2800, 0);
680 			break;
681 		case 1900:
682 			createModule(3000, 1);
683 			break;
684 		case 2000:
685 			createModule(2900, 4);
686 			break;
687 		case 2100:
688 			if (_moduleResult == 1)
689 				createModule(2900, 1);
690 			else
691 				createModule(1600, 0);
692 			break;
693 		case 2200:
694 			createModule(2300, 1);
695 			break;
696 		case 2300:
697 		debug(1, "module 23000 _moduleResult : %d", _moduleResult);
698 			if (_moduleResult == 2)
699 				createModule(1200, 0);
700 			else if (_moduleResult == 0)
701 				createModule(1000, 1);
702 			else if (_vm->isDemo())
703 				createModule(9999, -1);
704 			else if (_moduleResult == 1)
705 				createModule(2200, 0);
706 			else if (_moduleResult == 3)
707 				createModule(2400, 0);
708 			else if (_moduleResult == 4)
709 				createModule(3000, 0);
710 			break;
711 		case 2400:
712 			createModule(2300, 3);
713 			break;
714 		case 2500:
715 			createModule(2600, 1);
716 			break;
717 		case 2600:
718 			if (_moduleResult == 1) {
719 				if (_vm->isDemo())
720 					createModule(9999, -1);
721 				else
722 					createModule(2500, 0);
723 			} else
724 				createModule(1200, 1);
725 			break;
726 		case 2700:
727 			createModule(1800, 2);
728 			break;
729 		case 2800:
730 			if (_moduleResult == 1)
731 				createModule(2900, 5);
732 			else
733 				createModule(1800, 0);
734 			break;
735 		case 2900:
736 			if (_moduleResult != (uint32)-1) {
737 				switch (_moduleResult) {
738 				case 0:
739 					createModule(1300, 5);
740 					break;
741 				case 1:
742 					createModule(2100, 1);
743 					break;
744 				case 2:
745 					createModule(1100, 1);
746 					break;
747 				case 3:
748 					setSubVar(V_TELEPORTER_DEST_AVAILABLE, 2, 1);
749 					createModule(1700, 1);
750 					break;
751 				case 4:
752 					createModule(2000, 0);
753 					break;
754 				case 5:
755 				default:
756 					createModule(2800, 1);
757 					break;
758 				}
759 			} else {
760 				switch (getGlobalVar(V_TELEPORTER_CURR_LOCATION)) {
761 				case 0:
762 					createModule(1300, 6);
763 					break;
764 				case 1:
765 					createModule(2100, 2);
766 					break;
767 				case 2:
768 					createModule(1100, 2);
769 					break;
770 				case 3:
771 					createModule(1700, 2);
772 					break;
773 				case 4:
774 					createModule(2000, 1);
775 					break;
776 				case 5:
777 				default:
778 					createModule(2800, 2);
779 					break;
780 				}
781 			}
782 			setGlobalVar(V_TELEPORTER_CURR_LOCATION, 0);
783 			break;
784 		case 3000:
785 			// NOTE _moduleResult 2 never used
786 			// NOTE Check if _moduleResult 4 is used
787 			if (_moduleResult == 1)
788 				createModule(1900, 0);
789 			else if (_moduleResult == 3)
790 				createModule(1800, 3);
791 			else if (_moduleResult == 4)
792 				createModule(3000, 0);
793 			else
794 				createModule(2300, 4);
795 			break;
796 		case 9999:
797 			createModuleByHash(getGlobalVar(V_MODULE_NAME));
798 			break;
799 		default:
800 			break;
801 		}
802 	}
803 }
804 
openMainMenu()805 void GameModule::openMainMenu() {
806 	if (_childObject) {
807 		sendMessage(_childObject, NM_MOUSE_HIDE, 0);
808 		_childObject->draw();
809 	} else {
810 		// If there's no module, create one so there's something to return to
811 		createModule(1000, 0);
812 	}
813 	_vm->_screen->saveParams();
814 	_vm->_screen->update();
815 	_mainMenuRequested = false;
816 	createMenuModule();
817 }
818 
createMenuModule()819 void GameModule::createMenuModule() {
820 	if (!_prevChildObject) {
821 		_prevChildObject = _childObject;
822 		_prevModuleNum = _moduleNum;
823 		_childObject = new MenuModule(_vm, this, 0);
824 		_childObject->handleUpdate();
825 		SetUpdateHandler(&GameModule::updateMenuModule);
826 	}
827 }
828 
updateMenuModule()829 void GameModule::updateMenuModule() {
830 	if (!updateChild()) {
831 		_vm->_screen->restoreParams();
832 		_childObject = _prevChildObject;
833 		sendMessage(_childObject, NM_MOUSE_SHOW, 0);
834 		_prevChildObject = NULL;
835 		_moduleNum = _prevModuleNum;
836 		SetUpdateHandler(&GameModule::updateModule);
837 	}
838 }
839 
NonRepeatingRandomNumbers(Common::RandomSource * rnd,int count)840 NonRepeatingRandomNumbers::NonRepeatingRandomNumbers(Common::RandomSource *rnd, int count)
841 	: _rnd(rnd) {
842 	for (int i = 0; i < count; i++)
843 		push_back(i);
844 }
845 
getNumber()846 int NonRepeatingRandomNumbers::getNumber() {
847 	int number;
848 	if (!empty()) {
849 		uint index = _rnd->getRandomNumber(size() - 1);
850 		number = (*this)[index];
851 		remove_at(index);
852 	} else
853 		number = 0;
854 	return number;
855 }
856 
removeNumber(int number)857 void NonRepeatingRandomNumbers::removeNumber(int number) {
858 	for (uint i = 0; i < size(); ++i)
859 		if ((*this)[i] == number) {
860 			remove_at(i);
861 			break;
862 		}
863 }
864 
865 } // End of namespace Neverhood
866