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 "common/config-manager.h"
25 #include "graphics/scaler.h"
26 #include "mads/mads.h"
27 #include "mads/game.h"
28 #include "mads/screen.h"
29 #include "mads/msurface.h"
30 #include "mads/menu_views.h"
31 #include "mads/nebular/game_nebular.h"
32 #include "mads/nebular/dialogs_nebular.h"
33 #include "mads/nebular/globals_nebular.h"
34 #include "mads/nebular/nebular_scenes.h"
35 
36 namespace MADS {
37 
38 namespace Nebular {
39 
GameNebular(MADSEngine * vm)40 GameNebular::GameNebular(MADSEngine *vm)
41 	: Game(vm) {
42 	_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
43 	_storyMode = STORYMODE_NAUGHTY;
44 	_difficulty = DIFFICULTY_HARD;
45 }
46 
checkCopyProtection()47 ProtectionResult GameNebular::checkCopyProtection() {
48 	// Only show copy protection dialog if explicitly wanted
49 	if (!ConfMan.getBool("copy_protection"))
50 		return PROTECTION_SUCCEED;
51 
52 	CopyProtectionDialog *dlg;
53 	bool correctAnswer;
54 
55 	dlg = new CopyProtectionDialog(_vm, false);
56 	dlg->show();
57 	correctAnswer = dlg->isCorrectAnswer();
58 	delete dlg;
59 
60 	if (!correctAnswer && !_vm->shouldQuit()) {
61 		dlg = new CopyProtectionDialog(_vm, true);
62 		dlg->show();
63 		correctAnswer = dlg->isCorrectAnswer();
64 		delete dlg;
65 	}
66 
67 	return correctAnswer ? PROTECTION_SUCCEED : PROTECTION_FAIL;
68 }
69 
startGame()70 void GameNebular::startGame() {
71 	// First handle any ending credits from a just finished game session.
72 	// Note that, with the exception of the decompression ending, which doesn't
73 	// use animations, the remaining animations will automatically launch their
74 	// own text view credits when the animation is completed
75 	switch (_winStatus) {
76 	case 1:
77 		// No shields failure ending
78 		AnimationView::execute(_vm, "rexend1");
79 		break;
80 	case 2:
81 		// Shields, but no targetting failure ending
82 		AnimationView::execute(_vm, "rexend2");
83 		break;
84 	case 3:
85 		// Completed game successfully, so activate quotes item on the main menu
86 		ConfMan.setBool("ShowQuotes", true);
87 		ConfMan.flushToDisk();
88 
89 		AnimationView::execute(_vm, "rexend3");
90 		break;
91 	case 4:
92 		// Decompression ending
93 		TextView::execute(_vm, "ending4");
94 		break;
95 	}
96 
97 	do {
98 		checkShowDialog();
99 		_winStatus = 0;
100 
101 		_sectionNumber = 1;
102 		initSection(_sectionNumber);
103 		_vm->_events->setCursor(CURSOR_ARROW);
104 		_statusFlag = true;
105 
106 		// Show the main menu
107 		_vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
108 		_vm->_dialogs->showDialog();
109 	} while (!_vm->shouldQuit() && _vm->_dialogs->_pendingDialog != DIALOG_NONE);
110 
111 	if (_vm->shouldQuit())
112 		return;
113 
114 	_priorSectionNumber = 0;
115 	_priorSectionNumber = -1;
116 	_scene._priorSceneId = 0;
117 	_scene._currentSceneId = -1;
118 	_scene._nextSceneId = 101;
119 
120 	initializeGlobals();
121 
122 	if (_loadGameSlot >= 0)
123 		// User selected to resume a savegame
124 		return;
125 
126 	// Check copy protection
127 	ProtectionResult protectionResult = checkCopyProtection();
128 
129 	switch (protectionResult) {
130 	case PROTECTION_FAIL:
131 		// Copy protection failed
132 		_scene._nextSceneId = 804;
133 		_globals[kCopyProtectFailed] = true;
134 		return;
135 	case PROTECTION_ESCAPE:
136 		// User escaped out of copy protection dialog
137 		_vm->quitGame();
138 		return;
139 	default:
140 		// Copy protection check succeeded
141 		break;
142 	}
143 }
144 
initializeGlobals()145 void GameNebular::initializeGlobals() {
146 	int count, count2;
147 	int bad;
148 
149 	_globals.reset();
150 	_globals[kTalkInanimateCount] = 8;
151 
152 	/* Section #1 variables */
153 	_globals[kNeedToStandUp] = true;
154 	_globals[kTurkeyExploded] = false;
155 	_globals[kMedicineCabinetOpen] = false;
156 	_globals[kMedicineCabinetVirgin] = true;
157 	_globals[kWatchedViewScreen] = false;
158 	_globals[kHoovicAlive] = true;
159 	_globals[kWaterInAPuddle] = false;
160 
161 	_globals[kFishIn105] = true;
162 	_globals[kFishIn107] = true;
163 	_globals[kFishIn108] = true;
164 
165 	/* Section #2 variables */
166 	_globals[kLadderBroken] = false;
167 	_globals[kBone202Status] = 0;
168 	_globals[kRhotundaStatus] = RHOTUNDA_HUNGRY;
169 	_globals[kMonkeyStatus] = MONKEY_AMBUSH_READY;
170 	_globals[kMeteorologistStatus] = METEOROLOGIST_PRESENT;
171 	_globals[kMeteorologistEverSeen] = false;
172 	_globals[kMeteorologistWatch] = METEOROLOGIST_NORMAL;
173 	_globals[kTeleporterCommand] = TELEPORTER_NONE;
174 	_globals[kTeleporterUnderstood] = false;
175 	_globals[kTwinklesStatus] = TWINKLES_AT_HOME;
176 	_globals[kTwinklesApproached] = 0;
177 
178 	/* Section #3 variables */
179 	_globals[kAfterHavoc] = false;
180 	_globals[kKickedIn391Grate] = false;
181 
182 	/* Section #4 variables */
183 	_globals[kBadFirstIngredient] = -1;
184 	_objects[OBJ_CHARGE_CASES].setQuality(EXPLOSIVES_INSIDE, 0);
185 	_globals[kHasPurchased] = false;
186 	_globals[kBeenThruHelgaScene] = false;
187 	_globals[kNextIngredient] = 0;
188 	_globals[kHasSaidTimer] = false;
189 	_globals[kHasSaidBinocs] = false;
190 	_globals[kBottleDisplayed] = false;
191 	_globals[kHasBeenScanned] = false;
192 	_globals[kSomeoneHasExploded] = false;
193 
194 	// Generate a random ingredient list
195 	for (count = 0; count < 4; ++count) {
196 		do {
197 			_globals[kIngredientList + count] = _vm->getRandomNumber(3);
198 			bad = false;
199 			for (count2 = 0; count2 < count; ++count2) {
200 				if (_globals[kIngredientList + count] == _globals[kIngredientList + count2]) {
201 					bad = true;
202 				}
203 			}
204 		} while (bad);
205 	}
206 
207 	// Generate random ingredient quantities
208 	for (count = 0; count < 4; ++count) {
209 		do {
210 			_globals[kIngredientQuantity + count] = _vm->getRandomNumber(3);
211 			bad = false;
212 			for (count2 = 0; count2 < count; ++count2) {
213 				if (_globals[kIngredientQuantity + count] == _globals[kIngredientQuantity + count2]) {
214 					bad = true;
215 				}
216 			}
217 		} while (bad);
218 	}
219 
220 
221 	/* Section #5 variables */
222 	_globals[kHoverCarLocation] = 501;
223 	_globals[kHoverCarDestination] = -1;
224 	_globals[kCityFlooded] = false;
225 	_globals[kBoatRaised] = true;
226 	_globals[kLaserHoleIsThere] = false;
227 	_globals[kLineStatus] = LINE_NOT_DROPPED;
228 
229 
230 	/* Section #6 variables */
231 	_globals[kHasTalkedToHermit] = false;
232 	_globals[kHandsetCellStatus] = FIRST_TIME_PHONE_CELLS;
233 	_globals[kTimebombStatus] = TIMEBOMB_DEACTIVATED;
234 	_globals[kWarnedFloodCity] = false;
235 	_globals._timebombClock = 0;
236 	_globals._timebombTimer = 0;
237 
238 
239 	/* Section #7 variables */
240 	_globals[kBottleStatus] = BOTTLE_EMPTY;
241 	_globals[kBoatStatus] = BOAT_UNFLOODED;
242 
243 
244 	/* Section #8 variables */
245 	_globals[kWindowFixed] = false;
246 	_globals[kInSpace] = false;
247 	_globals[kReturnFromCut] = false;
248 	_globals[kBeamIsUp] = false;
249 	_globals[kForceBeamDown] = false;
250 	_globals[kCameFromCut] = false;
251 	_globals[kDontRepeat] = false;
252 	_globals[kHoppyDead] = false;
253 	_globals[kHasWatchedAntigrav] = false;
254 	_globals[kRemoteSequenceRan] = false;
255 	_globals[kRemoteOnGround] = false;
256 	_globals[kFromCockpit] = false;
257 	_globals[kExitShip] = false;
258 	_globals[kBetweenRooms] = false;
259 	_globals[kTopButtonPushed] = false;
260 	_globals[kShieldModInstalled] = false;
261 	_globals[kTargetModInstalled] = false;
262 	_globals[kUpBecauseOfRemote] = false;
263 
264 
265 	/* Set up the game's teleporters */
266 	_globals[kTeleporterRoom] = 201;
267 	_globals[kTeleporterRoom + 1] = 301;
268 	_globals[kTeleporterRoom + 2] = 413;
269 	_globals[kTeleporterRoom + 3] = 706;
270 	_globals[kTeleporterRoom + 4] = 801;
271 	_globals[kTeleporterRoom + 5] = 551;
272 	_globals[kTeleporterRoom + 6] = 752;
273 	_globals[kTeleporterRoom + 7] = 0;
274 	_globals[kTeleporterRoom + 8] = 0;
275 	_globals[kTeleporterRoom + 9] = 0;
276 
277 	for (count = 0; count < TELEPORTER_COUNT; ++count) {
278 		do {
279 			_globals[kTeleporterCode + count] = _vm->getRandomNumber(9999);
280 			bad = false;
281 			for (count2 = 0; count2 < count; ++count2) {
282 				if (_globals[kTeleporterCode + count] == _globals[kTeleporterCode + count2]) {
283 					bad = true;
284 				}
285 			}
286 		} while (bad);
287 	}
288 
289 	// Final setup based on selected difficulty level
290 	switch (_difficulty) {
291 	case DIFFICULTY_HARD:
292 		_objects.setRoom(OBJ_BLOWGUN, NOWHERE);
293 		_objects.setRoom(OBJ_NOTE, NOWHERE);
294 
295 		_globals[kLeavesStatus] = LEAVES_ON_GROUND;
296 		_globals[kDurafailRecharged] = 0;
297 		_globals[kPenlightCellStatus] = FIRST_TIME_UNCHARGED_DURAFAIL;
298 		break;
299 
300 	case DIFFICULTY_MEDIUM:
301 		_objects.setRoom(OBJ_PLANT_STALK, NOWHERE);
302 
303 		_globals[kLeavesStatus] = LEAVES_ON_GROUND;
304 		_globals[kDurafailRecharged] = 1;
305 		_globals[kPenlightCellStatus] = FIRST_TIME_CHARGED_DURAFAIL;
306 		break;
307 
308 	case DIFFICULTY_EASY:
309 		_objects.setRoom(OBJ_PLANT_STALK, NOWHERE);
310 		_objects.setRoom(OBJ_PENLIGHT, NOWHERE);
311 
312 		_globals[kLeavesStatus] = LEAVES_ON_TRAP;
313 		break;
314 	}
315 
316 	_player._facing = FACING_NORTH;
317 	_player._turnToFacing = FACING_NORTH;
318 
319 	Player::preloadSequences("RXM", 1);
320 	Player::preloadSequences("ROX", 1);
321 }
322 
setSectionHandler()323 void GameNebular::setSectionHandler() {
324 	delete _sectionHandler;
325 
326 	switch (_sectionNumber) {
327 	case 1:
328 		_sectionHandler = new Section1Handler(_vm);
329 		break;
330 	case 2:
331 		_sectionHandler = new Section2Handler(_vm);
332 		break;
333 	case 3:
334 		_sectionHandler = new Section3Handler(_vm);
335 		break;
336 	case 4:
337 		_sectionHandler = new Section4Handler(_vm);
338 		break;
339 	case 5:
340 		_sectionHandler = new Section5Handler(_vm);
341 		break;
342 	case 6:
343 		_sectionHandler = new Section6Handler(_vm);
344 		break;
345 	case 7:
346 		_sectionHandler = new Section7Handler(_vm);
347 		break;
348 	case 8:
349 		_sectionHandler = new Section8Handler(_vm);
350 		break;
351 	default:
352 		break;
353 	}
354 }
355 
checkShowDialog()356 void GameNebular::checkShowDialog() {
357 	// Loop for showing dialogs, if any need to be shown
358 	if (_vm->_dialogs->_pendingDialog && (_player._stepEnabled || _winStatus)
359 			&& !_globals[kCopyProtectFailed]) {
360 		_player.releasePlayerSprites();
361 
362 		// Make a thumbnail in case it's needed for making a savegame
363 		_vm->_game->createThumbnail();
364 
365 		// Show the dialog
366 		_vm->_dialogs->showDialog();
367 		_vm->_dialogs->_pendingDialog = DIALOG_NONE;
368 	}
369 }
370 
showRecipe()371 void GameNebular::showRecipe() {
372 	Dialogs &dialogs = *_vm->_dialogs;
373 	int count;
374 
375 	for (count = 0; count < 4; count++) {
376 		switch(_globals[kIngredientQuantity + count]) {
377 		case 0:
378 			dialogs._indexList[count] = NOUN_DROP;
379 			break;
380 		case 1:
381 			dialogs._indexList[count] = NOUN_DOLLOP;
382 			break;
383 		case 2:
384 			dialogs._indexList[count] = NOUN_DASH;
385 			break;
386 		case 3:
387 			dialogs._indexList[count] = NOUN_SPLASH;
388 			break;
389 		default:
390 			break;
391 		}
392 	}
393 
394 	for (count = 0; count < 4; count++) {
395 		switch(_globals[kIngredientList + count]) {
396 		case 0:
397 			dialogs._indexList[count + 4] = NOUN_ALCOHOL;
398 			break;
399 		case 1:
400 			dialogs._indexList[count + 4] = NOUN_LECITHIN;
401 			break;
402 		case 2:
403 			dialogs._indexList[count + 4] = NOUN_PETROX;
404 			break;
405 		case 3:
406 			dialogs._indexList[count + 4] = NOUN_FORMALDEHYDE;
407 			break;
408 		default:
409 			break;
410 		}
411 	}
412 
413 	_vm->_dialogs->show(401);
414 }
415 
doObjectAction()416 void GameNebular::doObjectAction() {
417 	Scene &scene = _scene;
418 	MADSAction &action = _scene._action;
419 	Dialogs &dialogs = *_vm->_dialogs;
420 	int id;
421 
422 	if (action.isAction(VERB_SMELL) && scene._currentSceneId > 103 && scene._currentSceneId < 111) {
423 		dialogs.show(440);
424 	} else if (action.isAction(VERB_EAT) && scene._currentSceneId > 103 && scene._currentSceneId < 111) {
425 		dialogs.show(441);
426 	} else if (action.isAction(VERB_SMELL, NOUN_BURGER)) {
427 		dialogs.show(442);
428 	} else if (action.isAction(VERB_EAT, NOUN_BURGER)) {
429 		dialogs.show(443);
430 	} else if (action.isAction(VERB_SMELL, NOUN_STUFFED_FISH)) {
431 		dialogs.show(444);
432 	} else if (action.isAction(VERB_EAT, NOUN_STUFFED_FISH)) {
433 		dialogs.show(445);
434 	} else if (action.isAction(VERB_WEAR, NOUN_REBREATHER)) {
435 		dialogs.show(scene._currentSceneId > 103 && scene._currentSceneId < 111 ? 446 : 447);
436 	} else if (action.isAction(VERB_SET, NOUN_TIMER_MODULE)) {
437 		dialogs.show(448);
438 	} else if (action.isAction(VERB_NIBBLE_ON, NOUN_BIG_LEAVES)) {
439 		dialogs.show(449);
440 	} else if (action.isAction(VERB_LICK, NOUN_POISON_DARTS)) {
441 		dialogs.show(450);
442 	} else if (action.isAction(VERB_EAT, NOUN_TWINKIFRUIT)) {
443 		_objects.setRoom(OBJ_TWINKIFRUIT, NOWHERE);
444 		dialogs.show(451);
445 	} else if (action.isAction(VERB_GORGE_ON, NOUN_TWINKIFRUIT)) {
446 		_objects.setRoom(OBJ_TWINKIFRUIT, NOWHERE);
447 		dialogs.show(452);
448 	} else if (action.isAction(VERB_GNAW_ON)) {
449 		dialogs.show(453);
450 	} else if (action.isAction(VERB_MASSAGE, NOUN_AUDIO_TAPE)) {
451 		dialogs.show(454);
452 	} else if (action.isAction(VERB_MANGLE, NOUN_CREDIT_CHIP)) {
453 		dialogs.show(455);
454 	} else if (action.isAction(VERB_FONDLE, NOUN_CHARGE_CASES)) {
455 		dialogs.show(456);
456 	} else if (action.isAction(VERB_RUB, NOUN_BOMB)) {
457 		dialogs.show(457);
458 	} else if (action.isAction(VERB_SET, NOUN_TIMEBOMB)) {
459 		dialogs.show(458);
460 	} else if (action.isAction(VERB_GUZZLE, NOUN_ALIEN_LIQUOR)) {
461 		dialogs.show(459);
462 	} else if (action.isAction(VERB_SMASH, NOUN_TARGET_MODULE)) {
463 		dialogs.show(460);
464 	} else if (action.isAction(VERB_JUGGLE)) {
465 		dialogs.show(461);
466 	} else if (action.isAction(VERB_APPLY, NOUN_POLYCEMENT)) {
467 		dialogs.show(462);
468 	} else if (action.isAction(VERB_SNIFF, NOUN_POLYCEMENT)) {
469 		dialogs.show(465);
470 	} else if (action.isAction(VERB_TIE, NOUN_FISHING_LINE)) {
471 		dialogs.show(463);
472 	} else if (action.isAction(VERB_ATTACH, NOUN_FISHING_LINE)) {
473 		dialogs.show(463);
474 	} else if (action.isAction(VERB_UNLOCK)) {
475 		dialogs.show(464);
476 	} else if (action.isAction(VERB_REFLECT)) {
477 		dialogs.show(466);
478 	} else if (action.isAction(VERB_GAZE_INTO, NOUN_REARVIEW_MIRROR)) {
479 		dialogs.show(467);
480 	} else if (action.isAction(VERB_EAT, NOUN_CHICKEN_BOMB)) {
481 		dialogs.show(469);
482 	} else if (action.isAction(VERB_BREAK, NOUN_VASE)) {
483 		dialogs.show(471);
484 	} else if (action.isAction(VERB_SHAKE_HANDS, NOUN_GUARDS_ARM2)) {
485 		dialogs.show(472);
486 	} else if (action.isAction(VERB_READ, NOUN_LOG)) {
487 		dialogs.show(473);
488 	} else if (action.isAction(VERB_RUB, NOUN_BOMBS)) {
489 		dialogs.show(474);
490 	} else if (action.isAction(VERB_DRINK, NOUN_FORMALDEHYDE)) {
491 		dialogs.show(475);
492 	} else if (action.isAction(VERB_DRINK, NOUN_PETROX)) {
493 		dialogs.show(476);
494 	} else if (action.isAction(VERB_DRINK, NOUN_LECITHIN)) {
495 		dialogs.show(477);
496 	} else if (action.isAction(VERB_PUT, NOUN_POISON_DARTS, NOUN_PLANT_STALK) && _objects.isInInventory(OBJ_POISON_DARTS)
497 			&& _objects.isInInventory(OBJ_PLANT_STALK)) {
498 		_objects.addToInventory(OBJ_BLOWGUN);
499 		_objects.setRoom(OBJ_PLANT_STALK, NOWHERE);
500 		_globals[kBlowgunStatus] = 0;
501 		dialogs.showItem(OBJ_BLOWGUN, 809);
502 	} else if (action.isAction(VERB_PUT, NOUN_POISON_DARTS, NOUN_BLOWGUN) && _objects.isInInventory(OBJ_POISON_DARTS)
503 			&& _objects.isInInventory(OBJ_BLOWGUN)) {
504 		dialogs.show(433);
505 	} else if (action.isAction(VERB_DEFACE) && action.isAction(VERB_FOLD) && action.isAction(VERB_MUTILATE)) {
506 		dialogs.show(434);
507 	} else if (action.isAction(VERB_SPINDLE)) {
508 		dialogs.show(479);
509 	} else if ((action.isAction(VERB_READ) || action.isAction(VERB_LOOK_AT) || action.isAction(VERB_LOOK)) &&
510 			action.isObject(NOUN_NOTE) && _objects.isInInventory(OBJ_NOTE)) {
511 		_objects.setRoom(OBJ_NOTE, NOWHERE);
512 		_objects.addToInventory(OBJ_COMBINATION);
513 		dialogs.showItem(OBJ_COMBINATION, 851);
514 	} else if ((action.isAction(VERB_LOOK) || action.isAction(VERB_READ)) &&
515 			((id = _objects.getIdFromDesc(action._activeAction._objectNameId)) > 0 ||
516 			(action._activeAction._indirectObjectId > 0 &&
517 			(id = _objects.getIdFromDesc(action._activeAction._indirectObjectId)))) &&
518 			_objects.isInInventory(id)) {
519 		if (id == OBJ_REPAIR_LIST) {
520 			dialogs._indexList[0] = _globals[kTeleporterCode + 7];
521 			dialogs._indexList[1] = _globals[kTeleporterCode + 8];
522 			dialogs._indexList[2] = _globals[kTeleporterCode + 6];
523 			dialogs._indexList[3] = _globals[kTeleporterCode + 9];
524 			dialogs._indexList[4] = _globals[kTeleporterCode + 0];
525 			dialogs._indexList[5] = _globals[kTeleporterCode + 1];
526 			dialogs._indexList[6] = _globals[kTeleporterCode + 4];
527 			dialogs._indexList[7] = _globals[kTeleporterCode + 5];
528 			dialogs._indexList[8] = _globals[kTeleporterCode + 2];
529 
530 			dialogs.showItem(id, 402);
531 		} else {
532 			int messageId = 800 + id;
533 			if ((id == OBJ_CHARGE_CASES) && _objects[OBJ_CHARGE_CASES].getQuality(3) != 0) {
534 				messageId = 860;
535 			}
536 
537 			if (id == OBJ_TAPE_PLAYER && _objects[OBJ_AUDIO_TAPE]._roomNumber == OBJ_TAPE_PLAYER)
538 				messageId = 867;
539 
540 			if (id == 32 && _objects[OBJ_FISHING_LINE]._roomNumber == 3)
541 				messageId = 862;
542 
543 			if (id == OBJ_BOTTLE && _globals[kBottleStatus] != 0)
544 				messageId = 862 + _globals[kBottleStatus];
545 
546 			if (id == OBJ_PHONE_HANDSET && _globals[kHandsetCellStatus])
547 				messageId = 861;
548 
549 			dialogs.showItem(id, messageId);
550 		}
551 	} else if (action.isAction(VERB_PUT, NOUN_BURGER, NOUN_DEAD_FISH)) {
552 		if (_objects.isInInventory(OBJ_BURGER) || _objects.isInInventory(OBJ_DEAD_FISH)) {
553 			_objects.removeFromInventory(OBJ_DEAD_FISH, PLAYER_INVENTORY);
554 			_objects.removeFromInventory(OBJ_BURGER, PLAYER_INVENTORY);
555 			_objects.addToInventory(OBJ_STUFFED_FISH);
556 			dialogs.showItem(OBJ_STUFFED_FISH, 803);
557 		}
558 	} else if (action.isAction(VERB_PUT, NOUN_AUDIO_TAPE, NOUN_TAPE_PLAYER) && _objects.isInInventory(OBJ_AUDIO_TAPE) &&
559 			_objects.isInInventory(OBJ_TAPE_PLAYER)) {
560 		_objects.setRoom(OBJ_AUDIO_TAPE, OBJ_TAPE_PLAYER);
561 	} else if (action.isAction(VERB_ACTIVATE, NOUN_TAPE_PLAYER) && _objects.isInInventory(OBJ_TAPE_PLAYER)) {
562 		if (_objects[OBJ_AUDIO_TAPE]._roomNumber == OBJ_TAPE_PLAYER) {
563 			showRecipe();
564 		} else {
565 			dialogs.show(406);
566 		}
567 	} else if (action.isAction(VERB_EJECT, NOUN_TAPE_PLAYER) && _objects.isInInventory(OBJ_TAPE_PLAYER)) {
568 		if (_objects[OBJ_AUDIO_TAPE]._roomNumber == OBJ_TAPE_PLAYER) {
569 			_objects.addToInventory(OBJ_AUDIO_TAPE);
570 		} else {
571 			dialogs.show(407);
572 		}
573 	} else if (action.isAction(VERB_DISASSEMBLE, NOUN_TAPE_PLAYER)) {
574 		dialogs.show(408);
575 	} else if (action.isAction(VERB_ACTIVATE, NOUN_REMOTE)) {
576 		dialogs.show(_globals[kTopButtonPushed] ? 502 : 501);
577 	} else if ((action.isAction(VERB_ATTACH, NOUN_DETONATORS, NOUN_CHARGE_CASES) || action.isAction(VERB_PUT, NOUN_DETONATORS, NOUN_CHARGE_CASES)) &&
578 			_objects.isInInventory(OBJ_DETONATORS) && _objects.isInInventory(OBJ_CHARGE_CASES)) {
579 		if (_objects[OBJ_CHARGE_CASES].getQuality(3)) {
580 			_objects.setRoom(OBJ_CHARGE_CASES, NOWHERE);
581 			_objects.setRoom(OBJ_DETONATORS, NOWHERE);
582 			_objects.addToInventory(OBJ_BOMBS);
583 			dialogs.showItem(OBJ_BOMBS, 403);
584 		} else {
585 			dialogs.show(405);
586 		}
587 	} else if (action.isAction(VERB_ATTACH, NOUN_DETONATORS)) {
588 		dialogs.show(470);
589 	} else if ((action.isAction(VERB_ATTACH, NOUN_TIMER_MODULE, NOUN_BOMBS) || action.isAction(VERB_PUT, NOUN_TIMER_MODULE, NOUN_BOMBS) || action.isAction(VERB_ATTACH, NOUN_TIMER_MODULE, NOUN_BOMB)
590 			|| action.isAction(VERB_PUT, NOUN_TIMER_MODULE, NOUN_BOMB)) && _objects.isInInventory(OBJ_TIMER_MODULE) && (
591 			_objects.isInInventory(OBJ_BOMBS) || _objects.isInInventory(OBJ_BOMB))) {
592 		if (_objects.isInInventory(OBJ_BOMBS)) {
593 			_objects.setRoom(OBJ_BOMBS, NOWHERE);
594 			_objects.addToInventory(OBJ_BOMB);
595 		} else {
596 			_objects.setRoom(OBJ_BOMB, NOWHERE);
597 		}
598 
599 		_objects.setRoom(OBJ_TIMER_MODULE, NOWHERE);
600 		_objects.addToInventory(OBJ_TIMEBOMB);
601 		dialogs.showItem(OBJ_TIMEBOMB, 404);
602 	} else if (action.isAction(VERB_FONDLE, NOUN_PLANT_STALK)) {
603 		dialogs.show(410);
604 	} else if (action.isAction(VERB_EMPTY, NOUN_BOTTLE)) {
605 		_globals[kBottleStatus] = 0;
606 		dialogs.show(432);
607 	} else if (action.isAction(VERB_DISASSEMBLE, NOUN_FISHING_ROD)) {
608 		if (_objects[OBJ_FISHING_LINE]._roomNumber == 3) {
609 			_objects.addToInventory(OBJ_FISHING_LINE);
610 			dialogs.showItem(OBJ_FISHING_LINE, 409);
611 		} else {
612 			dialogs.show(428);
613 		}
614 	} else if (action.isAction(VERB_DISASSEMBLE, NOUN_PENLIGHT)) {
615 		switch (_globals[kPenlightCellStatus]) {
616 		case 1:
617 		case 2:
618 			_objects.addToInventory(OBJ_DURAFAIL_CELLS);
619 			dialogs.showItem(OBJ_DURAFAIL_CELLS, 412);
620 			break;
621 		case 3:
622 			_objects.addToInventory(OBJ_PHONE_CELLS);
623 			dialogs.showItem(OBJ_DURAFAIL_CELLS, 413);
624 			break;
625 		case 5:
626 			_objects.addToInventory(OBJ_DURAFAIL_CELLS);
627 			dialogs.showItem(OBJ_DURAFAIL_CELLS, 411);
628 			break;
629 		case 6:
630 			_objects.addToInventory(OBJ_DURAFAIL_CELLS);
631 			dialogs.showItem(OBJ_DURAFAIL_CELLS, 429);
632 			break;
633 		default:
634 			dialogs.show(478);
635 			break;
636 		}
637 	} else if (action.isAction(VERB_DISASSEMBLE, NOUN_PHONE_HANDSET)) {
638 		switch (_globals[kHandsetCellStatus]) {
639 		case 1:
640 			_objects.addToInventory(OBJ_DURAFAIL_CELLS);
641 			dialogs.showItem(OBJ_DURAFAIL_CELLS,
642 				_difficulty != DIFFICULTY_HARD || _globals[kDurafailRecharged] ? 415 : 414);
643 			_globals[kDurafailRecharged] = true;
644 			break;
645 		case 2:
646 			_objects.addToInventory(OBJ_DURAFAIL_CELLS);
647 			if (_difficulty == DIFFICULTY_HARD) {
648 				dialogs.showItem(OBJ_DURAFAIL_CELLS, 416);
649 			}
650 			_globals[kHandsetCellStatus] = 0;
651 			break;
652 		case 3:
653 			_objects.addToInventory(OBJ_PHONE_CELLS);
654 			dialogs.showItem(OBJ_PHONE_CELLS, 418);
655 			break;
656 		case 4:
657 			_objects.addToInventory(OBJ_PHONE_CELLS);
658 			dialogs.showItem(OBJ_PHONE_CELLS, 417);
659 			_globals[kHandsetCellStatus] = 0;
660 			break;
661 		default:
662 			dialogs.show(478);
663 			break;
664 		}
665 	} else if (action.isAction(VERB_PUT, NOUN_PHONE_CELLS, NOUN_PENLIGHT)) {
666 		if (_globals[kPenlightCellStatus] == 0) {
667 			_globals[kPenlightCellStatus] = 3;
668 			_objects.setRoom(OBJ_PHONE_CELLS, NOWHERE);
669 			dialogs.show(419);
670 		} else {
671 			dialogs.show(420);
672 		}
673 	} else if (action.isAction(VERB_PUT, NOUN_PHONE_CELLS, NOUN_PHONE_HANDSET)) {
674 		if (_globals[kHandsetCellStatus] == 0) {
675 			_globals[kHandsetCellStatus] = 3;
676 			_objects.setRoom(OBJ_PHONE_CELLS, NOWHERE);
677 			dialogs.show(421);
678 		} else {
679 			dialogs.show(422);
680 		}
681 	} else if (action.isAction(VERB_PUT, NOUN_DURAFAIL_CELLS, NOUN_PENLIGHT)) {
682 		if (_globals[kPenlightCellStatus]) {
683 			dialogs.show(424);
684 		} else {
685 			_objects.setRoom(OBJ_DURAFAIL_CELLS, NOWHERE);
686 			_globals[kPenlightCellStatus] = _difficulty != DIFFICULTY_HARD || _globals[kDurafailRecharged] ? 1 : 2;
687 			dialogs.show(423);
688 		}
689 	} else if (action.isAction(VERB_PUT, NOUN_DURAFAIL_CELLS, NOUN_PHONE_HANDSET)) {
690 		if (_globals[kHandsetCellStatus]) {
691 			dialogs.show(426);
692 		} else {
693 			_objects.setRoom(OBJ_DURAFAIL_CELLS, NOWHERE);
694 			_globals[kHandsetCellStatus] = _difficulty != DIFFICULTY_HARD || _globals[kHandsetCellStatus] ? 1 : 2;
695 			dialogs.show(425);
696 		}
697 	} else if (action.isAction(VERB_PUT, NOUN_BOMB, NOUN_CHICKEN) || action.isAction(VERB_PUT, NOUN_BOMBS, NOUN_CHICKEN)) {
698 		_objects.setRoom(OBJ_CHICKEN, NOWHERE);
699 		if (_objects.isInInventory(OBJ_BOMBS)) {
700 			_objects.setRoom(OBJ_BOMBS, NOWHERE);
701 			_objects.addToInventory(OBJ_BOMB);
702 		} else {
703 			_objects.setRoom(OBJ_BOMB, NOWHERE);
704 		}
705 
706 		_objects.addToInventory(OBJ_CHICKEN_BOMB);
707 		dialogs.showItem(OBJ_CHICKEN_BOMB, 430);
708 	} else {
709 		return;
710 	}
711 
712 	action._inProgress = false;
713 }
714 
unhandledAction()715 void GameNebular::unhandledAction() {
716 	int randVal = _vm->getRandomNumber(1, 1000);
717 	MADSAction &action = _scene._action;
718 
719 	if (action.isAction(VERB_THROW, NOUN_BOMB) || action.isAction(VERB_THROW, NOUN_BOMBS)
720 	|| action.isAction(VERB_THROW, NOUN_TIMEBOMB) || action.isAction(VERB_THROW, NOUN_CHICKEN_BOMB))
721 		_vm->_dialogs->show(42);
722 	else if (action.isAction(VERB_DISASSEMBLE))
723 		_vm->_dialogs->show(435);
724 	else if ((action.isAction(VERB_EAT, NOUN_DEAD_FISH) || action.isAction(VERB_EAT, NOUN_STUFFED_FISH)) && _vm->_game->_objects.isInInventory(_vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId)))
725 		_vm->_dialogs->show(12);
726 	else if ((action.isAction(VERB_SMELL, NOUN_DEAD_FISH) || action.isAction(VERB_SMELL, NOUN_STUFFED_FISH)) && _vm->_game->_objects.isInInventory(_vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId)))
727 		_vm->_dialogs->show(13);
728 	else if (action.isAction(VERB_EAT, NOUN_CHICKEN) && _vm->_game->_objects.isInInventory(OBJ_CHICKEN))
729 		_vm->_dialogs->show(912);
730 	else if ((action.isAction(VERB_SHOOT) || action.isAction(VERB_HOSE_DOWN)) && action.isObject(NOUN_BLOWGUN)) {
731 		if ((_scene._currentSceneId >= 104) && (_scene._currentSceneId <= 111))
732 			_vm->_dialogs->show(38);
733 		else if (action.isObject(NOUN_PIRANHA))
734 			_vm->_dialogs->show(41);
735 		else if (action.isObject(NOUN_CHICKEN) || action.isObject(NOUN_VULTURE) || action.isObject(NOUN_SPIDER)
736 				|| action.isObject(NOUN_YELLOW_BIRD) || action.isObject(NOUN_SWOOPING_CREATURE) || action.isObject(NOUN_CAPTIVE_CREATURE)) {
737 			_vm->_dialogs->show(40);
738 		} else
739 			_vm->_dialogs->show(39);
740 	} else if (action.isAction(VERB_TALKTO)) {
741 		_globals[kTalkInanimateCount] = (_globals[kTalkInanimateCount] + 1) % 16;
742 		if (!_globals[kTalkInanimateCount]) {
743 			_vm->_dialogs->show(2);
744 		} else {
745 			Common::String tmpMsg = "\"Greetings, ";
746 			tmpMsg += _vm->_game->_scene.getVocab(action._activeAction._objectNameId);
747 			tmpMsg += "!\"";
748 			_scene._kernelMessages.reset();
749 			_scene._kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, tmpMsg);
750 		}
751 	} else if (action.isAction(VERB_GIVE, NOUN_DOOR, NOUN_CEILING) || action.isAction(VERB_CLOSE, NOUN_CHAIR))
752 		_vm->_dialogs->show(3);
753 	else if (action.isAction(VERB_THROW)) {
754 		int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
755 		if (objId < 0)
756 			_vm->_dialogs->show(4);
757 		else if (_vm->_game->_objects[objId]._roomNumber != 2)
758 			_vm->_dialogs->show(5);
759 		else
760 			_vm->_dialogs->show(6);
761 	} else if (action.isAction(VERB_LOOK)) {
762 		if (action.isObject(NOUN_BINOCULARS) && (action._activeAction._indirectObjectId > 0))
763 			_vm->_dialogs->show(10);
764 		else if (randVal < 600)
765 			_vm->_dialogs->show(7);
766 		else
767 			_vm->_dialogs->show(21);
768 	} else if (action.isAction(VERB_TAKE)) {
769 		int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
770 		if (_vm->_game->_objects.isInInventory(objId))
771 			_vm->_dialogs->show(16);
772 		else if (randVal <= 333)
773 			_vm->_dialogs->show(8);
774 		else if (randVal <= 666)
775 			_vm->_dialogs->show(22);
776 		else
777 			_vm->_dialogs->show(23);
778 	} else if (action.isAction(VERB_CLOSE)) {
779 		if (randVal <= 333)
780 			_vm->_dialogs->show(9);
781 		else
782 			_vm->_dialogs->show(33);
783 	} else if (action.isAction(VERB_OPEN)) {
784 		if (randVal <= 500)
785 			_vm->_dialogs->show(30);
786 		else if (randVal <= 750)
787 			_vm->_dialogs->show(31);
788 		else
789 			_vm->_dialogs->show(32);
790 	} else if (action.isAction(VERB_PULL))
791 		_vm->_dialogs->show(18);
792 	else if (action.isAction(VERB_PUSH)) {
793 		if (randVal < 750)
794 			_vm->_dialogs->show(19);
795 		else
796 			_vm->_dialogs->show(20);
797 	} else if (action.isAction(VERB_PUT)) {
798 		int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
799 		if (_vm->_game->_objects.isInInventory(objId))
800 			_vm->_dialogs->show(25);
801 		else
802 			_vm->_dialogs->show(24);
803 	} else if (action.isAction(VERB_GIVE)) {
804 		int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
805 		if (!_vm->_game->_objects.isInInventory(objId))
806 			_vm->_dialogs->show(26);
807 		else if (randVal <= 500)
808 			_vm->_dialogs->show(28);
809 		else
810 			_vm->_dialogs->show(29);
811 	} else if (!action.isAction(VERB_WALKTO) && !action.isAction(VERB_WALK_ACROSS) && !action.isAction(VERB_WALK_TOWARDS) && !action.isAction(VERB_WALK_DOWN)
812 			&& !action.isAction(VERB_SWIM_TO) && !action.isAction(VERB_SWIM_ACROSS) && !action.isAction(VERB_SWIM_INTO) && !action.isAction(VERB_SWIM_THROUGH)
813 			&& !action.isAction(VERB_SWIM_UNDER)) {
814 		if (randVal <= 100)
815 			_vm->_dialogs->show(36);
816 		else if (randVal <= 200)
817 			_vm->_dialogs->show(1);
818 		else if (randVal <= 475)
819 			_vm->_dialogs->show(34);
820 		else if (randVal <= 750)
821 			_vm->_dialogs->show(35);
822 		else
823 			_vm->_dialogs->show(37);
824 	}
825 }
826 
step()827 void GameNebular::step() {
828 	if (_player._visible && _player._stepEnabled && !_player._moving &&
829 		(_player._facing == _player._turnToFacing)) {
830 		if (_scene._frameStartTime >= (uint32)_globals[kWalkerTiming]) {
831 			if (_player._stopWalkers.empty()) {
832 				int randomVal = _vm->getRandomNumber(29999);
833 				if (_globals[kSexOfRex] == REX_MALE) {
834 					switch (_player._facing) {
835 					case FACING_SOUTHWEST:
836 					case FACING_SOUTHEAST:
837 					case FACING_NORTHWEST:
838 					case FACING_NORTHEAST:
839 						if (randomVal < 200) {
840 							_player.addWalker(-1, 0);
841 							_player.addWalker(1, 0);
842 						}
843 						break;
844 
845 					case FACING_WEST:
846 					case FACING_EAST:
847 						if (randomVal < 500) {
848 							for (int count = 0; count < 10; ++count) {
849 								_player.addWalker(1, 0);
850 							}
851 						}
852 						break;
853 
854 					case FACING_SOUTH:
855 						if (randomVal < 500) {
856 							for (int count = 0; count < 10; ++count) {
857 								_player.addWalker((randomVal < 250) ? 1 : 2, 0);
858 							}
859 						} else if (randomVal < 750) {
860 							for (int count = 0; count < 5; ++count) {
861 								_player.addWalker(1, 0);
862 							}
863 
864 							_player.addWalker(0, 0);
865 							_player.addWalker(0, 0);
866 
867 							for (int count = 0; count < 5; ++count) {
868 								_player.addWalker(2, 0);
869 							}
870 						}
871 						break;
872 
873 					default:
874 						break;
875 					}
876 				}
877 			}
878 
879 			_globals[kWalkerTiming] += 6;
880 		}
881 	}
882 
883 	// Below is countdown to set the timebomb off in room 604
884 	if (_globals[kTimebombStatus] == TIMEBOMB_ACTIVATED) {
885 		int diff = _scene._frameStartTime - _globals[kTimebombClock];
886 		if ((diff >= 0) && (diff <= 60))
887 			_globals[kTimebombTimer] += diff;
888 		else
889 			++_globals[kTimebombTimer];
890 
891 		_globals[kTimebombClock] = (int)_scene._frameStartTime;
892 	}
893 }
894 
synchronize(Common::Serializer & s,bool phase1)895 void GameNebular::synchronize(Common::Serializer &s, bool phase1) {
896 	Game::synchronize(s, phase1);
897 
898 	if (phase1) {
899 		_globals.synchronize(s);
900 		s.syncAsByte(_storyMode);
901 		s.syncAsByte(_difficulty);
902 	}
903 }
904 
905 } // End of namespace Nebular
906 
907 } // End of namespace MADS
908