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