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