[Scummvm-git-logs] scummvm master -> a4811f67b9eb670dc0492f5c82b7805422baaa8b
sev-
sev at scummvm.org
Wed Mar 17 16:34:49 UTC 2021
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
adaf5bb3b9 PEGASUS: Import the DVD version patch from GOG.com
a4811f67b9 NEWS: Mention recent improvements
Commit: adaf5bb3b93e99964abb6a13b20ab7bb901830ca
https://github.com/scummvm/scummvm/commit/adaf5bb3b93e99964abb6a13b20ab7bb901830ca
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2021-03-17T17:32:53+01:00
Commit Message:
PEGASUS: Import the DVD version patch from GOG.com
Co-Authored-By: Keith Kaisershot <keithkaisershot at gmail.com>
Co-Authored-By: Matthew Hoops <clone2727 at gmail.com>
Co-Authored-By: Bastien Bouclet <bastien.bouclet at gmail.com>
Changed paths:
A engines/pegasus/chase.cpp
A engines/pegasus/chase.h
A engines/pegasus/items/biochips/arthurchip.cpp
A engines/pegasus/items/biochips/arthurchip.h
A engines/pegasus/neighborhood/mars/canyonchase.cpp
A engines/pegasus/neighborhood/mars/canyonchase.h
A engines/pegasus/neighborhood/mars/tunnelpod.cpp
A engines/pegasus/neighborhood/mars/tunnelpod.h
A engines/pegasus/neighborhood/norad/alpha/subchase.cpp
A engines/pegasus/neighborhood/norad/alpha/subchase.h
AUTHORS
devtools/credits.pl
engines/pegasus/ai/ai_action.cpp
engines/pegasus/ai/ai_area.cpp
engines/pegasus/constants.h
engines/pegasus/cursor.cpp
engines/pegasus/detection.cpp
engines/pegasus/input.cpp
engines/pegasus/input.h
engines/pegasus/interface.cpp
engines/pegasus/items/biochips/opticalchip.cpp
engines/pegasus/items/inventorypicture.cpp
engines/pegasus/items/inventorypicture.h
engines/pegasus/items/item.h
engines/pegasus/menu.cpp
engines/pegasus/menu.h
engines/pegasus/metaengine.cpp
engines/pegasus/module.mk
engines/pegasus/neighborhood/caldoria/caldoria.cpp
engines/pegasus/neighborhood/caldoria/caldoria.h
engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp
engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
engines/pegasus/neighborhood/mars/constants.h
engines/pegasus/neighborhood/mars/mars.cpp
engines/pegasus/neighborhood/mars/mars.h
engines/pegasus/neighborhood/neighborhood.cpp
engines/pegasus/neighborhood/neighborhood.h
engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
engines/pegasus/neighborhood/norad/alpha/noradalpha.h
engines/pegasus/neighborhood/norad/constants.h
engines/pegasus/neighborhood/norad/delta/globegame.cpp
engines/pegasus/neighborhood/norad/delta/globegame.h
engines/pegasus/neighborhood/norad/delta/noraddelta.cpp
engines/pegasus/neighborhood/norad/delta/noraddelta.h
engines/pegasus/neighborhood/norad/norad.cpp
engines/pegasus/neighborhood/norad/subcontrolroom.cpp
engines/pegasus/neighborhood/norad/subplatform.cpp
engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
engines/pegasus/neighborhood/prehistoric/prehistoric.h
engines/pegasus/neighborhood/tsa/fulltsa.cpp
engines/pegasus/neighborhood/tsa/fulltsa.h
engines/pegasus/neighborhood/tsa/tinytsa.cpp
engines/pegasus/neighborhood/wsc/wsc.cpp
engines/pegasus/neighborhood/wsc/wsc.h
engines/pegasus/pegasus.cpp
engines/pegasus/pegasus.h
engines/pegasus/timers.cpp
gui/credits.h
diff --git a/AUTHORS b/AUTHORS
index 436a88edee..98a66370be 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -847,7 +847,8 @@ Other contributions
audio
Kovacs Endre Janos - Several fixes for Simon1
Jeroen Janssen - Numerous readability and bugfix patches
- Keith Kaisershot - Several Pegasus Prime patches
+ Keith Kaisershot - Several Pegasus Prime patches and DVD
+ additions
Andreas Karlsson - Initial port for SymbianOS
Stefan Kristiansson - Initial work on SDL2 support
Claudio Matsuoka - Daily Linux builds
@@ -1105,4 +1106,3 @@ Special thanks to
Benjamin Haisch, for emimeshviewer, which our EMI code borrows heavily
from.
-
diff --git a/devtools/credits.pl b/devtools/credits.pl
index a3638cd134..2c97fade40 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -1529,7 +1529,7 @@ begin_credits("Credits");
add_person("Janne Huttunen", "", "V3 actor mask support, Dig/FT SMUSH audio");
add_person("Kovács Endre János", "", "Several fixes for Simon1");
add_person("Jeroen Janssen", "japj", "Numerous readability and bugfix patches");
- add_person("Keith Kaisershot", "blitter", "Several Pegasus Prime patches");
+ add_person("Keith Kaisershot", "blitter", "Several Pegasus Prime patches and DVD additions");
add_person("Andreas Karlsson", "Sprawl", "Initial port for SymbianOS");
add_person("Stefan Kristiansson", "skristiansson", "Initial work on SDL2 support");
add_person("Claudio Matsuoka", "", "Daily Linux builds");
diff --git a/engines/pegasus/ai/ai_action.cpp b/engines/pegasus/ai/ai_action.cpp
index 61e2dba3d8..737cc246b3 100644
--- a/engines/pegasus/ai/ai_action.cpp
+++ b/engines/pegasus/ai/ai_action.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_action.h"
#include "pegasus/ai/ai_area.h"
@@ -45,7 +46,7 @@ AIPlayMessageAction::AIPlayMessageAction(const Common::String &movieName, bool k
}
void AIPlayMessageAction::performAIAction(AIRule *) {
- if (g_AIArea) {
+ if (g_AIArea && ((PegasusEngine *)g_engine)->isChattyAI()) {
g_AIArea->checkMiddleArea();
g_AIArea->playAIMovie(kRightAreaSignature, _movieName, _keepLastFrame, _interruptionFilter);
}
diff --git a/engines/pegasus/ai/ai_area.cpp b/engines/pegasus/ai/ai_area.cpp
index 34ca93e4e9..1becc00962 100644
--- a/engines/pegasus/ai/ai_area.cpp
+++ b/engines/pegasus/ai/ai_area.cpp
@@ -29,6 +29,7 @@
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/biochipitem.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/items/biochips/pegasuschip.h"
@@ -50,6 +51,7 @@ AIArea::AIArea(InputHandler *nextHandler) : InputHandler(nextHandler), _leftArea
_middleBiochipTime = 0xffffffff;
_rightBiochipTime = 0xffffffff;
_lockCount = 0;
+ ((PegasusEngine *)g_engine)->requestToggle(false);
startIdling();
}
@@ -458,6 +460,10 @@ void AIArea::activateHotspots() {
case kOpticalBiochip:
((OpticalChip *)currentBiochip)->activateOpticalHotspots();
break;
+ case kArthurBiochip:
+ if (vm->isDVD())
+ ((ArthurChip *)currentBiochip)->activateArthurHotspots();
+ break;
default:
break;
}
@@ -498,6 +504,12 @@ void AIArea::clickInHotspot(const Input &input, const Hotspot *hotspot) {
handled = true;
}
break;
+ case kArthurBiochip:
+ if (vm->isDVD() && (hotspot->getHotspotFlags() & kArthurBiochipSpotFlag) != 0) {
+ ((ArthurChip *)currentBiochip)->clickInArthurHotspot(hotspot->getObjectID());
+ handled = true;
+ }
+ break;
default:
break;
}
diff --git a/engines/pegasus/chase.cpp b/engines/pegasus/chase.cpp
new file mode 100644
index 0000000000..43f88d3656
--- /dev/null
+++ b/engines/pegasus/chase.cpp
@@ -0,0 +1,123 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/chase.h"
+
+namespace Pegasus {
+
+// Notification constants.
+
+static const NotificationFlags kChaseNotificationFlags = kChaseEnteredBranchZone |
+ kChaseExitedBranchZone |
+ kChaseFinished;
+
+ChaseInteraction::ChaseInteraction(const InteractionID interactionID, Neighborhood *handler,
+ const NotificationID notificationID, NotificationManager *manager) : GameInteraction(interactionID, handler),
+ _chaseNotification(notificationID, manager), _steerPict(kNoDisplayElement), _directionNeeded(false),
+ _turnDirection(kNoTurn) {
+
+ // HACK HACK HACK HACK HACK
+ // TRIPLE SUPER ULTRA HACK
+ // This avoids a nasty optimization bug I have been unable to track down
+ // after days and days of searching. Let's just ship the game already.
+ setNextHandler(0);
+
+ _neighborhoodNotification = handler->getNeighborhoodNotification();
+}
+
+void ChaseInteraction::openInteraction() {
+ _steerPict.initFromPICTFile("Images/Interface/steer.pict", true);
+
+ _chaseNotification.notifyMe(this, kChaseNotificationFlags, kChaseNotificationFlags);
+
+ _neighborhoodNotification->notifyMe(this, kDelayCompletedFlag | kSpotSoundCompletedFlag,
+ kDelayCompletedFlag | kSpotSoundCompletedFlag);
+}
+
+void ChaseInteraction::closeInteraction() {
+ _steerPict.hide();
+ _steerPict.deallocateSurface();
+
+ _chaseNotification.cancelNotification(this);
+
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void ChaseInteraction::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if (notification == &_chaseNotification)
+ switch (flags) {
+ case kChaseEnteredBranchZone:
+ _directionNeeded = true;
+ showControlsHint();
+ setUpBranch();
+ break;
+ case kChaseExitedBranchZone:
+ switch (_turnDirection) {
+ case kTurnLeft:
+ branchLeft();
+ break;
+ case kTurnRight:
+ branchRight();
+ break;
+ case kNoTurn:
+ dontBranch();
+ break;
+ default:
+ break;
+ }
+ hideControlsHint();
+ _turnDirection = kNoTurn;
+ _directionNeeded = false;
+ break;
+ case kChaseFinished:
+ _owner->requestDeleteCurrentInteraction();
+ break;
+ default:
+ break;
+ }
+}
+
+void ChaseInteraction::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (input.anyDirectionInput()) {
+ if (_directionNeeded) {
+ if (input.leftButtonAnyDown())
+ _turnDirection = kTurnLeft;
+ else if (input.rightButtonAnyDown())
+ _turnDirection = kTurnRight;
+ }
+ } else {
+ this->InputHandler::handleInput(input, cursorSpot);
+ }
+}
+
+void ChaseInteraction::showControlsHint() {
+ _steerPict.show();
+}
+
+void ChaseInteraction::hideControlsHint() {
+ _steerPict.hide();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/chase.h b/engines/pegasus/chase.h
new file mode 100644
index 0000000000..68b925baf9
--- /dev/null
+++ b/engines/pegasus/chase.h
@@ -0,0 +1,83 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_CHASE_H
+#define PEGASUS_CHASE_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+// Notification constants.
+
+static const NotificationFlags kChaseEnteredBranchZone = 1;
+static const NotificationFlags kChaseExitedBranchZone = kChaseEnteredBranchZone << 1;
+static const NotificationFlags kChaseFinished = kChaseExitedBranchZone << 1;
+
+// Time to choose a direction.
+
+static const TimeValue kDecisionTime = 600 * 2;
+
+class ChaseInteraction : public GameInteraction, public NotificationReceiver {
+public:
+ ChaseInteraction(const InteractionID, Neighborhood *, NotificationID, NotificationManager *);
+ virtual ~ChaseInteraction() {}
+
+ virtual void handleInput(const Input &, const Hotspot *);
+
+protected:
+
+ virtual void openInteraction();
+ virtual void initInteraction() {}
+ virtual void closeInteraction();
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ virtual void setUpBranch() {}
+ virtual void branchLeft() {}
+ virtual void branchRight() {}
+ virtual void dontBranch() {}
+
+ virtual void showControlsHint();
+ virtual void hideControlsHint();
+
+ Notification _chaseNotification;
+
+ Notification *_neighborhoodNotification;
+
+ Picture _steerPict;
+
+private:
+
+ bool _directionNeeded;
+ TurnDirection _turnDirection;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/constants.h b/engines/pegasus/constants.h
index f288729849..260779c442 100644
--- a/engines/pegasus/constants.h
+++ b/engines/pegasus/constants.h
@@ -379,12 +379,15 @@ static const NotificationID kNoradPressureNotificationID = kNoradFillingStationN
static const NotificationID kNoradUtilityNotificationID = kNoradPressureNotificationID + 1;
static const NotificationID kNoradElevatorNotificationID = kNoradUtilityNotificationID + 1;
static const NotificationID kNoradSubPlatformNotificationID = kNoradElevatorNotificationID + 1;
-static const NotificationID kSubControlNotificationID = kNoradSubPlatformNotificationID + 1;
+static const NotificationID kNoradSubChaseNotificationID = kNoradSubPlatformNotificationID + 1;
+static const NotificationID kSubControlNotificationID = kNoradSubChaseNotificationID + 1;
static const NotificationID kNoradGreenBallNotificationID = kSubControlNotificationID + 1;
static const NotificationID kNoradGlobeNotificationID = kNoradGreenBallNotificationID + 1;
static const NotificationID kCaldoriaVidPhoneNotificationID = kNoradGlobeNotificationID + 1;
static const NotificationID kCaldoriaMessagesNotificationID = kCaldoriaVidPhoneNotificationID + 1;
static const NotificationID kCaldoriaBombTimerNotificationID = kCaldoriaMessagesNotificationID + 1;
+static const NotificationID kMarsTunnelPodNotificationID = kCaldoriaBombTimerNotificationID + 1;
+static const NotificationID kMarsCanyonChaseNotificationID = kMarsTunnelPodNotificationID + 1;
// Sent to the shell by fShellNotification.
static const NotificationFlags kGameStartingFlag = 1;
@@ -463,7 +466,12 @@ static const HotSpotID kAISolveSpotID = kAIHint3SpotID + 1;
static const HotSpotID kAIBriefingSpotID = kAISolveSpotID + 1;
static const HotSpotID kAIScanSpotID = kAIBriefingSpotID + 1;
-static const HotSpotID kPegasusRecallSpotID = kAIScanSpotID + 1;
+static const HotSpotID kArthurWisdomSpotID = kAIScanSpotID + 1;
+static const HotSpotID kChattyArthurSpotID = kArthurWisdomSpotID + 1;
+static const HotSpotID kChattyAISpotID = kChattyArthurSpotID + 1;
+static const HotSpotID kArthurHeadSpotID = kChattyAISpotID + 1;
+
+static const HotSpotID kPegasusRecallSpotID = kArthurHeadSpotID + 1;
static const HotSpotID kAriesSpotID = kPegasusRecallSpotID + 1;
static const HotSpotID kMercurySpotID = kAriesSpotID + 1;
@@ -501,7 +509,8 @@ static const HotSpotFlags kInfoReturnSpotFlag = kDropBiochipSpotFlag << 1;
// Biochip and inventory hot spot flags...
static const HotSpotFlags kAIBiochipSpotFlag = kInfoReturnSpotFlag << 1;
-static const HotSpotFlags kPegasusBiochipSpotFlag = kAIBiochipSpotFlag << 1;
+static const HotSpotFlags kArthurBiochipSpotFlag = kAIBiochipSpotFlag << 1;
+static const HotSpotFlags kPegasusBiochipSpotFlag = kArthurBiochipSpotFlag << 1;
static const HotSpotFlags kOpticalBiochipSpotFlag = kPegasusBiochipSpotFlag << 1;
static const HotSpotFlags kAirMaskSpotFlag = kOpticalBiochipSpotFlag << 1;
@@ -510,6 +519,7 @@ static const HotSpotFlags kJMPClickingSpotFlags = kClickSpotFlag |
kOpenDoorSpotFlag |
kInfoReturnSpotFlag |
kAIBiochipSpotFlag |
+ kArthurBiochipSpotFlag |
kPegasusBiochipSpotFlag |
kOpticalBiochipSpotFlag |
kAirMaskSpotFlag;
@@ -655,6 +665,7 @@ enum {
// Mars
kDeathWrongShuttleLock,
kDeathArrestedInMars,
+ kDeathCollidedWithPod,
kDeathRunOverByPod,
kDeathDidntGetOutOfWay,
kDeathReactorBurn,
diff --git a/engines/pegasus/cursor.cpp b/engines/pegasus/cursor.cpp
index 636b52051e..0dadac207b 100644
--- a/engines/pegasus/cursor.cpp
+++ b/engines/pegasus/cursor.cpp
@@ -155,6 +155,7 @@ void Cursor::loadCursorImage(CursorInfo &cursorInfo) {
cursorInfo.surface = new Graphics::Surface();
+ // The CD version uses (only) lower color cicn images for its cursors
Common::SeekableReadStream *cicnStream = vm->_resFork->getResource(MKTAG('c', 'i', 'c', 'n'), cursorInfo.tag);
if (!cicnStream)
diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp
index aeb7f425ad..5dcaf66706 100644
--- a/engines/pegasus/detection.cpp
+++ b/engines/pegasus/detection.cpp
@@ -49,6 +49,41 @@ static const PegasusGameDescription gameDescriptions[] = {
},
},
+ {
+ {
+ "pegasus",
+ "DVD",
+ AD_ENTRY1s("JMP PP Resources", "d13a602d2498010d720a6534f097f88b", 2075337),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_MACRESFORK|GF_DVD,
+ GUIO0()
+ },
+ },
+
+ {
+ { "pegasus",
+ "DVD",
+ AD_ENTRY1s("JMP PP Resources", "d13a602d2498010d720a6534f097f88b", 2075337),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_MACRESFORK|GF_DVD,
+ GUIO0()
+ },
+ },
+
+ {
+ {
+ "pegasus",
+ "DVD",
+ AD_ENTRY1s("JMP PP Resources", "d13a602d2498010d720a6534f097f88b", 2075337),
+ Common::EN_ANY,
+ Common::kPlatformLinux,
+ ADGF_MACRESFORK|GF_DVD,
+ GUIO0()
+ },
+ },
+
{
{
"pegasus",
@@ -73,7 +108,7 @@ static const PegasusGameDescription gameDescriptions[] = {
},
},
- {
+ {
{
"pegasus",
"DVD Demo",
diff --git a/engines/pegasus/input.cpp b/engines/pegasus/input.cpp
index c9689adf07..471f1c5918 100644
--- a/engines/pegasus/input.cpp
+++ b/engines/pegasus/input.cpp
@@ -46,6 +46,7 @@ InputDeviceManager::InputDeviceManager() {
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 2, false);
_lastRawBits = kAllUpBits;
+ _AKeyWasDown = false;
}
InputDeviceManager::~InputDeviceManager() {
@@ -53,17 +54,29 @@ InputDeviceManager::~InputDeviceManager() {
}
void InputDeviceManager::getInput(Input &input, const InputBits filter) {
- // Poll for events, but ignore them!
- // We'll pick them up in notifyEvent()
+ // Poll for events, but ignore most of them!
+ // We'll pick the rest up in notifyEvent()
// We do that so that any pollEvent() call can update the variables
// (ie. if one uses enter to access the restore menu, we never receive
// the key up event, which leads to bad things)
// This is to closely emulate what the GetKeys() function did on Mac OS
- pumpEvents();
-
- // Now create the bitfield
InputBits currentBits = 0;
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_WHEELUP:
+ currentBits |= (kRawButtonDown << kUpButtonShift);
+ break;
+ case Common::EVENT_WHEELDOWN:
+ currentBits |= (kRawButtonDown << kDownButtonShift);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Now fill in the rest of the bitfield
if (_keysDown[kPegasusActionUp])
currentBits |= (kRawButtonDown << kUpButtonShift);
@@ -94,6 +107,21 @@ void InputDeviceManager::getInput(Input &input, const InputBits filter) {
if (_keysDown[kPegasusActionShowBiochip])
currentBits |= (kRawButtonDown << kRightFireButtonShift);
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ if (_keysDown[kPegasusActionToggleChattyAI] && !_AKeyWasDown) {
+ ((PegasusEngine *)g_engine)->requestToggle();
+ _AKeyWasDown = true;
+ } else if (!_keysDown[kPegasusActionToggleChattyAI])
+ _AKeyWasDown = false;
+ }
+
+ // Update mouse button state
+ // Note that we don't use EVENT_LBUTTONUP/EVENT_LBUTTONDOWN because
+ // they do not show if the button is being held down. We're treating
+ // both mouse buttons as the same for ease of use.
+ if (g_system->getEventManager()->getButtonState() != 0)
+ currentBits |= (kRawButtonDown << kTwoButtonShift);
+
// Update the mouse position too
input.setInputLocation(g_system->getEventManager()->getMousePos());
diff --git a/engines/pegasus/input.h b/engines/pegasus/input.h
index 68f9404259..151cdbe31d 100644
--- a/engines/pegasus/input.h
+++ b/engines/pegasus/input.h
@@ -53,6 +53,7 @@ enum PegasusAction {
kPegasusActionSaveGameState,
kPegasusActionLoadGameState,
kPegasusActionEnableEasterEgg,
+ kPegasusActionToggleChattyAI,
kPegasusActionCount
};
@@ -76,6 +77,7 @@ protected:
// Keep track of which keys are down (= true) or not
bool _keysDown[kPegasusActionCount];
InputBits _lastRawBits;
+ bool _AKeyWasDown;
};
enum {
@@ -297,7 +299,7 @@ enum {
};
static const InputBits kHintInterruption = kFilterAllInputNoAuto;
-static const InputBits kWarningInterruption = kFilterNoInput;
+static const InputBits kWarningInterruption = kFilterAllInputNoAuto;
static const InputBits kOpticalInterruption = kFilterAllInputNoAuto;
/*
@@ -496,7 +498,7 @@ public:
static bool isRaiseInventoryInput(const Input &input) { return input.leftFireButtonDown(); }
static bool isRaiseBiochipsInput(const Input &input) { return input.rightFireButtonDown(); }
- static InputBits getItemPanelsInputFilter() { return kFilterLeftFireButton | kFilterRightFireButton; }
+ static InputBits getItemPanelsInputFilter() { return kFilterFourButton | kFilterLeftFireButton | kFilterRightFireButton; }
static bool isToggleAIMiddleInput(const Input &input) { return input.threeButtonDown(); }
diff --git a/engines/pegasus/interface.cpp b/engines/pegasus/interface.cpp
index a0b3c1ca92..b4d23c0228 100644
--- a/engines/pegasus/interface.cpp
+++ b/engines/pegasus/interface.cpp
@@ -400,6 +400,7 @@ void Interface::raiseInventoryDrawer(const bool doCallBacks) {
if (((PegasusEngine *)g_engine)->isDVD()) {
_inventoryCloseSound.stopSound();
+ _inventoryOpenSound.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
_inventoryOpenSound.playSound();
}
}
@@ -414,6 +415,15 @@ void Interface::playEndMessage() {
void Interface::raiseInventoryDrawerForMessage() {
_inventoryPanel.disableLooping();
+
+ // The DVD version has a different image for the inventory
+ // for the end message.
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _inventoryPanel.setCommPicture();
+ _inventoryPanel.throwAwayInventoryImage();
+ _inventoryPanel.initInventoryImage(&_inventoryPush);
+ }
+
raiseInventoryDrawerSync();
}
@@ -466,6 +476,7 @@ void Interface::lowerInventoryDrawer(const bool doCallBacks) {
if (((PegasusEngine *)g_engine)->isDVD()) {
_inventoryOpenSound.stopSound();
+ _inventoryCloseSound.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
_inventoryCloseSound.playSound();
}
}
@@ -512,6 +523,7 @@ void Interface::raiseBiochipDrawer(const bool doCallBacks) {
if (((PegasusEngine *)g_engine)->isDVD()) {
_biochipCloseSound.stopSound();
+ _biochipOpenSound.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
_biochipOpenSound.playSound();
}
}
@@ -551,6 +563,7 @@ void Interface::lowerBiochipDrawer(const bool doCallBacks) {
if (((PegasusEngine *)g_engine)->isDVD()) {
_biochipOpenSound.stopSound();
+ _biochipCloseSound.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
_biochipCloseSound.playSound();
}
}
diff --git a/engines/pegasus/items/biochips/arthurchip.cpp b/engines/pegasus/items/biochips/arthurchip.cpp
new file mode 100644
index 0000000000..1ce093673e
--- /dev/null
+++ b/engines/pegasus/items/biochips/arthurchip.cpp
@@ -0,0 +1,275 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
+
+namespace Common {
+DECLARE_SINGLETON(Pegasus::ArthurManager);
+}
+
+namespace Pegasus {
+
+static const char *kArthurWisdomMovies[] = {
+ "Images/AI/Globals/XGLOBA01",
+ "Images/AI/Globals/XGLOBA03",
+ "Images/AI/Globals/XGLOBA06",
+ "Images/AI/Globals/XGLOBA07",
+ "Images/AI/Globals/XGLOBA09",
+ "Images/AI/Globals/XGLOBA17",
+ "Images/AI/Globals/XGLOBA18",
+ "Images/AI/Globals/XGLOBA25",
+ "Images/AI/Globals/XGLOBA26",
+ "Images/AI/Globals/XGLOBA27",
+ "Images/AI/Globals/XGLOBA28",
+ "Images/AI/Globals/XGLOBA30",
+ "Images/AI/Globals/XGLOBA34",
+ "Images/AI/Globals/XGLOBA35",
+ "Images/AI/Globals/XGLOBA43",
+ "Images/AI/Globals/XGLOBA50",
+ "Images/AI/Globals/XGLOBA56",
+ "Images/AI/Globals/XGLOBA59",
+ "Images/AI/Globals/XGLOBA63",
+ "Images/AI/Globals/XGLOBB10",
+ "Images/AI/Globals/XGLOBB11",
+ "Images/AI/Globals/XGLOBB12",
+ "Images/AI/Globals/XGLOBB13",
+ "Images/AI/Globals/XGLOBB14",
+ "Images/AI/Globals/XGLOBB15",
+ "Images/AI/Globals/XGLOBB16",
+ "Images/AI/Globals/XGLOBB17",
+ "Images/AI/Globals/XGLOBB18",
+ "Images/AI/Globals/XGLOBB19",
+ "Images/AI/Globals/XGLOBB20",
+ "Images/AI/Globals/XGLOBB21",
+ "Images/AI/Globals/XGLOBB22",
+ "Images/AI/Globals/XGLOBB23",
+ "Images/AI/Globals/XGLOBB24",
+ "Images/AI/Globals/XGLOBB25",
+ "Images/AI/Globals/XGLOBB26",
+ "Images/AI/Globals/XGLOBB27",
+ "Images/AI/Globals/XGLOBB28",
+ "Images/AI/Globals/XGLOBB29",
+ "Images/AI/Globals/XGLOBB30",
+ "Images/AI/Globals/XGLOBB31",
+ "Images/AI/Globals/XGLOBB32",
+ "Images/AI/Globals/XGLOBB33",
+ "Images/AI/Globals/XGLOBB34",
+ "Images/AI/Globals/XGLOBB35",
+ "Images/AI/Globals/XGLOBB36",
+ "Images/AI/Globals/XGLOBB37",
+ "Images/AI/Globals/XGLOBB38",
+ "Images/AI/Globals/XGLOBB39",
+ "Images/AI/Globals/XGLOBB43",
+ "Images/AI/Globals/XGLOBB44",
+ "Images/AI/Globals/XGLOBA62"
+};
+
+ArthurChip *g_arthurChip = 0;
+
+ArthurChip::ArthurChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction), _arthurWisdomHotspot(kArthurWisdomSpotID),
+ _chattyArthurHotspot(kChattyArthurSpotID), _chattyAIHotspot(kChattyAISpotID),
+ _arthurHeadHotspot(kArthurHeadSpotID) {
+ _lastArthurMovie = "";
+
+ _arthurWisdomHotspot.setArea(Common::Rect(kAIMiddleAreaLeft + 20, kAIMiddleAreaTop + 27, kAIMiddleAreaLeft + 20 + 161, kAIMiddleAreaTop + 27 + 30));
+ _arthurWisdomHotspot.setHotspotFlags(kArthurBiochipSpotFlag);
+ g_allHotspots.push_back(&_arthurWisdomHotspot);
+
+ _chattyArthurHotspot.setArea(Common::Rect(kAIMiddleAreaLeft + 100, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 100 + 20, kAIMiddleAreaTop + 67 + 20));
+ _chattyArthurHotspot.setHotspotFlags(kArthurBiochipSpotFlag);
+ g_allHotspots.push_back(&_chattyArthurHotspot);
+
+ _chattyAIHotspot.setArea(Common::Rect(kAIMiddleAreaLeft + 130, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 130 + 20, kAIMiddleAreaTop + 67 + 20));
+ _chattyAIHotspot.setHotspotFlags(kArthurBiochipSpotFlag);
+ g_allHotspots.push_back(&_chattyAIHotspot);
+
+ _arthurHeadHotspot.setArea(Common::Rect(kAIRightAreaLeft, kAIRightAreaTop, kAIRightAreaLeft + kAIRightAreaWidth, kAIRightAreaTop + kAIRightAreaHeight));
+ _arthurHeadHotspot.setHotspotFlags(kArthurBiochipSpotFlag);
+ g_allHotspots.push_back(&_arthurHeadHotspot);
+
+ setItemState(kArthur000);
+
+ g_arthurChip = this;
+}
+
+ArthurChip::~ArthurChip() {
+ g_arthurChip = NULL;
+
+ g_allHotspots.removeOneHotspot(kArthurWisdomSpotID);
+ g_allHotspots.removeOneHotspot(kChattyArthurSpotID);
+ g_allHotspots.removeOneHotspot(kChattyAISpotID);
+ g_allHotspots.removeOneHotspot(kArthurHeadSpotID);
+}
+
+void ArthurChip::select() {
+ BiochipItem::select();
+ setUpArthurChip();
+}
+
+void ArthurChip::setUpArthurChip() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ ItemState state = getItemState();
+
+ if (vm->isChattyArthur()) {
+ if (g_AIArea && vm->isChattyAI()) {
+ if (state != kArthur002)
+ setItemState(kArthur000);
+ } else if (state != kArthur102) {
+ setItemState(kArthur100);
+ }
+ } else {
+ if (g_AIArea && vm->isChattyAI()) {
+ if (state != kArthur012)
+ setItemState(kArthur010);
+ } else if (state != kArthur112) {
+ setItemState(kArthur110);
+ }
+ }
+}
+
+void ArthurChip::activateArthurHotspots() {
+ _arthurWisdomHotspot.setActive();
+ _chattyArthurHotspot.setActive();
+ _chattyAIHotspot.setActive();
+ _arthurHeadHotspot.setActive();
+}
+
+void ArthurChip::clickInArthurHotspot(HotSpotID id) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ ItemState state, newState;
+
+ if (id == kArthurHeadSpotID) {
+ if (_lastArthurMovie != "")
+ playArthurMovie(_lastArthurMovie);
+ return;
+ }
+
+ newState = state = getItemState();
+ switch (state) {
+ case kArthur000:
+ switch (id) {
+ case kArthurWisdomSpotID:
+ newState = kArthur002;
+ break;
+ case kChattyArthurSpotID:
+ newState = kArthur010;
+ break;
+ case kChattyAISpotID:
+ newState = kArthur100;
+ break;
+ }
+ break;
+ case kArthur010:
+ switch (id) {
+ case kArthurWisdomSpotID:
+ newState = kArthur012;
+ break;
+ case kChattyArthurSpotID:
+ newState = kArthur000;
+ break;
+ case kChattyAISpotID:
+ newState = kArthur110;
+ break;
+ }
+ break;
+ case kArthur100:
+ switch (id) {
+ case kArthurWisdomSpotID:
+ newState = kArthur102;
+ break;
+ case kChattyArthurSpotID:
+ newState = kArthur110;
+ break;
+ case kChattyAISpotID:
+ newState = kArthur010;
+ break;
+ }
+ break;
+ case kArthur110:
+ switch (id) {
+ case kArthurWisdomSpotID:
+ newState = kArthur112;
+ break;
+ case kChattyArthurSpotID:
+ newState = kArthur100;
+ break;
+ case kChattyAISpotID:
+ newState = kArthur010;
+ break;
+ }
+ break;
+ }
+ setItemState(newState);
+ switch (id) {
+ case kArthurWisdomSpotID:
+ playArthurMovie(kArthurWisdomMovies[((PegasusEngine *)g_engine)->getRandomNumber((
+ sizeof(kArthurWisdomMovies) / sizeof(const char *)) - 1)]);
+ break;
+ case kChattyArthurSpotID:
+ vm->setChattyArthur(!vm->isChattyArthur());
+ break;
+ case kChattyAISpotID:
+ vm->setChattyAI(!vm->isChattyAI());
+ break;
+ }
+
+ setItemState(state);
+}
+
+void ArthurChip::playArthurMovie(const Common::String &movieName) {
+ if (g_AIArea) {
+ g_AIArea->playAIMovie(kRightAreaSignature, movieName, false, kHintInterruption);
+ if (movieName != "Images/AI/Globals/XGLOB00" &&
+ movieName != "Images/AI/Globals/XGLOB01" &&
+ movieName != "Images/AI/Globals/XGLOBAA0" &&
+ movieName != "Images/AI/Globals/XGLOBAA1" &&
+ movieName != "Images/AI/Globals/XGLOBAA2")
+ _lastArthurMovie = movieName;
+ }
+}
+
+bool ArthurChip::playArthurMovieForEvent(const Common::String &movieName, ArthurEvent event) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (vm->isDVD() && vm->playerHasItemID(kArthurBiochip) &&
+ vm->isChattyArthur() && !Arthur._arthurFlags.getFlag(event)) {
+ Arthur._arthurFlags.setFlag(event, true);
+ playArthurMovie(movieName);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void ArthurManager::resetArthurState() {
+ bool savedGameFlag = _arthurFlags.getFlag(kArthurLoadedSavedGame);
+ _arthurFlags.clearAllFlags();
+ _arthurFlags.setFlag(kArthurLoadedSavedGame, savedGameFlag);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/arthurchip.h b/engines/pegasus/items/biochips/arthurchip.h
new file mode 100644
index 0000000000..a68c29f13d
--- /dev/null
+++ b/engines/pegasus/items/biochips/arthurchip.h
@@ -0,0 +1,222 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_ARTHURCHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_ARTHURCHIP_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/util.h"
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+enum ArthurEvent {
+ kArthurLoadedSavedGame,
+ kArthurAttemptedLockedDoor,
+ kArthurAttemptedLockedDoorAgain,
+ kArthurDestroyedInventoryItem,
+ kArthurDisabledAI,
+
+ kArthurCaldoriaFinishedJoyride,
+ kArthurCaldoriaSelectedStickyBuns,
+ kArthurCaldoriaCreatedCornbread,
+ kArthurCaldoriaDrankOJ,
+ kArthurCaldoriaZoomedToLaundry,
+ kArthurCaldoriaReachedToilet,
+ kArthurCaldoriaReadPaper,
+ kArthurCaldoriaChoseAgencyHairStyle,
+ kArthurCaldoriaSawVacantApartment,
+ kArthurCaldoriaLookThroughTelescope,
+ kArthurCaldoriaRoofDoor,
+ kArthurCaldoriaUsedCardBomb,
+ kArthurCaldoriaBlownDoor,
+ kArthurCaldoriaSawVoiceAnalysis,
+ kArthurCaldoriaStunningSinclair,
+ kArthurCaldoriaSeeRoofBomb,
+ kArthurCaldoriaDisarmedNuke,
+
+ kArthurTSAEnteredCave,
+ kArthurTSASawAgent3,
+ kArthurTSASawBust,
+ kArthurTSAReachedJunction,
+ kArthurTSAClickedRobot1,
+ kArthurTSAClickedRobot2,
+ kArthurTSAOpenTBPMonitor,
+ kArthurTSASawJourneymanKey,
+ kArthurTSASawBiochips,
+ kArthurTSAUsedPegasus,
+ kArthurTSAConfinedByBaldwin,
+ kArthurTSARedirectedRobots,
+ kArthurTSAUsedTurbolift,
+ kArthurTSASawFirstOpMemMovie,
+ kArthurTSAInPegasusNoVideo,
+ kArthurTSASawBaldwinSayGo,
+ kArthurTSALeaving,
+
+ kArthurGoToPrehistoric,
+
+ kArthurPrehistoricReachedJunction,
+ kArthurPrehistoricSawBreaker,
+ kArthurPrehistoricBreakerThrown,
+ kArthurPrehistoricAtCliffEdge,
+ kArthurPrehistoricSawEggs,
+ kArthurPrehistoricZoomedToVault,
+ kArthurPrehistoricAttemptedBridge,
+ kArthurPrehistoricExtendedBridge,
+ kArthurPrehistoricCrossedBridge,
+ kArthurPrehistoricUnlockedVault,
+
+ kArthurMarsReadyForKiosk,
+ kArthurMarsLookedAtGuards,
+ kArthurMarsZoomedToKeyCard,
+ kArthurMarsTurnedOnTransport,
+ kArthurMarsCantFillMask,
+ kArthurMarsSawWelcomeVideos,
+ kArthurMarsRobotThrownPlayerWithMask,
+ kArthurMarsLeftPodNoCrowBar,
+ kArthurMarsLookAtEmptyTracks,
+ kArthurMarsEnteredReactor,
+ kArthurMarsSawLockedPanel,
+ kArthurMarsSawLockedPanelNoNitrogen,
+ kArthurMarsUsedLiquidNitrogen,
+ kArthurMarsFoundCardBomb,
+ kArthurMarsSolvedReactorGame,
+ kArthurMarsDeactivatedCardBomb,
+ kArthurMarsExitedReactorWithCardBomb,
+ kArthurMarsInAirlockNoOxygen,
+ kArthurMarsMazeReachedJunction,
+ kArthurMarsOxygen50Warning,
+ kArthurMarsOxygen25Warning,
+ kArthurMarsOxygen5Warning,
+ kArthurMarsFoundBuckets,
+ kArthurMarsApproachedBuckets,
+ kArthurMarsEnteredGearRoom,
+ kArthurMarsLookAtGears,
+ kArthurMarsExitedGearRoom,
+ kArthurMarsFoundNoShuttlePresent,
+ kArthurMarsEnteredShuttle,
+ kArthurMarsFoundDeadRobot,
+ kArthurMarsRobotHeadOpen,
+
+ kArthurWSCRemovedDart,
+ kArthurWSCPoisonedDuringGame,
+ kArthurWSCFailedMolecule,
+ kArthurWSCDesignedAntidote,
+ kArthurWSCSawAresHologram,
+ kArthurWSCLookAtMorphExperiment,
+ kArthurWSCStartMorphExperiment,
+ kArthurWSCSawMorphExperiment,
+ kArthurWSCLeftLabNoKeyOrCanisters,
+ kArthurWSCAtOppositeDoor,
+ kArthurWSCReadyForMap,
+ kArthurWSCAttemptedLockedDoor,
+ kArthurWSCSawSinclairDoor,
+ kArthurWSCSawSinclairDoorNoKey,
+ kArthurWSCAttemptedSinclairDoorNoKey,
+ kArthurWSCZoomedToSnake,
+ kArthurWSCActivatedComputer,
+ kArthurWSCZoomedToSinclairMessages,
+ kArthurWSCPlayedEasterEggMessage,
+ kArthurWSCGotMachineGun,
+ kArthurWSCSeenNerd,
+ kArthurWSCSawBrokenDoor,
+ kArthurWSCSawBrokenDoorNoCrowBar,
+ kArthurWSCUsedCrowBar,
+ kArthurWSCDidPlasmaDodge,
+ kArthurWSCEnteredAuditorium,
+ kArthurWSCSawSinclairLecture,
+ kArthurWSCEnteredPassage,
+ kArthurWSCInPassage,
+ kArthurWSCExitedPassage,
+ kArthurWSCSawCatwalkDoor,
+ kArthurWSCRobotHeadOpen,
+
+ kArthurNoradAtSecurityMonitor,
+ kArthurNoradSawFillingStation,
+ kArthurNoradSawIntakeWarning,
+ kArthurNoradDidntFillCanisters,
+ kArthurNoradSawUnconsciousOperator,
+ kArthurNoradAttemptedLockedDoor,
+ kArthurNoradAttemptedLockedDoorAgain,
+ kArthurNoradReachedPressureDoor,
+ kArthurNoradSawSubMessage,
+ kArthurNoradSawClawMonitor,
+ kArthurNoradPlayedWithClaw,
+ kArthurNoradEnteredSub,
+ kArthurNoradExitedSub,
+ kArthurNoradApproachedDamagedDoor,
+ kArthurNoradAtRetScanNoBiochip,
+ kArthurNoradStartGlobeGame,
+ kArthurNoradSelectedIncorrectSilo,
+ kArthurNoradFinishedGlobeGame,
+ kArthurNoradThreatenedByRobot,
+ kArthurNoradBeatRobotWithClaw,
+ kArthurNoradRobotHeadOpen,
+
+ kNumArthurFlags
+};
+
+class ArthurChip : public BiochipItem {
+public:
+ ArthurChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~ArthurChip();
+
+ void select();
+
+ void setUpArthurChip();
+ void activateArthurHotspots();
+ void clickInArthurHotspot(HotSpotID);
+ void playArthurMovie(const Common::String &);
+ bool playArthurMovieForEvent(const Common::String &, ArthurEvent event);
+
+protected:
+ Hotspot _arthurWisdomHotspot;
+ Hotspot _chattyArthurHotspot;
+ Hotspot _chattyAIHotspot;
+ Hotspot _arthurHeadHotspot;
+ Common::String _lastArthurMovie;
+};
+
+class ArthurManager : public Common::Singleton<ArthurManager> {
+public:
+ ArthurManager() { resetArthurState(); }
+
+ void resetArthurState();
+
+protected:
+ friend class Common::Singleton<SingletonBaseType>;
+ friend class ArthurChip;
+
+private:
+ FlagsArray<byte, kNumArthurFlags> _arthurFlags;
+};
+
+extern ArthurChip *g_arthurChip;
+
+} // End of namespace Pegasus
+
+#define Arthur (::Pegasus::ArthurManager::instance())
+
+#endif
diff --git a/engines/pegasus/items/biochips/opticalchip.cpp b/engines/pegasus/items/biochips/opticalchip.cpp
index 888270dd8f..ad781f19b9 100644
--- a/engines/pegasus/items/biochips/opticalchip.cpp
+++ b/engines/pegasus/items/biochips/opticalchip.cpp
@@ -127,7 +127,16 @@ void OpticalChip::playOpMemMovie(HotSpotID id) {
Common::String movieName;
switch (id) {
case kAriesSpotID:
- movieName = "Images/AI/Globals/OMAI";
+ // WORKAROUND: The original CD release played the ares video even
+ // when you destroyed the shuttle. For the DVD release, we have
+ // some new videos that can be played instead to workaround a plot
+ // loophole.
+ if (!((PegasusEngine *)g_engine)->isDVD() || _opticalFlags.getFlag(kOpticalAriesExposed))
+ movieName = "Images/AI/Globals/OMAI";
+ else if (_itemOwnerID == kPlayerID)
+ movieName = "Images/AI/Globals/OMN1";
+ else
+ movieName = "Images/AI/Globals/OMN0";
break;
case kMercurySpotID:
movieName = "Images/AI/Globals/OMMI";
diff --git a/engines/pegasus/items/inventorypicture.cpp b/engines/pegasus/items/inventorypicture.cpp
index fb7af0b59d..ddb96a4ad1 100644
--- a/engines/pegasus/items/inventorypicture.cpp
+++ b/engines/pegasus/items/inventorypicture.cpp
@@ -318,6 +318,10 @@ void InventoryItemsPicture::deactivateInventoryPicture() {
}
}
+void InventoryItemsPicture::setCommPicture() {
+ _pictName = "Images/Items/Inventory/Comm Panel";
+}
+
void InventoryItemsPicture::playEndMessage(DisplayElement *pushElement) {
PegasusEngine *vm = (PegasusEngine *)g_engine;
@@ -326,6 +330,7 @@ void InventoryItemsPicture::playEndMessage(DisplayElement *pushElement) {
_shouldDrawHighlight = false;
endMessage.shareSurface(this);
endMessage.initFromMovieFile("Images/Caldoria/A56 Congrats");
+ endMessage.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
endMessage.moveMovieBoxTo(kFinalMessageLeft - kInventoryPushLeft, kFinalMessageTop - kInventoryPushTop);
endMessage.setTriggeredElement(pushElement);
endMessage.start();
diff --git a/engines/pegasus/items/inventorypicture.h b/engines/pegasus/items/inventorypicture.h
index c4dc3b298b..815b067ce6 100644
--- a/engines/pegasus/items/inventorypicture.h
+++ b/engines/pegasus/items/inventorypicture.h
@@ -98,6 +98,7 @@ public:
void disableLooping() { _isLooping = false; }
+ void setCommPicture();
void playEndMessage(DisplayElement *);
protected:
diff --git a/engines/pegasus/items/item.h b/engines/pegasus/items/item.h
index c8b8c51815..2fd600fec8 100644
--- a/engines/pegasus/items/item.h
+++ b/engines/pegasus/items/item.h
@@ -118,6 +118,7 @@ static const ItemID kArgonPickup = 24;
// Biochips.
static const ItemID kAIBiochip = 0;
+static const ItemID kArthurBiochip = 1;
static const ItemID kInterfaceBiochip = 1;
static const ItemID kMapBiochip = 2;
static const ItemID kOpticalBiochip = 3;
@@ -248,6 +249,14 @@ static const ItemState kFlashlightOn = 115;
static const ItemState kNitrogenEmpty = 116;
static const ItemState kNitrogenFull = 117;
static const ItemState kFullGlass = 118;
+static const ItemState kArthur000 = 119;
+static const ItemState kArthur002 = 120;
+static const ItemState kArthur010 = 121;
+static const ItemState kArthur012 = 122;
+static const ItemState kArthur100 = 123;
+static const ItemState kArthur102 = 124;
+static const ItemState kArthur110 = 125;
+static const ItemState kArthur112 = 126;
// Extra IDs.
diff --git a/engines/pegasus/menu.cpp b/engines/pegasus/menu.cpp
index 5d48bcfb3c..ff308f80dc 100644
--- a/engines/pegasus/menu.cpp
+++ b/engines/pegasus/menu.cpp
@@ -155,7 +155,10 @@ MainMenu::MainMenu() : GameMenu(kMainMenuID), _menuBackground(0), _overviewButto
else
_menuBackground.initFromPICTFile("Images/Demo/DemoMenu.pict");
} else {
- _menuBackground.initFromPICTFile("Images/Main Menu/MainMenu.mac");
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _menuBackground.initFromPICTFile("Images/Main Menu/MainMenu_hq.mac");
+ else
+ _menuBackground.initFromPICTFile("Images/Main Menu/MainMenu.mac");
}
_menuBackground.setDisplayOrder(0);
_menuBackground.startDisplaying();
@@ -453,9 +456,12 @@ static const CoordType kCreditsMainMenuSelectTop = 408;
static const TimeValue kCoreTeamTime = 0;
static const TimeValue kSupportTeamTime = 1920;
-static const TimeValue kOriginalTeamTime = 3000;
-static const TimeValue kTalentTime = 4440;
-static const TimeValue kOtherTitlesTime = 4680;
+static const TimeValue kOriginalTeamCDTime = 3000;
+static const TimeValue kOriginalTeamDVDTime = 3240;
+static const TimeValue kTalentCDTime = 4440;
+static const TimeValue kTalentDVDTime = 4680;
+static const TimeValue kOtherTitlesCDTime = 4680;
+static const TimeValue kOtherTitlesDVDTime = 4920;
static const TimeValue kFrameIncrement = 120; // Three frames...
@@ -463,12 +469,18 @@ static const TimeValue kFrameIncrement = 120; // Three frames...
CreditsMenu::CreditsMenu() : GameMenu(kCreditsMenuID), _menuBackground(0), _creditsMovie(0),
_mainMenuButton(0), _largeSelect(0), _smallSelect(0) {
- _menuBackground.initFromPICTFile("Images/Credits/CredScrn.pict");
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _menuBackground.initFromPICTFile("Images/Credits/CredScrnScummVM.pict");
+ else
+ _menuBackground.initFromPICTFile("Images/Credits/CredScrn.pict");
_menuBackground.setDisplayOrder(0);
_menuBackground.startDisplaying();
_menuBackground.show();
- _creditsMovie.initFromMovieFile("Images/Credits/Credits.movie");
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _creditsMovie.initFromMovieFile("Images/Credits/Credits_scummVM.movie");
+ else
+ _creditsMovie.initFromMovieFile("Images/Credits/Credits.movie");
_creditsMovie.setDisplayOrder(1);
_creditsMovie.moveElementTo(kCreditsMovieLeft, kCreditsMovieTop);
_creditsMovie.startDisplaying();
@@ -493,6 +505,38 @@ CreditsMenu::CreditsMenu() : GameMenu(kCreditsMenuID), _menuBackground(0), _cred
_menuSelection = -1;
newMenuSelection(kCreditsMenuCoreTeam);
+
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _menuLoop.attachFader(&_menuFader);
+ _menuLoop.initFromAIFFFile("Sounds/Credits.aiff");
+ _menuFader.setMasterVolume(((PegasusEngine *)g_engine)->getAmbienceLevel());
+ }
+}
+
+CreditsMenu::~CreditsMenu() {
+ if (_menuLoop.isPlaying())
+ stopCreditsMenuLoop();
+}
+
+void CreditsMenu::startCreditsMenuLoop() {
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ FaderMoveSpec spec;
+
+ _menuLoop.loopSound();
+ spec.makeTwoKnotFaderSpec(30, 0, 0, 30, 255);
+
+ _menuFader.startFader(spec);
+ }
+}
+
+void CreditsMenu::stopCreditsMenuLoop() {
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ FaderMoveSpec spec;
+
+ spec.makeTwoKnotFaderSpec(30, 0, 255, 30, 0);
+ _menuFader.startFaderSync(spec);
+ _menuLoop.stopSound();
+ }
}
// Assumes the new selection is never more than one away from the old...
@@ -502,29 +546,33 @@ void CreditsMenu::newMenuSelection(const int newSelection) {
case kCreditsMenuCoreTeam:
_smallSelect.moveElementTo(kCoreTeamSelectLeft, kCoreTeamSelectTop);
_creditsMovie.setTime(kCoreTeamTime);
- _creditsMovie.redrawMovieWorld();
break;
case kCreditsMenuSupportTeam:
_smallSelect.moveElementTo(kSupportTeamSelectLeft, kSupportTeamSelectTop);
_creditsMovie.setTime(kSupportTeamTime);
- _creditsMovie.redrawMovieWorld();
break;
case kCreditsMenuOriginalTeam:
_smallSelect.moveElementTo(kOriginalTeamSelectLeft, kOriginalTeamSelectTop);
- _creditsMovie.setTime(kOriginalTeamTime);
- _creditsMovie.redrawMovieWorld();
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _creditsMovie.setTime(kOriginalTeamDVDTime);
+ else
+ _creditsMovie.setTime(kOriginalTeamCDTime);
break;
case kCreditsMenuTalent:
_smallSelect.moveElementTo(kTalentSelectLeft, kTalentSelectTop);
- _creditsMovie.setTime(kTalentTime);
- _creditsMovie.redrawMovieWorld();
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _creditsMovie.setTime(kTalentDVDTime);
+ else
+ _creditsMovie.setTime(kTalentCDTime);
break;
case kCreditsMenuOtherTitles:
_smallSelect.moveElementTo(kOtherTitlesSelectLeft, kOtherTitlesSelectTop);
_smallSelect.show();
_largeSelect.hide();
- _creditsMovie.setTime(kOtherTitlesTime);
- _creditsMovie.redrawMovieWorld();
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _creditsMovie.setTime(kOtherTitlesDVDTime);
+ else
+ _creditsMovie.setTime(kOtherTitlesCDTime);
break;
case kCreditsMenuMainMenu:
_smallSelect.hide();
@@ -533,22 +581,26 @@ void CreditsMenu::newMenuSelection(const int newSelection) {
default:
break;
}
+ _creditsMovie.redrawMovieWorld();
_menuSelection = newSelection;
}
}
void CreditsMenu::newMovieTime(const TimeValue newTime) {
+ // The DVD credits have an extra frame in the support team section
+ bool isDVD = ((PegasusEngine *)g_engine)->isDVD();
+
if (newTime < kSupportTeamTime) {
_smallSelect.moveElementTo(kCoreTeamSelectLeft, kCoreTeamSelectTop);
_menuSelection = kCreditsMenuCoreTeam;
- } else if (newTime < kOriginalTeamTime) {
+ } else if ((isDVD && newTime < kOriginalTeamDVDTime) || (!isDVD && newTime < kOriginalTeamCDTime)) {
_smallSelect.moveElementTo(kSupportTeamSelectLeft, kSupportTeamSelectTop);
_menuSelection = kCreditsMenuSupportTeam;
- } else if (newTime < kTalentTime) {
+ } else if ((isDVD && newTime < kTalentDVDTime) || (!isDVD && newTime < kTalentCDTime)) {
_smallSelect.moveElementTo(kOriginalTeamSelectLeft, kOriginalTeamSelectTop);
_menuSelection = kCreditsMenuOriginalTeam;
- } else if (newTime < kOtherTitlesTime) {
+ } else if ((isDVD && newTime < kOtherTitlesDVDTime) || (!isDVD && newTime < kOtherTitlesCDTime)) {
_smallSelect.moveElementTo(kTalentSelectLeft, kTalentSelectTop);
_smallSelect.show();
_largeSelect.hide();
@@ -675,10 +727,11 @@ DeathMenu::DeathMenu(const DeathReason deathReason) : GameMenu(kDeathMenuID), _d
"dAunmade", "dAbombed", "dAshot", "dAassass", "dAnuked",
"dTunmade", "dTshot", "dPfall", "dPdino", "dPstuck",
"dNchoke", "dNcaught", "dNcaught", "dNsub", "dNrobot1",
- "dNrobot2", "dMfall", "dMcaught", "dMtracks", "dMrobot",
- "dMtoast", "dMexplo1", "dMexplo2", "dMchoke1", "dMchoke2",
- "dMdroid", "dMfall", "dMgears", "dMshutt1", "dMshutt2",
- "dWpoison", "dWcaught", "dWplasma", "dWshot", "dAfinale"
+ "dNrobot2", "dMfall", "dMcaught", "dMcollision", "dMtracks",
+ "dMrobot", "dMtoast", "dMexplo1", "dMexplo2", "dMchoke1",
+ "dMchoke2", "dMdroid", "dMshaft", "dMgears", "dMshutt1",
+ "dMshutt2", "dWpoison", "dWcaught", "dWplasma", "dWshot",
+ "dAfinale"
};
imageName += fileNames[deathReason - 1];
@@ -746,7 +799,10 @@ DeathMenu::DeathMenu(const DeathReason deathReason) : GameMenu(kDeathMenuID), _d
_largeSelect.setDisplayOrder(2);
_largeSelect.startDisplaying();
} else {
- _triumphSound.initFromQuickTime("Sounds/Caldoria/Galactic Triumph");
+ if (vm->isDVD()) // Updated file for the DVD version
+ _triumphSound.initFromAIFFFile("Sounds/Caldoria/Galactic Triumph.44K.aiff");
+ else
+ _triumphSound.initFromQuickTime("Sounds/Caldoria/Galactic Triumph");
_triumphSound.setVolume(((PegasusEngine *)g_engine)->getAmbienceLevel());
_triumphSound.playSound();
}
@@ -884,6 +940,7 @@ void DeathMenu::drawAllScores() {
case kDeathRobotSubControlRoom:
case kDeathWrongShuttleLock:
case kDeathArrestedInMars:
+ case kDeathCollidedWithPod:
case kDeathRunOverByPod:
case kDeathDidntGetOutOfWay:
case kDeathReactorBurn:
diff --git a/engines/pegasus/menu.h b/engines/pegasus/menu.h
index 2a062232ac..232835f12a 100644
--- a/engines/pegasus/menu.h
+++ b/engines/pegasus/menu.h
@@ -97,9 +97,11 @@ protected:
class CreditsMenu : public GameMenu {
public:
CreditsMenu();
- ~CreditsMenu() override {}
+ ~CreditsMenu() override;
void handleInput(const Input &input, const Hotspot *) override;
+ void startCreditsMenuLoop();
+ void stopCreditsMenuLoop();
protected:
void newMenuSelection(const int);
@@ -111,6 +113,9 @@ protected:
Picture _mainMenuButton;
Picture _largeSelect;
Picture _smallSelect;
+
+ Sound _menuLoop;
+ SoundFader _menuFader;
};
class DeathMenu : public GameMenu {
diff --git a/engines/pegasus/metaengine.cpp b/engines/pegasus/metaengine.cpp
index aefc3b74c5..8f0e19243c 100644
--- a/engines/pegasus/metaengine.cpp
+++ b/engines/pegasus/metaengine.cpp
@@ -59,6 +59,10 @@ bool PegasusEngine::isWindows() const {
return _gameDescription->desc.platform == Common::kPlatformWindows;
}
+bool PegasusEngine::isLinux() const {
+ return _gameDescription->desc.platform == Common::kPlatformLinux;
+}
+
} // End of namespace Pegasus
class PegasusMetaEngine : public AdvancedMetaEngine {
diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk
index 1fe1963f32..3e1bf4ab11 100644
--- a/engines/pegasus/module.mk
+++ b/engines/pegasus/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/pegasus
MODULE_OBJS = \
+ chase.o \
compass.o \
console.o \
cursor.o \
@@ -34,6 +35,7 @@ MODULE_OBJS = \
items/itemdragger.o \
items/itemlist.o \
items/biochips/aichip.o \
+ items/biochips/arthurchip.o \
items/biochips/biochipitem.o \
items/biochips/mapchip.o \
items/biochips/mapimage.o \
@@ -59,6 +61,7 @@ MODULE_OBJS = \
neighborhood/caldoria/caldoriabomb.o \
neighborhood/caldoria/caldoriamessages.o \
neighborhood/caldoria/caldoriamirror.o \
+ neighborhood/mars/canyonchase.o \
neighborhood/mars/energybeam.o \
neighborhood/mars/gravitoncannon.o \
neighborhood/mars/hermite.o \
@@ -72,6 +75,7 @@ MODULE_OBJS = \
neighborhood/mars/spacechase3d.o \
neighborhood/mars/spacejunk.o \
neighborhood/mars/tractorbeam.o \
+ neighborhood/mars/tunnelpod.o \
neighborhood/norad/norad.o \
neighborhood/norad/noradelevator.o \
neighborhood/norad/pressuredoor.o \
@@ -83,6 +87,7 @@ MODULE_OBJS = \
neighborhood/norad/alpha/noradalpha.o \
neighborhood/norad/alpha/panorama.o \
neighborhood/norad/alpha/panoramascroll.o \
+ neighborhood/norad/alpha/subchase.o \
neighborhood/norad/delta/globegame.o \
neighborhood/norad/delta/noraddelta.o \
neighborhood/prehistoric/prehistoric.o \
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
index 42eca2a635..60a4a2fe08 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -25,6 +25,7 @@
#include "common/system.h"
#include "video/qt_decoder.h"
+#include "video/theora_decoder.h"
#include "pegasus/cursor.h"
#include "pegasus/energymonitor.h"
@@ -32,6 +33,7 @@
#include "pegasus/interface.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/biochipitem.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/caldoria/caldoria4dsystem.h"
@@ -50,6 +52,19 @@ enum {
kCaldoria55Angle = -45
};
+enum {
+ kCreateCornbread = 1000,
+ kWashingMachineZoomIn = 1001,
+ kWashingMachineLoop = 1002,
+ kWashingMachineZoomOut = 1003
+};
+
+enum {
+ kCaldoriaLaundryZoomInHotSpotID = 10000,
+ kCaldoriaLaundryZoomOutHotSpotID = 10001,
+ kCaldoriaCornbreadHotSpotID = 10002
+};
+
enum {
kSinclairInterruptionTime1 = 2955,
kSinclairInterruptionTime2 = 6835,
@@ -63,6 +78,12 @@ enum {
};
enum {
+ kCaldoriaLaundryIntro1In = 0,
+ kCaldoriaLaundryIntro1Out = 2645,
+
+ kCaldoriaLaundryIntro2In = 2645,
+ kCaldoriaLaundryIntro2Out = 4933,
+
kCaldoriaReplicatorIntroIn = 4933,
kCaldoriaReplicatorIntroOut = 6557,
@@ -99,9 +120,6 @@ enum {
kCaldoriaNoOtherFloorIn = 21469,
kCaldoriaNoOtherFloorOut = 28013,
- kCaldoria4DInstructionsIn = 28013,
- kCaldoria4DInstructionsOut = 29730,
-
kCaldoriaDrinkOJIn = 33910,
kCaldoriaDrinkOJOut = 35846,
@@ -169,7 +187,9 @@ void SinclairCallBack::callBack() {
}
Caldoria::Caldoria(InputHandler* nextHandler, PegasusEngine *owner)
- : Neighborhood(nextHandler, owner, "Caldoria", kCaldoriaID), _sinclairInterrupt(this) {
+ : Neighborhood(nextHandler, owner, "Caldoria", kCaldoriaID), _extraMovie(kNoDisplayElement),
+ _laundryZoomInSpot(kCaldoriaLaundryZoomInHotSpotID), _laundryZoomOutSpot(kCaldoriaLaundryZoomOutHotSpotID),
+ _cornbreadSpot(kCaldoriaCornbreadHotSpotID), _sinclairInterrupt(this), _lookingAtLaundry(false) {
setIsItemTaken(kKeyCard);
setIsItemTaken(kOrangeJuiceGlassEmpty);
GameState.setTakenItemID(kOrangeJuiceGlassFull, GameState.isTakenItemID(kOrangeJuiceGlassEmpty));
@@ -179,14 +199,35 @@ Caldoria::Caldoria(InputHandler* nextHandler, PegasusEngine *owner)
Caldoria::~Caldoria() {
_sinclairInterrupt.releaseCallBack();
+ if (_vm->isDVD()) {
+ _vm->getAllHotspots().remove(&_laundryZoomInSpot);
+ _vm->getAllHotspots().remove(&_laundryZoomOutSpot);
+ _vm->getAllHotspots().remove(&_cornbreadSpot);
+ }
}
void Caldoria::init() {
Neighborhood::init();
+ if (_vm->isDVD()) {
+ _laundryZoomInSpot.setArea(Common::Rect(384, 120, 576, 320));
+ _laundryZoomInSpot.setHotspotFlags(kNeighborhoodSpotFlag | kZoomInSpotFlag);
+ _vm->getAllHotspots().push_back(&_laundryZoomInSpot);
+
+ _laundryZoomOutSpot.setArea(Common::Rect(64, 64, 576, 320));
+ _laundryZoomOutSpot.setHotspotFlags(kNeighborhoodSpotFlag | kZoomOutSpotFlag);
+ _vm->getAllHotspots().push_back(&_laundryZoomOutSpot);
+
+ _cornbreadSpot.setArea(Common::Rect(270, 233, 381, 298));
+ _cornbreadSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_cornbreadSpot);
+ }
+
// We need this notification flag as well.
_neighborhoodNotification.notifyMe(this, kSinclairLoopDoneFlag, kSinclairLoopDoneFlag);
+ _extraMovieCallBack.setNotification(&_neighborhoodNotification);
+
_sinclairInterrupt.initCallBack(&_navMovie, kCallBackAtTime);
forceStridingStop(kCaldoria55, kSouth, kAltCaldoriaSinclairDown);
@@ -197,29 +238,66 @@ void Caldoria::start() {
g_energyMonitor->stopEnergyDraining();
if (!GameState.getCaldoriaSeenPullback()) {
+ Input input;
+ Common::String wakeModeMoviePath;
+ InputDevice.getInput(input, kPullbackInterruptFilter);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input)) {
+ wakeModeMoviePath = "Images/Caldoria/A00WM";
+ } else {
+ wakeModeMoviePath = "Images/Caldoria/A00WN";
+ }
+
_vm->_gfx->doFadeOutSync(kOneSecond * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
- g_system->delayMillis(2 * 1000);
+ Video::VideoDecoder *pullbackMovie = 0;
+ uint16 pullbackX, pullbackY;
- Video::VideoDecoder *pullbackMovie = new Video::QuickTimeDecoder();
+#ifdef USE_THEORADEC
+ if (_vm->isDVD()) {
+ // Updated larger version
+ pullbackMovie = new Video::TheoraDecoder();
- if (!pullbackMovie->loadFile("Images/Caldoria/Pullback.movie"))
- error("Could not load pullback movie");
+ if (!pullbackMovie->loadFile("Images/Caldoria/Pullback.ogg")) {
+ delete pullbackMovie;
+ pullbackMovie = 0;
+ }
+ }
+#endif
+
+ if (!pullbackMovie) {
+ pullbackMovie = new Video::QuickTimeDecoder();
+
+ if (!pullbackMovie->loadFile("Images/Caldoria/Pullback.movie"))
+ error("Could not load Pullback.movie");
+ }
pullbackMovie->setVolume(MIN<uint>(_vm->getSoundFXLevel(), 0xFF));
// Draw the first frame so we can fade to it
- const Graphics::Surface *frame = pullbackMovie->decodeNextFrame();
- assert(frame);
- assert(frame->format == g_system->getScreenFormat());
- g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 64, 112, frame->w, frame->h);
- _vm->_gfx->doFadeInSync(kTwoSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
+ const Graphics::Surface *frame = 0;
+
+ if (_vm->isDVD()) {
+ uint16 newHeight = (uint16)((640.0f / (float)pullbackMovie->getWidth()) * (float)pullbackMovie->getHeight());
+ pullbackX = 0;
+ pullbackY = (480 - newHeight) / 2;
+
+ _vm->_gfx->enableUpdates();
+ } else {
+ pullbackX = 80;
+ pullbackY = 112;
+
+ // Draw the first frame so we can fade to it
+ frame = pullbackMovie->decodeNextFrame();
+ assert(frame);
+ assert(frame->format == g_system->getScreenFormat());
+ g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, pullbackX, pullbackY, frame->w, frame->h);
+ _vm->_gfx->doFadeInSync(kTwoSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
+ }
bool saveAllowed = _vm->swapSaveAllowed(false);
bool openAllowed = _vm->swapLoadAllowed(false);
bool skipped = false;
- Input input;
pullbackMovie->start();
@@ -228,13 +306,13 @@ void Caldoria::start() {
frame = pullbackMovie->decodeNextFrame();
if (frame) {
- g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 64, 112, frame->w, frame->h);
+ g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, pullbackX, pullbackY, frame->w, frame->h);
g_system->updateScreen();
}
}
InputDevice.getInput(input, kPullbackInterruptFilter);
- if (input.anyInput() || _vm->saveRequested() || _vm->loadRequested()) {
+ if ((input.anyInput() || _vm->saveRequested() || _vm->loadRequested()) && !GameState.getEasterEgg()) {
skipped = true;
break;
}
@@ -253,14 +331,58 @@ void Caldoria::start() {
ExtraTable::Entry entry;
if (!skipped) {
- _vm->_gfx->doFadeOutSync(kThreeSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond, false);
- g_system->delayMillis(3 * 1000 / 2);
- getExtraEntry(kCaldoria00WakeUp1, entry);
- _navMovie.setTime(entry.movieStart);
- _navMovie.redrawMovieWorld();
- _navMovie.show();
- _vm->refreshDisplay();
- _vm->_gfx->doFadeInSync(kOneSecond * kFifteenTicksPerSecond, kFifteenTicksPerSecond, false);
+ if (_vm->isDVD()) {
+ Video::VideoDecoder* wakeModeMovie = 0;
+#ifdef USE_THEORADEC
+ wakeModeMovie = new Video::TheoraDecoder();
+ if (!wakeModeMovie->loadFile(wakeModeMoviePath + ".ogg")) {
+ delete wakeModeMovie;
+ wakeModeMovie = 0;
+ }
+#endif
+ if (!wakeModeMovie) {
+ wakeModeMovie = new Video::QuickTimeDecoder();
+ if (!wakeModeMovie->loadFile(wakeModeMoviePath + ".movie"))
+ error("Could not load Jonny Ego movie");
+ }
+
+ wakeModeMovie->setVolume(MIN<uint>(_vm->getSoundFXLevel(), 0xFF));
+
+ wakeModeMovie->start();
+
+ while (!_vm->shouldQuit() && !wakeModeMovie->endOfVideo()) {
+ if (wakeModeMovie->needsUpdate()) {
+ frame = wakeModeMovie->decodeNextFrame();
+
+ if (frame) {
+ g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
+ g_system->updateScreen();
+ }
+ }
+
+ InputDevice.getInput(input, kPullbackInterruptFilter);
+ if ((input.anyInput() || _vm->saveRequested() || _vm->loadRequested()) && !GameState.getEasterEgg()) {
+ skipped = true;
+ break;
+ }
+
+ g_system->delayMillis(10);
+ }
+
+ delete wakeModeMovie;
+
+ if (_vm->shouldQuit())
+ return;
+ } else {
+ _vm->_gfx->doFadeOutSync(kThreeSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond, false);
+ g_system->delayMillis(3 * 1000 / 2);
+ getExtraEntry(kCaldoria00WakeUp1, entry);
+ _navMovie.setTime(entry.movieStart);
+ _navMovie.redrawMovieWorld();
+ _navMovie.show();
+ _vm->refreshDisplay();
+ _vm->_gfx->doFadeInSync(kOneSecond * kFifteenTicksPerSecond, kFifteenTicksPerSecond, false);
+ }
} else {
getExtraEntry(kCaldoria00WakeUp1, entry);
_navMovie.setTime(entry.movieStart);
@@ -274,6 +396,15 @@ void Caldoria::start() {
Neighborhood::start();
}
+void Caldoria::throwAwayInterface() {
+ Neighborhood::throwAwayInterface();
+ if (_vm->isDVD()) {
+ _vm->getAllHotspots().remove(&_laundryZoomInSpot);
+ _vm->getAllHotspots().remove(&_laundryZoomOutSpot);
+ _vm->getAllHotspots().remove(&_cornbreadSpot);
+ }
+}
+
void Caldoria::flushGameState() {
GameState.setCaldoriaFuseTimeLimit(_utilityFuse.getTimeRemaining());
}
@@ -714,18 +845,34 @@ void Caldoria::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec
void Caldoria::loadAmbientLoops() {
RoomID room = GameState.getCurrentRoom();
- if (room == kCaldoria00 && GameState.getCaldoriaWokenUp())
- loadLoopSound1("Sounds/Caldoria/Apartment Music.AIFF", 0x100 / 4);
- else if (room >= kCaldoria01 && room <= kCaldoria14)
- loadLoopSound1("Sounds/Caldoria/Apartment Music.AIFF", 0x100 / 4);
- else if (room == kCaldoria27 || room == kCaldoria28 || room == kCaldoria45)
- loadLoopSound1("Sounds/Caldoria/Elevator Loop.AIFF", 0x100 / 5);
- else if (room == kCaldoria44)
- loadLoopSound1("Sounds/Caldoria/TSA Hum Loop.AIFF");
- else if (room >= kCaldoria15 && room <= kCaldoria48)
- loadLoopSound1("Sounds/Caldoria/Industrial Nuage.aiff", 2 * 0x100 / 3);
- else if (room >= kCaldoria49 && room <= kCaldoria56)
- loadLoopSound1("Sounds/Caldoria/A50NLB00.22K.AIFF", 0x100 / 4);
+ if (_vm->isDVD()) {
+ // Updated sounds in the DVD version
+ if (room == kCaldoria00 && GameState.getCaldoriaWokenUp())
+ loadLoopSound1("Sounds/Caldoria/Apartment Music.32K.aiff", 0x100 / 4);
+ else if (room >= kCaldoria01 && room <= kCaldoria14)
+ loadLoopSound1("Sounds/Caldoria/Apartment Music.32K.aiff", 0x100 / 4);
+ else if (room == kCaldoria27 || room == kCaldoria28 || room == kCaldoria45)
+ loadLoopSound1("Sounds/Caldoria/Elevator Loop.32K.aiff", 0x100 / 5);
+ else if (room == kCaldoria44)
+ loadLoopSound1("Sounds/Caldoria/TSA Hum Loop.44K.aiff");
+ else if (room >= kCaldoria15 && room <= kCaldoria48)
+ loadLoopSound1("Sounds/Caldoria/Industrial Nuage.44K.aiff", 2 * 0x100 / 3);
+ else if (room >= kCaldoria49 && room <= kCaldoria56)
+ loadLoopSound1("Sounds/Caldoria/A50NLB00.32K.AIFF", 0x100 / 4);
+ } else {
+ if (room == kCaldoria00 && GameState.getCaldoriaWokenUp())
+ loadLoopSound1("Sounds/Caldoria/Apartment Music.AIFF", 0x100 / 4);
+ else if (room >= kCaldoria01 && room <= kCaldoria14)
+ loadLoopSound1("Sounds/Caldoria/Apartment Music.AIFF", 0x100 / 4);
+ else if (room == kCaldoria27 || room == kCaldoria28 || room == kCaldoria45)
+ loadLoopSound1("Sounds/Caldoria/Elevator Loop.AIFF", 0x100 / 5);
+ else if (room == kCaldoria44)
+ loadLoopSound1("Sounds/Caldoria/TSA Hum Loop.AIFF");
+ else if (room >= kCaldoria15 && room <= kCaldoria48)
+ loadLoopSound1("Sounds/Caldoria/Industrial Nuage.aiff", 2 * 0x100 / 3);
+ else if (room >= kCaldoria49 && room <= kCaldoria56)
+ loadLoopSound1("Sounds/Caldoria/A50NLB00.22K.AIFF", 0x100 / 4);
+ }
}
void Caldoria::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
@@ -748,8 +895,15 @@ void Caldoria::checkContinuePoint(const RoomID room, const DirectionConstant dir
void Caldoria::spotCompleted() {
Neighborhood::spotCompleted();
- if (GameState.getCurrentRoom() == kCaldoriaBinoculars)
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoriaBinoculars:
startExtraSequence(kBinocularsZoomInOnShip, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaToilet:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA47", kArthurCaldoriaReadPaper);
+ break;
+ }
}
void Caldoria::arriveAt(const RoomID room, const DirectionConstant direction) {
@@ -773,6 +927,7 @@ void Caldoria::arriveAt(const RoomID room, const DirectionConstant direction) {
Neighborhood::arriveAt(room, direction);
Input dummy;
+ Sound flushSound;
switch (room) {
case kCaldoria00:
@@ -789,6 +944,27 @@ void Caldoria::arriveAt(const RoomID room, const DirectionConstant direction) {
case kCaldoria09:
_lastExtra = 0xffffffff;
break;
+ case kCaldoria10:
+ if (_vm->isDVD() && direction == kWest) {
+ _vm->_cursor->hide();
+ flushSound.initFromAIFFFile("Sounds/Caldoria/Apartment Toilet.32K.aiff");
+ flushSound.setVolume(_vm->getSoundFXLevel());
+ flushSound.playSound();
+ while (flushSound.isPlaying() && !_vm->shouldQuit()) {
+ InputDevice.getInput(dummy, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+ if (_vm->shouldQuit())
+ return;
+ _vm->_cursor->hideUntilMoved();
+ } else if (direction == kEast) {
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA42", kArthurCaldoriaReachedToilet);
+ }
+ break;
case kCaldoriaToilet:
GameState.setScoringReadPaper(true);
break;
@@ -844,6 +1020,10 @@ void Caldoria::arriveAt(const RoomID room, const DirectionConstant direction) {
case kCaldoria49:
arriveAtCaldoria49();
break;
+ case kCaldoria48:
+ if (direction == kNorth && !GameState.getCaldoriaDoorBombed() && GameState.isTakenItemID(kCardBomb) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA12", kArthurCaldoriaRoofDoor);
+ break;
case kCaldoria53:
if (direction == kEast && !GameState.getCaldoriaSinclairShot())
zoomToSinclair();
@@ -873,30 +1053,77 @@ void Caldoria::arriveAt(const RoomID room, const DirectionConstant direction) {
void Caldoria::doAIRecalibration() {
GameState.setCaldoriaDidRecalibration(true);
- if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB1", true, kRecalibrationInterruptFilter))
- return;
+ Input input;
+ InputDevice.getInput(input, kPullbackInterruptFilter);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input)) {
+ Video::VideoDecoder *video = 0;
- g_interface->calibrateEnergyBar();
- if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB4", true, kRecalibrationInterruptFilter))
- return;
+ _vm->_cursor->hide();
+
+#ifdef USE_THEORADEC
+ video = new Video::TheoraDecoder();
+ if (!video->loadFile("Images/Caldoria/A00EA.ogg")) {
+ delete video;
+ video = 0;
+ }
+#endif
+
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile("Images/Caldoria/A00EA.movie"))
+ error("Could not load Month-O-Matic video");
+ }
+
+ video->setVolume(MIN<uint>(_vm->getSoundFXLevel(), 0xFF));
+ video->start();
+
+ while (!_vm->shouldQuit() && !video->endOfVideo()) {
+ if (video->needsUpdate()) {
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (frame) {
+ g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, kNavAreaLeft, kNavAreaTop, frame->w, frame->h);
+ g_system->updateScreen();
+ }
+ }
+
+ InputDevice.pumpEvents();
+
+ g_system->delayMillis(10);
+ }
+
+ delete video;
+
+ if (_vm->shouldQuit())
+ return;
+
+ arriveAt(kCaldoria01, kEast);
+ } else if (_vm->isChattyAI()) {
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB1", true, kRecalibrationInterruptFilter))
+ return;
+
+ g_interface->calibrateEnergyBar();
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB4", true, kRecalibrationInterruptFilter))
+ return;
+
+ g_interface->raiseInventoryDrawerSync();
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB6", true, kRecalibrationInterruptFilter)) {
+ g_interface->lowerInventoryDrawerSync();
+ return;
+ }
- g_interface->raiseInventoryDrawerSync();
- if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB6", true, kRecalibrationInterruptFilter)) {
g_interface->lowerInventoryDrawerSync();
- return;
- }
+ g_interface->raiseBiochipDrawerSync();
- g_interface->lowerInventoryDrawerSync();
- g_interface->raiseBiochipDrawerSync();
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB5", true, kRecalibrationInterruptFilter)) {
+ g_interface->lowerBiochipDrawerSync();
+ return;
+ }
- if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB5", true, kRecalibrationInterruptFilter)) {
g_interface->lowerBiochipDrawerSync();
- return;
- }
- g_interface->lowerBiochipDrawerSync();
-
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB8", false, kRecalibrationInterruptFilter);
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB8", false, kRecalibrationInterruptFilter);
+ }
}
void Caldoria::arriveAtCaldoria00() {
@@ -1021,12 +1248,26 @@ void Caldoria::setUpRoofTop() {
}
}
+void Caldoria::leftButton(const Input &input) {
+ if (!(GameState.getCurrentRoomAndView() == MakeRoomView(kCaldoria11, kWest) && _lookingAtLaundry))
+ Neighborhood::leftButton(input);
+}
+
+void Caldoria::rightButton(const Input &input) {
+ if (!(GameState.getCurrentRoomAndView() == MakeRoomView(kCaldoria11, kWest) && _lookingAtLaundry))
+ Neighborhood::rightButton(input);
+}
+
void Caldoria::downButton(const Input &input) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kCaldoria01, kEast):
GameState.setCaldoriaWokenUp(true);
startExtraSequence(kCaldoria00SitDown, kExtraCompletedFlag, kFilterNoInput);
break;
+ case MakeRoomView(kCaldoria11, kWest):
+ if (_lookingAtLaundry)
+ startExtraSequence(kWashingMachineZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
default:
Neighborhood::downButton(input);
break;
@@ -1062,6 +1303,10 @@ void Caldoria::turnTo(const DirectionConstant direction) {
case kCaldoria09:
_lastExtra = 0xffffffff;
break;
+ case kCaldoria10:
+ if (direction == kEast && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA42", kArthurCaldoriaReachedToilet);
+ break;
case kCaldoria11:
if (direction == kEast && !GameState.getCaldoriaSeenMessages())
loopCroppedMovie("Images/Caldoria/A11 Message Machine Loop", kCaldoria11MessageLoopLeft, kCaldoria11MessageLoopTop);
@@ -1087,8 +1332,11 @@ void Caldoria::turnTo(const DirectionConstant direction) {
closeCroppedMovie();
break;
case kCaldoria48:
- if (direction == kNorth && !GameState.getCaldoriaDoorBombed())
+ if (direction == kNorth && !GameState.getCaldoriaDoorBombed()) {
setCurrentActivation(kActivateRoofSlotEmpty);
+ if (GameState.isTakenItemID(kCardBomb) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA12", kArthurCaldoriaRoofDoor);
+ }
break;
case kCaldoria53:
if (GameState.getCurrentDirection() == kEast && !GameState.getCaldoriaSinclairShot())
@@ -1123,7 +1371,10 @@ void Caldoria::zoomTo(const Hotspot *zoomOutSpot) {
// that doesn't involve the ClickInHotSpot function.
_zoomOutSpot = zoomOutSpot;
- if (zoomOutSpot->getObjectID() == kCaldoriaDrawersOutSpotID) {
+ if (_vm->isDVD() && zoomOutSpot->getObjectID() == kCaldoriaReplicatorOutSpotID) {
+ GameState.setEasterEgg(false);
+ Neighborhood::zoomTo(zoomOutSpot);
+ } else if (zoomOutSpot->getObjectID() == kCaldoriaDrawersOutSpotID) {
if (_privateFlags.getFlag(kCaloriaPrivateLeftDrawerOpenFlag)) {
_privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, false);
startExtraSequence(kLeftDrawerClose, kExtraCompletedFlag, kFilterNoInput);
@@ -1160,6 +1411,100 @@ void Caldoria::zoomToSinclair() {
startExtraSequence(kCa53EastZoomToSinclair, kExtraCompletedFlag, kFilterAllInput);
}
+void Caldoria::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
+ short left = kNavAreaLeft, top = kNavAreaTop;
+ DisplayOrder displayOrder = kNavMovieOrder + 1;
+ TimeValue segmentStart = 0, segmentStop = 0;
+ bool loopSequence = false;
+ Common::Rect pushBounds;
+ NotificationFlags extraFlags;
+
+ switch (extraID) {
+ case kCreateCornbread:
+ case kWashingMachineZoomIn:
+ case kWashingMachineLoop:
+ case kWashingMachineZoomOut:
+ _turnPush.getBounds(pushBounds);
+
+ switch (extraID) {
+ case kCreateCornbread:
+ _extraMovie.initFromMovieFile("Images/Caldoria/A12RC.movie");
+ left = pushBounds.left;
+ top = pushBounds.top;
+ displayOrder = kNavMovieOrder + 1;
+ segmentStart = 0;
+ segmentStop = _extraMovie.getDuration();
+ loopSequence = false;
+ break;
+ case kWashingMachineZoomIn:
+ _extraMovie.initFromMovieFile("Images/Caldoria/A11WAS.movie");
+ left = pushBounds.left;
+ top = pushBounds.top;
+ displayOrder = kNavMovieOrder + 1;
+ segmentStart = 0;
+ segmentStop = 5480;
+ loopSequence = false;
+ break;
+ case kWashingMachineLoop:
+ // The washing machine movie will already be loaded after zooming in
+ left = pushBounds.left;
+ top = pushBounds.top;
+ displayOrder = kNavMovieOrder + 1;
+ segmentStart = 5480;
+ segmentStop = 9880;
+ loopSequence = true;
+ break;
+ case kWashingMachineZoomOut:
+ // The washing machine movie will still be loaded after looping
+ left = pushBounds.left;
+ top = pushBounds.top;
+ displayOrder = kNavMovieOrder + 1;
+ segmentStart = 9880;
+ segmentStop = 11200;
+ loopSequence = false;
+ break;
+ default:
+ break;
+ }
+
+ _lastExtra = extraID;
+ _turnPush.hide();
+
+ if (!loopSequence && g_AIArea)
+ g_AIArea->lockAIOut();
+
+ extraFlags = flags;
+ _interruptionFilter = interruptionFilter;
+ // Stop the nav movie before doing anything else
+ _navMovie.stop();
+ _navMovie.stopDisplaying();
+
+ _extraMovie.setVolume(_vm->getSoundFXLevel());
+ _extraMovie.moveElementTo(left, top);
+ _extraMovie.setDisplayOrder(displayOrder);
+ _extraMovie.startDisplaying();
+ _extraMovie.show();
+ _extraMovie.setFlags(0);
+ _extraMovie.setSegment(segmentStart, segmentStop);
+ _extraMovie.setTime(segmentStart);
+ if (loopSequence)
+ _extraMovie.setFlags(kLoopTimeBase);
+ else
+ extraFlags |= kNeighborhoodMovieCompletedFlag;
+ _extraMovieCallBack.cancelCallBack();
+ _extraMovieCallBack.initCallBack(&_extraMovie, kCallBackAtExtremes);
+ if (extraFlags != 0) {
+ _extraMovieCallBack.setCallBackFlag(extraFlags);
+ _extraMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+ _extraMovie.start();
+ break;
+ default:
+ Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+ break;
+ }
+}
+
void Caldoria::receiveNotification(Notification *notification, const NotificationFlags flags) {
Neighborhood::receiveNotification(notification, flags);
@@ -1196,8 +1541,31 @@ void Caldoria::receiveNotification(Notification *notification, const Notificatio
}
break;
case kCreateOrangeJuice:
+ GameState.setCaldoriaMadeOJ(true);
setCurrentActivation(kActivateOJOnThePad);
- requestSpotSound(kCaldoriaReplicatorOJChoiceIn, kCaldoriaReplicatorOJChoiceOut, kFilterNoInput, 0);
+ GameState.setEasterEgg(false);
+ break;
+ case kCreateCornbread:
+ _extraMovie.moveElementTo(0, 0);
+ _vm->_gfx->setCurSurface(_navMovie.getSurface());
+ _extraMovie.copyToCurrentPort();
+ _vm->_gfx->setCurSurface(_vm->_gfx->getWorkArea());
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ GameState.setEasterEgg(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB39", kArthurCaldoriaCreatedCornbread);
+ break;
+ case kWashingMachineZoomIn:
+ _lookingAtLaundry = true;
+ startExtraSequence(kWashingMachineLoop, kExtraCompletedFlag, kFilterAllInput);
+ break;
+ case kWashingMachineZoomOut:
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ _lookingAtLaundry = false;
break;
case kCaldoria00SitDown:
arriveAt(kCaldoria00, kEast);
@@ -1240,15 +1608,27 @@ void Caldoria::receiveNotification(Notification *notification, const Notificatio
case kCa48NorthExplosion:
// Current biochip must be the shield if we got here.
_vm->getCurrentBiochip()->setItemState(kShieldNormal);
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA41", kArthurCaldoriaBlownDoor);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB42", kArthurCaldoriaBlownDoor);
+ }
break;
case kBinocularsZoomInOnShip:
setCurrentActivation(kActivateFocusedOnShip);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA03", kArthurCaldoriaLookThroughTelescope);
break;
case kCa49NorthVoiceAnalysis:
_utilityFuse.primeFuse(kSinclairShootsTimeLimit);
_utilityFuse.setFunctor(new Common::Functor0Mem<void, Caldoria>(this, &Caldoria::sinclairTimerExpired));
_utilityFuse.lightFuse();
GameState.setCaldoriaSawVoiceAnalysis(true);
+ if (_vm->isDVD() && g_AIArea)
+ g_AIArea->checkRules();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA20", kArthurCaldoriaSawVoiceAnalysis);
break;
case kCa53EastZoomToSinclair:
if (GameState.getCaldoriaSinclairShot()) {
@@ -1274,6 +1654,10 @@ void Caldoria::receiveNotification(Notification *notification, const Notificatio
}
} else if ((flags & kSpotSoundCompletedFlag) != 0) {
switch (GameState.getCurrentRoom()) {
+ case kCaldoria11:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA46", kArthurCaldoriaZoomedToLaundry);
+ break;
case kCaldoria20:
case kCaldoria21:
case kCaldoria26:
@@ -1281,6 +1665,8 @@ void Caldoria::receiveNotification(Notification *notification, const Notificatio
case kCaldoria34:
case kCaldoria35:
updateViewFrame();
+ if ((GameState.getCurrentRoom() == kCaldoria34 || GameState.getCurrentRoom() == kCaldoria35) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA44", kArthurCaldoriaSawVacantApartment);
break;
case kCaldoria27:
case kCaldoria28:
@@ -1288,7 +1674,14 @@ void Caldoria::receiveNotification(Notification *notification, const Notificatio
updateElevatorMovie();
break;
case kCaldoriaReplicator:
- emptyOJGlass();
+ if (_spotSounds.getStart() == kCaldoriaReplicatorWrongChoiceIn) {
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA16", kArthurCaldoriaSelectedStickyBuns);
+ } else {
+ emptyOJGlass();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA45", kArthurCaldoriaDrankOJ);
+ }
break;
default:
break;
@@ -1360,6 +1753,16 @@ void Caldoria::activateHotspots() {
case kCaldoriaReplicator:
if (GameState.getCaldoriaMadeOJ())
_vm->getAllHotspots().deactivateOneHotspot(kCaldoriaMakeOJSpotID);
+ if (GameState.getEasterEgg())
+ _vm->getAllHotspots().activateOneHotspot(kCaldoriaCornbreadHotSpotID);
+ break;
+ case kCaldoria11:
+ if (_vm->isDVD() && GameState.getCurrentDirection() == kWest) {
+ if (_lookingAtLaundry)
+ _vm->getAllHotspots().activateOneHotspot(kCaldoriaLaundryZoomOutHotSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kCaldoriaLaundryZoomInHotSpotID);
+ }
break;
case kCaldoria27:
if (GameState.isCurrentDoorOpen()) {
@@ -1454,11 +1857,28 @@ void Caldoria::clickInHotspot(const Input &input, const Hotspot *spot) {
startExtraSequence(kRightDrawerCloseNoKeys, kExtraCompletedFlag, kFilterNoInput);
break;
case kCaldoriaMakeStickyBunsSpotID:
- requestSpotSound(kCaldoriaReplicatorWrongChoiceIn, kCaldoriaReplicatorWrongChoiceOut, kFilterNoInput, 0);
+ requestSpotSound(kCaldoriaReplicatorWrongChoiceIn, kCaldoriaReplicatorWrongChoiceOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case kCaldoriaMakeOJSpotID:
- GameState.setCaldoriaMadeOJ(true);
- startExtraSequence(kCreateOrangeJuice, kExtraCompletedFlag, kFilterNoInput);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input)) {
+ startExtraSequence(kCreateCornbread, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestSpotSound(kCaldoriaReplicatorOJChoiceIn, kCaldoriaReplicatorOJChoiceOut, kFilterNoInput, 0);
+ requestExtraSequence(kCreateOrangeJuice, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCaldoriaCornbreadHotSpotID:
+ doArthurJoyride();
+ break;
+ case kCaldoriaLaundryZoomInHotSpotID:
+ if (_vm->isDVD()) {
+ startExtraSequence(kWashingMachineZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ requestDelay(30, 10, kFilterNoInput, kDelayCompletedFlag);
+ requestSpotSound(kCaldoriaLaundryIntro1In, kCaldoriaLaundryIntro2Out, kFilterNoInput, kSpotSoundCompletedFlag);
+ }
+ break;
+ case kCaldoriaLaundryZoomOutHotSpotID:
+ startExtraSequence(kWashingMachineZoomOut, kExtraCompletedFlag, kFilterNoInput);
break;
case kCaBedroomVidPhoneActivationSpotID:
newInteraction(kCaldoriaMessagesInteractionID);
@@ -1540,19 +1960,29 @@ void Caldoria::clickInHotspot(const Input &input, const Hotspot *spot) {
void Caldoria::clickOnDoorbell(const HotSpotID doorBellSpotID) {
uint32 extra;
+ Sound doorbellSound;
ExtraTable::Entry entry;
+ Input input;
switch (doorBellSpotID) {
case kCaldoria20DoorbellSpotID:
+ if (_vm->isDVD())
+ doorbellSound.initFromAIFFFile("Sounds/Caldoria/AH5.AIFF");
extra = kCaldoria20Doorbell;
break;
case kCaldoria21DoorbellSpotID:
+ if (_vm->isDVD())
+ doorbellSound.initFromAIFFFile("Sounds/Caldoria/AH4.AIFF");
extra = kCaldoria21Doorbell;
break;
case kCaldoria26DoorbellSpotID:
+ if (_vm->isDVD())
+ doorbellSound.initFromAIFFFile("Sounds/Caldoria/AH3.AIFF");
extra = kCaldoria26Doorbell;
break;
case kCaldoria29DoorbellSpotID:
+ if (_vm->isDVD())
+ doorbellSound.initFromAIFFFile("Sounds/Caldoria/AH1.AIFF");
extra = kCaldoria29Doorbell;
break;
case kCaldoria34DoorbellSpotID:
@@ -1567,7 +1997,51 @@ void Caldoria::clickOnDoorbell(const HotSpotID doorBellSpotID) {
getExtraEntry(extra, entry);
showViewFrame(entry.movieStart);
- requestSpotSound(kCaldoriaNobodyHomeIn, kCaldoriaNobodyHomeOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ if (_vm->isDVD() && doorBellSpotID != kCaldoria34DoorbellSpotID && doorBellSpotID != kCaldoria35DoorbellSpotID) {
+ _vm->_cursor->hide();
+ doorbellSound.setVolume(_vm->getSoundFXLevel());
+ doorbellSound.playSound();
+ while (doorbellSound.isPlaying() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+ if (_vm->shouldQuit())
+ return;
+ _vm->_cursor->hideUntilMoved();
+ updateViewFrame();
+ } else {
+ requestSpotSound(kCaldoriaNobodyHomeIn, kCaldoriaNobodyHomeOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ }
+}
+
+void Caldoria::cantMoveThatWay(CanOpenDoorReason reason) {
+ switch (reason) {
+ case kCantMoveDoorClosed:
+ case kCantMoveDoorLocked:
+ openDoor();
+ break;
+ case kCantMoveBlocked:
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria20, kWest):
+ case MakeRoomView(kCaldoria21, kEast):
+ case MakeRoomView(kCaldoria26, kSouth):
+ case MakeRoomView(kCaldoria29, kSouth):
+ case MakeRoomView(kCaldoria34, kWest):
+ case MakeRoomView(kCaldoria35, kEast):
+ cantOpenDoor(kCantOpenLocked);
+ break;
+ default:
+ zoomUpOrBump();
+ break;
+ }
+ break;
+ default:
+ bumpIntoWall();
+ break;
+ }
}
CanOpenDoorReason Caldoria::canOpenDoor(DoorTable::Entry &entry) {
@@ -1663,6 +2137,9 @@ void Caldoria::pickedUpItem(Item *item) {
}
void Caldoria::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ Input input;
+ Sound cardBombVoice;
+
switch (item->getObjectID()) {
case kKeyCard:
Neighborhood::dropItemIntoRoom(item, dropSpot);
@@ -1686,7 +2163,27 @@ void Caldoria::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
_utilityFuse.lightFuse();
GameState.setCaldoriaFuseTimeLimit(kCardBombCountDownTime);
loopCroppedMovie("Images/Caldoria/A48 Bomb Loop", kCaldoria48CardBombLoopLeft, kCaldoria48CardBombLoopTop);
+ if (_vm->isDVD()) {
+ InputDevice.getInput(input, kFilterAllInput);
+ if (JMPPPInput::isEasterEggModifierInput(input))
+ cardBombVoice.initFromAIFFFile("Sounds/Caldoria/Card Bomb.Geno.aiff");
+ else
+ cardBombVoice.initFromAIFFFile("Sounds/Caldoria/Card Bomb.44K.aiff");
+ cardBombVoice.setVolume(_vm->getSoundFXLevel());
+ cardBombVoice.playSound();
+ while (cardBombVoice.isPlaying() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+ if (_vm->shouldQuit())
+ return;
+ }
GameState.setScoringUsedCardBomb(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA19", kArthurCaldoriaUsedCardBomb);
break;
case kStunGun:
GameState.setCaldoriaGunAimed(true);
@@ -1697,6 +2194,8 @@ void Caldoria::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
_gunSprite->moveElementTo(kCaldoriaGunSpriteLeft, kCaldoriaGunSpriteTop);
_gunSprite->startDisplaying();
_gunSprite->show();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA17", kArthurCaldoriaStunningSinclair);
break;
default:
Neighborhood::dropItemIntoRoom(item, dropSpot);
@@ -1704,6 +2203,42 @@ void Caldoria::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
}
}
+void Caldoria::setSoundFXLevel(const uint16 level) {
+ Neighborhood::setSoundFXLevel(level);
+
+ if (_extraMovie.isMovieValid())
+ _extraMovie.setVolume(level);
+}
+
+void Caldoria::playMissingFloorSound() {
+ Input input;
+ Sound elevatorVoice;
+
+ InputDevice.getInput(input, kFilterAllInput);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input)) {
+ _vm->_cursor->hide();
+ elevatorVoice.initFromAIFFFile("Sounds/Caldoria/Elevator Denied.32K.aiff");
+ elevatorVoice.setVolume(_vm->getSoundFXLevel());
+ elevatorVoice.playSound();
+ while (elevatorVoice.isPlaying() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+ if (_vm->shouldQuit())
+ return;
+ _vm->_cursor->hideUntilMoved();
+ updateElevatorMovie();
+ } else {
+ requestSpotSound(kCaldoriaNoOtherFloorIn,
+ kCaldoriaNoOtherFloorOut,
+ kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ }
+}
+
void Caldoria::takeElevator(uint startFloor, uint endFloor) {
_croppedMovie.stop();
_croppedMovie.setSegment(0, _croppedMovie.getDuration());
@@ -1717,12 +2252,12 @@ void Caldoria::takeElevator(uint startFloor, uint endFloor) {
case 2:
_croppedMovie.setTime(k1To2Time);
_croppedMovie.redrawMovieWorld();
- requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ playMissingFloorSound();
break;
case 3:
_croppedMovie.setTime(k1To3Time);
_croppedMovie.redrawMovieWorld();
- requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ playMissingFloorSound();
break;
case 4:
_croppedMovie.setSegment(k1To4Start, k1To4Stop);
@@ -1751,12 +2286,12 @@ void Caldoria::takeElevator(uint startFloor, uint endFloor) {
case 2:
_croppedMovie.setTime(k4To2Time);
_croppedMovie.redrawMovieWorld();
- requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ playMissingFloorSound();
break;
case 3:
_croppedMovie.setTime(k4To3Time);
_croppedMovie.redrawMovieWorld();
- requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ playMissingFloorSound();
break;
case 4:
// Do nothing.
@@ -1782,12 +2317,12 @@ void Caldoria::takeElevator(uint startFloor, uint endFloor) {
case 2:
_croppedMovie.setTime(k5To2Time);
_croppedMovie.redrawMovieWorld();
- requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ playMissingFloorSound();
break;
case 3:
_croppedMovie.setTime(k5To3Time);
_croppedMovie.redrawMovieWorld();
- requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ playMissingFloorSound();
break;
case 4:
_croppedMovie.setSegment(k5To4Start, k5To4Stop);
@@ -2065,4 +2600,64 @@ Common::String Caldoria::getSoundSpotsName() {
return "Sounds/Caldoria/Caldoria Spots";
}
+void Caldoria::doArthurJoyride() {
+ Video::VideoDecoder *video = 0;
+ BiochipItem *item;
+
+ setNextHandler(_vm);
+ throwAwayInterface();
+ loadLoopSound1("");
+
+ _vm->_cursor->hide();
+
+#ifdef USE_THEORADEC
+ video = new Video::TheoraDecoder();
+ if (!video->loadFile("Images/Caldoria/A12RD.ogg")) {
+ delete video;
+ video = 0;
+ }
+#endif
+
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile("Images/Caldoria/A12RD.movie"))
+ error("Could not load joyride video");
+ }
+
+ video->setVolume(MIN<uint>(_vm->getSoundFXLevel(), 0xFF));
+ video->start();
+
+ while (!_vm->shouldQuit() && !video->endOfVideo()) {
+ if (video->needsUpdate()) {
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (frame) {
+ g_system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
+ g_system->updateScreen();
+ }
+ }
+
+ InputDevice.pumpEvents();
+
+ g_system->delayMillis(10);
+ }
+
+ delete video;
+
+ if (_vm->shouldQuit())
+ return;
+
+ reinstateMonocleInterface();
+ loadAmbientLoops();
+ updateViewFrame();
+ if (!_vm->playerHasItemID(kArthurBiochip)) {
+ item = (BiochipItem *)_vm->getAllItems().findItemByID(kArthurBiochip);
+ _vm->addItemToBiochips(item);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA06", kArthurCaldoriaFinishedJoyride);
+ }
+ g_interface->setCurrentBiochipID(kArthurBiochip);
+ GameState.setEasterEgg(false);
+}
+
} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.h b/engines/pegasus/neighborhood/caldoria/caldoria.h
index 5fca53baf9..8f242891b9 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria.h
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.h
@@ -195,6 +195,7 @@ static const HotSpotID kCaldoriaRoofElevatorSpotID = 5065;
static const HotSpotID kCaldoriaRoofDoorSpotID = 5066;
static const HotSpotID kCaldoriaRoofCardDropSpotID = 5067;
static const HotSpotID kCaldoria53EastSinclairTargetSpotID = 5068;
+static const HotSpotID kCaldoriaCornbread = 5069;
// Extra sequence IDs.
@@ -383,6 +384,9 @@ static const DisplayElementID kCaldoriaUtilityID = kCaldoriaMessagesID + 1;
static const DisplayElementID kCaldoriaBombGridID = kCaldoriaUtilityID + 1;
static const DisplayElementID kCaldoriaBombTimerID = kCaldoriaBombGridID + 1;
+static const TimeValue kCaldoria4DInstructionsIn = 28013;
+static const TimeValue kCaldoria4DInstructionsOut = 29730;
+
static const TimeValue kCaldoria4DBlankChoiceIn = 29730;
static const TimeValue kCaldoria4DBlankChoiceOut = 33910;
@@ -422,6 +426,8 @@ public:
void checkContinuePoint(const RoomID, const DirectionConstant) override;
+ void setSoundFXLevel(const uint16) override;
+
protected:
enum {
kCaldoriaPrivate4DSystemOpenFlag,
@@ -445,6 +451,7 @@ protected:
void init() override;
void start() override;
+ void throwAwayInterface() override;
void setUpRoofTop();
@@ -472,7 +479,10 @@ protected:
void arriveAtCaldoriaDeath();
void turnTo(const DirectionConstant) override;
void zoomTo(const Hotspot *) override;
+ void leftButton(const Input &) override;
+ void rightButton(const Input &) override;
void downButton(const Input &) override;
+ void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void receiveNotification(Notification *, const NotificationFlags) override;
InputBits getInputFilter() override;
void activateHotspots() override;
@@ -483,6 +493,7 @@ protected:
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
+ void playMissingFloorSound();
void takeElevator(uint, uint);
void updateElevatorMovie();
void openElevatorMovie();
@@ -495,7 +506,9 @@ protected:
void zoomToSinclair();
void playEndMessage();
void checkInterruptSinclair();
+ void doArthurJoyride();
+ void cantMoveThatWay(CanMoveForwardReason) override;
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void doorOpened() override;
@@ -505,6 +518,15 @@ protected:
const Hotspot *_zoomOutSpot;
+ Hotspot _laundryZoomInSpot;
+ Hotspot _laundryZoomOutSpot;
+ Hotspot _cornbreadSpot;
+
+ Movie _extraMovie;
+ NotificationCallBack _extraMovieCallBack;
+
+ bool _lookingAtLaundry;
+
FuseFunction _utilityFuse;
long _sinclairLoopCount;
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
index 303bcc2946..8539e16d38 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
@@ -222,7 +222,8 @@ void Caldoria4DSystem::useIdleTime() {
void Caldoria4DSystem::initInteraction() {
setSpritesMovie();
- _owner->loadLoopSound1("Sounds/Caldoria/Rock.aiff");
+ playSound("Rock");
+ _owner->playSpotSoundSync(kCaldoria4DInstructionsIn, kCaldoria4DInstructionsOut);
loopExtra(k4DIslandLoop);
}
@@ -255,8 +256,7 @@ void Caldoria4DSystem::handleInput(const Input &input, const Hotspot *cursorSpot
void Caldoria4DSystem::activateHotspots() {
GameInteraction::activateHotspots();
- if (_whichMenu == k4DAudioMenu)
- g_allHotspots.activateOneHotspot(kCa4DChoice4SpotID);
+ g_allHotspots.activateOneHotspot(kCa4DChoice4SpotID);
}
void Caldoria4DSystem::clickInHotspot(const Input &input, const Hotspot *spot) {
@@ -347,7 +347,7 @@ void Caldoria4DSystem::makeRockChoice() {
if (_audioChoice != k4DRockChoice) {
_audioChoice = k4DRockChoice;
setSpritesMovie();
- _owner->loadLoopSound1("Sounds/Caldoria/Rock.aiff");
+ playSound("Rock");
}
}
@@ -355,7 +355,7 @@ void Caldoria4DSystem::makeOrchestralChoice() {
if (_audioChoice != k4DOrchestralChoice) {
_audioChoice = k4DOrchestralChoice;
setSpritesMovie();
- _owner->loadLoopSound1("Sounds/Caldoria/Orchestral.aiff");
+ playSound("Orchestral");
}
}
@@ -363,7 +363,7 @@ void Caldoria4DSystem::makeRhythmsChoice() {
if (_audioChoice != k4DRhythmsChoice) {
_audioChoice = k4DRhythmsChoice;
setSpritesMovie();
- _owner->loadLoopSound1("Sounds/Caldoria/Rhythms.aiff");
+ playSound("Rhythms");
}
}
@@ -371,7 +371,7 @@ void Caldoria4DSystem::makeAcousticChoice() {
if (_audioChoice != k4DAcousticChoice) {
_audioChoice = k4DAcousticChoice;
setSpritesMovie();
- _owner->loadLoopSound1("Sounds/Caldoria/Acoustic.aiff");
+ playSound("Acoustic");
}
}
@@ -379,4 +379,14 @@ void Caldoria4DSystem::shutDown4DSystem() {
_whichMenu = k4DShuttingDown;
}
+void Caldoria4DSystem::playSound(const Common::String &baseFileName) {
+ Common::String fileName = "Sounds/Caldoria/" + baseFileName;
+
+ // Updated DVD files
+ if (((PegasusEngine *)g_engine)->isDVD())
+ fileName += ".44K";
+
+ _owner->loadLoopSound1(fileName + ".aiff");
+}
+
} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
index 1a057ec483..03477c1ed8 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
@@ -63,6 +63,8 @@ protected:
void useIdleTime() override;
void loopExtra(const ExtraID);
+ void playSound(const Common::String &baseFileName);
+
Movie _4DSpritesMovie;
TimeScale _4DSpritesScale;
uint _whichMenu;
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp b/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp
index 5da18ab9ea..97dbd9cb71 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp
@@ -25,6 +25,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/caldoria/caldoriabomb.h"
@@ -48,7 +49,9 @@ static const uint32 kOnTime3 = kOffTime2 + kFlashOnTime;
static const uint32 kOffTime3 = kOnTime3 + kFlashOffTime;
static const uint32 kOnTime4 = kOffTime3 + kFlashOnTime;
-static const HotSpotID kVertextHotSpotBaseID = 10000;
+// Bomb hotspots start at 20000 since the extra Caldoria hotspots start at 10000.
+// Assigning these vice versa causes a hotspot in level 4 to never activate for some reason.
+static const HotSpotID kVertextHotSpotBaseID = 20000;
static const CoordType kVertextHotSpotWidth = 24;
static const CoordType kVertextHotSpotHeight = 24;
@@ -1248,6 +1251,12 @@ void CaldoriaBomb::receiveNotification(Notification *notification, const Notific
_lastVertex = -1;
_owner->_navMovie.setVolume(((PegasusEngine *)g_engine)->getAmbienceLevel());
startBombAmbient("Sounds/Caldoria/BmbLoop1.22K.AIFF");
+ if (g_arthurChip) {
+ if (((PegasusEngine *)g_engine)->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA14", kArthurCaldoriaSeeRoofBomb);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB28", kArthurCaldoriaSeeRoofBomb);
+ }
break;
case kCaldoria56BombStage2:
case kCaldoria56BombStage3:
@@ -1429,6 +1438,8 @@ void CaldoriaBomb::handleInput(const Input &input, const Hotspot *hotspot) {
_timer.hide();
_owner->_navMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
_owner->startExtraSequence(kCaldoria56BombStage7, kExtraCompletedFlag, kFilterNoInput);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA02", kArthurCaldoriaDisarmedNuke);
break;
default:
break;
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
index d39e9a7677..e53122d400 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
@@ -25,6 +25,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/neighborhood.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/caldoria/caldoriamirror.h"
@@ -43,6 +44,11 @@ void CaldoriaMirror::openInteraction() {
void CaldoriaMirror::initInteraction() {
_owner->setCurrentActivation(kActivateMirrorReady);
_owner->startExtraSequence(kCaBathroomGreeting, kExtraCompletedFlag, kFilterNoInput);
+ // The original made the player click to start each of the following sequences,
+ // which was unnecessary, so it is automated here.
+ _owner->startExtraSequenceSync(kCaBathroomGreeting, kFilterNoInput);
+ _owner->startExtraSequenceSync(kCaBathroomBodyFat, kFilterNoInput);
+ _owner->startExtraSequence(kCaBathroomStylistIntro, kExtraCompletedFlag, kFilterNoInput);
}
void CaldoriaMirror::closeInteraction() {
@@ -82,32 +88,18 @@ void CaldoriaMirror::activateHotspots() {
void CaldoriaMirror::clickInHotspot(const Input &input, const Hotspot *spot) {
switch (spot->getObjectID()) {
- case kCaBathroomMirrorSpotID:
- switch (_owner->getLastExtra()) {
- case kCaBathroomGreeting:
- _owner->startExtraSequence(kCaBathroomBodyFat, kExtraCompletedFlag, kFilterNoInput);
- break;
- case kCaBathroomBodyFat:
- _owner->startExtraSequence(kCaBathroomStylistIntro, kExtraCompletedFlag, kFilterNoInput);
- break;
- case kCaBathroomRetrothrash:
- _owner->startExtraSequence(kCaBathroomRetrothrashReturn, kExtraCompletedFlag, kFilterNoInput);
- break;
- case kCaBathroomGeoWave:
- _owner->startExtraSequence(kCaBathroomGeoWaveReturn, kExtraCompletedFlag, kFilterNoInput);
- break;
- default:
- break;
- }
- break;
+ // The original made the player click through several interstitial screens before
+ // reaching the hairstyle menu, which was unnecessary, so it's skipped here.
case kCaHairStyle1SpotID:
- _owner->startExtraSequence(kCaBathroomRetrothrash, kExtraCompletedFlag, kFilterNoInput);
+ _owner->startExtraSequenceSync(kCaBathroomRetrothrash, kFilterNoInput);
+ _owner->startExtraSequence(kCaBathroomRetrothrashReturn, kExtraCompletedFlag, kFilterNoInput);
break;
case kCaHairStyle2SpotID:
_owner->startExtraSequence(kCaBathroomAgencyStandard, kExtraCompletedFlag, kFilterNoInput);
break;
case kCaHairStyle3SpotID:
- _owner->startExtraSequence(kCaBathroomGeoWave, kExtraCompletedFlag, kFilterNoInput);
+ _owner->startExtraSequenceSync(kCaBathroomGeoWave, kFilterNoInput);
+ _owner->startExtraSequence(kCaBathroomGeoWaveReturn, kExtraCompletedFlag, kFilterNoInput);
break;
default:
GameInteraction::clickInHotspot(input, spot);
@@ -131,12 +123,12 @@ void CaldoriaMirror::receiveNotification(Notification *, const NotificationFlags
_owner->requestDeleteCurrentInteraction();
GameState.setScoringFixedHair(true);
GameState.setCaldoriaDoneHygiene(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA43", kArthurCaldoriaChoseAgencyHairStyle);
break;
default:
break;
}
-
- allowInput(true);
}
} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/canyonchase.cpp b/engines/pegasus/neighborhood/mars/canyonchase.cpp
new file mode 100644
index 0000000000..9149f12c92
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/canyonchase.cpp
@@ -0,0 +1,540 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/canyonchase.h"
+#include "pegasus/neighborhood/mars/mars.h"
+
+namespace Pegasus {
+
+// Segment start and end points.
+
+//static const TimeValue kPrepStart = 0;
+static const TimeValue kPrepEnd = 3000;
+static const TimeValue kLaunchStart = kPrepEnd;
+static const TimeValue kLaunchEnd = 6640;
+static const TimeValue kBranch1Start = kLaunchEnd;
+static const TimeValue kBranch1End = 22240;
+static const TimeValue kBranch2Start = kBranch1End;
+static const TimeValue kBranch2End = 28440;
+static const TimeValue kBranch3Start = kBranch2End;
+static const TimeValue kBranch3End = 38640;
+static const TimeValue kBranch4Start = kBranch3End;
+static const TimeValue kBranch4End = 43880;
+static const TimeValue kBranch5Start = kBranch4End;
+static const TimeValue kBranch5End = 58680;
+static const TimeValue kExitStart = kBranch5End;
+static const TimeValue kExitEnd = 66480;
+static const TimeValue kExitLoopPoint = 66200;
+static const TimeValue kExitGenoPoint = 62560;
+
+// Death start and end points.
+
+static const TimeValue kDeath1Start = 0;
+static const TimeValue kDeath1End = 2400;
+static const TimeValue kDeath2Start = kDeath1End;
+static const TimeValue kDeath2End = 4720;
+static const TimeValue kDeath3Start = kDeath2End;
+static const TimeValue kDeath3End = 7120;
+static const TimeValue kDeath4Start = kDeath3End;
+static const TimeValue kDeath4End = 9280;
+static const TimeValue kDeath5Start = kDeath4End;
+static const TimeValue kDeath5End = 12000;
+
+// Chase state.
+
+enum {
+ kCanyonLaunch,
+ kCanyonBranch1Left,
+ kCanyonBranch1Right,
+ kCanyonBranch2Left,
+ kCanyonBranch2Right,
+ kCanyonBranch3Left,
+ kCanyonBranch4Left,
+ kCanyonBranch4Right,
+ kCanyonBranch5Left,
+ kCanyonBranch5Right,
+ kCanyonExit,
+ kCanyonLoop
+};
+
+void MusicTimerEvent::fire() {
+ canyonChase->musicTimerExpired(*this);
+}
+
+CanyonChase::CanyonChase(Neighborhood *handler) : ChaseInteraction(kMarsCanyonChaseInteractionID, handler,
+ kMarsCanyonChaseNotificationID, (PegasusEngine *)g_engine), _canyonMovie1(kNoDisplayElement),
+ _canyonMovie2(kNoDisplayElement), _deathMovie(kNoDisplayElement), _genoMovie(kNoDisplayElement) {
+ _currentMovie = NULL;
+ _currentCallBack = NULL;
+}
+
+void CanyonChase::setSoundFXLevel(const uint16 fxLevel) {
+ _canyonMovie1.setVolume(fxLevel);
+ _canyonMovie2.setVolume(fxLevel);
+ _deathMovie.setVolume(fxLevel);
+}
+
+void CanyonChase::setAmbienceLevel(const uint16 level) {
+ _genoMovie.setVolume(level);
+ _musicFader.setMasterVolume(level);
+}
+
+void CanyonChase::startCanyonMusicLoop(void) {
+ FaderMoveSpec spec;
+
+ _musicLoop.loopSound();
+ spec.makeTwoKnotFaderSpec(10, 0, 0, 1, 255);
+ _musicFader.startFader(spec);
+}
+
+void CanyonChase::stopCanyonMusicLoop(const long ticks) {
+ FaderMoveSpec spec;
+
+ spec.makeTwoKnotFaderSpec(10, 0, 255, ticks, 0);
+ _musicFader.startFader(spec);
+}
+
+void CanyonChase::openInteraction() {
+ _canyonMovie1.initFromMovieFile("Images/Mars/Canyon_hq1.mov");
+ _canyonMovie1.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _canyonMovie1.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
+ _canyonMovie1.setDisplayOrder(kShuttleMonitorOrder);
+
+ _canyon1CallBack.setNotification(&_chaseNotification);
+ _canyon1CallBack.initCallBack(&_canyonMovie1, kCallBackAtExtremes);
+ _canyon1CallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _canyon1CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _canyonMovie2.initFromMovieFile("Images/Mars/Canyon_hq2.mov");
+ _canyonMovie2.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _canyonMovie2.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
+ _canyonMovie2.setDisplayOrder(kShuttleMonitorOrder);
+
+ _canyon2CallBack.setNotification(&_chaseNotification);
+ _canyon2CallBack.initCallBack(&_canyonMovie2, kCallBackAtExtremes);
+ _canyon2CallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _deathMovie.initFromMovieFile("Images/Mars/Canyon_hqD.mov");
+ _deathMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _deathMovie.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
+ _deathMovie.setDisplayOrder(kShuttleMonitorOrder);
+
+ _deathCallBack.setNotification(&_chaseNotification);
+ _deathCallBack.initCallBack(&_deathMovie, kCallBackAtExtremes);
+ _deathCallBack.setCallBackFlag(kChaseFinished);
+ _deathCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _musicLoop.attachFader(&_musicFader);
+ _musicLoop.initFromAIFFFile("Sounds/Mars/Canyon Loop.44K.16.AIFF");
+ _musicFader.setMasterVolume(((PegasusEngine *)g_engine)->getAmbienceLevel());
+
+ ChaseInteraction::openInteraction();
+
+ _steerPict.setDisplayOrder(kShuttleMonitorOrder + 1);
+ _steerPict.moveElementTo(kShuttleSteerLeft, kShuttleSteerTop);
+}
+
+void CanyonChase::initInteraction() {
+ _steerPict.startDisplaying();
+
+ // Launch branch is identical in both movies
+ _canyonState = kCanyonLaunch;
+ _canyonMovie1.setSegment(kLaunchStart, kLaunchEnd - kDecisionTime);
+ _canyonMovie1.setTime(kLaunchStart);
+ switchTo(_canyonMovie1, _canyon1CallBack);
+ startCanyonMusicLoop();
+ ChaseInteraction::initInteraction();
+}
+
+void CanyonChase::closeInteraction() {
+ _canyonMovie1.stop();
+ _canyonMovie1.stopDisplaying();
+ _canyonMovie1.releaseMovie();
+ _canyon1CallBack.releaseCallBack();
+
+ _canyonMovie2.stop();
+ _canyonMovie2.stopDisplaying();
+ _canyonMovie2.releaseMovie();
+ _canyon2CallBack.releaseCallBack();
+
+ _deathMovie.stop();
+ _deathMovie.stopDisplaying();
+ _deathMovie.releaseMovie();
+ _deathCallBack.releaseCallBack();
+
+ _genoMovie.stop();
+ _genoMovie.stopDisplaying();
+ _genoMovie.releaseMovie();
+ _genoCallBack.releaseCallBack();
+
+ ChaseInteraction::closeInteraction();
+}
+
+void CanyonChase::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ Input input;
+
+ if (notification == &_chaseNotification && flags == kChaseFinished) {
+ if (_canyonState == kCanyonLoop) {
+ // Swallow the notification if we loop back to the beginning
+ InputDevice.getInput(input, kFilterAllInput);
+ if (JMPPPInput::isEasterEggModifierInput(input)) {
+ stopCanyonMusicLoop(15);
+ doGenoChase();
+ } else {
+ _canyonMovie2.setSegment(kExitGenoPoint, kExitLoopPoint - kDecisionTime);
+ _canyonMovie2.setTime(kExitGenoPoint);
+ switchTo(_canyonMovie2, _canyon2CallBack);
+ _canyon2CallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _canyonState = kCanyonLaunch;
+ }
+ return;
+ } else if (_canyonState != kCanyonExit) {
+ // We died
+ ((Mars *)_owner)->die(kDeathRanIntoCanyonWall);
+ }
+ }
+ ChaseInteraction::receiveNotification(notification, flags);
+}
+
+void CanyonChase::setUpBranch() {
+ TimeValue branchStart, branchEnd;
+
+ branchStart = 0;
+ branchEnd = 0;
+ switch (_canyonState) {
+ case kCanyonLaunch:
+ case kCanyonExit:
+ branchStart = kLaunchEnd - kDecisionTime;
+ branchEnd = kLaunchEnd;
+ break;
+ case kCanyonBranch1Left:
+ case kCanyonBranch1Right:
+ branchStart = kBranch1End - kDecisionTime;
+ branchEnd = kBranch1End;
+ break;
+ case kCanyonBranch2Left:
+ case kCanyonBranch2Right:
+ branchStart = kBranch2End - kDecisionTime;
+ branchEnd = kBranch2End;
+ break;
+ case kCanyonBranch3Left:
+ branchStart = kBranch3End - kDecisionTime;
+ branchEnd = kBranch3End;
+ break;
+ case kCanyonBranch4Left:
+ case kCanyonBranch4Right:
+ branchStart = kBranch4End - kDecisionTime;
+ branchEnd = kBranch4End;
+ break;
+ case kCanyonBranch5Left:
+ case kCanyonBranch5Right:
+ branchStart = kBranch5End - kDecisionTime;
+ branchEnd = kBranch5End;
+ break;
+ default:
+ break;
+ }
+
+ _currentMovie->setSegment(branchStart, branchEnd);
+ // Need to call SetTime here in case we loop
+ _currentMovie->setTime(branchStart);
+
+ _currentCallBack->setCallBackFlag(kChaseExitedBranchZone);
+ _currentCallBack->scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void CanyonChase::branchLeft() {
+ TimeValue branchStart, branchEnd;
+ Movie *movie;
+ NotificationCallBack *callBack;
+
+ branchStart = 0;
+ branchEnd = 0;
+ switch (_canyonState) {
+ case kCanyonLaunch:
+ branchStart = kBranch1Start;
+ branchEnd = kBranch1End - kDecisionTime;
+ _canyonState = kCanyonBranch1Left;
+ break;
+ case kCanyonBranch1Left:
+ case kCanyonBranch1Right:
+ branchStart = kBranch2Start;
+ branchEnd = kBranch2End - kDecisionTime;
+ _canyonState = kCanyonBranch2Left;
+ break;
+ case kCanyonBranch2Left:
+ case kCanyonBranch2Right:
+ branchStart = kBranch3Start;
+ branchEnd = kBranch3End - kDecisionTime;
+ _canyonState = kCanyonBranch3Left;
+ break;
+ case kCanyonBranch3Left:
+ branchStart = kBranch4Start;
+ branchEnd = kBranch4End - kDecisionTime;
+ _canyonState = kCanyonBranch4Left;
+ break;
+ case kCanyonBranch4Left:
+ case kCanyonBranch4Right:
+ branchStart = kBranch5Start;
+ branchEnd = kBranch5End - kDecisionTime;
+ _canyonState = kCanyonBranch5Left;
+ break;
+ case kCanyonBranch5Left:
+ case kCanyonBranch5Right:
+ dontBranch();
+ return;
+ default:
+ break;
+ }
+
+ // Left branches are in hq2 (except exit)
+ // Segment 5 branches are switched
+ if (_canyonState == kCanyonBranch5Left || _canyonState == kCanyonBranch5Right) {
+ movie = &_canyonMovie1;
+ callBack = &_canyon1CallBack;
+ } else {
+ movie = &_canyonMovie2;
+ callBack = &_canyon2CallBack;
+ }
+
+ movie->setSegment(branchStart, branchEnd);
+ movie->setTime(branchStart);
+
+ switchTo(*movie, *callBack);
+
+ callBack->setCallBackFlag(kChaseEnteredBranchZone);
+ callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void CanyonChase::branchRight() {
+ TimeValue branchStart, branchEnd;
+ NotificationFlags flag;
+ Movie *movie;
+ NotificationCallBack *callBack;
+
+ branchStart = 0;
+ branchEnd = 0;
+ flag = 0;
+ switch (_canyonState) {
+ case kCanyonLaunch:
+ branchStart = kBranch1Start;
+ branchEnd = kBranch1End - kDecisionTime;
+ _canyonState = kCanyonBranch1Right;
+ flag = kChaseEnteredBranchZone;
+ break;
+ case kCanyonBranch1Left:
+ case kCanyonBranch1Right:
+ branchStart = kBranch2Start;
+ branchEnd = kBranch2End - kDecisionTime;
+ _canyonState = kCanyonBranch2Right;
+ flag = kChaseEnteredBranchZone;
+ break;
+ case kCanyonBranch2Left:
+ case kCanyonBranch2Right:
+ dontBranch();
+ return;
+ case kCanyonBranch3Left:
+ branchStart = kBranch4Start;
+ branchEnd = kBranch4End - kDecisionTime;
+ _canyonState = kCanyonBranch4Right;
+ flag = kChaseEnteredBranchZone;
+ break;
+ case kCanyonBranch4Left:
+ case kCanyonBranch4Right:
+ branchStart = kBranch5Start;
+ branchEnd = kBranch5End - kDecisionTime;
+ _canyonState = kCanyonBranch5Right;
+ flag = kChaseEnteredBranchZone;
+ break;
+ case kCanyonBranch5Left:
+ case kCanyonBranch5Right:
+ // Exit loop branch is in hq2
+ branchStart = kExitStart;
+ branchEnd = kExitEnd;
+ _canyonState = kCanyonExit;
+ flag = kChaseFinished;
+ startMusicTimer(kCanyonChaseStart + kCanyonChaseExitedTime - kExitStart, kMovieTicksPerSecond,
+ kCanyonExited);
+ break;
+ default:
+ break;
+ }
+
+ // Right branches are in hq1 (except exit)
+ // Segment 5 branches are switched
+ if (_canyonState == kCanyonBranch5Left || _canyonState == kCanyonBranch5Right) {
+ movie = &_canyonMovie2;
+ callBack = &_canyon2CallBack;
+ } else {
+ movie = &_canyonMovie1;
+ callBack = &_canyon1CallBack;
+ }
+
+ movie->setSegment(branchStart, branchEnd);
+ movie->setTime(branchStart);
+
+ switchTo(*movie, *callBack);
+
+ callBack->setCallBackFlag(flag);
+ callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void CanyonChase::dontBranch() {
+ TimeValue branchStart, branchEnd;
+
+ branchStart = 0;
+ branchEnd = 0;
+ switch (_canyonState) {
+ case kCanyonLaunch:
+ branchStart = kDeath1Start;
+ branchEnd = kDeath1End;
+ break;
+ case kCanyonBranch1Left:
+ case kCanyonBranch1Right:
+ branchStart = kDeath2Start;
+ branchEnd = kDeath2End;
+ break;
+ case kCanyonBranch2Left:
+ case kCanyonBranch2Right:
+ branchStart = kDeath3Start;
+ branchEnd = kDeath3End;
+ break;
+ case kCanyonBranch3Left:
+ branchStart = kDeath4Start;
+ branchEnd = kDeath4End;
+ break;
+ case kCanyonBranch4Left:
+ case kCanyonBranch4Right:
+ branchStart = kDeath5Start;
+ branchEnd = kDeath5End;
+ break;
+ case kCanyonBranch5Left:
+ case kCanyonBranch5Right:
+ _canyonMovie2.setSegment(kExitStart, kExitGenoPoint);
+ _canyonMovie2.setTime(kExitStart);
+ switchTo(_canyonMovie2, _canyon2CallBack);
+ _canyon2CallBack.setCallBackFlag(kChaseFinished);
+ _canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _canyonState = kCanyonLoop;
+ return;
+ default:
+ break;
+ }
+
+ _deathMovie.setSegment(branchStart, branchEnd);
+ _deathMovie.setTime(branchStart);
+
+ switchTo(_deathMovie, _deathCallBack);
+
+ startMusicTimer(10, 10, kCanyonRanIntoWall);
+}
+
+void CanyonChase::showControlsHint() {
+ ((Mars *)_owner)->_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftKeypadHintTime);
+ ((Mars *)_owner)->_lowerLeftShuttleMovie.redrawMovieWorld();
+ ChaseInteraction::showControlsHint();
+}
+
+void CanyonChase::hideControlsHint() {
+ ((Mars *)_owner)->_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftCollisionTime);
+ ((Mars *)_owner)->_lowerLeftShuttleMovie.redrawMovieWorld();
+ ChaseInteraction::hideControlsHint();
+}
+
+void CanyonChase::switchTo(Movie &movie, NotificationCallBack &callBack) {
+ if (_currentMovie != &movie) {
+ if (_currentMovie != NULL) {
+ _currentMovie->stop();
+ _currentMovie->hide();
+ _currentMovie->stopDisplaying();
+ }
+
+ _currentMovie = &movie;
+
+ _currentMovie->startDisplaying();
+ _currentMovie->show();
+ _currentMovie->start();
+ }
+
+ if (_currentCallBack != &callBack) {
+ _currentCallBack = &callBack;
+ }
+}
+
+void CanyonChase::startMusicTimer(TimeValue time, TimeScale scale, MusicTimerCode code) {
+ _musicFuse.primeFuse(time, scale);
+ _musicEvent.canyonChase = this;
+ _musicEvent.theEvent = code;
+ _musicFuse.setFunctor(new Common::Functor0Mem<void, MusicTimerEvent>(&_musicEvent, &MusicTimerEvent::fire));
+ _musicFuse.lightFuse();
+}
+
+void CanyonChase::musicTimerExpired(MusicTimerEvent &event) {
+ FaderMoveSpec spec;
+
+ switch (event.theEvent) {
+ case kCanyonRanIntoWall:
+ stopCanyonMusicLoop(5);
+ break;
+ case kCanyonExited:
+ spec.makeTwoKnotFaderSpec(20, 0, 255, 5, 160);
+ _musicFader.startFader(spec);
+ startMusicTimer(kCanyonChaseFadedTime, kMovieTicksPerSecond, kCanyonFaded);
+ break;
+ case kCanyonFaded:
+ spec.makeTwoKnotFaderSpec(10, 0, 160, 30, 0);
+ _musicFader.startFader(spec);
+ ((Mars *)_owner)->startMarsTimer(kLaunchTubeDVDReachedTime, kMovieTicksPerSecond,
+ kMarsLaunchTubeReached);
+ break;
+ default:
+ break;
+ }
+}
+
+void CanyonChase::doGenoChase() {
+ _genoMovie.initFromMovieFile("Images/Mars/Canyon_hqG.mov");
+ _genoMovie.setVolume(((PegasusEngine *)g_engine)->getAmbienceLevel());
+ _genoMovie.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
+ _genoMovie.setDisplayOrder(kShuttleMonitorOrder);
+ _genoMovie.startDisplaying();
+ _genoMovie.show();
+ _genoMovie.start();
+
+ _genoCallBack.setNotification(&_chaseNotification);
+ _genoCallBack.initCallBack(&_genoMovie, kCallBackAtExtremes);
+ _genoCallBack.setCallBackFlag(kChaseFinished);
+ _genoCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _canyonState = kCanyonExit;
+
+ ((Mars *)_owner)->startMarsTimer(_genoMovie.getDuration() - 5 * kMovieTicksPerSecond,
+ kMovieTicksPerSecond, kMarsLaunchTubeReached);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/canyonchase.h b/engines/pegasus/neighborhood/mars/canyonchase.h
new file mode 100644
index 0000000000..489fca0697
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/canyonchase.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_CANYONCHASE_H
+#define PEGASUS_NEIGHBORHOOD_MARS_CANYONCHASE_H
+
+#include "pegasus/chase.h"
+#include "pegasus/fader.h"
+#include "pegasus/movie.h"
+#include "pegasus/sound.h"
+
+namespace Pegasus {
+
+class CanyonChase;
+class Mars;
+
+enum MusicTimerCode {
+ kCanyonRanIntoWall,
+ kCanyonExited,
+ kCanyonFaded
+};
+
+struct MusicTimerEvent {
+ CanyonChase *canyonChase;
+ MusicTimerCode theEvent;
+
+ void fire();
+};
+
+class CanyonChase : public ChaseInteraction {
+friend class Mars;
+friend struct MusicTimerEvent;
+public:
+
+ CanyonChase(Neighborhood *);
+ virtual ~CanyonChase() {}
+
+ void setSoundFXLevel(const uint16);
+ void setAmbienceLevel(const uint16);
+
+protected:
+
+ void startCanyonMusicLoop();
+ void stopCanyonMusicLoop(const long);
+
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ void setUpBranch();
+ void branchLeft();
+ void branchRight();
+ void dontBranch();
+
+ void showControlsHint();
+ void hideControlsHint();
+
+ void switchTo(Movie &, NotificationCallBack &);
+ void startMusicTimer(TimeValue, TimeScale, MusicTimerCode);
+ void musicTimerExpired(MusicTimerEvent &);
+ void doGenoChase();
+
+ Movie _canyonMovie1;
+ Movie _canyonMovie2;
+ Movie _deathMovie;
+ Movie _genoMovie;
+ NotificationCallBack _canyon1CallBack;
+ NotificationCallBack _canyon2CallBack;
+ NotificationCallBack _deathCallBack;
+ NotificationCallBack _genoCallBack;
+ Sound _musicLoop;
+ SoundFader _musicFader;
+ FuseFunction _musicFuse;
+
+ MusicTimerEvent _musicEvent;
+
+ Movie *_currentMovie;
+ NotificationCallBack *_currentCallBack;
+ short _canyonState;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/constants.h b/engines/pegasus/neighborhood/mars/constants.h
index 0a0ec521c8..528a3b8514 100644
--- a/engines/pegasus/neighborhood/mars/constants.h
+++ b/engines/pegasus/neighborhood/mars/constants.h
@@ -32,6 +32,12 @@ namespace Pegasus {
// Element Coordinates
+static const CoordType kPodScreenLeft = kNavAreaLeft + 88;
+static const CoordType kPodScreenTop = kNavAreaTop + 204;
+
+static const CoordType kPodSteerLeft = kNavAreaLeft + 212;
+static const CoordType kPodSteerTop = kNavAreaTop + 232;
+
static const CoordType kUndoHiliteLeft = kNavAreaLeft + 140;
static const CoordType kUndoHiliteTop = kNavAreaTop + 36;
@@ -99,6 +105,9 @@ static const CoordType kShuttleEnergyTop = 60;
static const CoordType kShuttleEnergyWidth = 252;
static const CoordType kShuttleEnergyHeight = 22;
+static const CoordType kShuttleSteerLeft = kShuttleWindowLeft + 136;
+static const CoordType kShuttleSteerTop = kShuttleWindowTop + 196;
+
static const CoordType kPlanetStartLeft = kShuttleWindowLeft;
static const CoordType kPlanetStartTop = kShuttleWindowTop + kShuttleWindowHeight;
@@ -130,11 +139,21 @@ static const TimeValue kShuttleSwingStart = 0;
static const TimeValue kShuttleSwingStop = 5 * 600;
static const TimeValue kCanyonChaseStart = kShuttleSwingStop;
-static const TimeValue kCanyonChaseStop = 60 * 600 + 43 * 600 + 14 * 40;
-
-static const TimeValue kLaunchTubeReachedTime = 60 * 600 + 38 * 600 - kCanyonChaseStart;
-static const TimeValue kCanyonChaseFinishedTime = kCanyonChaseStop - kCanyonChaseStart -
- kLaunchTubeReachedTime;
+static const TimeValue kCanyonChaseCDStop = 60 * 600 + 43 * 600 + 14 * 40;
+static const TimeValue kCanyonChaseDVDStop = 60 * 600 + 50 * 600 + 12 * 40;
+
+static const TimeValue kCanyonChaseExitedTime = 60 * 600 + 40 * 600 + 13 * 40 - kCanyonChaseStart;
+static const TimeValue kCanyonChaseFadedTime = 60 * 600 + 43 * 600 + 6 * 40 - kCanyonChaseStart -
+ kCanyonChaseExitedTime;
+
+static const TimeValue kLaunchTubeCDReachedTime = 60 * 600 + 38 * 600 - kCanyonChaseStart;
+static const TimeValue kLaunchTubeDVDReachedTime = 60 * 600 + 45 * 600 - kCanyonChaseStart -
+ kCanyonChaseExitedTime - kCanyonChaseFadedTime;
+static const TimeValue kCanyonChaseCDFinishedTime = kCanyonChaseCDStop - kCanyonChaseStart -
+ kLaunchTubeCDReachedTime;
+static const TimeValue kCanyonChaseDVDFinishedTime = kCanyonChaseDVDStop - kCanyonChaseStart -
+ kCanyonChaseExitedTime - kCanyonChaseFadedTime -
+ kLaunchTubeDVDReachedTime;
// Left shuttle.
@@ -183,6 +202,8 @@ static const TimeValue kShuttleLowerLeftTubeTime = 40;
static const TimeValue kShuttleLowerLeftAutopilotTime = 80;
+static const TimeValue kShuttleLowerLeftKeypadHintTime = 120;
+
// Lower Right shuttle.
static const TimeValue kShuttleLowerRightOffTime = 0;
@@ -929,6 +950,11 @@ static const ExtraID kMarsMaze184WestLoop = 109;
static const ExtraID kMarsMaze184WestDeath = 110;
static const ExtraID kMars200DeathInBucket = 111;
+// Mars interactions.
+
+static const InteractionID kMarsTunnelPodInteractionID = 0;
+static const InteractionID kMarsCanyonChaseInteractionID = 1;
+
static const ResIDType kReactorUndoHilitePICTID = 900;
static const int16 kMars52Compass = 90;
diff --git a/engines/pegasus/neighborhood/mars/mars.cpp b/engines/pegasus/neighborhood/mars/mars.cpp
index 2350be1a17..8f5104ff4c 100644
--- a/engines/pegasus/neighborhood/mars/mars.cpp
+++ b/engines/pegasus/neighborhood/mars/mars.cpp
@@ -25,16 +25,20 @@
#include "common/events.h"
#include "video/qt_decoder.h"
+#include "video/theora_decoder.h"
#include "pegasus/cursor.h"
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/items/biochips/shieldchip.h"
#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/mars/canyonchase.h"
#include "pegasus/neighborhood/mars/mars.h"
+#include "pegasus/neighborhood/mars/tunnelpod.h"
namespace Pegasus {
@@ -44,6 +48,10 @@ static const int16 kMarsShieldPanelOffsetAngle = 22;
static const CanMoveForwardReason kCantMoveRobotBlocking = kCantMoveLastReason + 1;
+static const ExtraID kMarsTurnOnSteerPod = 1000;
+static const ExtraID kMarsRobotBobSlow = 1001;
+static const ExtraID kMarsRobotGenoSlow = 1002;
+
static const NotificationFlags kTimeForCanyonChaseFlag = kLastNeighborhoodNotificationFlag << 1;
static const NotificationFlags kExplosionFinishedFlag = kTimeForCanyonChaseFlag << 1;
static const NotificationFlags kTimeToTransportFlag = kExplosionFinishedFlag << 1;
@@ -52,6 +60,13 @@ static const NotificationFlags kMarsNotificationFlags = kTimeForCanyonChaseFlag
kExplosionFinishedFlag |
kTimeToTransportFlag;
+static const TimeValue kBucketClimbInTime = 1393980;
+static const TimeValue kBucketSeeGearRoomTime = 2240;
+static const TimeValue kBucketClimbOutTime = 1340;
+
+static const TimeValue kPodCautionDisplayedTime = 1631;
+static const TimeValue kPodCautionDismissedTime = 3889;
+
static const TimeValue kLittleExplosionStart = 0 * 40;
static const TimeValue kLittleExplosionStop = 24 * 40;
@@ -90,7 +105,7 @@ void MarsTimerEvent::fire() {
}
Mars::Mars(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Mars", kMarsID),
- _guessObject(kNoDisplayElement), _undoPict(kNoDisplayElement), _guessHistory(kNoDisplayElement),
+ _extraMovie(kNoDisplayElement), _guessObject(kNoDisplayElement), _undoPict(kNoDisplayElement), _guessHistory(kNoDisplayElement),
_choiceHighlight(kNoDisplayElement), _shuttleInterface1(kNoDisplayElement), _shuttleInterface2(kNoDisplayElement),
_shuttleInterface3(kNoDisplayElement), _shuttleInterface4(kNoDisplayElement), _canyonChaseMovie(kNoDisplayElement),
_leftShuttleMovie(kNoDisplayElement), _rightShuttleMovie(kNoDisplayElement), _lowerLeftShuttleMovie(kNoDisplayElement),
@@ -134,12 +149,25 @@ void Mars::init() {
_neighborhoodNotification.notifyMe(this, kMarsNotificationFlags, kMarsNotificationFlags);
+ _extraMovieCallBack.setNotification(&_neighborhoodNotification);
+
_explosionCallBack.setNotification(&_neighborhoodNotification);
_explosionCallBack.setCallBackFlag(kExplosionFinishedFlag);
_weaponSelection = kNoWeapon;
}
+GameInteraction *Mars::makeInteraction(const InteractionID interactionID) {
+ switch (interactionID) {
+ case kMarsTunnelPodInteractionID:
+ return new TunnelPod(this);
+ case kMarsCanyonChaseInteractionID:
+ return new CanyonChase(this);
+ default:
+ return NULL;
+ }
+}
+
void Mars::flushGameState() {
g_energyMonitor->saveCurrentEnergyValue();
}
@@ -152,6 +180,71 @@ void Mars::start() {
Neighborhood::start();
}
+class ArthurOxygen50Action : public AIPlayMessageAction {
+public:
+ ArthurOxygen50Action();
+
+ virtual void performAIAction(AIRule *);
+};
+
+ArthurOxygen50Action::ArthurOxygen50Action() : AIPlayMessageAction("Images/AI/Mars/XMMAZB1", false, kWarningInterruption) {
+}
+
+void ArthurOxygen50Action::performAIAction(AIRule *rule) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (GameState.isTakenItemID(kArthurBiochip) && g_arthurChip && vm->isChattyArthur())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA84", kArthurMarsOxygen50Warning);
+ else
+ AIPlayMessageAction::performAIAction(rule);
+}
+
+class ArthurOxygen25Action : public AIPlayMessageAction {
+public:
+ ArthurOxygen25Action();
+
+ virtual void performAIAction(AIRule *);
+};
+
+ArthurOxygen25Action::ArthurOxygen25Action() : AIPlayMessageAction("Images/AI/Mars/XMMAZB2", false, kWarningInterruption) {
+}
+
+void ArthurOxygen25Action::performAIAction(AIRule *rule) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (GameState.isTakenItemID(kArthurBiochip) && g_arthurChip && vm->isChattyArthur()) {
+ if (vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA85", kArthurMarsOxygen25Warning);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA87", kArthurMarsOxygen25Warning);
+ } else {
+ AIPlayMessageAction::performAIAction(rule);
+ }
+}
+
+class ArthurOxygen5Action : public AIPlayMessageAction {
+public:
+ ArthurOxygen5Action();
+
+ virtual void performAIAction(AIRule *);
+};
+
+ArthurOxygen5Action::ArthurOxygen5Action() : AIPlayMessageAction("Images/AI/Mars/XMMAZB3", false, kWarningInterruption) {
+}
+
+void ArthurOxygen5Action::performAIAction(AIRule *rule) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (GameState.isTakenItemID(kArthurBiochip) && g_arthurChip && vm->isChattyArthur()) {
+ if (vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA86", kArthurMarsOxygen5Warning);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA88", kArthurMarsOxygen5Warning);
+ } else {
+ AIPlayMessageAction::performAIAction(rule);
+ }
+}
+
class AirMaskCondition : public AICondition {
public:
AirMaskCondition(const uint32);
@@ -218,12 +311,18 @@ void Mars::setUpAIRules() {
g_AIArea->addAIRule(rule);
AirMaskCondition *airMask50Condition = new AirMaskCondition(50);
- messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB1", false);
+ if (_vm->isDVD())
+ messageAction = new ArthurOxygen50Action();
+ else
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB1", false);
AIRule *rule50 = new AIRule(airMask50Condition, messageAction);
AirMaskCondition *airMask25Condition = new AirMaskCondition(25);
AICompoundAction *compound = new AICompoundAction();
- messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB2", false);
+ if (_vm->isDVD())
+ messageAction = new ArthurOxygen25Action();
+ else
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB2", false);
compound->addAction(messageAction);
deactivate = new AIDeactivateRuleAction(rule50);
compound->addAction(deactivate);
@@ -231,7 +330,10 @@ void Mars::setUpAIRules() {
AirMaskCondition *airMask5Condition = new AirMaskCondition(5);
compound = new AICompoundAction;
- messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB3", false);
+ if (_vm->isDVD())
+ messageAction = new ArthurOxygen5Action();
+ else
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB3", false);
compound->addAction(messageAction);
deactivate = new AIDeactivateRuleAction(rule50);
compound->addAction(deactivate);
@@ -412,8 +514,155 @@ void Mars::cantMoveThatWay(CanMoveForwardReason reason) {
}
void Mars::moveForward() {
- if (GameState.getCurrentRoom() == kMars02 || (GameState.getCurrentRoom() >= kMars05 && GameState.getCurrentRoom() <= kMars08))
+ if (GameState.getCurrentRoom() == kMars02 || (GameState.getCurrentRoom() >= kMars05 && GameState.getCurrentRoom() <= kMars08)) {
loadLoopSound2("");
+ } else if (_vm->isDVD()) {
+ Movie movie(kNoDisplayElement);
+ Input input;
+
+ if (!GameState.isTakenItemID(kCardBomb) &&
+ GameState.getCurrentRoom() == kMars60 &&
+ GameState.getCurrentDirection() == kWest) {
+ loadLoopSound1("");
+ loadLoopSound2("");
+ movie.initFromMovieFile("Images/Mars/MMbomb.mov");
+ movie.setVolume(_vm->getSoundFXLevel());
+ movie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ movie.setDisplayOrder(kNavMovieOrder + 1);
+ movie.startDisplaying();
+ movie.show();
+ movie.start();
+
+ while (movie.isRunning() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ if (_vm->shouldQuit())
+ return;
+
+ movie.moveElementTo(0, 0);
+ _vm->_gfx->setCurSurface(_navMovie.getSurface());
+ movie.copyToCurrentPort();
+ _vm->_gfx->setCurSurface(_vm->_gfx->getWorkArea());
+
+ movie.hide();
+ movie.stopDisplaying();
+ movie.releaseMovie();
+
+ didntFindBomb();
+ return;
+ } else if (!GameState.getWalkthroughMode() &&
+ GameState.getCurrentRoom() == kMarsMaze200 &&
+ GameState.getCurrentDirection() == kWest) {
+ ExitTable::Entry exitEntry;
+ Common::Rect pushBounds;
+ bool leavingBucket;
+
+ // Fall down the shaft immediately if we miss the climb-in
+ if (_navMovie.getTime() >= kBucketClimbInTime) {
+ _navMovie.stop();
+
+ movie.initFromMovieFile("Images/Mars/MMfall.mov");
+ movie.setVolume(_vm->getSoundFXLevel());
+ movie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ movie.setDisplayOrder(kNavMovieOrder + 1);
+ movie.startDisplaying();
+ movie.show();
+ movie.start();
+
+ while (movie.isRunning() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ if (_vm->shouldQuit())
+ return;
+
+ movie.moveElementTo(0, 0);
+ _vm->_gfx->setCurSurface(_navMovie.getSurface());
+ movie.copyToCurrentPort();
+ _vm->_gfx->setCurSurface(_vm->_gfx->getWorkArea());
+
+ movie.hide();
+ movie.stopDisplaying();
+ movie.releaseMovie();
+
+ die(kDeathMissedOreBucket);
+ return;
+ }
+
+ canMoveForward(exitEntry);
+
+ leavingBucket = false;
+ _navMovie.stop();
+ _turnPush.getBounds(pushBounds);
+ _navMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _navMovie.show();
+ _navMovie.setFlags(0);
+
+ // Set segment so we can skip ahead as needed
+ // Ride up the shaft but don't try to get out
+ _navMovie.setSegment(exitEntry.movieStart, exitEntry.movieEnd - kBucketClimbOutTime);
+ _navMovie.setTime(exitEntry.movieStart);
+ _navMovie.start();
+ while (_navMovie.isRunning() && _navMovie.getTime() < exitEntry.movieEnd - kBucketSeeGearRoomTime) {
+ InputDevice.getInput(input, kFilterAllDirections);
+
+ if (input.upButtonDown() ||
+ input.downButtonDown() ||
+ input.leftButtonDown() ||
+ input.rightButtonDown()) {
+ _navMovie.stop();
+ _vm->getDeathSound().initFromAIFFFile("Sounds/Mars/Mars Maze Fall.AIFF");
+ _vm->getDeathSound().setVolume(_vm->getSoundFXLevel());
+ _vm->getDeathSound().playSound();
+ die(kDeathMissedOreBucket);
+ return;
+ }
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ // We can see the gear room at this point so it's safe to try to get out
+ _navMovie.setTime(exitEntry.movieEnd - kBucketSeeGearRoomTime);
+ while (_navMovie.isRunning()) {
+ InputDevice.getInput(input, kFilterAllDirections);
+
+ if (input.upButtonAnyDown()) {
+ leavingBucket = true;
+ } else if (input.anyDirectionInput()) {
+ _navMovie.stop();
+ _vm->getDeathSound().initFromAIFFFile("Sounds/Mars/Mars Maze Fall.AIFF");
+ _vm->getDeathSound().setVolume(_vm->getSoundFXLevel());
+ _vm->getDeathSound().playSound();
+ die(kDeathMissedOreBucket);
+ return;
+ }
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+ _navMovie.stop();
+
+ if (leavingBucket) {
+ exitEntry.movieStart = exitEntry.movieEnd - kBucketClimbOutTime;
+ startExitMovie(exitEntry);
+ } else {
+ playDeathExtra(kMars200DeathInBucket, kDeathDidntLeaveBucket);
+ }
+ return;
+ }
+ }
Neighborhood::moveForward();
}
@@ -735,6 +984,88 @@ void Mars::checkAirlockDoors() {
}
}
+void Mars::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
+ Movie movie(kNoDisplayElement);
+ Input input;
+
+ if (_vm->isDVD() && GameState.getCurrentRoomAndView() == MakeRoomView(kMars18, kNorth) &&
+ GameState.getMarsPodAtUpperPlatform()) {
+ movie.initFromMovieFile("Images/Mars/M45DF.movie");
+ movie.setVolume(_vm->getSoundFXLevel());
+ movie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ movie.setDisplayOrder(kNavMovieOrder + 1);
+ movie.startDisplaying();
+ movie.show();
+ movie.start();
+
+ while (movie.isRunning() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ if (_vm->shouldQuit())
+ return;
+
+ movie.moveElementTo(0, 0);
+ _vm->_gfx->setCurSurface(_navMovie.getSurface());
+ movie.copyToCurrentPort();
+ _vm->_gfx->setCurSurface(_vm->_gfx->getWorkArea());
+
+ movie.hide();
+ movie.stopDisplaying();
+ movie.releaseMovie();
+
+ Neighborhood::doorOpened();
+ } else {
+ Neighborhood::startDoorOpenMovie(startTime, stopTime);
+ }
+}
+
+void Mars::startExitMovie(const ExitTable::Entry &exitEntry) {
+ Movie movie(kNoDisplayElement);
+ Input input;
+
+ if (_vm->isDVD() && GameState.getCurrentRoomAndView() == MakeRoomView(kMars18, kNorth) &&
+ GameState.getMarsPodAtUpperPlatform()) {
+ movie.initFromMovieFile("Images/Mars/M45DG.movie");
+ movie.setVolume(_vm->getSoundFXLevel());
+ movie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ movie.setDisplayOrder(kNavMovieOrder + 1);
+ movie.startDisplaying();
+ movie.show();
+ movie.start();
+
+ while (movie.isRunning() && !_vm->shouldQuit()) {
+ InputDevice.getInput(input, kFilterNoInput);
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ if (_vm->shouldQuit())
+ return;
+
+ movie.moveElementTo(0, 0);
+ _vm->_gfx->setCurSurface(_navMovie.getSurface());
+ movie.copyToCurrentPort();
+ _vm->_gfx->setCurSurface(_vm->_gfx->getWorkArea());
+
+ movie.hide();
+ movie.stopDisplaying();
+ movie.releaseMovie();
+
+ arriveAt(kMars32, kNorth);
+ } else {
+ Neighborhood::startExitMovie(exitEntry);
+ }
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kMars43, kEast) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA07", kArthurMarsEnteredShuttle);
+}
+
int16 Mars::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
int16 angle = Neighborhood::getStaticCompassAngle(room, dir);
@@ -906,33 +1237,78 @@ void Mars::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &co
}
void Mars::loadAmbientLoops() {
+ // Don't load an ambient loop if we died in a chase sequence
+ if (_vm->getEnergyDeathReason() == kDeathRanIntoCanyonWall || _vm->getEnergyDeathReason() == kDeathCollidedWithPod)
+ return;
+
RoomID room = GameState.getCurrentRoom();
if ((room >= kMars0A && room <= kMars21) || (room >= kMars41 && room <= kMars43)) {
- if (GameState.getMarsSeenTimeStream())
- loadLoopSound1("Sounds/Mars/Gantry Ambient.22K.8.AIFF");
+ if (GameState.getMarsSeenTimeStream()) {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Gantry Ambient.32K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Gantry Ambient.22K.8.AIFF");
+ }
} else if (room >= kMars22 && room <= kMars31South) {
- loadLoopSound1("Sounds/Mars/Reception.02.22K.8.AIFF", 0x100 / 4);
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Reception.02.32K.16.AIFF", 0x100 / 4);
+ else
+ loadLoopSound1("Sounds/Mars/Reception.02.22K.8.AIFF", 0x100 / 4);
} else if (room >= kMars32 && room <= kMars34) {
- loadLoopSound1("Sounds/Mars/Pod Room Ambient.22K.8.AIFF");
- } else if (room == kMars35) {
- if (getAirQuality(room) == kAirQualityVacuum)
- loadLoopSound1("Sounds/Mars/Gear Room Ambient.22K.8.AIFF");
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Pod Room Ambient.32K.16.AIFF");
else
- loadLoopSound1("Sounds/Mars/Gantry Ambient.22K.8.AIFF", 0x100 / 2);
+ loadLoopSound1("Sounds/Mars/Pod Room Ambient.22K.8.AIFF");
+ } else if (room == kMars35) {
+ if (getAirQuality(room) == kAirQualityVacuum) {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Gear Room Ambient.44K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Gear Room Ambient.22K.8.AIFF");
+ } else {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Gantry Ambient.32K.16.AIFF", 0x100 / 2);
+ else
+ loadLoopSound1("Sounds/Mars/Gantry Ambient.22K.8.AIFF", 0x100 / 2);
+ }
} else if (room >= kMars36 && room <= kMars39) {
- loadLoopSound1("Sounds/Mars/Gear Room Ambient.22K.8.AIFF");
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Gear Room Ambient.44K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Gear Room Ambient.22K.8.AIFF");
} else if (room >= kMars45 && room <= kMars51) {
- loadLoopSound1("Sounds/Mars/Lower Mars Ambient.22K.8.AIFF");
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Lower Mars Ambient.32K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Lower Mars Ambient.22K.8.AIFF");
} else if (room >= kMars52 && room <= kMars58) {
- loadLoopSound1("Sounds/Mars/ReactorLoop.22K.8.AIFF");
- } else if (room == kMars60) {
- if (getAirQuality(room) == kAirQualityVacuum)
- loadLoopSound1("Sounds/Mars/Mars Maze Ambient.22K.8.AIFF");
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/ReactorLoop.44K.16.AIFF");
else
- loadLoopSound1("Sounds/Mars/Lower Mars Ambient.22K.8.AIFF", 0x100 / 2);
+ loadLoopSound1("Sounds/Mars/ReactorLoop.22K.8.AIFF");
+ } else if (room == kMars60) {
+ if (getAirQuality(room) == kAirQualityVacuum) {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Mars Maze Ambient.32K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Mars Maze Ambient.22K.8.AIFF");
+ } else {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/Mars/Lower Mars Ambient.32K.16.AIFF", 0x100 / 2);
+ else
+ loadLoopSound1("Sounds/Mars/Lower Mars Ambient.22K.8.AIFF", 0x100 / 2);
+ }
} else if (room >= kMarsMaze004 && room <= kMarsMaze200) {
- loadLoopSound1("Sounds/Mars/Mars Maze Ambient.22K.8.AIFF");
+ if (_vm->isDVD()) { // Updated for the DVD version
+ if (GameState.getEasterEgg() || room == kMarsMaze200 ||
+ (room == kMarsMaze199 && GameState.getCurrentDirection() == kWest))
+ loadLoopSound1("Sounds/Mars/Mars Maze Ambient.32K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Mars Maze GenoLoop.32K.16.AIFF");
+ } else {
+ loadLoopSound1("Sounds/Mars/Mars Maze Ambient.22K.8.AIFF");
+ }
} else if (room == kMarsRobotShuttle) {
loadLoopSound1("Sounds/Mars/Robot Shuttle.22K.8.AIFF");
}
@@ -1163,6 +1539,9 @@ void Mars::timerExpired(const uint32 eventType) {
}
void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
+ Input input;
+ InventoryItem *item;
+
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kMars18, kNorth):
if (GameState.getMarsPodAtUpperPlatform())
@@ -1175,6 +1554,14 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
else
setCurrentAlternate(kAltMarsNormal);
break;
+ case MakeRoomView(kMars31South, kSouth):
+ if (!GameState.isTakenItemID(kMarsCard) && g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA05", kArthurMarsZoomedToKeyCard);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA96", kArthurMarsZoomedToKeyCard);
+ }
+ break;
case MakeRoomView(kMars35, kEast):
case MakeRoomView(kMars35, kWest):
if (GameState.getMarsAirlockOpen())
@@ -1188,6 +1575,8 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
setCurrentAlternate(kAltMars60AirlockEast);
else
setCurrentAlternate(kAltMars60AirlockWest);
+ if (!(g_airMask && g_airMask->getAirLeft() > 0) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurMarsInAirlockNoOxygen);
break;
case MakeRoomView(kMars45, kNorth):
case MakeRoomView(kMars45, kSouth):
@@ -1208,6 +1597,12 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
setCurrentAlternate(kAltMarsNormal);
else
setCurrentAlternate(kAltMarsPodAtMars45);
+ if (g_arthurChip && room == kMars46) {
+ if (direction == kEast && !GameState.isTakenItemID(kCrowbar))
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA34", kArthurMarsLeftPodNoCrowBar);
+ else if (direction == kWest && GameState.getMarsPodAtUpperPlatform())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA82", kArthurMarsLookAtEmptyTracks);
+ }
break;
case MakeRoomView(kMars48, kNorth):
case MakeRoomView(kMars48, kSouth):
@@ -1229,6 +1624,16 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
else
setCurrentAlternate(kAltMarsNormal);
break;
+ case MakeRoomView(kMarsMaze004, kWest):
+ if (_vm->isDVD() && GameState.getCurrentRoom() == kMars60) {
+ InputDevice.getInput(input, kFilterAllInput);
+ // Check easter egg modifier for the Geno mix
+ if (JMPPPInput::isEasterEggModifierInput(input))
+ GameState.setEasterEgg(true);
+ else
+ GameState.setEasterEgg(false);
+ }
+ break;
default:
break;
}
@@ -1242,6 +1647,11 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
if (!GameState.getMarsSeenTimeStream())
startExtraLongSequence(kMarsArrivalFromTSA, kMars0AWatchShuttleDepart, kExtraCompletedFlag, kFilterNoInput);
break;
+ case MakeRoomView(kMars07, kNorth):
+ item = (InventoryItem *)g_allItems.findItemByID(kNitrogenCanister);
+ if (((g_airMask && g_airMask->getAirLeft() > 0) || item->getItemState() == kNitrogenFull) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA24", kArthurMarsSawWelcomeVideos);
+ break;
case MakeRoomView(kMars07, kSouth):
case MakeRoomView(kMars13, kNorth):
if (!GameState.getMarsHeardCheckInMessage()) {
@@ -1249,6 +1659,11 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
GameState.setMarsHeardCheckInMessage(true);
}
break;
+ case MakeRoomView(kMars41, kEast):
+ case MakeRoomView(kMars42, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA73", kArthurMarsFoundNoShuttlePresent);
+ break;
case MakeRoomView(kMars44, kWest):
if (GameState.getMarsReadyForShuttleTransport())
startUpFromFinishedSpaceChase();
@@ -1264,6 +1679,8 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
case MakeRoomView(kMars11, kSouth):
case MakeRoomView(kMars12, kSouth):
setCurrentActivation(kActivationReadyForKiosk);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurMarsReadyForKiosk);
break;
case MakeRoomView(kMars15, kWest):
if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown()) {
@@ -1288,8 +1705,11 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
case MakeRoomView(kMars19, kNorth):
case MakeRoomView(kMars19, kSouth):
case MakeRoomView(kMars19, kWest):
- if (GameState.getMarsThreadedMaze() && !GameState.getMarsSawRobotLeave())
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSawRobotLeave()) {
forceStridingStop(kMars19, kWest, kAltMarsNormal);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA38", kArthurMarsExitedGearRoom);
+ }
if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown())
forceStridingStop(kMars17, kWest, kAltMarsNormal);
@@ -1340,8 +1760,24 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
setCurrentActivation(kActivateReadyToPressurizeAirlock);
break;
case MakeRoomView(kMars39, kWest):
- if (GameState.getLastRoom() == kMarsMaze200)
+ if (GameState.getLastRoom() == kMarsMaze200) {
GameState.setMarsPodAtUpperPlatform(false);
+ if (_vm->isDVD())
+ GameState.setEasterEgg(false);
+ }
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB40", kArthurMarsEnteredGearRoom);
+ break;
+ case MakeRoomView(kMars39, kNorth):
+ case MakeRoomView(kMars39, kSouth):
+ case MakeRoomView(kMars38, kNorth):
+ case MakeRoomView(kMars38, kSouth):
+ case MakeRoomView(kMars37, kNorth):
+ case MakeRoomView(kMars37, kSouth):
+ case MakeRoomView(kMars36, kNorth):
+ case MakeRoomView(kMars36, kSouth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA83", kArthurMarsLookAtGears);
break;
case MakeRoomView(kMars45, kSouth):
// Set up maze doors here.
@@ -1357,7 +1793,19 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
if (!GameState.getMarsSeenRobotAtReactor()) {
// Preload the looping sound...
loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0, 0, 0);
- startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ if (!_vm->isDVD()) {
+ startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ InputDevice.getInput(input, kFilterAllInput);
+ if (JMPPPInput::isEasterEggModifierInput(input)) {
+ if (_vm->getRandomBit())
+ startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMarsRobotBobSlow, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ startExtraSequence(kMarsRobotGenoSlow, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
} else if (!GameState.getMarsAvoidedReactorRobot()) {
loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0x100, 0, 0);
loopExtraSequence(kMars48RobotLoops);
@@ -1397,10 +1845,14 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
g_shield->setItemState(kShieldNormal);
g_energyMonitor->setEnergyDrainRate(kEnergyDrainNormal);
_vm->resetEnergyDeathReason();
+ if (GameState.isTakenItemID(kCardBomb) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA78", kArthurMarsExitedReactorWithCardBomb);
break;
+ case MakeRoomView(kMars52, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA11", kArthurMarsEnteredReactor);
case MakeRoomView(kMars52, kNorth):
case MakeRoomView(kMars52, kSouth):
- case MakeRoomView(kMars52, kEast):
case MakeRoomView(kMars52, kWest):
case MakeRoomView(kMars54, kNorth):
case MakeRoomView(kMars54, kSouth):
@@ -1442,6 +1894,10 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
case MakeRoomView(kMarsMaze007, kNorth):
launchMaze007Robot();
break;
+ case MakeRoomView(kMarsMaze009, kWest):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA20", kArthurMarsMazeReachedJunction);
+ break;
case MakeRoomView(kMarsMaze015, kSouth):
launchMaze015Robot();
break;
@@ -1464,6 +1920,18 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
GameState.setScoringThreadedMaze();
GameState.setMarsThreadedMaze(true);
break;
+ case MakeRoomView(kMarsMaze199, kWest):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA77", kArthurMarsFoundBuckets);
+ break;
+ case MakeRoomView(kMarsMaze200, kWest):
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA10", kArthurMarsApproachedBuckets);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA76", kArthurMarsApproachedBuckets);
+ }
+ break;
case MakeRoomView(kMarsDeathRoom, kNorth):
case MakeRoomView(kMarsDeathRoom, kSouth):
case MakeRoomView(kMarsDeathRoom, kEast):
@@ -1495,6 +1963,8 @@ void Mars::shieldOff() {
}
void Mars::turnTo(const DirectionConstant direction) {
+ Input input;
+
switch (MakeRoomView(GameState.getCurrentRoom(), direction)) {
case MakeRoomView(kMars27, kNorth):
case MakeRoomView(kMars27, kSouth):
@@ -1522,6 +1992,8 @@ void Mars::turnTo(const DirectionConstant direction) {
case MakeRoomView(kMars11, kSouth):
case MakeRoomView(kMars12, kSouth):
setCurrentActivation(kActivationReadyForKiosk);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurMarsReadyForKiosk);
break;
case MakeRoomView(kMars18, kNorth):
if (GameState.getMarsPodAtUpperPlatform())
@@ -1533,6 +2005,11 @@ void Mars::turnTo(const DirectionConstant direction) {
GameState.setMarsHeardCheckInMessage(true);
}
break;
+ case MakeRoomView(kMars41, kEast):
+ case MakeRoomView(kMars42, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA73", kArthurMarsFoundNoShuttlePresent);
+ break;
case MakeRoomView(kMars34, kSouth):
case MakeRoomView(kMars45, kNorth):
setCurrentActivation(kActivateMarsPodClosed);
@@ -1558,6 +2035,21 @@ void Mars::turnTo(const DirectionConstant direction) {
if (GameState.getMarsThreadedMaze())
GameState.setScoringThreadedGearRoom();
break;
+ case MakeRoomView(kMars39, kNorth):
+ case MakeRoomView(kMars39, kSouth):
+ case MakeRoomView(kMars38, kNorth):
+ case MakeRoomView(kMars38, kSouth):
+ case MakeRoomView(kMars37, kNorth):
+ case MakeRoomView(kMars37, kSouth):
+ case MakeRoomView(kMars36, kNorth):
+ case MakeRoomView(kMars36, kSouth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA83", kArthurMarsLookAtGears);
+ break;
+ case MakeRoomView(kMars46, kWest):
+ if (GameState.getMarsPodAtUpperPlatform() && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA82", kArthurMarsLookAtEmptyTracks);
+ break;
case MakeRoomView(kMars48, kNorth):
if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot())
die(kDeathDidntGetOutOfWay);
@@ -1566,7 +2058,19 @@ void Mars::turnTo(const DirectionConstant direction) {
if (!GameState.getMarsSeenRobotAtReactor()) {
// Preload the looping sound...
loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0, 0, 0);
- startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ if (!_vm->isDVD()) {
+ startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ InputDevice.getInput(input, kFilterAllInput);
+ if (JMPPPInput::isEasterEggModifierInput(input)) {
+ if (_vm->getRandomBit())
+ startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMarsRobotBobSlow, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ startExtraSequence(kMarsRobotGenoSlow, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
} else if (!GameState.getMarsAvoidedReactorRobot()) {
loopExtraSequence(kMars48RobotLoops);
} else if (GameState.isTakenItemID(kAirMask)) {
@@ -1582,6 +2086,8 @@ void Mars::turnTo(const DirectionConstant direction) {
setCurrentAlternate(kAltMarsTookMask);
else
setCurrentAlternate(kAltMarsNormal);
+ if (GameState.isTakenItemID(kCardBomb) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA78", kArthurMarsExitedReactorWithCardBomb);
break;
case MakeRoomView(kMars49, kSouth):
if (GameState.isTakenItemID(kAirMask))
@@ -1589,6 +2095,11 @@ void Mars::turnTo(const DirectionConstant direction) {
else
setCurrentActivation(kActivateMaskOnHolder);
break;
+ case MakeRoomView(kMars51, kWest):
+ case MakeRoomView(kMars50, kWest):
+ if (GameState.isTakenItemID(kCardBomb) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA78", kArthurMarsExitedReactorWithCardBomb);
+ break;
case MakeRoomView(kMars52, kNorth):
case MakeRoomView(kMars52, kSouth):
case MakeRoomView(kMars52, kEast):
@@ -1628,6 +2139,23 @@ void Mars::turnTo(const DirectionConstant direction) {
case MakeRoomView(kMarsMaze184, kWest):
launchMaze184Robot();
break;
+ case MakeRoomView(kMarsMaze199, kNorth):
+ case MakeRoomView(kMarsMaze199, kSouth):
+ case MakeRoomView(kMarsMaze199, kEast):
+ case MakeRoomView(kMarsMaze199, kWest):
+ if (_vm->isDVD())
+ loadAmbientLoops();
+ if (GameState.getCurrentDirection() == kWest && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA77", kArthurMarsFoundBuckets);
+ break;
+ case MakeRoomView(kMarsMaze200, kWest):
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA10", kArthurMarsApproachedBuckets);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA76", kArthurMarsApproachedBuckets);
+ }
+ break;
default:
break;
}
@@ -1940,7 +2468,8 @@ void Mars::pickedUpItem(Item *item) {
case kAirMask:
setCurrentActivation(kActivateHotSpotAlways);
if (!GameState.getScoringGotOxygenMask()) {
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XM48SB", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XM48SB", false, kWarningInterruption);
GameState.setScoringGotOxygenMask();
}
break;
@@ -2005,13 +2534,25 @@ void Mars::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
switch (item->getObjectID()) {
case kMarsCard:
Neighborhood::dropItemIntoRoom(item, dropSpot);
- if (dropSpot && dropSpot->getObjectID() == kMars34NorthCardDropSpotID)
- startExtraSequence(kMarsTurnOnPod, kExtraCompletedFlag, kFilterNoInput);
+ if (dropSpot && dropSpot->getObjectID() == kMars34NorthCardDropSpotID) {
+ if (_vm->isDVD()) {
+ if (!GameState.getWalkthroughMode())
+ startExtraSequence(kMarsTurnOnSteerPod, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMarsTurnOnPod, kExtraCompletedFlag, kFilterNoInput);
+ startMarsTimer(kPodCautionDisplayedTime, kMovieTicksPerSecond, kMarsPodCautionDisplayed);
+ } else {
+ startExtraSequence(kMarsTurnOnPod, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
break;
case kNitrogenCanister:
Neighborhood::dropItemIntoRoom(item, dropSpot);
- if (dropSpot && dropSpot->getObjectID() == kMars57DropNitrogenSpotID)
+ if (dropSpot && dropSpot->getObjectID() == kMars57DropNitrogenSpotID) {
startExtraSequence(kMars57FreezeLock, kExtraCompletedFlag, kFilterNoInput);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA19", kArthurMarsUsedLiquidNitrogen);
+ }
break;
case kCrowbar:
_utilityFuse.stopFuse();
@@ -2139,6 +2680,73 @@ void Mars::turnRight() {
}
}
+void Mars::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
+ TimeValue segmentStart = 0, segmentStop = 0;
+ bool loopSequence = false;
+ Common::Rect pushBounds;
+ NotificationFlags extraFlags;
+
+ switch (extraID) {
+ case kMarsTurnOnSteerPod:
+ case kMarsRobotBobSlow:
+ case kMarsRobotGenoSlow:
+ _turnPush.getBounds(pushBounds);
+
+ switch (extraID) {
+ case kMarsTurnOnSteerPod:
+ _extraMovie.initFromMovieFile("Images/Mars/M45OMK.movie");
+ break;
+ case kMarsRobotBobSlow:
+ _extraMovie.initFromMovieFile("Images/Mars/M48RSB.movie");
+ break;
+ case kMarsRobotGenoSlow:
+ _extraMovie.initFromMovieFile("Images/Mars/M48RSA.movie");
+ break;
+ default:
+ break;
+ }
+ segmentStart = 0;
+ segmentStop = _extraMovie.getDuration();
+ loopSequence = false;
+
+ _lastExtra = extraID;
+ _turnPush.hide();
+
+ if (!loopSequence && g_AIArea)
+ g_AIArea->lockAIOut();
+
+ extraFlags = flags;
+ _interruptionFilter = interruptionFilter;
+ // Stop the nav movie before doing anything else
+ _navMovie.stop();
+ _navMovie.stopDisplaying();
+
+ _extraMovie.setVolume(_vm->getSoundFXLevel());
+ _extraMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _extraMovie.setDisplayOrder(kNavMovieOrder + 1);
+ _extraMovie.startDisplaying();
+ _extraMovie.show();
+ _extraMovie.setFlags(0);
+ _extraMovie.setSegment(segmentStart, segmentStop);
+ _extraMovie.setTime(segmentStart);
+ if (loopSequence)
+ _extraMovie.setFlags(kLoopTimeBase);
+ else
+ extraFlags |= kNeighborhoodMovieCompletedFlag;
+ _extraMovieCallBack.cancelCallBack();
+ _extraMovieCallBack.initCallBack(&_extraMovie, kCallBackAtExtremes);
+ if (extraFlags != 0) {
+ _extraMovieCallBack.setCallBackFlag(extraFlags);
+ _extraMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+ _extraMovie.start();
+ break;
+ default:
+ Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+ break;
+ }
+}
+
void Mars::receiveNotification(Notification *notification, const NotificationFlags flag) {
InventoryItem *item;
@@ -2164,6 +2772,8 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
kMarsPodDepartedUpperPlatformOut);
GameState.setMarsHeardUpperPodMessage(true);
}
+ if (g_airMask && g_airMask->getAirLeft() > 0 && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA74", kArthurMarsRobotThrownPlayerWithMask);
break;
case kMarsInfoKioskIntro:
GameState.setScoringSawMarsKiosk();
@@ -2195,12 +2805,15 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
}
break;
case kMarsTurnOnPod:
- item = (InventoryItem *)_vm->getAllItems().findItemByID(kMarsCard);
- _vm->addItemToInventory(item);
- GameState.setScoringTurnedOnTransport();
- loadLoopSound1("");
- loadLoopSound2("");
- startExtraSequence(kMarsTakePodToMars45, kExtraCompletedFlag, kFilterNoInput);
+ if (!_vm->isDVD()) {
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kMarsCard);
+ _vm->addItemToInventory(item);
+ GameState.setScoringTurnedOnTransport();
+ loadLoopSound1("");
+ loadLoopSound2("");
+ }
+ if (!_vm->isDVD() || GameState.getWalkthroughMode())
+ startExtraSequence(kMarsTakePodToMars45, kExtraCompletedFlag, kFilterNoInput);
break;
case kMarsTakePodToMars45:
arriveAt(kMars45, kSouth);
@@ -2223,6 +2836,12 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
checkAirMask();
loadAmbientLoops();
break;
+ case kMarsRobotBobSlow:
+ case kMarsRobotGenoSlow:
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ // Fall through...
case kMars48RobotApproaches:
loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0x100, 0, 0);
GameState.setMarsSeenRobotAtReactor(true);
@@ -2250,6 +2869,12 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
setCurrentActivation(kActivateMaskOnFiller);
setCurrentAlternate(kAltMarsMaskOnFiller);
GameState.setMarsMaskOnFiller(true);
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA13", kArthurMarsCantFillMask);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA80", kArthurMarsCantFillMask);
+ }
break;
case kMars58SpinLeft:
case kMars54SpinRight:
@@ -2298,6 +2923,14 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
setCurrentActivation(kActivateReactorAskLowerScreen);
break;
case kMars57LowerScreenClosed:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kNitrogenCanister);
+ if (g_arthurChip) {
+ if (item->getItemState() == kNitrogenFull)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA12", kArthurMarsSawLockedPanel);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurMarsSawLockedPanelNoNitrogen);
+ }
+ // Fall through...
case kMars57ThawLock:
setCurrentActivation(kActivateReactorReadyForNitrogen);
GameState.setMarsLockFrozen(false);
@@ -2334,6 +2967,12 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
case kMars57RunDiagnostics:
setCurrentActivation(kActivateReactorRanDiagnostics);
GameState.setScoringFoundCardBomb();
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA73", kArthurMarsFoundCardBomb);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB34", kArthurMarsFoundCardBomb);
+ }
break;
case kMars57BombExplodes:
case kMars57BombExplodesInGame:
@@ -2361,11 +3000,16 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
case kMars57ExposeBomb:
setCurrentActivation(kActivateReactorBombExposed);
_privateFlags.setFlag(kMarsPrivateBombExposedFlag, true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA75", kArthurMarsDeactivatedCardBomb);
break;
case kMars57BackToNormal:
setCurrentActivation(kActivateReactorPlatformIn);
_privateFlags.setFlag(kMarsPrivateBombExposedFlag, false);
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XM51SW", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XM51SW", false, kWarningInterruption);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA02", kArthurMarsSolvedReactorGame);
break;
case kMars60WestSpinAirlockToEast:
GameState.setMarsAirlockOpen(true);
@@ -2387,6 +3031,19 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
break;
case kMarsRobotHeadOpen:
setCurrentActivation(kActivationRobotHeadOpen);
+ if (g_arthurChip) {
+ switch (_vm->getRandomNumber(2)) {
+ case 0:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA36", kArthurMarsRobotHeadOpen);
+ break;
+ case 1:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA37", kArthurMarsRobotHeadOpen);
+ break;
+ case 2:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA40", kArthurMarsRobotHeadOpen);
+ break;
+ }
+ }
break;
case kMarsRobotHeadClose:
recallToTSASuccess();
@@ -2417,12 +3074,12 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
_rightDamageShuttleMovie.hide();
playMovieSegment(&_rightShuttleMovie, kShuttleRightDestroyedStart, kShuttleRightDestroyedStop);
playSpotSoundSync(kShuttleDestroyedIn, kShuttleDestroyedOut);
- throwAwayMarsShuttle();
+ transportOutFromSpaceChase(true);
reinstateMonocleInterface();
recallToTSASuccess();
}
} else if ((flag & kTimeToTransportFlag) != 0) {
- transportToRobotShip();
+ transportOutFromSpaceChase(false);
}
if (g_AIArea)
@@ -2432,11 +3089,42 @@ void Mars::receiveNotification(Notification *notification, const NotificationFla
void Mars::spotCompleted() {
Neighborhood::spotCompleted();
- if (GameState.getCurrentRoom() == kMarsRobotShuttle)
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XN59WD", false, kWarningInterruption);
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars27, kNorth):
+ case MakeRoomView(kMars28, kNorth):
+ if (g_arthurChip) {
+ switch (_vm->getRandomNumber(2)) {
+ case 0:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA09", kArthurMarsLookedAtGuards);
+ break;
+ case 1:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA81", kArthurMarsLookedAtGuards);
+ break;
+ case 2:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB32", kArthurMarsLookedAtGuards);
+ break;
+ }
+ }
+ break;
+ case MakeRoomView(kMarsRobotShuttle, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA79", kArthurMarsFoundDeadRobot);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XN59WD", false, kWarningInterruption);
+ break;
+ }
+}
+
+void Mars::startUpFromFinishedTunnelPod() {
+ arriveAt(kMars45, kSouth);
+ if (g_AIArea != NULL)
+ g_AIArea->checkMiddleArea();
}
void Mars::doCanyonChase() {
+ Input input;
+ FaderMoveSpec spec;
+
GameState.setScoringEnteredShuttle();
setNextHandler(_vm);
throwAwayInterface();
@@ -2447,9 +3135,24 @@ void Mars::doCanyonChase() {
_spotSounds.initFromQuickTime(getSoundSpotsName());
_spotSounds.setVolume(_vm->getSoundFXLevel());
- Video::VideoDecoder *video = new Video::QuickTimeDecoder();
- if (!video->loadFile("Images/Mars/M44ESA.movie"))
- error("Could not load interface->shuttle transition video");
+ Video::VideoDecoder *video = 0;
+
+#ifdef USE_THEORADEC
+ if (_vm->isDVD()) {
+ video = new Video::TheoraDecoder();
+
+ if (!video->loadFile("Images/Mars/M44ESA_hq.ogg")) {
+ delete video;
+ video = 0;
+ }
+ }
+#endif
+
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile("Images/Mars/M44ESA.movie"))
+ error("Could not load interface->shuttle transition video");
+ }
video->setVolume(MIN<uint>(_vm->getSoundFXLevel(), 0xFF));
@@ -2482,11 +3185,18 @@ void Mars::doCanyonChase() {
initOnePicture(&_shuttleInterface4, "Images/Mars/MCmain4.pict", kShuttleBackgroundOrder, kShuttle4Left,
kShuttle4Top, true);
- initOneMovie(&_canyonChaseMovie, "Images/Mars/Canyon.movie",
+ if (_vm->isDVD())
+ initOneMovie(&_canyonChaseMovie, "Images/Mars/Canyon_hq1.mov",
+ kShuttleMonitorOrder, kShuttleWindowLeft, kShuttleWindowTop, true);
+ else
+ initOneMovie(&_canyonChaseMovie, "Images/Mars/Canyon.movie",
kShuttleMonitorOrder, kShuttleWindowLeft, kShuttleWindowTop, true);
_canyonChaseMovie.setVolume(_vm->getSoundFXLevel());
- loadLoopSound1("Sounds/Mars/Inside Cockpit.22K.8.AIFF");
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Mars/Inside Cockpit.44K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Inside Cockpit.22K.8.AIFF");
// Swing shuttle around...
playMovieSegment(&_canyonChaseMovie, kShuttleSwingStart, kShuttleSwingStop);
@@ -2518,6 +3228,12 @@ void Mars::doCanyonChase() {
initOneMovie(&_rightDamageShuttleMovie, "Images/Mars/Right Damage Shuttle.movie",
kShuttleStatusOrder, kShuttleRightEnergyLeft, kShuttleRightEnergyTop, false);
+ if (_vm->isDVD()) {
+ _musicLoop.attachFader(&_musicFader);
+ _musicLoop.initFromAIFFFile("Sounds/Mars/Canyon Loop.44K.16.AIFF");
+ _musicFader.setMasterVolume(_vm->getAmbienceLevel());
+ }
+
_centerShuttleMovie.show();
_centerShuttleMovie.setTime(kShuttleCenterBoardingTime);
playSpotSoundSync(kShuttleCockpitIn, kShuttleCockpitOut);
@@ -2592,10 +3308,39 @@ void Mars::doCanyonChase() {
loadLoopSound1("");
- _canyonChaseMovie.setSegment(kCanyonChaseStart, kCanyonChaseStop);
- _canyonChaseMovie.start();
+ if (_vm->isDVD()) {
+ InputDevice.getInput(input, kFilterAllInput);
+ if (JMPPPInput::isEasterEggModifierInput(input)) {
+ GameState.setEasterEgg(true);
+ initOneMovie(&_canyonChaseMovie, "Images/Mars/Canyon_hqG.mov",
+ kShuttleMonitorOrder, kShuttleWindowLeft, kShuttleWindowTop, true);
+ _canyonChaseMovie.setVolume(_vm->getAmbienceLevel());
+ _canyonChaseMovie.start();
+
+ startMarsTimer(_canyonChaseMovie.getDuration() - 5 * kMovieTicksPerSecond,
+ kMovieTicksPerSecond, kMarsLaunchTubeReached);
+ } else if (GameState.getWalkthroughMode()) {
+ _canyonChaseMovie.setSegment(kCanyonChaseStart, kCanyonChaseDVDStop);
+ _canyonChaseMovie.start();
+
+ _musicLoop.loopSound();
+ spec.makeTwoKnotFaderSpec(10, 0, 0, 1, 255);
+ _musicFader.startFader(spec);
+
+ startMarsTimer(kCanyonChaseExitedTime, kMovieTicksPerSecond, kMarsCanyonChaseExited);
+ } else {
+ _canyonChaseMovie.stop();
+ _canyonChaseMovie.stopDisplaying();
+ _canyonChaseMovie.releaseMovie();
- startMarsTimer(kLaunchTubeReachedTime, kMovieTicksPerSecond, kMarsLaunchTubeReached);
+ newInteraction(kMarsCanyonChaseInteractionID);
+ }
+ } else {
+ _canyonChaseMovie.setSegment(kCanyonChaseStart, kCanyonChaseCDStop);
+ _canyonChaseMovie.start();
+
+ startMarsTimer(kLaunchTubeCDReachedTime, kMovieTicksPerSecond, kMarsLaunchTubeReached);
+ }
}
void Mars::startUpFromFinishedSpaceChase() {
@@ -2655,7 +3400,7 @@ void Mars::startUpFromFinishedSpaceChase() {
_lowerLeftShuttleMovie.show();
- loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+ playSpaceAmbient();
initOneMovie(&_junk, "Images/Mars/Junk.movie", kShuttleJunkOrder, kShuttleJunkLeft,
kShuttleJunkTop, false);
@@ -2766,7 +3511,7 @@ void Mars::startUpFromSpaceChase() {
_lowerLeftShuttleMovie.show();
- loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+ playSpaceAmbient();
initOneMovie(&_planetMovie, "Images/Mars/Planet.movie", kShuttlePlanetOrder,
kPlanetStartLeft, kPlanetStartTop, true);
@@ -2844,13 +3589,26 @@ void Mars::setSoundFXLevel(const uint16 level) {
!GameState.getMarsAvoidedReactorRobot())
_loop2Fader.setMasterVolume(level);
- if (_canyonChaseMovie.isMovieValid())
+ if (_extraMovie.isMovieValid())
+ _extraMovie.setVolume(level);
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kMars48, kEast) &&
+ !GameState.getMarsAvoidedReactorRobot())
+ _loop2Fader.setMasterVolume(level);
+ if (!GameState.getEasterEgg() && _canyonChaseMovie.isMovieValid())
_canyonChaseMovie.setVolume(level);
-
if (_explosions.isMovieValid())
_explosions.setVolume(level);
}
+void Mars::setAmbienceLevel(const uint16 level) {
+ Neighborhood::setAmbienceLevel(level);
+
+ if (GameState.getEasterEgg() && _canyonChaseMovie.isMovieValid())
+ _canyonChaseMovie.setVolume(level);
+ if (_musicLoop.isSoundLoaded())
+ _musicFader.setMasterVolume(level);
+}
+
void Mars::startMarsTimer(TimeValue time, TimeScale scale, MarsTimerCode code) {
_utilityFuse.primeFuse(time, scale);
_marsEvent.mars = this;
@@ -2860,37 +3618,72 @@ void Mars::startMarsTimer(TimeValue time, TimeScale scale, MarsTimerCode code) {
}
void Mars::marsTimerExpired(MarsTimerEvent &event) {
+ InventoryItem *item;
+ FaderMoveSpec spec;
Common::Rect r;
uint16 x, y;
switch (event.event) {
+ case kMarsPodCautionDisplayed:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kMarsCard);
+ _vm->addItemToInventory(item);
+ startMarsTimer(kPodCautionDismissedTime, kMovieTicksPerSecond, kMarsPodCautionDismissed);
+ return;
+ case kMarsPodCautionDismissed:
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ GameState.setScoringTurnedOnTransport();
+ loadLoopSound1("");
+ loadLoopSound2("");
+ if (!GameState.getWalkthroughMode())
+ newInteraction(kMarsTunnelPodInteractionID);
+ return;
+ // Bail out early for pod events so input is not filtered
+ case kMarsCanyonChaseExited:
+ spec.makeTwoKnotFaderSpec(20, 0, 255, 5, 160);
+ _musicFader.startFader(spec);
+ startMarsTimer(kCanyonChaseFadedTime, kMovieTicksPerSecond, kMarsCanyonChaseFaded);
+ break;
+ case kMarsCanyonChaseFaded:
+ spec.makeTwoKnotFaderSpec(10, 0, 160, 30, 0);
+ _musicFader.startFader(spec);
+ startMarsTimer(kLaunchTubeDVDReachedTime, kMovieTicksPerSecond, kMarsLaunchTubeReached);
+ break;
case kMarsLaunchTubeReached:
_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftTubeTime);
_lowerLeftShuttleMovie.redrawMovieWorld();
- startMarsTimer(kCanyonChaseFinishedTime, kMovieTicksPerSecond, kMarsCanyonChaseFinished);
+ startMarsTimer(kCanyonChaseCDFinishedTime, kMovieTicksPerSecond, kMarsCanyonChaseFinished);
break;
case kMarsCanyonChaseFinished:
GameState.setScoringEnteredLaunchTube();
+ GameState.setEasterEgg(false);
+
+ if (_canyonChaseMovie.isMovieValid()) {
+ while (_canyonChaseMovie.isRunning()) {
+ InputDevice.pumpEvents();
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
- while (_canyonChaseMovie.isRunning()) {
- InputDevice.pumpEvents();
- _vm->checkCallBacks();
- _vm->refreshDisplay();
- _vm->_system->delayMillis(10);
+ _canyonChaseMovie.stop();
+ _canyonChaseMovie.stopDisplaying();
+ _canyonChaseMovie.releaseMovie();
}
- _canyonChaseMovie.stop();
- _canyonChaseMovie.stopDisplaying();
- _canyonChaseMovie.releaseMovie();
-
_vm->_gfx->enableErase();
- loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+ playSpaceAmbient();
- playSpotSoundSync(kShuttleConfiguringIn, kShuttleConfiguringOut);
- playSpotSoundSync(kShuttleGeneratingIn, kShuttleGeneratingOut);
- playSpotSoundSync(kShuttleBreakawayIn, kShuttleBreakawayOut);
- playSpotSoundSync(kMarsAtmosphericBreakawayIn, kMarsAtmosphericBreakawayOut);
+ if (!_vm->isDVD()) {
+ // Don't play a couple sounds in the DVD version; they were put into
+ // the canyon video.
+ playSpotSoundSync(kShuttleConfiguringIn, kShuttleConfiguringOut);
+ playSpotSoundSync(kShuttleGeneratingIn, kShuttleGeneratingOut);
+ playSpotSoundSync(kShuttleBreakawayIn, kShuttleBreakawayOut);
+ playSpotSoundSync(kMarsAtmosphericBreakawayIn, kMarsAtmosphericBreakawayOut);
+ }
initOneMovie(&_planetMovie, "Images/Mars/Planet.movie", kShuttlePlanetOrder, kPlanetStartLeft, kPlanetStartTop, true);
_planetMovie.setFlags(kLoopTimeBase);
@@ -3077,13 +3870,44 @@ void Mars::throwAwayMarsShuttle() {
loadLoopSound1("");
}
-void Mars::transportToRobotShip() {
+void Mars::playSpaceAmbient() {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Mars/Space Ambient.44K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+}
+
+void Mars::transportOutFromSpaceChase(bool destroyedShip) {
throwAwayMarsShuttle();
- Video::VideoDecoder *video = new Video::QuickTimeDecoder();
- if (!video->loadFile("Images/Mars/M98EAE.movie"))
- error("Could not load shuttle->interface transition video");
+ Video::VideoDecoder *video = 0;
+#ifdef USE_THEORADEC
+ if (_vm->isDVD()) {
+ video = new Video::TheoraDecoder();
+
+ if (destroyedShip) {
+ if (!video->loadFile("Images/Mars/M98EAP_hq.ogg")) {
+ delete video;
+ video = 0;
+ }
+ } else if (!video->loadFile("Images/Mars/M98EAE_hq.ogg")) {
+ delete video;
+ video = 0;
+ }
+ }
+#endif
+
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (destroyedShip && _vm->isDVD()) {
+ if (!video->loadFile("Images/Mars/M98EAP.movie"))
+ error("Could not load shuttle->TSA transition video");
+ } else if (!video->loadFile("Images/Mars/M98EAE.movie"))
+ error("Could not load shuttle->interface transition video");
+ }
+
+ video->setVolume(MIN<uint>(_vm->getSoundFXLevel(), 0xFF));
video->start();
while (!_vm->shouldQuit() && !video->endOfVideo()) {
@@ -3104,18 +3928,20 @@ void Mars::transportToRobotShip() {
if (_vm->shouldQuit())
return;
- reinstateMonocleInterface();
+ if (!destroyedShip) {
+ reinstateMonocleInterface();
- g_energyMonitor->stopEnergyDraining();
- g_energyMonitor->restoreLastEnergyValue();
- _vm->resetEnergyDeathReason();
- g_energyMonitor->startEnergyDraining();
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
- arriveAt(kMarsRobotShuttle, kEast);
+ arriveAt(kMarsRobotShuttle, kEast);
- _navMovie.stop();
- _navMovie.setTime(_navMovie.getStart());
- _navMovie.start();
+ _navMovie.stop();
+ _navMovie.setTime(_navMovie.getStart());
+ _navMovie.start();
+ }
}
const int kRobotTooStrong = 1;
diff --git a/engines/pegasus/neighborhood/mars/mars.h b/engines/pegasus/neighborhood/mars/mars.h
index 0f07bb2d16..5459091a0d 100644
--- a/engines/pegasus/neighborhood/mars/mars.h
+++ b/engines/pegasus/neighborhood/mars/mars.h
@@ -40,10 +40,16 @@
namespace Pegasus {
+class CanyonChase;
class InventoryItem;
class Mars;
+class TunnelPod;
enum MarsTimerCode {
+ kMarsPodCautionDisplayed,
+ kMarsPodCautionDismissed,
+ kMarsCanyonChaseExited,
+ kMarsCanyonChaseFaded,
kMarsLaunchTubeReached,
kMarsCanyonChaseFinished,
kMarsSpaceChaseFinished // Player ran out of time...
@@ -64,11 +70,14 @@ enum ShuttleWeaponSelection {
};
class Mars : public Neighborhood {
+friend class CanyonChase;
+friend class TunnelPod;
friend struct MarsTimerEvent;
public:
Mars(InputHandler *, PegasusEngine *);
~Mars() override;
+ GameInteraction *makeInteraction(const InteractionID) override;
void flushGameState() override;
uint16 getDateResID() const override;
@@ -94,6 +103,7 @@ public:
void checkContinuePoint(const RoomID, const DirectionConstant) override;
void setSoundFXLevel(const uint16) override;
+ void setAmbienceLevel(const uint16) override;
bool canSolve() override;
void doSolve() override;
@@ -133,12 +143,16 @@ protected:
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void openDoor() override;
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
+ void startDoorOpenMovie(const TimeValue, const TimeValue) override;
+ void startExitMovie(const ExitTable::Entry &) override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &) override;
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
void turnTo(const DirectionConstant) override;
+ void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void doorOpened() override;
+ void startUpFromFinishedTunnelPod();
void setUpReactorEnergyDrain();
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void lockThawed();
@@ -170,6 +184,7 @@ protected:
void launchMaze136Robot();
void launchMaze184Robot();
void timerExpired(const uint32) override;
+ void showRobotAtReactor();
void spotCompleted() override;
void doCanyonChase(void);
@@ -178,13 +193,17 @@ protected:
void throwAwayMarsShuttle();
void startUpFromFinishedSpaceChase();
void startUpFromSpaceChase();
- void transportToRobotShip();
+ void transportOutFromSpaceChase(bool);
void spaceChaseClick(const Input &, const HotSpotID);
void updateCursor(const Common::Point, const Hotspot *) override;
+ void playSpaceAmbient();
Common::String getSoundSpotsName() override;
Common::String getNavMovieName() override;
+ Movie _extraMovie;
+ NotificationCallBack _extraMovieCallBack;
+
InventoryItem *_attackingItem;
FuseFunction _bombFuse;
FuseFunction _noAirFuse;
@@ -202,6 +221,8 @@ protected:
Picture _shuttleInterface3;
Picture _shuttleInterface4;
Movie _canyonChaseMovie;
+ Sound _musicLoop;
+ SoundFader _musicFader;
MarsTimerEvent _marsEvent;
diff --git a/engines/pegasus/neighborhood/mars/tunnelpod.cpp b/engines/pegasus/neighborhood/mars/tunnelpod.cpp
new file mode 100644
index 0000000000..61ba86cdd5
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/tunnelpod.cpp
@@ -0,0 +1,373 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
+#include "pegasus/neighborhood/mars/tunnelpod.h"
+#include "pegasus/neighborhood/mars/mars.h"
+
+namespace Pegasus {
+
+// Segment start and end points.
+
+static const TimeValue kLaunchStart = 315754;
+static const TimeValue kLaunchEnd = 319392;
+
+static const TimeValue kBranch1MainStart = 0;
+static const TimeValue kBranch1MainEnd = 3600;
+static const TimeValue kBranch2MainStart = kBranch1MainEnd;
+static const TimeValue kBranch2MainEnd = 13200;
+static const TimeValue kBranch3MainStart = kBranch2MainEnd;
+static const TimeValue kBranch3MainEnd = 20400;
+static const TimeValue kFinishMainStart = kBranch3MainEnd;
+static const TimeValue kFinishMainEnd = 30640;
+
+static const TimeValue kBranch2AltStart = 0;
+static const TimeValue kBranch2AltEnd = 13200;
+static const TimeValue kBranch3AltStart = kBranch2AltEnd;
+static const TimeValue kBranch3AltEnd = 22800;
+static const TimeValue kFinishAltStart = kBranch3AltEnd;
+static const TimeValue kFinishAltEnd = 33640;
+
+// Tunnel state.
+
+enum {
+ kTunnelLaunch,
+ kTunnelBranch1Left,
+ kTunnelBranch2Left,
+ kTunnelBranch2Right,
+ kTunnelBranch3Left,
+ kTunnelBranch3Right,
+ kTunnelFinish
+};
+
+
+TunnelPod::TunnelPod(Neighborhood *handler) : ChaseInteraction(kMarsTunnelPodInteractionID, handler,
+ kMarsTunnelPodNotificationID, (PegasusEngine *)g_engine), _tunnelMainMovie(kNoDisplayElement),
+ _tunnelAltMovie(kNoDisplayElement), _deathMovie(kNoDisplayElement) {
+ _currentMovie = NULL;
+ _currentCallBack = NULL;
+}
+
+void TunnelPod::setSoundFXLevel(const uint16 fxLevel) {
+ _tunnelMainMovie.setVolume(fxLevel);
+ _tunnelAltMovie.setVolume(fxLevel);
+ _deathMovie.setVolume(fxLevel);
+}
+
+void TunnelPod::openInteraction() {
+ ((Mars *)_owner)->_navMovie.stop();
+
+ _tunnelCallBack.setNotification(&_chaseNotification);
+ _tunnelCallBack.initCallBack(&((Mars *)_owner)->_navMovie, kCallBackAtExtremes);
+ _tunnelCallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _tunnelCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _tunnelMainMovie.initFromMovieFile("Images/Mars/Pod 2345M.mov");
+ _tunnelMainMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _tunnelMainMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _tunnelMainMovie.setDisplayOrder(kNavMovieOrder);
+
+ _tunnelMainCallBack.setNotification(&_chaseNotification);
+ _tunnelMainCallBack.initCallBack(&_tunnelMainMovie, kCallBackAtExtremes);
+ _tunnelMainCallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _tunnelMainCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _tunnelAltMovie.initFromMovieFile("Images/Mars/Pod 345A.mov");
+ _tunnelAltMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _tunnelAltMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _tunnelAltMovie.setDisplayOrder(kNavMovieOrder);
+
+ _tunnelAltCallBack.setNotification(&_chaseNotification);
+ _tunnelAltCallBack.initCallBack(&_tunnelAltMovie, kCallBackAtExtremes);
+ _tunnelAltCallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _tunnelAltCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _deathMovie.initFromMovieFile("Images/Mars/Pod 2D.mov");
+ _deathMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _deathMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _deathMovie.setDisplayOrder(kNavMovieOrder);
+
+ _deathCallBack.setNotification(&_chaseNotification);
+ _deathCallBack.initCallBack(&_deathMovie, kCallBackAtExtremes);
+ _deathCallBack.setCallBackFlag(kChaseFinished);
+ _deathCallBack.scheduleCallBack(kTriggerAtStop, 0 ,0);
+
+ ChaseInteraction::openInteraction();
+
+ _steerPict.setDisplayOrder(kNavMovieOrder + 1);
+ _steerPict.moveElementTo(kPodSteerLeft, kPodSteerTop);
+}
+
+void TunnelPod::initInteraction() {
+ _steerPict.startDisplaying();
+
+ _tunnelState = kTunnelLaunch;
+ ((Mars *)_owner)->_navMovie.setSegment(kLaunchStart, kLaunchEnd - kDecisionTime);
+ ((Mars *)_owner)->_navMovie.setTime(kLaunchStart);
+ ((Mars *)_owner)->_navMovie.start();
+ _currentMovie = &((Mars *)_owner)->_navMovie;
+ _currentCallBack = &_tunnelCallBack;
+ ChaseInteraction::initInteraction();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB27", kArthurMarsTurnedOnTransport);
+}
+
+void TunnelPod::closeInteraction() {
+ ((Mars *)_owner)->_navMovie.stop();
+ if (_tunnelState == kTunnelFinish) {
+ // Only bring nack the nav movie if we successfully finished the chase
+ ((Mars *)_owner)->_navMovie.startDisplaying();
+ ((Mars *)_owner)->_navMovie.show();
+ }
+ _tunnelCallBack.releaseCallBack();
+
+ _tunnelAltMovie.stop();
+ _tunnelAltMovie.stopDisplaying();
+ _tunnelAltMovie.releaseMovie();
+ _tunnelAltCallBack.releaseCallBack();
+
+ _deathMovie.stop();
+ _deathMovie.stopDisplaying();
+ _deathMovie.releaseMovie();
+ _deathCallBack.releaseCallBack();
+
+ ChaseInteraction::closeInteraction();
+}
+
+void TunnelPod::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if (notification == &_chaseNotification && flags == kChaseFinished) {
+ if (_tunnelState != kTunnelFinish) {
+ // We died
+ ((Mars *)_owner)->die(kDeathCollidedWithPod);
+ } else {
+ ((Mars *)_owner)->startUpFromFinishedTunnelPod();
+ }
+ }
+ ChaseInteraction::receiveNotification(notification, flags);
+}
+
+void TunnelPod::setUpBranch() {
+ TimeValue branchStart, branchEnd;
+
+ branchStart = 0;
+ branchEnd = 0;
+ switch (_tunnelState) {
+ case kTunnelLaunch:
+ branchStart = kLaunchEnd - kDecisionTime;
+ branchEnd = kLaunchEnd;
+ break;
+ case kTunnelBranch1Left:
+ branchStart = kBranch1MainEnd - kDecisionTime;
+ branchEnd = kBranch1MainEnd;
+ break;
+ case kTunnelBranch2Left:
+ branchStart = kBranch2AltEnd - kDecisionTime;
+ branchEnd = kBranch2AltEnd;
+ break;
+ case kTunnelBranch2Right:
+ branchStart = kBranch2MainEnd - kDecisionTime;
+ branchEnd = kBranch2MainEnd;
+ break;
+ case kTunnelBranch3Left:
+ branchStart = kBranch3MainEnd - kDecisionTime;
+ branchEnd = kBranch3MainEnd;
+ break;
+ case kTunnelBranch3Right:
+ branchStart = kBranch3AltEnd - kDecisionTime;
+ branchEnd = kBranch3AltEnd;
+ break;
+ default:
+ break;
+ }
+
+ _currentMovie->setSegment(branchStart, branchEnd);
+
+ _currentCallBack->setCallBackFlag(kChaseExitedBranchZone);
+ _currentCallBack->scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void TunnelPod::branchLeft() {
+ TimeValue branchStart, branchEnd;
+ NotificationFlags flag;
+ Movie *movie;
+ NotificationCallBack *callBack;
+
+ branchStart = 0;
+ branchEnd = 0;
+ flag = 0;
+ movie = NULL;
+ callBack = NULL;
+ switch (_tunnelState) {
+ case kTunnelLaunch:
+ branchStart = kBranch1MainStart;
+ branchEnd = kBranch1MainEnd - kDecisionTime;
+ _tunnelState = kTunnelBranch1Left;
+ flag = kChaseEnteredBranchZone;
+ movie = &_tunnelMainMovie;
+ callBack = &_tunnelMainCallBack;
+ break;
+ case kTunnelBranch1Left:
+ branchStart = kBranch2AltStart;
+ branchEnd = kBranch2AltEnd - kDecisionTime;
+ _tunnelState = kTunnelBranch2Left;
+ flag = kChaseEnteredBranchZone;
+ movie = &_tunnelAltMovie;
+ callBack = &_tunnelAltCallBack;
+ break;
+ case kTunnelBranch2Left:
+ case kTunnelBranch2Right:
+ branchStart = kBranch3MainStart;
+ branchEnd = kBranch3MainEnd - kDecisionTime;
+ _tunnelState = kTunnelBranch3Left;
+ flag = kChaseEnteredBranchZone;
+ movie = &_tunnelMainMovie;
+ callBack = &_tunnelMainCallBack;
+ break;
+ case kTunnelBranch3Left:
+ case kTunnelBranch3Right:
+ branchStart = kFinishAltStart;
+ branchEnd = kFinishAltEnd;
+ _tunnelState = kTunnelFinish;
+ flag = kChaseFinished;
+ movie = &_tunnelAltMovie;
+ callBack = &_tunnelAltCallBack;
+ break;
+ default:
+ break;
+ }
+
+ movie->setSegment(branchStart, branchEnd);
+ movie->setTime(branchStart);
+
+ switchTo(*movie, *callBack);
+
+ callBack->setCallBackFlag(flag);
+ callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void TunnelPod::branchRight() {
+ TimeValue branchStart, branchEnd;
+ NotificationFlags flag;
+ Movie *movie;
+ NotificationCallBack *callBack;
+
+ branchStart = 0;
+ branchEnd = 0;
+ flag = 0;
+ movie = NULL;
+ callBack = NULL;
+ switch (_tunnelState) {
+ case kTunnelLaunch:
+ switchTo(_deathMovie, _deathCallBack);
+ return;
+ case kTunnelBranch1Left:
+ branchStart = kBranch2MainStart;
+ branchEnd = kBranch2MainEnd - kDecisionTime;
+ _tunnelState = kTunnelBranch2Right;
+ flag = kChaseEnteredBranchZone;
+ movie = &_tunnelMainMovie;
+ callBack = &_tunnelMainCallBack;
+ break;
+ case kTunnelBranch2Left:
+ case kTunnelBranch2Right:
+ branchStart = kBranch3AltStart;
+ branchEnd = kBranch3AltEnd - kDecisionTime;
+ _tunnelState = kTunnelBranch3Right;
+ flag = kChaseEnteredBranchZone;
+ movie = &_tunnelAltMovie;
+ callBack = &_tunnelAltCallBack;
+ break;
+ case kTunnelBranch3Left:
+ case kTunnelBranch3Right:
+ branchStart = kFinishMainStart;
+ branchEnd = kFinishMainEnd;
+ _tunnelState = kTunnelFinish;
+ flag = kChaseFinished;
+ movie = &_tunnelMainMovie;
+ callBack = &_tunnelMainCallBack;
+ break;
+ default:
+ break;
+ }
+
+ movie->setSegment(branchStart, branchEnd);
+ movie->setTime(branchStart);
+
+ switchTo(*movie, *callBack);
+
+ callBack->setCallBackFlag(flag);
+ callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void TunnelPod::dontBranch() {
+ switch (_tunnelState) {
+ case kTunnelLaunch:
+ case kTunnelBranch1Left:
+ if (_currentMovie == &_tunnelAltMovie)
+ branchLeft();
+ else
+ branchRight();
+ break;
+ case kTunnelBranch2Left:
+ case kTunnelBranch2Right:
+ if (_currentMovie == &_tunnelAltMovie)
+ branchRight();
+ else
+ branchLeft();
+ break;
+ case kTunnelBranch3Left:
+ case kTunnelBranch3Right:
+ if (_currentMovie == &_tunnelAltMovie)
+ branchLeft();
+ else
+ branchRight();
+ break;
+ default:
+ break;
+ }
+}
+
+void TunnelPod::switchTo(Movie &movie, NotificationCallBack &callBack) {
+ if (_currentMovie != &movie) {
+ if (_currentMovie != NULL) {
+ _currentMovie->stop();
+ _currentMovie->hide();
+ _currentMovie->stopDisplaying();
+ }
+
+ _currentMovie = &movie;
+
+ _currentMovie->startDisplaying();
+ _currentMovie->show();
+ _currentMovie->start();
+ }
+
+ if (_currentCallBack != &callBack) {
+ _currentCallBack = &callBack;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/tunnelpod.h b/engines/pegasus/neighborhood/mars/tunnelpod.h
new file mode 100644
index 0000000000..75d842e282
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/tunnelpod.h
@@ -0,0 +1,76 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_TUNNELPOD_H
+#define PEGASUS_NEIGHBORHOOD_MARS_TUNNELPOD_H
+
+#include "pegasus/chase.h"
+#include "pegasus/movie.h"
+
+namespace Pegasus {
+
+class Mars;
+
+class TunnelPod : public ChaseInteraction {
+friend class Mars;
+friend struct MusicTimerEvent;
+public:
+
+ TunnelPod(Neighborhood *);
+ virtual ~TunnelPod() {}
+
+ void setSoundFXLevel(const uint16);
+
+protected:
+
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ void setUpBranch();
+ void branchLeft();
+ void branchRight();
+ void dontBranch();
+
+ void switchTo(Movie &, NotificationCallBack &);
+
+ Movie _tunnelMainMovie;
+ Movie _tunnelAltMovie;
+ Movie _deathMovie;
+ NotificationCallBack _tunnelCallBack;
+ NotificationCallBack _tunnelMainCallBack;
+ NotificationCallBack _tunnelAltCallBack;
+ NotificationCallBack _deathCallBack;
+
+ Movie *_currentMovie;
+ NotificationCallBack *_currentCallBack;
+ short _tunnelState;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp
index 0980240d40..a91431762f 100644
--- a/engines/pegasus/neighborhood/neighborhood.cpp
+++ b/engines/pegasus/neighborhood/neighborhood.cpp
@@ -36,6 +36,7 @@
#include "pegasus/interface.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/mapchip.h"
#include "pegasus/neighborhood/neighborhood.h"
#include "pegasus/neighborhood/tsa/fulltsa.h"
@@ -725,7 +726,15 @@ void Neighborhood::cantMoveThatWay(CanMoveForwardReason reason) {
}
void Neighborhood::cantOpenDoor(CanOpenDoorReason) {
+ bool firstLockedDoor;
+
bumpIntoWall();
+ if (g_arthurChip) {
+ firstLockedDoor = g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA31", kArthurAttemptedLockedDoor);
+
+ if (!firstLockedDoor)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA32", kArthurAttemptedLockedDoorAgain);
+ }
}
void Neighborhood::turnTo(const DirectionConstant direction) {
@@ -1010,9 +1019,9 @@ void Neighborhood::startExitMovie(const ExitTable::Entry &exitEntry) {
GameState.setNextDirection(exitEntry.exitDirection);
if (exitEntry.movieEnd == exitEntry.exitEnd) // Just a walk.
- startMovieSequence(exitEntry.movieStart, exitEntry.movieEnd, kMoveForwardCompletedFlag, kFilterNoInput, false);
+ startMovieSequence(exitEntry.movieStart, exitEntry.movieEnd, kMoveForwardCompletedFlag, false, kFilterNoInput);
else // We're stridin'!
- startMovieSequence(exitEntry.movieStart, exitEntry.exitEnd, kStrideCompletedFlag, kFilterNoInput, false, exitEntry.movieEnd);
+ startMovieSequence(exitEntry.movieStart, exitEntry.exitEnd, kStrideCompletedFlag, false, kFilterNoInput, exitEntry.movieEnd);
if (g_compass)
g_compass->startFader(compassMove);
@@ -1027,14 +1036,14 @@ void Neighborhood::startZoomMovie(const ZoomTable::Entry &zoomEntry) {
GameState.setNextRoom(zoomEntry.room);
GameState.setNextDirection(zoomEntry.direction);
- startMovieSequence(zoomEntry.movieStart, zoomEntry.movieEnd, kMoveForwardCompletedFlag, kFilterNoInput, false);
+ startMovieSequence(zoomEntry.movieStart, zoomEntry.movieEnd, kMoveForwardCompletedFlag, false, kFilterNoInput);
if (g_compass)
g_compass->startFader(compassMove);
}
void Neighborhood::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
- startMovieSequence(startTime, stopTime, kDoorOpenCompletedFlag, kFilterNoInput, false);
+ startMovieSequence(startTime, stopTime, kDoorOpenCompletedFlag, false, kFilterNoInput);
}
void Neighborhood::startTurnPush(const TurnDirection turnDirection, const TimeValue newView, const DirectionConstant nextDir) {
@@ -1195,7 +1204,7 @@ void Neighborhood::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *h
void Neighborhood::startSpotOnceOnly(TimeValue startTime, TimeValue stopTime) {
_turnPush.hide();
- startMovieSequence(startTime, stopTime, kSpotCompletedFlag, kFilterNoInput, false);
+ startMovieSequence(startTime, stopTime, kSpotCompletedFlag, false, kFilterNoInput);
}
void Neighborhood::startMovieSequence(const TimeValue startTime, const TimeValue stopTime, NotificationFlags flags, bool loopSequence,
@@ -1567,7 +1576,7 @@ void Neighborhood::startExtraLongSequence(const uint32 firstExtra, const uint32
getExtraEntry(lastExtra, lastEntry);
_lastExtra = firstExtra;
_turnPush.hide();
- startMovieSequence(firstEntry.movieStart, lastEntry.movieEnd, flags, kFilterNoInput, interruptionFilter);
+ startMovieSequence(firstEntry.movieStart, lastEntry.movieEnd, flags, false, interruptionFilter);
}
}
@@ -1583,6 +1592,7 @@ void Neighborhood::openCroppedMovie(const Common::String &movieName, CoordType l
void Neighborhood::loopCroppedMovie(const Common::String &movieName, CoordType left, CoordType top) {
openCroppedMovie(movieName, left, top);
+ _croppedMovie.setVolume(_vm->getSoundFXLevel());
_croppedMovie.redrawMovieWorld();
_croppedMovie.setFlags(kLoopTimeBase);
_croppedMovie.start();
@@ -1666,7 +1676,10 @@ void Neighborhood::handleInput(const Input &input, const Hotspot *cursorSpot) {
else if (input.rightButtonAnyDown())
rightButton(input);
}
-
+ if (_vm->toggleRequested()) {
+ _vm->requestToggle(false);
+ _vm->setChattyAI(!_vm->isChattyAI());
+ }
InputHandler::handleInput(input, cursorSpot);
}
diff --git a/engines/pegasus/neighborhood/neighborhood.h b/engines/pegasus/neighborhood/neighborhood.h
index 1d63a85821..adaa113fcc 100644
--- a/engines/pegasus/neighborhood/neighborhood.h
+++ b/engines/pegasus/neighborhood/neighborhood.h
@@ -292,7 +292,7 @@ protected:
virtual void createNeighborhoodSpots();
- void resetLastExtra() { _lastExtra = -1; }
+ void resetLastExtra() { _lastExtra = 0xffffffff; }
virtual void throwAwayInterface();
@@ -354,7 +354,7 @@ protected:
AlternateID _currentAlternate;
HotSpotActivationID _currentActivation;
- int32 _lastExtra;
+ ExtraID _lastExtra;
DeathReason _extraDeathReason;
// Graphics
diff --git a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
index 33d61c766e..46481a948d 100644
--- a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
@@ -24,6 +24,7 @@
*/
#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/alpha/ecrmonitor.h"
@@ -216,6 +217,9 @@ void NoradAlphaECRMonitor::closeInteraction() {
_ecrPan.stopDisplaying();
_ecrPan.releasePanorama();
_ecrPanCallBack.releaseCallBack();
+
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB33", kArthurNoradAtSecurityMonitor);
}
} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
index bc78fd9af9..e5c9063c31 100644
--- a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
@@ -25,6 +25,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/alpha/fillingstation.h"
@@ -194,6 +195,8 @@ void NoradAlphaFillingStation::splashFinished() {
void NoradAlphaFillingStation::intakeWarningFinished() {
setStaticState(kFSMainMenu, kMainMenu);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA29", kArthurNoradSawIntakeWarning);
}
void NoradAlphaFillingStation::showIntakeInProgress(uint16 numSeconds) {
diff --git a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
index fd8d19e362..d5e2dc4dc1 100644
--- a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
@@ -23,19 +23,27 @@
*
*/
+#include "pegasus/cursor.h"
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
+#include "pegasus/interface.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/subcontrolroom.h"
#include "pegasus/neighborhood/norad/alpha/ecrmonitor.h"
#include "pegasus/neighborhood/norad/alpha/fillingstation.h"
#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
+#include "pegasus/neighborhood/norad/alpha/subchase.h"
namespace Pegasus {
+static const ExtraID kShowThermalScan = 1000;
+
+static const HotSpotID kThermalScanHotSpotID = 10000;
+
const uint32 NoradAlpha::_noradAlphaClawExtras[22] = {
kN22ClawFromAToB,
kN22ClawALoop,
@@ -61,7 +69,9 @@ const uint32 NoradAlpha::_noradAlphaClawExtras[22] = {
kN22ClawDClockwise
};
-NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner) : Norad(nextHandler, owner, "Norad Alpha", kNoradAlphaID) {
+NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner)
+ : Norad(nextHandler, owner, "Norad Alpha", kNoradAlphaID),
+ _thermalScanSpot(kThermalScanHotSpotID), _extraMovie(kNoDisplayElement) {
_elevatorUpRoomID = kNorad11South;
_elevatorDownRoomID = kNorad12South;
_elevatorUpSpotID = kNorad12ElevatorUpSpotID;
@@ -82,10 +92,10 @@ NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner) : Norad(
_lowerPressureDoorDownSpotID = kAlphaLowerPressureDoorDownSpotID;
_lowerPressureDoorAbortSpotID = kNorad21WestOutSpotID;
- _pressureSoundIn = kPressureDoorIntro1In;
- _pressureSoundOut = kPressureDoorIntro1Out;
- _equalizeSoundIn = kPressureDoorIntro2In;
- _equalizeSoundOut = kPressureDoorIntro2Out;
+ _pressureSoundIn = kAlphaPressureDoorIntro1In;
+ _pressureSoundOut = kAlphaPressureDoorIntro1Out;
+ _equalizeSoundIn = kAlphaPressureDoorIntro2In;
+ _equalizeSoundOut = kAlphaPressureDoorIntro2Out;
_accessDeniedIn = kAlphaAccessDeniedIn;
_accessDeniedOut = kAlphaAccessDeniedOut;
@@ -98,9 +108,22 @@ NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner) : Norad(
setIsItemTaken(kGasCanister);
}
+NoradAlpha::~NoradAlpha() {
+ if (_vm->isDVD())
+ _vm->getAllHotspots().remove(&_thermalScanSpot);
+}
+
void NoradAlpha::init() {
Norad::init();
+ _extraMovieCallBack.setNotification(&_neighborhoodNotification);
+
+ if (_vm->isDVD()) {
+ _thermalScanSpot.setArea(Common::Rect(216, 112, 336, 312));
+ _thermalScanSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_thermalScanSpot);
+ }
+
Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(kN01GasCanisterSpotID);
hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kN01GasCanisterSpotID);
@@ -209,7 +232,7 @@ void NoradAlpha::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSp
}
void NoradAlpha::playClawMonitorIntro() {
- playSpotSoundSync(kLoadClawIntroIn, kLoadClawIntroOut);
+ playSpotSoundSync(kAlphaLoadClawIntroIn, kAlphaLoadClawIntroOut);
}
GameInteraction *NoradAlpha::makeInteraction(const InteractionID interactionID) {
@@ -218,6 +241,8 @@ GameInteraction *NoradAlpha::makeInteraction(const InteractionID interactionID)
return new NoradAlphaECRMonitor(this);
case kNoradFillingStationInteractionID:
return new NoradAlphaFillingStation(this);
+ case kNoradSubChaseInteractionID:
+ return new SubChase(this);
default:
break;
}
@@ -250,17 +275,27 @@ void NoradAlpha::loadAmbientLoops() {
play unmanned loop
*/
- if (!GameState.getNoradSeenTimeStream())
+ if (!GameState.getNoradSeenTimeStream() || !g_interface || _vm->getEnergyDeathReason() == kDeathSubDestroyed)
return;
RoomID room = GameState.getCurrentRoom();
if (GameState.getNoradGassed()) {
- if (room >= kNorad11 && room <= kNorad19West)
- loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
- else if (room >= kNorad21 && room <= kNorad22West)
- loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
- else
- loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
+ if (room >= kNorad11 && room <= kNorad19West) {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.44K.AIFF", kNoradWarningVolume * 3);
+ else
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
+ } else if (room >= kNorad21 && room <= kNorad22West) {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.32K.AIFF", kNoradWarningVolume * 3);
+ else
+ loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
+ } else {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/WARNING LOOP.32K.AIFF", kNoradWarningVolume);
+ else
+ loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
+ }
} else {
loadLoopSound1("");
}
@@ -322,8 +357,14 @@ void NoradAlpha::arriveAt(const RoomID room, const DirectionConstant direction)
case kNorad04:
arriveAtNorad04();
break;
+ case kNorad07:
+ if (_vm->isDVD() && GameState.getLastRoom() == kNorad06)
+ startExtraSequence(kShowThermalScan, kExtraCompletedFlag, kFilterNoInput);
+ break;
case kNorad07North:
GameState.setScoringSawUnconsciousOperator(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA70", kArthurNoradSawUnconsciousOperator);
break;
case kNorad11:
GameState.setScoringWentThroughPressureDoor(true);
@@ -337,11 +378,30 @@ void NoradAlpha::arriveAt(const RoomID room, const DirectionConstant direction)
}
void NoradAlpha::arriveAtNorad01() {
- if (!GameState.getNoradSeenTimeStream() && GameState.getCurrentDirection() == kSouth) {
- GameState.setNoradN22MessagePlayed(false);
- requestExtraSequence(kNoradArriveFromTSA, kExtraCompletedFlag, kFilterNoInput);
- // You are no match for me, human.
- requestExtraSequence(kNorad01RobotTaunt, kExtraCompletedFlag, kFilterNoInput);
+ Item *argonCanister, *nitrogenCanister;
+
+ switch (GameState.getCurrentDirection()) {
+ case kSouth:
+ if (!GameState.getNoradSeenTimeStream()) {
+ GameState.setNoradN22MessagePlayed(false);
+ requestExtraSequence(kNoradArriveFromTSA, kExtraCompletedFlag, kFilterNoInput);
+ // You are no match for me, human.
+ requestExtraSequence(kNorad01RobotTaunt, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kEast:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurNoradAtSecurityMonitor);
+ break;
+ case kWest:
+ if (GameState.getLastRoom() == kNorad01West) {
+ argonCanister = g_allItems.findItemByID(kArgonCanister);
+ nitrogenCanister = g_allItems.findItemByID(kNitrogenCanister);
+ if (((GameState.isTakenItemID(kArgonCanister) && argonCanister->getItemState() != kArgonFull) ||
+ (GameState.isTakenItemID(kNitrogenCanister) && nitrogenCanister->getItemState() != kNitrogenFull)) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA34", kArthurNoradDidntFillCanisters);
+ }
+ break;
}
}
@@ -366,20 +426,103 @@ void NoradAlpha::arriveAtNorad22() {
}
}
+void NoradAlpha::turnTo(const DirectionConstant direction) {
+ Norad::turnTo(direction);
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad01, kEast) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurNoradAtSecurityMonitor);
+}
+
void NoradAlpha::bumpIntoWall() {
requestSpotSound(kAlphaBumpIntoWallIn, kAlphaBumpIntoWallOut, kFilterNoInput, 0);
Neighborhood::bumpIntoWall();
}
+void NoradAlpha::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
+ TimeValue segmentStart = 0, segmentStop = 0;
+ bool loopSequence = false;
+ Common::Rect pushBounds;
+ NotificationFlags extraFlags;
+
+ switch (extraID) {
+ case kShowThermalScan:
+ _turnPush.getBounds(pushBounds);
+
+ switch (extraID) {
+ case kShowThermalScan:
+ _extraMovie.initFromMovieFile("Images/Norad Alpha/N07NS.movie");
+ segmentStart = 0;
+ segmentStop = _extraMovie.getDuration();
+ loopSequence = false;
+ break;
+ default:
+ break;
+ }
+
+ _lastExtra = extraID;
+ _turnPush.hide();
+
+ if (!loopSequence && g_AIArea)
+ g_AIArea->lockAIOut();
+
+ extraFlags = flags;
+ _interruptionFilter = interruptionFilter;
+ // Stop the nav movie before doing anything else
+ _navMovie.stop();
+ _navMovie.stopDisplaying();
+
+ _extraMovie.setVolume(_vm->getSoundFXLevel());
+ _extraMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _extraMovie.setDisplayOrder(kNavMovieOrder + 1);
+ _extraMovie.startDisplaying();
+ _extraMovie.show();
+ _extraMovie.setFlags(0);
+ _extraMovie.setSegment(segmentStart, segmentStop);
+ _extraMovie.setTime(segmentStart);
+ if (loopSequence)
+ _extraMovie.setFlags(kLoopTimeBase);
+ else
+ extraFlags |= kNeighborhoodMovieCompletedFlag;
+ _extraMovieCallBack.cancelCallBack();
+ _extraMovieCallBack.initCallBack(&_extraMovie, kCallBackAtExtremes);
+ if (extraFlags != 0) {
+ _extraMovieCallBack.setCallBackFlag(extraFlags);
+ _extraMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+ _extraMovie.start();
+ break;
+ default:
+ Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+ break;
+ }
+}
+
void NoradAlpha::receiveNotification(Notification *notification, const NotificationFlags flags) {
if ((flags & kExtraCompletedFlag) != 0) {
switch (_lastExtra) {
+ case kShowThermalScan:
+ _interruptionFilter = kFilterAllInput;
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ break;
+ case kNorad19ExitToSub:
+ if (_vm->isDVD()) {
+ _interruptionFilter = kFilterAllInput;
+ _vm->_cursor->hide();
+ setNextHandler(_vm);
+ throwAwayInterface();
+ loadLoopSound1("");
+ newInteraction(kNoradSubChaseInteractionID);
+ GameState.setScoringEnteredSub(true);
+ }
+ break;
case kNoradArriveFromTSA:
GameState.setNoradSeenTimeStream(true);
loadAmbientLoops();
break;
case kNorad01RobotTaunt:
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN01SB", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN01SB", false, kWarningInterruption);
_interruptionFilter = kFilterAllInput;
makeContinuePoint();
break;
@@ -398,11 +541,38 @@ void NoradAlpha::receiveNotification(Notification *notification, const Notificat
startExtraSequence(kNorad22SouthFinish, kExtraCompletedFlag, kFilterNoInput);
break;
case kNorad22SouthFinish:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB29", kArthurNoradSawSubMessage);
_interruptionFilter = kFilterAllInput;
// Force ArriveAt to do its thing...
GameState.setCurrentRoom(kNorad21);
arriveAt(kNorad22, kSouth);
break;
+ case kN22ClawFromAToB:
+ case kN22ClawAPinch:
+ case kN22ClawACounterclockwise:
+ case kN22ClawAClockwise:
+ case kN22ClawFromBToA:
+ case kN22ClawFromBToC:
+ case kN22ClawFromBToD:
+ case kN22ClawBPinch:
+ case kN22ClawBCounterclockwise:
+ case kN22ClawBClockwise:
+ case kN22ClawFromCToB:
+ case kN22ClawCPinch:
+ case kN22ClawCCounterclockwise:
+ case kN22ClawCClockwise:
+ case kN22ClawFromDToB:
+ case kN22ClawDPinch:
+ case kN22ClawDCounterclockwise:
+ case kN22ClawDClockwise:
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA64", kArthurNoradPlayedWithClaw);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA66", kArthurNoradPlayedWithClaw);
+ }
+ break;
default:
break;
}
@@ -501,10 +671,19 @@ TimeValue NoradAlpha::getViewTime(const RoomID room, const DirectionConstant dir
return Norad::getViewTime(room, direction);
}
+void NoradAlpha::setSoundFXLevel(const uint16 level) {
+ Neighborhood::setSoundFXLevel(level);
+
+ if (_extraMovie.isMovieValid())
+ _extraMovie.setVolume(level);
+}
+
void NoradAlpha::turnOnFillingStation() {
if (GameState.getCurrentRoom() == kNorad01West && !GameState.getNoradFillingStationOn()) {
GameState.setNoradFillingStationOn(true);
updateViewFrame();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA72", kArthurNoradSawFillingStation);
}
}
@@ -556,6 +735,10 @@ void NoradAlpha::activateHotspots() {
}
}
break;
+ case MakeRoomView(kNorad07, kNorth):
+ if (_vm->isDVD())
+ _vm->getAllHotspots().activateOneHotspot(kThermalScanHotSpotID);
+ break;
case MakeRoomView(kNorad10, kEast):
if (GameState.isCurrentDoorOpen())
_vm->getAllHotspots().deactivateOneHotspot(kNorad10DoorSpotID);
@@ -581,6 +764,9 @@ void NoradAlpha::clickInHotspot(const Input &input, const Hotspot *cursorSpot) {
hotspotEntry->hotspotItem = item->getObjectID();
}
}
+ } else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad07, kNorth) &&
+ cursorSpot->getObjectID() == kThermalScanHotSpotID) {
+ startExtraSequence(kShowThermalScan, kExtraCompletedFlag, kFilterNoInput);
}
}
diff --git a/engines/pegasus/neighborhood/norad/alpha/noradalpha.h b/engines/pegasus/neighborhood/norad/alpha/noradalpha.h
index 5c709b9723..97a154ad83 100644
--- a/engines/pegasus/neighborhood/norad/alpha/noradalpha.h
+++ b/engines/pegasus/neighborhood/norad/alpha/noradalpha.h
@@ -31,11 +31,13 @@
namespace Pegasus {
class Item;
+class SubChase;
class NoradAlpha : public Norad {
+friend class SubChase;
public:
NoradAlpha(InputHandler *, PegasusEngine *);
- ~NoradAlpha() override {}
+ ~NoradAlpha() override;
void init() override;
void start() override;
@@ -77,6 +79,8 @@ public:
void checkContinuePoint(const RoomID, const DirectionConstant) override;
+ void setSoundFXLevel(const uint16) override;
+
bool canSolve() override;
void doSolve() override;
@@ -90,6 +94,9 @@ protected:
virtual void arriveAtNorad22();
void arriveAt(const RoomID, const DirectionConstant) override;
+ void turnTo(const DirectionConstant) override;
+
+ void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void getZoomEntry(const HotSpotID, ZoomTable::Entry &) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
@@ -102,6 +109,11 @@ protected:
void bumpIntoWall() override;
+ Hotspot _thermalScanSpot;
+
+ Movie _extraMovie;
+ NotificationCallBack _extraMovieCallBack;
+
Item *_fillingStationItem;
bool _subPrepFailed;
diff --git a/engines/pegasus/neighborhood/norad/alpha/subchase.cpp b/engines/pegasus/neighborhood/norad/alpha/subchase.cpp
new file mode 100644
index 0000000000..36eb3d6780
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/subchase.cpp
@@ -0,0 +1,459 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/neighborhood/norad/alpha/subchase.h"
+#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
+#include "pegasus/neighborhood/norad/constants.h"
+
+namespace Pegasus {
+
+static const TimeScale kSubChaseScale = 600;
+
+static const DisplayOrder kSubChaseOrder = 27000;
+
+// Segment start and end points.
+
+static const TimeValue kIntroStart = 0;
+static const TimeValue kIntroEnd = 2400;
+static const TimeValue kDialogStart = kIntroEnd;
+static const TimeValue kDialogEnd = 20920;
+static const TimeValue kBranch1Start = kDialogEnd;
+static const TimeValue kBranch1End = 32120;
+static const TimeValue kBranch2LeftStart = kBranch1End;
+static const TimeValue kBranch2LeftEnd = 48080;
+static const TimeValue kBranch3Start = kBranch2LeftEnd;
+static const TimeValue kBranch3End = 61080;
+static const TimeValue kBranch4Start = kBranch3End;
+static const TimeValue kBranch4End = 84080;
+static const TimeValue kBranch5Start = kBranch4End;
+static const TimeValue kBranch5End = 94840;
+static const TimeValue kBranch6Start = kBranch5End;
+static const TimeValue kBranch6End = 106040;
+static const TimeValue kBranch7LeftStart = kBranch6End;
+static const TimeValue kBranch7LeftEnd = 118840;
+static const TimeValue kExitStart = kBranch7LeftEnd;
+static const TimeValue kExitEnd = 133200;
+static const TimeValue kBranch2RightStart = 133200;
+static const TimeValue kBranch2RightEnd = 149160;
+static const TimeValue kBranch7RightStart = 168000;
+static const TimeValue kBranch7RightEnd = 180800;
+
+// Death start and end points.
+
+static const TimeValue kDeath4Start = 149160;
+static const TimeValue kDeath4End = 158040;
+static const TimeValue kDeath5Start = kDeath4End;
+static const TimeValue kDeath5End = 163760;
+static const TimeValue kDeath6Start = kDeath5End;
+static const TimeValue kDeath6End = 168000;
+static const TimeValue kDeath7Start = 180800;
+static const TimeValue kDeath7End = 187040;
+
+// Chase state.
+
+enum {
+ kSubDialog,
+ kSubBranch1,
+ kSubBranch2Left,
+ kSubBranch2Right,
+ kSubBranch3,
+ kSubBranch4,
+ kSubBranch5,
+ kSubBranch6,
+ kSubBranch7Left,
+ kSubBranch7Right,
+ kSubExit
+};
+
+void HintTimerEvent::fire() {
+ subChase->hintTimerExpired(*this);
+}
+
+void BlinkTimerEvent::fire() {
+ subChase->blinkTimerExpired(*this);
+}
+
+SubChase::SubChase(Neighborhood *handler) : ChaseInteraction(kNoradSubChaseInteractionID, handler,
+ kNoradSubChaseNotificationID, (PegasusEngine *)g_engine), _subMovie(kNoDisplayElement),
+ _hintPict(kNoDisplayElement), _blinkPict(kNoDisplayElement), _canSteerSub(true) {
+}
+
+void SubChase::setSoundFXLevel(const uint16 fxLevel) {
+ _subMovie.setVolume(fxLevel);
+}
+
+void SubChase::openInteraction() {
+ _subMovie.initFromMovieFile("Images/Norad Alpha/Sub Chase Movie");
+ _subMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _subMovie.moveElementTo(0, 0);
+ _subMovie.setDisplayOrder(kSubChaseOrder);
+ _subMovie.startDisplaying();
+ _subMovie.show();
+
+ _subCallBack.setNotification(&_chaseNotification);
+ _subCallBack.initCallBack(&_subMovie, kCallBackAtExtremes);
+
+ ChaseInteraction::openInteraction();
+
+ _steerPict.setDisplayOrder(kSubChaseOrder + 1);
+ _steerPict.moveElementTo(kNoradSubSteerLeft, kNoradSubSteerTop);
+
+ _hintPict.initFromPICTFile("Images/Norad Alpha/Sub Chase steerk1.pict", true);
+ _hintPict.setDisplayOrder(kSubChaseOrder + 1);
+ _hintPict.moveElementTo(kNoradSubHintLeft, kNoradSubHintTop);
+ _blinkPict.initFromPICTFile("Images/Norad Alpha/Sub Chase steerk0.pict", true);
+ _blinkPict.setDisplayOrder(kSubChaseOrder + 1);
+ _blinkPict.moveElementTo(kNoradSubHintLeft, kNoradSubHintTop);
+}
+
+void SubChase::initInteraction() {
+ _canSteerSub = !GameState.getWalkthroughMode();
+
+ _owner->playMovieSegment(&_subMovie, kIntroStart, kIntroEnd);
+
+ _subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ if (_canSteerSub) {
+ _steerPict.startDisplaying();
+ _hintPict.startDisplaying();
+ _blinkPict.startDisplaying();
+ startHintTimer(20000 - kDialogStart, kSubChaseScale, kStartedHint);
+ _subCallBack.setCallBackFlag(kChaseEnteredBranchZone);
+ _subMovie.setSegment(kDialogStart, kBranch1End - kDecisionTime);
+ } else {
+ _subCallBack.setCallBackFlag(kChaseFinished);
+ _subMovie.setSegment(kDialogStart, kExitEnd);
+ }
+
+ _subState = kSubDialog;
+ _subMovie.setTime(kDialogStart);
+ _subMovie.start();
+
+ ChaseInteraction::initInteraction();
+}
+
+void SubChase::closeInteraction() {
+ _subMovie.stop();
+ _subMovie.stopDisplaying();
+ _subMovie.releaseMovie();
+ _subCallBack.releaseCallBack();
+
+ _hintPict.hide();
+ _hintPict.deallocateSurface();
+
+ _blinkPict.hide();
+ _blinkPict.deallocateSurface();
+
+ ChaseInteraction::closeInteraction();
+}
+
+void SubChase::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if (notification == &_chaseNotification && flags == kChaseFinished) {
+ if (_subState != kSubDialog && _subState != kSubExit) {
+ // We died
+ ((NoradAlpha *)_owner)->die(kDeathSubDestroyed);
+ } else {
+ _subMovie.stopDisplaying();
+ ((PegasusEngine *)g_engine)->_gfx->enableErase();
+ ((PegasusEngine *)g_engine)->_gfx->updateDisplay();
+ ((PegasusEngine *)g_engine)->_gfx->disableErase();
+ ((PegasusEngine *)g_engine)->jumpToNewEnvironment(kNoradDeltaID, kNorad41, kEast);
+ }
+ }
+ ChaseInteraction::receiveNotification(notification, flags);
+}
+
+void SubChase::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_subMovie.getTime() < kBranch1Start && input.anyInput()) {
+ if (_canSteerSub) {
+ if (!_blinkFuse.isFuseLit()) {
+ // If the hint is not blinking then it must not be running, so display it
+ _hintPict.show();
+ startBlinkTimer(10, 10, kEnteredBlinkState);
+ }
+ _subState = kSubBranch1;
+ startHintTimer(3000, kSubChaseScale, kEndedHint);
+ } else {
+ _subState = kSubExit;
+ }
+ _subMovie.setTime(kBranch1Start);
+ } else {
+ ChaseInteraction::handleInput(input, cursorSpot);
+ }
+}
+
+void SubChase::setUpBranch() {
+ TimeValue branchStart, branchEnd;
+
+ branchStart = 0;
+ branchEnd = 0;
+ switch (_subState) {
+ case kSubDialog:
+ case kSubBranch1:
+ branchStart = kBranch1End - kDecisionTime;
+ branchEnd = kBranch1End;
+ break;
+ case kSubBranch2Left:
+ branchStart = kBranch2LeftEnd - kDecisionTime;
+ branchEnd = kBranch2LeftEnd;
+ break;
+ case kSubBranch2Right:
+ branchStart = kBranch2RightEnd - kDecisionTime;
+ branchEnd = kBranch2RightEnd;
+ break;
+ case kSubBranch3:
+ branchStart = kBranch3End - kDecisionTime;
+ branchEnd = kBranch3End;
+ break;
+ case kSubBranch4:
+ branchStart = kBranch4End - kDecisionTime;
+ branchEnd = kBranch4End;
+ break;
+ case kSubBranch5:
+ branchStart = kBranch5End - kDecisionTime;
+ branchEnd = kBranch5End;
+ break;
+ case kSubBranch6:
+ branchStart = kBranch6End - kDecisionTime;
+ branchEnd = kBranch6End;
+ break;
+ case kSubBranch7Left:
+ branchStart = kBranch7LeftEnd - kDecisionTime;
+ branchEnd = kBranch7LeftEnd;
+ break;
+ case kSubBranch7Right:
+ branchStart = kBranch7RightEnd - kDecisionTime;
+ branchEnd = kBranch7RightEnd;
+ break;
+ default:
+ break;
+ }
+
+ _subMovie.setSegment(branchStart, branchEnd);
+
+ _subCallBack.setCallBackFlag(kChaseExitedBranchZone);
+ _subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void SubChase::branchLeft() {
+ TimeValue branchStart, branchEnd;
+ NotificationFlags flag;
+
+ branchStart = 0;
+ branchEnd = 0;
+ flag = 0;
+ switch (_subState) {
+ case kSubDialog:
+ case kSubBranch1:
+ branchStart = kBranch2LeftStart;
+ branchEnd = kBranch2LeftEnd;
+ // Don't show the controls hint when we approach the whale
+ // since the branch segments here are identical
+ flag = kChaseExitedBranchZone;
+ _subState = kSubBranch2Left;
+ break;
+ case kSubBranch2Left:
+ case kSubBranch2Right:
+ branchStart = kBranch3Start;
+ branchEnd = kBranch3End - kDecisionTime;
+ flag = kChaseEnteredBranchZone;
+ _subState = kSubBranch3;
+ break;
+ case kSubBranch3:
+ branchStart = kBranch4Start;
+ branchEnd = kBranch4End - kDecisionTime;
+ flag = kChaseEnteredBranchZone;
+ _subState = kSubBranch4;
+ break;
+ case kSubBranch4:
+ branchStart = kDeath5Start;
+ branchEnd = kDeath5End;
+ flag = kChaseFinished;
+ _subState = kSubBranch5;
+ break;
+ case kSubBranch5:
+ branchStart = kBranch6Start;
+ branchEnd = kBranch6End - kDecisionTime;
+ flag = kChaseEnteredBranchZone;
+ _subState = kSubBranch6;
+ break;
+ case kSubBranch6:
+ branchStart = kBranch7LeftStart;
+ branchEnd = kBranch7LeftEnd;
+ flag = kChaseExitedBranchZone;
+ _subState = kSubBranch7Left;
+ break;
+ case kSubBranch7Left:
+ case kSubBranch7Right:
+ branchStart = kExitStart;
+ branchEnd = kExitEnd;
+ flag = kChaseFinished;
+ _subState = kSubExit;
+ break;
+ default:
+ break;
+ }
+
+ _subMovie.setSegment(branchStart, branchEnd);
+ _subMovie.setTime(branchStart);
+
+ _subCallBack.setCallBackFlag(flag);
+ _subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void SubChase::branchRight() {
+ TimeValue branchStart, branchEnd;
+ NotificationFlags flag;
+
+ branchStart = 0;
+ branchEnd = 0;
+ flag = 0;
+ switch (_subState) {
+ case kSubDialog:
+ case kSubBranch1:
+ branchStart = kBranch2RightStart;
+ branchEnd = kBranch2RightEnd;
+ // Don't show the controls hint when we approach the whale
+ // since the branch segments here are identical
+ flag = kChaseExitedBranchZone;
+ _subState = kSubBranch2Right;
+ break;
+ case kSubBranch2Left:
+ case kSubBranch2Right:
+ branchStart = kBranch3Start;
+ branchEnd = kBranch3End - kDecisionTime;
+ flag = kChaseEnteredBranchZone;
+ _subState = kSubBranch3;
+ break;
+ case kSubBranch3:
+ branchStart = kDeath4Start;
+ branchEnd = kDeath4End;
+ flag = kChaseFinished;
+ _subState = kSubBranch4;
+ break;
+ case kSubBranch4:
+ branchStart = kBranch5Start;
+ branchEnd = kBranch5End - kDecisionTime;
+ flag = kChaseEnteredBranchZone;
+ _subState = kSubBranch5;
+ break;
+ case kSubBranch5:
+ branchStart = kDeath6Start;
+ branchEnd = kDeath6End;
+ flag = kChaseFinished;
+ _subState = kSubBranch6;
+ break;
+ case kSubBranch6:
+ if (((PegasusEngine *)g_engine)->getRandomBit()) {
+ branchStart = kBranch7RightStart;
+ branchEnd = kBranch7RightEnd;
+ flag = kChaseExitedBranchZone;
+ } else {
+ branchStart = kDeath7Start;
+ branchEnd = kDeath7End;
+ flag = kChaseFinished;
+ }
+ _subState = kSubBranch7Right;
+ break;
+ case kSubBranch7Left:
+ case kSubBranch7Right:
+ branchStart = kExitStart;
+ branchEnd = kExitEnd;
+ flag = kChaseFinished;
+ _subState = kSubExit;
+ break;
+ default:
+ break;
+ }
+
+ _subMovie.setSegment(branchStart, branchEnd);
+ _subMovie.setTime(branchStart);
+
+ _subCallBack.setCallBackFlag(flag);
+ _subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+}
+
+void SubChase::dontBranch() {
+ if (((PegasusEngine *)g_engine)->getRandomBit())
+ branchLeft();
+ else
+ branchRight();
+}
+
+void SubChase::startHintTimer(TimeValue time, TimeScale scale, HintTimerCode code) {
+ if (_canSteerSub) {
+ _hintFuse.primeFuse(time, scale);
+ _hintEvent.subChase = this;
+ _hintEvent.theEvent = code;
+ _hintFuse.setFunctor(new Common::Functor0Mem<void, HintTimerEvent>(&_hintEvent, &HintTimerEvent::fire));
+ _hintFuse.lightFuse();
+ }
+}
+
+void SubChase::hintTimerExpired(HintTimerEvent &event) {
+ switch (event.theEvent) {
+ case kStartedHint:
+ _hintPict.show();
+ startBlinkTimer(10, 10, kEnteredBlinkState);
+ startHintTimer(3920, kSubChaseScale, kEndedHint);
+ break;
+ case kEndedHint:
+ _hintPict.hide();
+ _blinkPict.hide();
+ _blinkFuse.stopFuse();
+ break;
+ default:
+ break;
+ }
+}
+
+void SubChase::startBlinkTimer(TimeValue time, TimeScale scale, BlinkTimerCode code) {
+ _blinkFuse.primeFuse(time, scale);
+ _blinkEvent.subChase = this;
+ _blinkEvent.theEvent = code;
+ _blinkFuse.setFunctor(new Common::Functor0Mem<void, BlinkTimerEvent>(&_blinkEvent, &BlinkTimerEvent::fire));
+ _blinkFuse.lightFuse();
+}
+
+void SubChase::blinkTimerExpired(BlinkTimerEvent &event) {
+ switch (event.theEvent) {
+ case kEnteredBlinkState:
+ _hintPict.hide();
+ _blinkPict.show();
+ startBlinkTimer(5, 10, kExitedBlinkState);
+ break;
+ case kExitedBlinkState:
+ _blinkPict.hide();
+ _hintPict.show();
+ startBlinkTimer(10, 10, kEnteredBlinkState);
+ break;
+ default:
+ break;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/subchase.h b/engines/pegasus/neighborhood/norad/alpha/subchase.h
new file mode 100644
index 0000000000..8907dc8ac0
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/subchase.h
@@ -0,0 +1,111 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-2013 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_SUBCHASE_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_SUBCHASE_H
+
+#include "pegasus/chase.h"
+#include "pegasus/movie.h"
+
+namespace Pegasus {
+
+class NoradAlpha;
+class SubChase;
+
+enum HintTimerCode {
+ kStartedHint,
+ kEndedHint
+};
+
+struct HintTimerEvent {
+ SubChase *subChase;
+ HintTimerCode theEvent;
+
+ void fire();
+};
+
+enum BlinkTimerCode {
+ kEnteredBlinkState,
+ kExitedBlinkState
+};
+
+struct BlinkTimerEvent {
+ SubChase *subChase;
+ BlinkTimerCode theEvent;
+
+ void fire();
+};
+
+class SubChase : public ChaseInteraction {
+friend class NoradAlpha;
+friend struct HintTimerEvent;
+friend struct BlinkTimerEvent;
+public:
+
+ SubChase(Neighborhood *);
+ virtual ~SubChase() {}
+
+ void setSoundFXLevel(const uint16);
+
+ void handleInput(const Input &, const Hotspot *);
+
+protected:
+
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ void startBranching();
+ void setUpBranch();
+ void branchLeft();
+ void branchRight();
+ void dontBranch();
+
+ void startHintTimer(TimeValue, TimeScale, HintTimerCode);
+ void hintTimerExpired(HintTimerEvent &);
+
+ void startBlinkTimer(TimeValue, TimeScale, BlinkTimerCode);
+ void blinkTimerExpired(BlinkTimerEvent &);
+
+ Movie _subMovie;
+ NotificationCallBack _subCallBack;
+ Picture _hintPict;
+ Picture _blinkPict;
+ FuseFunction _hintFuse;
+ FuseFunction _blinkFuse;
+
+ HintTimerEvent _hintEvent;
+ BlinkTimerEvent _blinkEvent;
+
+ short _subState;
+
+ bool _canSteerSub;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/constants.h b/engines/pegasus/neighborhood/norad/constants.h
index 52e889f2e0..0b03064c9d 100644
--- a/engines/pegasus/neighborhood/norad/constants.h
+++ b/engines/pegasus/neighborhood/norad/constants.h
@@ -216,6 +216,7 @@ static const InteractionID kNoradElevatorInteractionID = 3;
static const InteractionID kNoradPressureDoorInteractionID = 4;
static const InteractionID kNoradSubControlRoomInteractionID = 5;
static const InteractionID kNoradSubPlatformInteractionID = 6;
+static const InteractionID kNoradSubChaseInteractionID = 7;
/////////////////////////////////////////////
//
@@ -265,6 +266,12 @@ static const CoordType kNoradLowerDownTop = kNavAreaTop + 212;
static const CoordType kNoradPlatformLeft = kNavAreaLeft + 36;
static const CoordType kNoradPlatformTop = kNavAreaTop + 87;
+static const CoordType kNoradSubSteerLeft = 288;
+static const CoordType kNoradSubSteerTop = 28;
+
+static const CoordType kNoradSubHintLeft = 480;
+static const CoordType kNoradSubHintTop = 240;
+
static const CoordType kNoradSubControlLeft = kNavAreaLeft + 0;
static const CoordType kNoradSubControlTop = kNavAreaTop + 84;
@@ -385,8 +392,9 @@ static const DisplayElementID kClawMonitorGreenBallID = kSubControlCWID + 1;
// Norad Delta display IDs.
-static const DisplayElementID kGlobeMonitorID = kNeighborhoodDisplayID;
-static const DisplayElementID kGlobeMovieID = kGlobeMonitorID + 14;
+static const DisplayElementID kGlobeRobotID = kNeighborhoodDisplayID;
+static const DisplayElementID kGlobeMonitorID = kGlobeRobotID + 1;
+static const DisplayElementID kGlobeMovieID = kGlobeMonitorID + 1;
static const DisplayElementID kGlobeCircleLeftID = kGlobeMovieID + 1;
static const DisplayElementID kGlobeCircleRightID = kGlobeCircleLeftID + 1;
static const DisplayElementID kGlobeCircleUpID = kGlobeCircleRightID + 1;
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
index 3735f6d854..ad60c987fd 100644
--- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
@@ -25,6 +25,7 @@
#include "pegasus/cursor.h"
#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/delta/globegame.h"
#include "pegasus/neighborhood/norad/delta/noraddelta.h"
@@ -396,10 +397,22 @@ static const TimeValue kGlobeMovieStartTime = 2 * 2 * kNumLongSlices * 600 / 15;
static const TimeValue kTimePerGlobeFrame = 40;
static const NotificationFlags kGlobeSplash1Finished = 1;
-static const NotificationFlags kGlobeTimerExpired = kGlobeSplash1Finished << 1;
+static const NotificationFlags kGlobeRobot1Finished = kGlobeSplash1Finished << 1;
+static const NotificationFlags kGlobeRobot2Finished = kGlobeRobot1Finished << 1;
+static const NotificationFlags kGlobeRobot3Finished = kGlobeRobot2Finished << 1;
+static const NotificationFlags kGlobeRobot4Finished = kGlobeRobot3Finished << 1;
+static const NotificationFlags kGlobeRobot5Finished = kGlobeRobot4Finished << 1;
+static const NotificationFlags kGlobeRobot6Finished = kGlobeRobot5Finished << 1;
+static const NotificationFlags kGlobeTimerExpired = kGlobeRobot6Finished << 1;
static const NotificationFlags kMaxDeactivatedFinished = kGlobeTimerExpired << 1;
static const NotificationFlags kGlobeNotificationFlags = kGlobeSplash1Finished |
+ kGlobeRobot1Finished |
+ kGlobeRobot2Finished |
+ kGlobeRobot3Finished |
+ kGlobeRobot4Finished |
+ kGlobeRobot5Finished |
+ kGlobeRobot6Finished |
kGlobeTimerExpired |
kMaxDeactivatedFinished;
@@ -451,10 +464,10 @@ float radiansToDegrees(float angle) {
}
GlobeGame::GlobeGame(Neighborhood *handler) : GameInteraction(kNoradGlobeGameInteractionID, handler),
- _monitorMovie(kGlobeMonitorID), _globeMovie(kGlobeMovieID), _upperNamesMovie(kGlobeUpperNamesID),
- _lowerNamesMovie(kGlobeLowerNamesID), _globeNotification(kNoradGlobeNotificationID, (PegasusEngine *)g_engine),
- _globeCircleLeft(kGlobeCircleLeftID), _globeCircleRight(kGlobeCircleRightID),
- _globeCircleUp(kGlobeCircleUpID), _globeCircleDown(kGlobeCircleDownID),
+ _robotMovie(kGlobeRobotID), _monitorMovie(kGlobeMonitorID), _globeMovie(kGlobeMovieID),
+ _upperNamesMovie(kGlobeUpperNamesID), _lowerNamesMovie(kGlobeLowerNamesID),
+ _globeNotification(kNoradGlobeNotificationID, (PegasusEngine *)g_engine), _globeCircleLeft(kGlobeCircleLeftID),
+ _globeCircleRight(kGlobeCircleRightID), _globeCircleUp(kGlobeCircleUpID), _globeCircleDown(kGlobeCircleDownID),
_motionHighlightLeft(kMotionHiliteLeftID), _motionHighlightRight(kMotionHiliteRightID),
_motionHighlightUp(kMotionHiliteUpID), _motionHighlightDown(kMotionHiliteDownID),
_targetHighlightUpperLeft(kTargetHiliteUpperLeftID), _targetHighlightUpperRight(kTargetHiliteUpperRightID),
@@ -469,6 +482,20 @@ void GlobeGame::setSoundFXLevel(const uint16 fxLevel) {
}
void GlobeGame::openInteraction() {
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _robotMovie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor1");
+ _robotMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _robotMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _robotMovie.setDisplayOrder(kGlobeMonitorLayer);
+ _robotMovie.startDisplaying();
+ _robotMovie.show();
+
+ _robotCallBack.setNotification(&_globeNotification);
+ _robotCallBack.initCallBack(&_robotMovie, kCallBackAtExtremes);
+ _robotCallBack.setCallBackFlag(kGlobeRobot1Finished);
+ _robotCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
_monitorMovie.initFromMovieFile("Images/Norad Delta/N79 Left Monitor");
_monitorMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
_monitorMovie.moveElementTo(kGlobeMonitorLeft, kGlobeMonitorTop);
@@ -579,11 +606,20 @@ void GlobeGame::openInteraction() {
}
void GlobeGame::initInteraction() {
+ if (((PegasusEngine *)g_engine)->isDVD())
+ _robotMovie.start();
_monitorMovie.start();
_monitorMovie.redrawMovieWorld();
}
void GlobeGame::closeInteraction() {
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _robotMovie.stop();
+ _robotMovie.stopDisplaying();
+ _robotMovie.releaseMovie();
+ _robotCallBack.releaseCallBack();
+ }
+
_monitorMovie.stop();
_monitorMovie.stopDisplaying();
_monitorMovie.releaseMovie();
@@ -642,16 +678,18 @@ void GlobeGame::receiveNotification(Notification *notification, const Notificati
if (notification == _neighborhoodNotification) {
switch (_gameState) {
case kPlayingRobotIntro:
- _monitorMovie.stop();
- _monitorMovie.setSegment(0, _monitorMovie.getDuration());
- _monitorMovie.setTime(kSplash2End * scale - 1);
- _monitorMovie.redrawMovieWorld();
- _monitorMovie.setFlags(0);
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(0, _monitorMovie.getDuration());
+ _monitorMovie.setTime(kSplash2End * scale - 1);
+ _monitorMovie.redrawMovieWorld();
+ _monitorMovie.setFlags(0);
- _owner->requestDelay(1, 2, kFilterNoInput, 0);
- _owner->requestSpotSound(kStrikeAuthorizedIn, kStrikeAuthorizedOut,
- kFilterNoInput, kSpotSoundCompletedFlag);
- _gameState = kPlayingStrikeAuthorized;
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _owner->requestSpotSound(kStrikeAuthorizedIn, kStrikeAuthorizedOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ _gameState = kPlayingStrikeAuthorized;
+ }
break;
case kPlayingStrikeAuthorized:
_monitorMovie.setSegment(kSplash3Start * scale, kSplash3Stop * scale);
@@ -761,20 +799,80 @@ void GlobeGame::receiveNotification(Notification *notification, const Notificati
switch (_currentSiloIndex) {
case 3:
- _owner->requestSpotSound(kYouCannotPossiblyIn, kYouCannotPossiblyOut,
- kFilterNoInput, kSpotSoundCompletedFlag);
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->requestSpotSound(kYouCannotPossiblyIn, kYouCannotPossiblyOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ } else {
+ _robotMovie.hide();
+ _robotMovie.stopDisplaying();
+ _robotMovie.releaseMovie();
+
+ _robotMovie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor2");
+ _robotMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _robotMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _robotMovie.startDisplaying();
+ _robotMovie.show();
+ _robotMovie.start();
+
+ _owner->requestDelay(_robotMovie.getDuration(), 0, kFilterNoInput, kDelayCompletedFlag);
+ }
break;
case 5:
- _owner->requestSpotSound(kYouWillFailIn, kYouWillFailOut, kFilterNoInput,
- kSpotSoundCompletedFlag);
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->requestSpotSound(kYouWillFailIn, kYouWillFailOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ } else {
+ _robotMovie.hide();
+ _robotMovie.stopDisplaying();
+ _robotMovie.releaseMovie();
+
+ _robotMovie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor3");
+ _robotMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _robotMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _robotMovie.startDisplaying();
+ _robotMovie.show();
+ _robotMovie.start();
+
+ _owner->requestDelay(_robotMovie.getDuration(), 0, kFilterNoInput, kDelayCompletedFlag);
+ }
break;
case 7:
- _owner->requestSpotSound(kGiveUpHumanIn, kGiveUpHumanOut, kFilterNoInput,
- kSpotSoundCompletedFlag);
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->requestSpotSound(kGiveUpHumanIn, kGiveUpHumanOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ } else {
+ _robotMovie.hide();
+ _robotMovie.stopDisplaying();
+ _robotMovie.releaseMovie();
+
+ _robotMovie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor4");
+ _robotMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _robotMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _robotMovie.startDisplaying();
+ _robotMovie.show();
+ _robotMovie.start();
+
+ _owner->requestDelay(_robotMovie.getDuration(), 0, kFilterNoInput, kDelayCompletedFlag);
+ }
break;
case 9:
- _owner->requestSpotSound(kYouAreRunningIn, kYouAreRunningOut,
- kFilterNoInput, kSpotSoundCompletedFlag);
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->requestSpotSound(kYouAreRunningIn, kYouAreRunningOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ } else {
+ _robotMovie.hide();
+ _robotMovie.stopDisplaying();
+ _robotMovie.releaseMovie();
+
+ _robotMovie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor5");
+ _robotMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _robotMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _robotMovie.startDisplaying();
+ _robotMovie.show();
+ _robotMovie.start();
+
+ _owner->requestDelay(_robotMovie.getDuration(), 0, kFilterNoInput, kDelayCompletedFlag);
+ }
break;
default:
_owner->requestSpotSound(kNewLaunchSiloIn, kNewLaunchSiloOut,
@@ -786,7 +884,7 @@ void GlobeGame::receiveNotification(Notification *notification, const Notificati
}
break;
case kRobotTaunting:
- _owner->requestDelay(1, 1, kFilterNoInput, 0);
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
_owner->requestSpotSound(kNewLaunchSiloIn, kNewLaunchSiloOut, kFilterNoInput, kSpotSoundCompletedFlag);
_monitorMovie.setTime(kNewLaunchSiloTime * scale);
_monitorMovie.redrawMovieWorld();
@@ -810,27 +908,69 @@ void GlobeGame::receiveNotification(Notification *notification, const Notificati
switch (flags) {
case kGlobeSplash1Finished:
- _owner->getExtraEntry(kN79BrightView, entry);
_monitorMovie.stop();
_monitorMovie.setSegment(kSplash1End * scale, kSplash2End * scale);
_monitorMovie.setFlags(kLoopTimeBase);
_monitorMovie.start();
- _owner->showViewFrame(entry.movieStart);
- _owner->requestSpotSound(kIJustBrokeIn, kIJustBrokeOut, kFilterNoInput, 0);
- _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
- _gameState = kPlayingRobotIntro;
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->getExtraEntry(kN79BrightView, entry);
+ _owner->showViewFrame(entry.movieStart);
+ _owner->requestSpotSound(kIJustBrokeIn, kIJustBrokeOut, kFilterNoInput, 0);
+ _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingRobotIntro;
+ }
+ break;
+ case kGlobeRobot1Finished:
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->getExtraEntry(kN79BrightView, entry);
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(0, _monitorMovie.getDuration());
+ _monitorMovie.setTime(kSplash2End * scale - 1);
+ _monitorMovie.redrawMovieWorld();
+ _monitorMovie.setFlags(0);
+
+ _owner->showViewFrame(entry.movieStart);
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _owner->requestSpotSound(kStrikeAuthorizedIn, kStrikeAuthorizedOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+
+ _gameState = kPlayingStrikeAuthorized;
+ }
break;
case kGlobeTimerExpired:
// Missile launched, player loses.
+ _upperNamesMovie.hide();
+ _lowerNamesMovie.hide();
+ _countdown.hide();
+ _monitorMovie.setTime(kMissileLaunchedTime * scale);
+ _monitorMovie.redrawMovieWorld();
_owner->requestSpotSound(kMissileLaunchedIn, kMissileLaunchedOut, kFilterNoInput, kSpotSoundCompletedFlag);
_gameState = kPlayerLost1;
break;
case kMaxDeactivatedFinished:
_monitorMovie.stop();
_monitorMovie.setSegment(0, _monitorMovie.getDuration());
- _owner->requestDelay(1, 2, kFilterNoInput, 0);
- _owner->requestSpotSound(kTheOnlyGoodHumanIn, kTheOnlyGoodHumanOut, kFilterNoInput, 0);
- _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA02", kArthurNoradFinishedGlobeGame);
+ if (!((PegasusEngine *)g_engine)->isDVD()) {
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _owner->requestSpotSound(kTheOnlyGoodHumanIn, kTheOnlyGoodHumanOut, kFilterNoInput, 0);
+ _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
+ } else {
+ _robotMovie.hide();
+ _robotMovie.stopDisplaying();
+ _robotMovie.releaseMovie();
+
+ _robotMovie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor6");
+ _robotMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _robotMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _robotMovie.setDisplayOrder(kGlobeCountdownLayer + 1);
+ _robotMovie.startDisplaying();
+ _robotMovie.show();
+ _robotMovie.start();
+
+ _owner->requestDelay(_robotMovie.getDuration(), 0, kFilterNoInput, kDelayCompletedFlag);
+ }
_gameState = kPlayerWon2;
break;
default:
@@ -894,56 +1034,89 @@ void GlobeGame::spinGlobe(const Input &input, const Hotspot *spot, GlobeTrackDir
}
void GlobeGame::clickGlobe(const Input &input) {
- int16 newSilo = findClickedSilo(input);
-
- if (newSilo != -1) {
- _targetHighlightUpperLeft.hide();
- _targetHighlightUpperRight.hide();
- _targetHighlightLowerLeft.hide();
- _targetHighlightLowerRight.hide();
- _lowerNamesMovie.show();
- _lowerNamesMovie.setTime(newSilo * _lowerNamesMovie.getScale());
- _lowerNamesMovie.redrawMovieWorld();
- _owner->requestSpotSound(kSiloBeepIn, kSiloBeepOut, kFilterNoInput, 0);
+ Movie movie(kNoDisplayElement);
+ Input movieInput;
+
+ if (((PegasusEngine *)g_engine)->isDVD() && JMPPPInput::isEasterEggModifierInput(input)) {
+ ((PegasusEngine *)g_engine)->_cursor->hide();
+
+ movie.initFromMovieFile("Images/Norad Delta/N79 Back Monitor7");
+ movie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ movie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ movie.setDisplayOrder(kGlobeCountdownLayer + 1);
+ movie.startDisplaying();
+ movie.show();
+ movie.start();
+
+ while (movie.isRunning() && !((PegasusEngine *)g_engine)->shouldQuit()) {
+ InputDevice.getInput(movieInput, kFilterNoInput);
+
+ ((PegasusEngine *)g_engine)->checkCallBacks();
+ ((PegasusEngine *)g_engine)->refreshDisplay();
+ ((PegasusEngine *)g_engine)->_system->delayMillis(10);
+ }
- if (newSilo == _targetSilo[_currentSiloIndex]) {
- _currentSiloIndex++;
- _countdown.stopCountdown();
- _owner->requestSpotSound(kSiloDeactivatedIn, kSiloDeactivatedOut, kFilterNoInput, 0);
+ if (((PegasusEngine *)g_engine)->shouldQuit())
+ return;
- if (_currentSiloIndex == kNumTargetSilos) {
- // Player won.
- _owner->requestDelay(1, 2, kFilterNoInput, 0);
- _upperNamesMovie.hide();
- _lowerNamesMovie.hide();
- _countdown.hide();
- _monitorMovie.setSegment(kMaxDeactivatedStart * _monitorMovie.getScale(),
- kMaxDeactivatedStop * _monitorMovie.getScale());
- _monitorMovie.setTime(kMaxDeactivatedStart * _monitorMovie.getScale());
- _monitorCallBack.setCallBackFlag(kMaxDeactivatedFinished);
- _monitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
- _monitorMovie.start();
- _owner->requestSpotSound(kMaximumDeactivationIn, kMaximumDeactivationOut,
- kFilterNoInput, kSpotSoundCompletedFlag);
+ movie.hide();
+ movie.stopDisplaying();
+ movie.releaseMovie();
- // This sound was left out of the original.
- _owner->requestSpotSound(kAllSilosDeactivatedIn, kAllSilosDeactivatedOut,
- kFilterNoInput, kSpotSoundCompletedFlag);
-
- _gameState = kPlayerWon1;
+ ((PegasusEngine *)g_engine)->_cursor->hideUntilMoved();
+ } else {
+ int16 newSilo = findClickedSilo(input);
+ if (newSilo != -1) {
+ _targetHighlightUpperLeft.hide();
+ _targetHighlightUpperRight.hide();
+ _targetHighlightLowerLeft.hide();
+ _targetHighlightLowerRight.hide();
+ _lowerNamesMovie.show();
+ _lowerNamesMovie.setTime(newSilo * _lowerNamesMovie.getScale());
+ _lowerNamesMovie.redrawMovieWorld();
+ _owner->requestSpotSound(kSiloBeepIn, kSiloBeepOut, kFilterNoInput, 0);
+
+ if (newSilo == _targetSilo[_currentSiloIndex]) {
+ _currentSiloIndex++;
+ _countdown.stopCountdown();
+ _owner->requestSpotSound(kSiloDeactivatedIn, kSiloDeactivatedOut, kFilterNoInput, 0);
+
+ if (_currentSiloIndex == kNumTargetSilos) {
+ // Player won.
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _upperNamesMovie.hide();
+ _lowerNamesMovie.hide();
+ _countdown.hide();
+ _monitorMovie.setSegment(kMaxDeactivatedStart * _monitorMovie.getScale(),
+ kMaxDeactivatedStop * _monitorMovie.getScale());
+ _monitorMovie.setTime(kMaxDeactivatedStart * _monitorMovie.getScale());
+ _monitorCallBack.setCallBackFlag(kMaxDeactivatedFinished);
+ _monitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _monitorMovie.start();
+ _owner->requestSpotSound(kMaximumDeactivationIn, kMaximumDeactivationOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+
+ // This sound was left out of the original.
+ _owner->requestSpotSound(kAllSilosDeactivatedIn, kAllSilosDeactivatedOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+
+ _gameState = kPlayerWon1;
+ } else {
+ _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
+ _upperNamesMovie.hide();
+ _lowerNamesMovie.hide();
+ _countdown.hide();
+ _monitorMovie.setTime(kSiloDeactivatedTime * _monitorMovie.getScale());
+ _monitorMovie.redrawMovieWorld();
+ _gameState = kSiloDeactivated;
+ }
} else {
- _owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag);
- _upperNamesMovie.hide();
- _lowerNamesMovie.hide();
- _countdown.hide();
- _monitorMovie.setTime(kSiloDeactivatedTime * _monitorMovie.getScale());
- _monitorMovie.redrawMovieWorld();
- _gameState = kSiloDeactivated;
+ _owner->requestDelay(5, 1, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kDelayingPlayer;
+ // Play "incorrect" sound?
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB38", kArthurNoradSelectedIncorrectSilo);
}
- } else {
- _owner->requestDelay(5, 1, kFilterNoInput, kDelayCompletedFlag);
- _gameState = kDelayingPlayer;
- // Play "incorrect" sound?
}
}
}
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.h b/engines/pegasus/neighborhood/norad/delta/globegame.h
index 3f2ec7fec9..d75cc5cf86 100644
--- a/engines/pegasus/neighborhood/norad/delta/globegame.h
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.h
@@ -139,11 +139,13 @@ protected:
void screenPointTo3DPoint(int16, int16, Point3D &);
bool lineHitsGlobe(const Line3D &, Point3D &);
+ Movie _robotMovie;
Movie _monitorMovie;
Movie _globeMovie;
Movie _upperNamesMovie;
Movie _lowerNamesMovie;
Notification _globeNotification;
+ NotificationCallBack _robotCallBack;
NotificationCallBack _monitorCallBack;
GlobeTracker _globeTracker;
Picture _globeCircleLeft;
diff --git a/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp b/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp
index 96000d10d4..4c9f307b88 100644
--- a/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp
+++ b/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp
@@ -28,6 +28,7 @@
#include "pegasus/interface.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/items/biochips/retscanchip.h"
#include "pegasus/items/inventory/airmask.h"
@@ -267,21 +268,39 @@ void NoradDelta::loadAmbientLoops() {
if (GameState.getNoradArrivedFromSub()) {
RoomID room = GameState.getCurrentRoom();
- if (room == kNorad79West) {
- if (_privateFlags.getFlag(kNoradPrivateFinishedGlobeGameFlag))
- loadLoopSound1("Sounds/Norad/GlobAmb2.22K.AIFF");
- else
+ if (room >= kNorad78 && room <= kNorad79West) {
+ if (GameState.getNoradPlayedGlobeGame()) {
+ // blitter moved clone2727's globe room loop fix up here
+ // since the original didn't play the red alert sound during the
+ // globe game.
+
+ // clone2727 added this fix so we can play the correct sound
+ // with the DVD version. This originally loaded it into slot 2,
+ // which in addition to having the corrupted sound on the disk,
+ // caused it to never play.
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/GlobAmb2.32K.AIFF");
+ else
+ loadLoopSound1("Sounds/Norad/GlobAmb2.22K.AIFF");
+ } else
loadLoopSound1("Sounds/Norad/RedAlert.22K.AIFF");
- } else if (room >= kNorad78 && room <= kNorad79) {
- // clone2727 says: This looks like it should be loadLoopSound1...
- loadLoopSound2("Sounds/Norad/RedAlert.22K.AIFF");
} else if (GameState.getNoradGassed()) {
- if (room >= kNorad41 && room <= kNorad49South)
- loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
- else if (room >= kNorad59 && room <= kNorad60West)
- loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
- else
- loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
+ if (room >= kNorad41 && room <= kNorad49South) {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.44K.AIFF", kNoradWarningVolume * 3);
+ else
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
+ } else if (room >= kNorad59 && room <= kNorad60West) {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.32K.AIFF", kNoradWarningVolume * 3);
+ else
+ loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
+ } else {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/WARNING LOOP.32K.AIFF", kNoradWarningVolume);
+ else
+ loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
+ }
} else {
loadLoopSound1("");
}
@@ -292,15 +311,22 @@ void NoradDelta::loadAmbientLoops() {
else
loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
} else {
- if (room == kNorad54North)
- loadLoopSound2("Sounds/Norad/N54NAS.22K.AIFF", 0x100 / 2);
- else
+ if (room == kNorad54North) {
+ if (_vm->isDVD())
+ loadLoopSound2("Sounds/Norad/N54NAS.32K.AIFF", 0x100 / 2);
+ else
+ loadLoopSound2("Sounds/Norad/N54NAS.22K.AIFF", 0x100 / 2);
+ } else
loadLoopSound2("");
}
} else {
// Start them off at zero...
- if (GameState.getNoradGassed())
- loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", 0, 0, 0);
+ if (GameState.getNoradGassed()) {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.44K.AIFF", 0, 0, 0);
+ else
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", 0, 0, 0);
+ }
if (!g_airMask->isAirFilterOn())
loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", 0, 0, 0);
}
@@ -332,39 +358,50 @@ void NoradDelta::arriveAt(const RoomID room, const DirectionConstant direction)
switch (room) {
case kNorad41:
- if (direction == kEast && !GameState.getNoradArrivedFromSub()) {
- GameState.setNoradPlayedGlobeGame(false);
+ if (direction == kEast) {
+ if (!GameState.getNoradArrivedFromSub()) {
+ GameState.setNoradPlayedGlobeGame(false);
- GameState.setNoradBeatRobotWithClaw(false);
- GameState.setNoradBeatRobotWithDoor(false);
- GameState.setNoradRetScanGood(false);
+ GameState.setNoradBeatRobotWithClaw(false);
+ GameState.setNoradBeatRobotWithDoor(false);
+ GameState.setNoradRetScanGood(false);
- GameState.setScoringExitedSub(true);
+ GameState.setScoringExitedSub(true);
- getExtraEntry(kArriveFromSubChase, entry);
+ getExtraEntry(kArriveFromSubChase, entry);
- loop1Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
- entry.movieStart, kNoradWarningVolume);
- loop1Spec.insertFaderKnot(7320, 0);
- loop1Spec.insertFaderKnot(7880, kNoradWarningVolume);
+ loop1Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
+ entry.movieStart, kNoradWarningVolume);
+ loop1Spec.insertFaderKnot(7320, 0);
+ loop1Spec.insertFaderKnot(7880, kNoradWarningVolume);
- loop2Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
- entry.movieStart, kNoradSuckWindVolume);
- loop1Spec.insertFaderKnot(7320, 0);
- loop1Spec.insertFaderKnot(7880, kNoradSuckWindVolume);
+ loop2Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
+ entry.movieStart, kNoradSuckWindVolume);
+ loop1Spec.insertFaderKnot(7320, 0);
+ loop1Spec.insertFaderKnot(7880, kNoradSuckWindVolume);
- startExtraSequence(kArriveFromSubChase, kExtraCompletedFlag, kFilterNoInput);
+ startExtraSequence(kArriveFromSubChase, kExtraCompletedFlag, kFilterNoInput);
- startLoop1Fader(loop1Spec);
- startLoop2Fader(loop2Spec);
+ startLoop1Fader(loop1Spec);
+ startLoop2Fader(loop2Spec);
+ } else {
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA08", kArthurNoradExitedSub);
+ }
}
break;
+ case kNorad54:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA71", kArthurNoradApproachedDamagedDoor);
+ break;
case kNorad54North:
GameState.setScoringSawRobotAt54North(true);
break;
case kNorad68:
if (GameState.getNoradRetScanGood())
openDoor();
+ else if (!_vm->playerHasItemID(kRetinalScanBiochip) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurNoradAtRetScanNoBiochip);
break;
case kNorad68West:
arriveAtNorad68West();
@@ -400,6 +437,20 @@ void NoradDelta::arriveAtNorad79West() {
newInteraction(kNoradGlobeGameInteractionID);
}
+void NoradDelta::turnTo(const DirectionConstant direction) {
+ Norad::turnTo(direction);
+ if (g_arthurChip) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kNorad54, kNorth):
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA71", kArthurNoradApproachedDamagedDoor);
+ break;
+ case MakeRoomView(kNorad68, kWest):
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurNoradApproachedDamagedDoor);
+ break;
+ }
+ }
+}
+
void NoradDelta::bumpIntoWall() {
requestSpotSound(kDeltaBumpIntoWallIn, kDeltaBumpIntoWallOut, kFilterNoInput, 0);
Neighborhood::bumpIntoWall();
@@ -427,7 +478,11 @@ void NoradDelta::finishedGlobeGame() {
_privateFlags.setFlag(kNoradPrivateFinishedGlobeGameFlag, true);
GameState.setScoringFinishedGlobeGame(true);
loadAmbientLoops();
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN60WD1", false, kWarningInterruption);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA63", kArthurNoradThreatenedByRobot);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN60WD1", false, kWarningInterruption);
+ updateViewFrame();
}
bool NoradDelta::playingAgainstRobot() {
@@ -455,7 +510,8 @@ void NoradDelta::playerBeatRobotWithDoor() {
GameState.setNoradBeatRobotWithDoor(true);
updateViewFrame();
GameState.setScoringStoppedNoradRobot(true);
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
}
void NoradDelta::playerBeatRobotWithClaw() {
@@ -463,7 +519,8 @@ void NoradDelta::playerBeatRobotWithClaw() {
updateViewFrame();
GameState.setScoringStoppedNoradRobot(true);
GameState.setScoringNoradGandhi(true);
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
}
TimeValue NoradDelta::getViewTime(const RoomID room, const DirectionConstant direction) {
@@ -619,12 +676,27 @@ void NoradDelta::receiveNotification(Notification *notification, const Notificat
case kN59RobotHeadOpens:
case kN60RobotHeadOpens:
_privateFlags.setFlag(kNoradPrivateRobotHeadOpenFlag, true);
+ if (g_arthurChip) {
+ switch (_vm->getRandomNumber(2)) {
+ case 0:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA36", kArthurNoradRobotHeadOpen);
+ break;
+ case 1:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA37", kArthurNoradRobotHeadOpen);
+ break;
+ case 2:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA40", kArthurNoradRobotHeadOpen);
+ break;
+ }
+ }
break;
case kNoradDeltaRetinalScanBad:
retScan = (RetScanChip *)_vm->getCurrentBiochip();
retScan->setItemState(kNormalItem);
playSpotSoundSync(kRetinalScanFailedIn, kRetinalScanFailedOut);
downButton(dummy);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA13", kArthurNoradAtRetScanNoBiochip);
break;
case kNoradDeltaRetinalScanGood:
retScan = (RetScanChip *)_vm->getCurrentBiochip();
@@ -640,6 +712,9 @@ void NoradDelta::receiveNotification(Notification *notification, const Notificat
}
_interruptionFilter = kFilterAllInput;
+ } else if ((flags & kSpotSoundCompletedFlag) != 0) {
+ if (_spotSounds.getStart() == kToDeactivateIn && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB41", kArthurNoradStartGlobeGame);
}
g_AIArea->checkMiddleArea();
diff --git a/engines/pegasus/neighborhood/norad/delta/noraddelta.h b/engines/pegasus/neighborhood/norad/delta/noraddelta.h
index 9132893c6d..e3d3b81a2b 100644
--- a/engines/pegasus/neighborhood/norad/delta/noraddelta.h
+++ b/engines/pegasus/neighborhood/norad/delta/noraddelta.h
@@ -90,6 +90,7 @@ protected:
void arriveAt(const RoomID, const DirectionConstant) override;
void arriveAtNorad68West();
void arriveAtNorad79West();
+ void turnTo(const DirectionConstant) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void openDoor() override;
void cantMoveThatWay(CanMoveForwardReason) override;
diff --git a/engines/pegasus/neighborhood/norad/norad.cpp b/engines/pegasus/neighborhood/norad/norad.cpp
index 770d559bf6..5b0d0b483a 100644
--- a/engines/pegasus/neighborhood/norad/norad.cpp
+++ b/engines/pegasus/neighborhood/norad/norad.cpp
@@ -27,6 +27,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
@@ -162,10 +163,14 @@ void Norad::arriveAtNoradElevator() {
void Norad::arriveAtUpperPressureDoorRoom() {
newInteraction(kNoradPressureDoorInteractionID);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA69", kArthurNoradReachedPressureDoor);
}
void Norad::arriveAtLowerPressureDoorRoom() {
newInteraction(kNoradPressureDoorInteractionID);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA69", kArthurNoradReachedPressureDoor);
}
void Norad::arriveAtSubPlatformRoom() {
@@ -199,10 +204,18 @@ CanOpenDoorReason Norad::canOpenDoor(DoorTable::Entry &entry) {
}
void Norad::cantOpenDoor(CanOpenDoorReason reason) {
+ bool firstLockedDoor;
+
if (reason == kCantOpenBadPressure)
playSpotSoundSync(_pressureSoundIn, _pressureSoundOut);
else
playSpotSoundSync(_accessDeniedIn, _accessDeniedOut);
+ if (g_arthurChip) {
+ firstLockedDoor = g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA65", kArthurNoradAttemptedLockedDoor);
+
+ if (!firstLockedDoor)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA68", kArthurNoradAttemptedLockedDoorAgain);
+ }
}
void Norad::startExitMovie(const ExitTable::Entry &exitEntry) {
diff --git a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
index b7a39fdc8f..98e6f68026 100644
--- a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
+++ b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
@@ -25,6 +25,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/subcontrolroom.h"
@@ -565,6 +566,8 @@ void SubControlRoom::receiveNotification(Notification *notification, const Notif
switch (flags) {
case kAlphaSplashFinished:
setControlMonitorToTime(kMainMenuTime * _subControlScale, kAlphaMainMenu, true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA29", kArthurNoradSawClawMonitor);
break;
case kPrepHighlightFinished:
if (GameState.getNoradSubPrepState() == kSubDamaged)
@@ -660,6 +663,8 @@ void SubControlRoom::receiveNotification(Notification *notification, const Notif
hideEverything();
_robotState = kPlayerWon;
owner->startExtraSequence(kN60PlayerFollowsRobotToDoor, kExtraCompletedFlag, kFilterAllInput);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA67", kArthurNoradBeatRobotWithClaw);
break;
case kPlayerWon:
((NoradDelta *)owner)->playerBeatRobotWithClaw();
diff --git a/engines/pegasus/neighborhood/norad/subplatform.cpp b/engines/pegasus/neighborhood/norad/subplatform.cpp
index 16b8ad658e..41cdeaf864 100644
--- a/engines/pegasus/neighborhood/norad/subplatform.cpp
+++ b/engines/pegasus/neighborhood/norad/subplatform.cpp
@@ -26,6 +26,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/subplatform.h"
@@ -148,6 +149,8 @@ void SubPlatform::receiveNotification(Notification *notification, const Notifica
loop1Spec.insertFaderKnot(5080, 0);
owner->startExtraSequence(kNorad19ExitToSub, kExtraCompletedFlag, kFilterNoInput);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA07", kArthurNoradEnteredSub);
owner->startLoop1Fader(loop1Spec);
owner->startLoop2Fader(loop2Spec);
@@ -165,7 +168,7 @@ void SubPlatform::receiveNotification(Notification *notification, const Notifica
default:
break;
}
- } else if (notification == _neighborhoodNotification) {
+ } else if (notification == _neighborhoodNotification && !((PegasusEngine *)g_engine)->isDVD()) {
allowInput(true);
((PegasusEngine *)g_engine)->jumpToNewEnvironment(kNoradSubChaseID, kNoRoomID, kNoDirection);
GameState.setScoringEnteredSub(true);
diff --git a/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp b/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
index 16482c23a8..d147d99698 100644
--- a/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
+++ b/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
@@ -31,6 +31,7 @@
#include "pegasus/ai/ai_area.h"
#include "pegasus/ai/ai_condition.h"
#include "pegasus/ai/ai_rule.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/prehistoric/prehistoric.h"
namespace Pegasus {
@@ -99,6 +100,9 @@ void Prehistoric::start() {
}
Neighborhood::start();
+
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric02, kSouth) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA01", kArthurGoToPrehistoric);
}
class FinishPrehistoricAction : public AIPlayMessageAction {
@@ -276,8 +280,16 @@ void Prehistoric::turnTo(const DirectionConstant newDirection) {
Neighborhood::turnTo(newDirection);
Item *keyCard;
+ bool doArthurFeelLikeYodelingMovie = false;
switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kPrehistoric08, kEast):
+ case MakeRoomView(kPrehistoric10, kEast):
+ case MakeRoomView(kPrehistoric12, kEast):
+ case MakeRoomView(kPrehistoric14, kEast):
+ case MakeRoomView(kPrehistoric25, kWest):
+ doArthurFeelLikeYodelingMovie = true;
+ break;
case MakeRoomView(kPrehistoric18, kEast):
zoomToVault();
break;
@@ -291,6 +303,13 @@ void Prehistoric::turnTo(const DirectionConstant newDirection) {
// fall through
case MakeRoomView(kPrehistoric25, kEast):
setCurrentActivation(kActivationVaultClosed);
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric25, kEast) &&
+ !GameState.isTakenItemID(kHistoricalLog) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA60", kArthurPrehistoricCrossedBridge);
+ break;
+ case MakeRoomView(kPrehistoric23, kWest):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA59", kArthurPrehistoricSawEggs);
break;
case MakeRoomView(kPrehistoric16, kNorth):
case MakeRoomView(kPrehistoric21, kWest):
@@ -313,6 +332,8 @@ void Prehistoric::turnTo(const DirectionConstant newDirection) {
default:
break;
}
+ if (doArthurFeelLikeYodelingMovie && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
}
void Prehistoric::zoomToVault() {
@@ -336,6 +357,7 @@ void Prehistoric::checkContinuePoint(const RoomID room, const DirectionConstant
void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction) {
Item *keyCard;
+ bool doArthurLetsSpreadOutMovie, doArthurFeelLikeYodelingMovie;
if (MakeRoomView(room, direction) == MakeRoomView(kPrehistoric25, kEast) &&
_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
@@ -346,6 +368,8 @@ void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction)
Neighborhood::arriveAt(room, direction);
+ doArthurLetsSpreadOutMovie = false;
+ doArthurFeelLikeYodelingMovie = false;
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kPrehistoricDeath, kNorth):
case MakeRoomView(kPrehistoricDeath, kSouth):
@@ -366,6 +390,20 @@ void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction)
startExtraSequence(kPreArrivalFromTSA, kExtraCompletedFlag, kFilterNoInput);
}
break;
+ case MakeRoomView(kPrehistoric06, kNorth):
+ case MakeRoomView(kPrehistoric13, kWest):
+ doArthurLetsSpreadOutMovie = true;
+ break;
+ case MakeRoomView(kPrehistoric22North, kNorth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB44", kArthurPrehistoricSawBreaker);
+ break;
+ case MakeRoomView(kPrehistoric10, kEast):
+ case MakeRoomView(kPrehistoric12, kEast):
+ case MakeRoomView(kPrehistoric14, kEast):
+ case MakeRoomView(kPrehistoric25, kWest):
+ doArthurFeelLikeYodelingMovie = true;
+ break;
case MakeRoomView(kPrehistoric18, kEast):
zoomToVault();
break;
@@ -385,10 +423,11 @@ void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction)
if (g_AIArea)
g_AIArea->checkRules();
break;
+ case MakeRoomView(kPrehistoric13, kNorth):
+ doArthurLetsSpreadOutMovie = true;
case MakeRoomView(kPrehistoric08, kSouth):
case MakeRoomView(kPrehistoric10, kSouth):
case MakeRoomView(kPrehistoric12, kSouth):
- case MakeRoomView(kPrehistoric13, kNorth):
case MakeRoomView(kPrehistoric14, kSouth):
case MakeRoomView(kPrehistoric15, kNorth):
case MakeRoomView(kPrehistoric16, kSouth):
@@ -406,10 +445,22 @@ void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction)
break;
case MakeRoomView(kPrehistoric25, kEast):
setCurrentActivation(kActivationVaultClosed);
+ if (!GameState.isTakenItemID(kHistoricalLog) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA60", kArthurPrehistoricCrossedBridge);
+ break;
+ case MakeRoomView(kPrehistoric23, kWest):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA59", kArthurPrehistoricSawEggs);
break;
default:
break;
}
+ if (g_arthurChip) {
+ if (doArthurLetsSpreadOutMovie)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA20", kArthurPrehistoricReachedJunction);
+ else if (doArthurFeelLikeYodelingMovie)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
+ }
}
void Prehistoric::loadAmbientLoops() {
@@ -437,9 +488,9 @@ void Prehistoric::loadAmbientLoops() {
case kPrehistoric20:
// 1/4 volume.
if (_vm->isDVD()) // Updated sound for the DVD version
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.32k.AIFF", 64);
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.32K.AIFF", 64);
else
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 64);
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22K.AIFF", 64);
break;
case kPrehistoric08:
case kPrehistoric10:
@@ -450,16 +501,16 @@ void Prehistoric::loadAmbientLoops() {
case kPrehistoric21:
// 3/16 volume.
if (_vm->isDVD()) // Updated sound for the DVD version
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.32k.AIFF", 48);
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.32K.AIFF", 48);
else
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 48);
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22K.AIFF", 48);
break;
case kPrehistoric25:
// 1/8 volume.
if (_vm->isDVD()) // Updated sound for the DVD version
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.32k.AIFF", 32);
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.32K.AIFF", 32);
else
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 32);
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22K.AIFF", 32);
break;
case kPrehistoric22:
case kPrehistoric22North:
@@ -506,9 +557,9 @@ void Prehistoric::loadAmbientLoops() {
case kPrehistoric18:
if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
if (_vm->isDVD()) // Updated sound for the DVD version
- loadLoopSound2("Sounds/Prehistoric/P18EAL00.44K.aiff", 0x100, 0, 0);
+ loadLoopSound2("Sounds/Prehistoric/P18EAL00.44K.AIFF", 0x100, 0, 0);
else
- loadLoopSound2("Sounds/Prehistoric/P18EAL00.22k.AIFF", 0x100, 0, 0);
+ loadLoopSound2("Sounds/Prehistoric/P18EAL00.22K.AIFF", 0x100, 0, 0);
} else {
loadLoopSound2("");
}
@@ -518,9 +569,9 @@ void Prehistoric::loadAmbientLoops() {
case kPrehistoric22:
case kPrehistoric22North:
if (_vm->isDVD()) // Updated sound for the DVD version
- loadLoopSound2("Sounds/Prehistoric/P24NAL00.32k.AIFF", 64);
+ loadLoopSound2("Sounds/Prehistoric/P24NAL00.32K.AIFF", 64);
else
- loadLoopSound2("Sounds/Prehistoric/P24NAL00.22k.AIFF", 64);
+ loadLoopSound2("Sounds/Prehistoric/P24NAL00.22K.aiff", 64);
break;
default:
break;
@@ -574,6 +625,8 @@ void Prehistoric::receiveNotification(Notification *notification, const Notifica
break;
case kPre18EastZoom:
startExtraSequence(kPre18EastZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA61", kArthurPrehistoricZoomedToVault);
break;
case kPre18EastZoomOut:
GameState.setPrehistoricSeenBridgeZoom(true);
@@ -584,28 +637,50 @@ void Prehistoric::receiveNotification(Notification *notification, const Notifica
GameState.setPrehistoricTriedToExtendBridge(false);
loadAmbientLoops();
GameState.setScoringExtendedBridge(true);
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA10", kArthurPrehistoricExtendedBridge);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA56", kArthurPrehistoricExtendedBridge);
+ }
break;
case kPre18EastBridgeOut:
GameState.setPrehistoricTriedToExtendBridge(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA58", kArthurPrehistoricAttemptedBridge);
if (g_AIArea)
g_AIArea->checkMiddleArea();
break;
case kPre22ThrowBreaker:
GameState.setPrehistoricBreakerThrown(true);
GameState.setScoringThrewBreaker(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA57", kArthurPrehistoricBreakerThrown);
break;
case kPre25EastUnlockingVaultNoLog:
case kPre25EastUnlockingVaultWithLog:
+ if (!GameState.isTakenItemID(kHistoricalLog) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA05", kArthurPrehistoricUnlockedVault);
_vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kJourneymanKey));
break;
default:
break;
}
+ } else if ((flags & kSpotCompletedFlag) != 0 &&
+ GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric08, kEast)) {
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
}
g_AIArea->checkMiddleArea();
}
+void Prehistoric::spotCompleted() {
+ Neighborhood::spotCompleted();
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric08, kEast) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
+}
+
Common::String Prehistoric::getBriefingMovie() {
Common::String movieName = Neighborhood::getBriefingMovie();
diff --git a/engines/pegasus/neighborhood/prehistoric/prehistoric.h b/engines/pegasus/neighborhood/prehistoric/prehistoric.h
index f703acf2f5..57776d6e2d 100644
--- a/engines/pegasus/neighborhood/prehistoric/prehistoric.h
+++ b/engines/pegasus/neighborhood/prehistoric/prehistoric.h
@@ -140,6 +140,7 @@ protected:
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &) override;
void receiveNotification(Notification *, const NotificationFlags) override;
+ void spotCompleted() override;
void turnTo(const DirectionConstant) override;
void zoomToVault();
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
index 7dcb58a413..07949dac00 100644
--- a/engines/pegasus/neighborhood/tsa/fulltsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
@@ -23,12 +23,16 @@
*
*/
+#include "common/file.h"
+
+#include "pegasus/compass.h"
#include "pegasus/cursor.h"
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/norad/constants.h"
@@ -492,7 +496,7 @@ enum {
kRedirectionCCDoorLeft = kNavAreaLeft + 174,
kRedirectionCCDoorTop = kNavAreaTop + 36,
- kRedirectionRRDoorLeft = kNavAreaLeft + 418,
+ kRedirectionRRDoorLeft = kNavAreaLeft + 428,
kRedirectionRRDoorTop = kNavAreaTop + 32,
kRedirectionFDDoorLeft = kNavAreaLeft + 298,
@@ -536,6 +540,10 @@ enum {
kPegasusCanExit = true
};
+static const ExtraID kEasterEggJimenez = 1000;
+static const ExtraID kEasterEggCastillo = 1001;
+static const ExtraID kEasterEggSinclair = 1002;
+
// Monitor modes
enum {
kMonitorNeutral = 0,
@@ -661,7 +669,8 @@ void RipTimer::timeChanged(const TimeValue newTime) {
}
FullTSA::FullTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Full TSA", kFullTSAID),
- _ripTimer(kNoDisplayElement), _sprite1(kNoDisplayElement), _sprite2(kNoDisplayElement), _sprite3(kNoDisplayElement) {
+ _extraMovie(kNoDisplayElement), _blankMovie(kNoDisplayElement), _playedSolvedMusicCue(false), _ripTimer(kNoDisplayElement),
+ _sprite1(kNoDisplayElement), _sprite2(kNoDisplayElement), _sprite3(kNoDisplayElement) {
setIsItemTaken(kJourneymanKey);
setIsItemTaken(kPegasusBiochip);
setIsItemTaken(kMapBiochip);
@@ -669,6 +678,12 @@ FullTSA::FullTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood
void FullTSA::init() {
Neighborhood::init();
+ _extraMovieCallBack.setNotification(&_neighborhoodNotification);
+ if (Common::File::exists("Images/TSA/Blank TSA.movie"))
+ _blankMovie.initFromMovieFile("Images/TSA/Blank TSA.movie");
+ _blankMovie.setVolume(_vm->getSoundFXLevel());
+ _blankMovie.setDisplayOrder(kNavMovieOrder + 1);
+ _blankMovie.startDisplaying();
_ripTimer.setDisplayOrder(kRipTimerOrder);
_ripTimer.startDisplaying();
@@ -694,6 +709,11 @@ void FullTSA::dieUncreatedInTSA() {
void FullTSA::start() {
g_energyMonitor->stopEnergyDraining();
+ if (_vm->isDVD()) {
+ _entranceMusic.attachFader(&_entranceFader);
+ _entranceMusic.initFromAIFFFile("Sounds/TSA/TSA Entrance.32K.AIFF");
+ _entranceFader.setMasterVolume(_vm->getAmbienceLevel() / 2);
+ }
if (!GameState.getScoringEnterTSA()) {
_utilityFuse.primeFuse(GameState.getTSAFuseTimeLimit());
_utilityFuse.setFunctor(new Common::Functor0Mem<void, FullTSA>(this, &FullTSA::dieUncreatedInTSA));
@@ -855,24 +875,38 @@ void FullTSA::loadAmbientLoops() {
switch (GameState.getTSAState()) {
case kTSAPlayerDetectedRip:
case kTSAPlayerNeedsHistoricalLog:
- if ((room >= kTSA16 && room <= kTSA0B) || (room >= kTSA21Cyan && room <= kTSA24Cyan) || (room >= kTSA21Red && room <= kTSA24Red))
- loadLoopSound1("Sounds/TSA/TSA CLAXON.22K.AIFF", 0x100 / 4, 0, 0);
- else if (room == kTSA25Cyan || room == kTSA25Red)
- loadLoopSound1("Sounds/TSA/TSA CLAXON.22K.AIFF", 0x100 / 6, 0, 0);
- else
- loadLoopSound1("Sounds/TSA/TSA EchoClaxon.22K.AIFF", 0x100 / 4, 0, 0);
+ if (_vm->isDVD()) {
+ if ((room >= kTSA16 && room <= kTSA0B) || (room >= kTSA21Cyan && room <= kTSA24Cyan) || (room >= kTSA21Red && room <= kTSA24Red))
+ loadLoopSound1("Sounds/TSA/TSA CLAXON.44K.AIFF", 0x100 * 3 / 16, 0, 0);
+ else if (room == kTSA25Cyan || room == kTSA25Red)
+ loadLoopSound1("Sounds/TSA/TSA CLAXON.44K.AIFF", 0x100 / 8, 0, 0);
+ else
+ loadLoopSound1("Sounds/TSA/TSA EchoClaxon.22K.AIFF", 0x100 * 3 / 16, 0, 0);
+ } else {
+ if ((room >= kTSA16 && room <= kTSA0B) || (room >= kTSA21Cyan && room <= kTSA24Cyan) || (room >= kTSA21Red && room <= kTSA24Red))
+ loadLoopSound1("Sounds/TSA/TSA CLAXON.22K.AIFF", 0x100 / 4, 0, 0);
+ else if (room == kTSA25Cyan || room == kTSA25Red)
+ loadLoopSound1("Sounds/TSA/TSA CLAXON.22K.AIFF", 0x100 / 6, 0, 0);
+ else
+ loadLoopSound1("Sounds/TSA/TSA EchoClaxon.22K.AIFF", 0x100 / 4, 0, 0);
+ }
break;
default:
- if (room >= kTSA00 && room <= kTSA02)
- loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
- else if (room >= kTSA03 && room <= kTSA15)
- loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
- else if (room >= kTSA16 && room <= kTSA0B)
- loadLoopSound1("Sounds/TSA/T14SAEO1.22K.AIFF");
- else if (room >= kTSA21Cyan && room <= kTSA25Red)
- loadLoopSound1("Sounds/TSA/T15SAE01.22K.AIFF");
- else if (room >= kTSA26 && room <= kTSA37)
- loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+ if (_vm->isDVD()) {
+ if ((room >= kTSA00 && room <= kTSA02) || (room >= kTSA03 && room <= kTSA15) || (room >= kTSA26 && room <= kTSA37))
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.32K.AIFF", 0x100 * 3 / 4, 0, 0);
+ else if (room >= kTSA16 && room <= kTSA0B)
+ loadLoopSound1("Sounds/TSA/T14SAEO1.32K.AIFF", 0x100 * 3 / 4, 0, 0);
+ else if (room >= kTSA21Cyan && room <= kTSA25Red)
+ loadLoopSound1("Sounds/TSA/T15SAE01.32K.AIFF", 0x100 * 3 / 4, 0, 0);
+ } else {
+ if ((room >= kTSA00 && room <= kTSA02) || (room >= kTSA03 && room <= kTSA15) || (room >= kTSA26 && room <= kTSA37))
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+ else if (room >= kTSA16 && room <= kTSA0B)
+ loadLoopSound1("Sounds/TSA/T14SAEO1.22K.AIFF");
+ else if (room >= kTSA21Cyan && room <= kTSA25Red)
+ loadLoopSound1("Sounds/TSA/T15SAE01.22K.AIFF");
+ }
break;
}
}
@@ -1132,6 +1166,50 @@ void FullTSA::getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry) {
extraEntry.movieStart += kFullTSAFrameDuration * 3;
}
+void FullTSA::showViewFrame(TimeValue viewTime) {
+ if ((int32)viewTime >= 0) {
+ _turnPush.hide();
+ _navMovie.stop();
+ _navMovie.setFlags(0);
+ if (_blankMovie.isMovieValid() &&
+ (GameState.getTSAState() == kRobotsAtCommandCenter ||
+ GameState.getTSAState() == kRobotsAtFrontDoor ||
+ GameState.getTSAState() == kRobotsAtReadyRoom) &&
+ (GameState.getCurrentRoom() == kTSA0A ||
+ GameState.getCurrentRoom() == kTSA06) &&
+ (GameState.getCurrentDirection() == kEast ||
+ GameState.getCurrentDirection() == kWest)) {
+ viewTime = 0;
+ if (GameState.getCurrentRoom() == kTSA06)
+ viewTime = 2 * _blankMovie.getScale();
+ if (GameState.getCurrentDirection() == kWest)
+ viewTime += _blankMovie.getScale();
+
+ _navMovie.hide();
+ _blankMovie.setSegment(0, _blankMovie.getDuration());
+ _blankMovie.setTime(viewTime);
+
+ Common::Rect pushBounds;
+ _turnPush.getBounds(pushBounds);
+
+ _blankMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _blankMovie.show();
+ _blankMovie.redrawMovieWorld();
+ } else {
+ _blankMovie.hide();
+ _navMovie.setSegment(0, _navMovie.getDuration());
+ _navMovie.setTime(viewTime);
+
+ Common::Rect pushBounds;
+ _turnPush.getBounds(pushBounds);
+
+ _navMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _navMovie.show();
+ _navMovie.redrawMovieWorld();
+ }
+ }
+}
+
void FullTSA::pickedUpItem(Item *item) {
BiochipItem *biochip;
@@ -1220,6 +1298,119 @@ void FullTSA::startDoorOpenMovie(const TimeValue startTime, const TimeValue stop
Neighborhood::startDoorOpenMovie(startTime, stopTime);
}
+void FullTSA::startTurnPush(const TurnDirection turnDirection, const TimeValue newView, const DirectionConstant nextDir) {
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+
+ _vm->_cursor->hide();
+
+ GameState.setNextDirection(nextDir);
+
+ _interruptionFilter = kFilterNoInput;
+ _turnPush.stopFader();
+
+ // Set up callback.
+ _turnPushCallBack.setCallBackFlag(kTurnCompletedFlag);
+ _turnPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ // Stop nav movie.
+ _navMovie.stop();
+ _navMovie.setFlags(0);
+
+ if (_blankMovie.isMovieValid() &&
+ (GameState.getTSAState() == kRobotsAtCommandCenter ||
+ GameState.getTSAState() == kRobotsAtFrontDoor ||
+ GameState.getTSAState() == kRobotsAtReadyRoom) &&
+ (GameState.getCurrentRoom() == kTSA0A || GameState.getCurrentRoom() == kTSA06) &&
+ (nextDir == kEast || nextDir == kWest)) {
+ TimeValue newRobotView = 0;
+ if (GameState.getCurrentRoom() == kTSA06)
+ newRobotView = 2 * _blankMovie.getScale();
+ if (nextDir == kWest)
+ newRobotView += _blankMovie.getScale();
+
+ _blankMovie.setSegment(0, _blankMovie.getDuration());
+
+ _pushIn.initFromMovieFrame(_blankMovie.getMovie(), newRobotView);
+ _turnPush.setInAndOutElements(&_pushIn, &_navMovie);
+ } else {
+ // Set segment of nav movie to whole movie, so that subsequent initFromMovieFrame
+ // will work.
+ _navMovie.setSegment(0, _navMovie.getDuration());
+
+ _pushIn.initFromMovieFrame(_navMovie.getMovie(), newView);
+ if (_blankMovie.isMovieValid() &&
+ (GameState.getTSAState() == kRobotsAtCommandCenter ||
+ GameState.getTSAState() == kRobotsAtFrontDoor ||
+ GameState.getTSAState() == kRobotsAtReadyRoom) &&
+ (GameState.getCurrentRoom() == kTSA0A ||
+ GameState.getCurrentRoom() == kTSA06))
+ _turnPush.setInAndOutElements(&_pushIn, &_blankMovie);
+ else
+ _turnPush.setInAndOutElements(&_pushIn, &_navMovie);
+ }
+
+ _blankMovie.hide();
+ _navMovie.hide();
+
+ switch (turnDirection) {
+ case kTurnLeft:
+ _turnPush.setSlideDirection(kSlideRightMask);
+ break;
+ case kTurnRight:
+ _turnPush.setSlideDirection(kSlideLeftMask);
+ break;
+ case kTurnUp:
+ _turnPush.setSlideDirection(kSlideDownMask);
+ break;
+ case kTurnDown:
+ _turnPush.setSlideDirection(kSlideUpMask);
+ break;
+ }
+
+ _turnPush.show();
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(60, 0, 0, 15, 1000);
+ _turnPush.startFader(moveSpec);
+
+ if (g_compass) {
+ _turnPush.pauseFader();
+
+ int32 startAngle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ int32 stopAngle = getStaticCompassAngle(GameState.getCurrentRoom(), nextDir);
+
+ if (turnDirection == kTurnLeft) {
+ if (startAngle < stopAngle)
+ startAngle += 360;
+ } else {
+ if (stopAngle < startAngle)
+ stopAngle += 360;
+ }
+
+ FaderMoveSpec turnSpec;
+ _turnPush.getCurrentFaderMove(turnSpec);
+
+ FaderMoveSpec compassMove;
+ compassMove.makeTwoKnotFaderSpec(turnSpec.getFaderScale(), turnSpec.getNthKnotTime(0), startAngle, turnSpec.getNthKnotTime(1), stopAngle);
+ g_compass->startFader(compassMove);
+ }
+
+ _turnPushCallBack.cancelCallBack();
+ _turnPush.continueFader();
+
+ do {
+ InputDevice.pumpEvents();
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ } while (_turnPush.isFading());
+
+ _turnPush.stopFader();
+ _neighborhoodNotification.setNotificationFlags(kTurnCompletedFlag, kTurnCompletedFlag);
+}
+
InputBits FullTSA::getInputFilter() {
InputBits result = Neighborhood::getInputFilter();
@@ -1283,8 +1474,20 @@ void FullTSA::turnRight() {
}
void FullTSA::openDoor() {
+ FaderMoveSpec spec;
+
switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA14, kSouth):
+ if (_vm->isDVD()) {
+ spec.makeTwoKnotFaderSpec(10, 0, 255, 5, 0);
+ _entranceFader.startFader(spec);
+ }
+ break;
case MakeRoomView(kTSA15, kSouth):
+ if (_vm->isDVD()) {
+ spec.makeTwoKnotFaderSpec(10, 0, 255, 5, 0);
+ _entranceFader.startFader(spec);
+ }
if (GameState.getTSAState() == kTSAPlayerNeedsHistoricalLog || GameState.getTSAState() == kRobotsAtFrontDoor)
setCurrentAlternate(kAltTSARedAlert);
break;
@@ -1295,6 +1498,26 @@ void FullTSA::openDoor() {
Neighborhood::openDoor();
}
+void FullTSA::doorOpened() {
+ if (_vm->isDVD()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA02, kNorth):
+ if (_lastExtra == kTSA02NorthDoorWithAgent3 && g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB36", kArthurTSASawAgent3);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB37", kArthurTSASawAgent3);
+ }
+ break;
+ case MakeRoomView(kTSA16, kSouth):
+ case MakeRoomView(kTSA21Cyan, kSouth):
+ _entranceMusic.stopSound();
+ break;
+ }
+ }
+ Neighborhood::doorOpened();
+}
+
CanMoveForwardReason FullTSA::canMoveForward(ExitTable::Entry &entry) {
if (GameState.getCurrentRoomAndView() == MakeRoomView(kTSA25Red, kNorth))
return kCantMoveBlocked;
@@ -1302,6 +1525,27 @@ CanMoveForwardReason FullTSA::canMoveForward(ExitTable::Entry &entry) {
return Neighborhood::canMoveForward(entry);
}
+void FullTSA::moveForward() {
+ ExitTable::Entry exitEntry;
+ CanMoveForwardReason moveReason = kCanMoveForward;
+ FaderMoveSpec spec;
+
+ if (_vm->isDVD()) {
+ moveReason = canMoveForward(exitEntry);
+ if (moveReason == kCanMoveForward &&
+ GameState.getCurrentRoomAndView() == MakeRoomView(kTSA02, kNorth) &&
+ !GameState.allTimeZonesFinished()) {
+ _entranceMusic.playSound();
+ spec.makeOneKnotFaderSpec(255);
+ _entranceFader.startFader(spec);
+ }
+ }
+ Neighborhood::moveForward();
+ if (moveReason == kCanMoveForward && GameState.getCurrentRoomAndView() == MakeRoomView(kTSA01, kSouth) &&
+ GameState.allTimeZonesFinished() && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA51", kArthurTSALeaving);
+}
+
CanOpenDoorReason FullTSA::canOpenDoor(DoorTable::Entry &entry) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kTSA02, kNorth):
@@ -1378,6 +1622,18 @@ void FullTSA::activateHotspots() {
if (!GameState.getTSAFrontDoorUnlockedOutside())
_vm->getAllHotspots().activateOneHotspot(kTSA02DoorSpotID);
break;
+ case MakeRoomView(kTSA0A, kEast):
+ if (GameState.getTSAState() == kRobotsAtCommandCenter ||
+ GameState.getTSAState() == kRobotsAtFrontDoor ||
+ GameState.getTSAState() == kRobotsAtReadyRoom)
+ _vm->getAllHotspots().deactivateOneHotspot(kTSA0AEastSpotID);
+ break;
+ case MakeRoomView(kTSA0A, kWest):
+ if (GameState.getTSAState() == kRobotsAtCommandCenter ||
+ GameState.getTSAState() == kRobotsAtFrontDoor ||
+ GameState.getTSAState() == kRobotsAtReadyRoom)
+ _vm->getAllHotspots().deactivateOneHotspot(kTSA0AWastSpotID);
+ break;
case MakeRoomView(kTSA0B, kEast):
if (GameState.getTSA0BZoomedIn())
switch (GameState.getTSAState()) {
@@ -1428,7 +1684,10 @@ void FullTSA::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
Neighborhood::clickInHotspot(input, clickedSpot);
break;
case kTSA03EastJimenezSpotID:
- startExtraLongSequence(kTSA03JimenezZoomIn, kTSA03JimenezZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input))
+ startExtraSequence(kEasterEggJimenez, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraLongSequence(kTSA03JimenezZoomIn, kTSA03JimenezZoomOut, kExtraCompletedFlag, kFilterNoInput);
break;
case kTSA03WestCrenshawSpotID:
startExtraLongSequence(kTSA03CrenshawZoomIn, kTSA03CrenshawZoomOut, kExtraCompletedFlag, kFilterNoInput);
@@ -1437,10 +1696,16 @@ void FullTSA::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
startExtraLongSequence(kTSA04MatsumotoZoomIn, kTSA04MatsumotoZoomOut, kExtraCompletedFlag, kFilterNoInput);
break;
case kTSA04WestCastilleSpotID:
- startExtraLongSequence(kTSA04CastilleZoomIn, kTSA04CastilleZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input))
+ startExtraSequence(kEasterEggCastillo, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraLongSequence(kTSA04CastilleZoomIn, kTSA04CastilleZoomOut, kExtraCompletedFlag, kFilterNoInput);
break;
case kTSA05EastSinclairSpotID:
- startExtraLongSequence(kTSA05SinclairZoomIn, kTSA05SinclairZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ if (_vm->isDVD() && JMPPPInput::isEasterEggModifierInput(input))
+ startExtraSequence(kEasterEggSinclair, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraLongSequence(kTSA05SinclairZoomIn, kTSA05SinclairZoomOut, kExtraCompletedFlag, kFilterNoInput);
break;
case kTSA05WestWhiteSpotID:
startExtraLongSequence(kTSA05WhiteZoomIn, kTSA05WhiteZoomOut, kExtraCompletedFlag, kFilterNoInput);
@@ -1603,6 +1868,12 @@ void FullTSA::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
// Pegasus
case kTSA37NorthJumpToPrehistoricSpotID:
startExtraSequence(kTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA30", kArthurTSAUsedPegasus);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA35", kArthurTSAUsedPegasus);
+ }
break;
case kTSA37NorthExitSpotID:
_sprite2.setCurrentFrameIndex(1);
@@ -1829,7 +2100,9 @@ void FullTSA::initializeComparisonMonitor(const int newMode, const ExtraID compa
}
}
- _interruptionFilter = kFilterAllInput;
+ // Only allow input if we're not in the middle of series of queue requests.
+ if (actionQueueEmpty())
+ _interruptionFilter = kFilterAllInput;
}
void FullTSA::playLeftComparison() {
@@ -1940,7 +2213,7 @@ void FullTSA::playRightComparison() {
// TSA state is kTSABossSawHistoricalLog.
void FullTSA::startRobotGame() {
requestExtraSequence(kTSA0BNorthCantChangeHistory, 0, kFilterNoInput);
- requestExtraSequence(kTSA0BAIInterruption, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BAIInterruption, kExtraCompletedFlag, kFilterNoInput);
requestExtraSequence(kTSA0BShowGuardRobots, 0, kFilterNoInput);
requestExtraSequence(kTSA0BRobotsToCommandCenter, kExtraCompletedFlag, kFilterNoInput);
}
@@ -1954,7 +2227,7 @@ void FullTSA::startUpRobotMonitor() {
_sprite1.addPICTResourceFrame(kRedirectionRRRolloverPICTID, true,
kRedirectionRRRolloverLeft - kRedirectionSprite1Left,
kRedirectionRRRolloverTop - kRedirectionSprite1Top);
- _sprite1.addPICTResourceFrame(kRedirectionFDRolloverPICTID, false,
+ _sprite1.addPICTResourceFrame(kRedirectionFDRolloverPICTID, true,
kRedirectionFDRolloverLeft - kRedirectionSprite1Left,
kRedirectionFDRolloverTop - kRedirectionSprite1Top);
_sprite1.addPICTResourceFrame(kRedirectionCCDoorPICTID, true,
@@ -1963,7 +2236,7 @@ void FullTSA::startUpRobotMonitor() {
_sprite1.addPICTResourceFrame(kRedirectionRRDoorPICTID, true,
kRedirectionRRDoorLeft - kRedirectionSprite1Left,
kRedirectionRRDoorTop - kRedirectionSprite1Top);
- _sprite1.addPICTResourceFrame(kRedirectionFDDoorPICTID, false,
+ _sprite1.addPICTResourceFrame(kRedirectionFDDoorPICTID, true,
kRedirectionFDDoorLeft - kRedirectionSprite1Left,
kRedirectionFDDoorTop - kRedirectionSprite1Top);
_sprite1.addPICTResourceFrame(kRedirectionClosePICTID, false,
@@ -2052,11 +2325,14 @@ void FullTSA::arriveAt(const RoomID room, const DirectionConstant direction) {
loopExtraSequence(kTSATransporterArrowLoop, 0);
}
break;
+ case MakeRoomView(kTSA01, kNorth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA22", kArthurTSAEnteredCave);
+ break;
case MakeRoomView(kTSA03, kNorth):
case MakeRoomView(kTSA05, kNorth):
case MakeRoomView(kTSA0A, kNorth):
case MakeRoomView(kTSA06, kNorth):
- case MakeRoomView(kTSA07, kNorth):
if (_utilityFuse.isFuseLit())
_utilityFuse.stopFuse();
GameState.setScoringEnterTSA(true);
@@ -2067,6 +2343,13 @@ void FullTSA::arriveAt(const RoomID room, const DirectionConstant direction) {
if (!GameState.getTSASeenRobotGreeting())
startExtraSequence(kTSA04NorthRobotGreeting, kExtraCompletedFlag, kFilterNoInput);
break;
+ case MakeRoomView(kTSA07, kNorth):
+ if (_utilityFuse.isFuseLit())
+ _utilityFuse.stopFuse();
+ GameState.setScoringEnterTSA(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA23", kArthurTSAReachedJunction);
+ break;
case MakeRoomView(kTSA03, kSouth):
GameState.setTSAFrontDoorUnlockedInside(GameState.getTSAState() == kRobotsAtFrontDoor || GameState.allTimeZonesFinished());
break;
@@ -2157,8 +2440,15 @@ void FullTSA::arriveAt(const RoomID room, const DirectionConstant direction) {
arriveAtTSA25Red();
break;
case MakeRoomView(kTSA34, kSouth):
- if (GameState.getLastRoom() == kTSA37)
+ if (GameState.getLastRoom() == kTSA37) {
closeDoorOffScreen(kTSA37, kNorth);
+ if (_vm->isDVD() && GameState.allTimeZonesFinished() && !_playedSolvedMusicCue) {
+ _solvedMusicCue.initFromAIFFFile("Sounds/TSA/TSA NORM.32K.AIFF");
+ _solvedMusicCue.setVolume(_vm->getAmbienceLevel());
+ _solvedMusicCue.playSound();
+ _playedSolvedMusicCue = true;
+ }
+ }
break;
case MakeRoomView(kTSA37, kNorth):
arriveAtTSA37();
@@ -2200,7 +2490,8 @@ void FullTSA::checkRobotLocations(const RoomID room, const DirectionConstant dir
switch (GameState.getTSAState()) {
case kRobotsAtCommandCenter:
if (!_privateFlags.getFlag(kTSAPrivateSeenRobotWarningFlag)) {
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/TSA/XT11WB", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/TSA/XT11WB", false, kWarningInterruption);
_privateFlags.setFlag(kTSAPrivateSeenRobotWarningFlag, true);
}
break;
@@ -2364,7 +2655,8 @@ void FullTSA::turnTo(const DirectionConstant newDirection) {
switch (GameState.getTSAState()) {
case kRobotsAtCommandCenter:
if (!_privateFlags.getFlag(kTSAPrivateSeenRobotWarningFlag)) {
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/TSA/XT11WB", false, kWarningInterruption);
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/TSA/XT11WB", false, kWarningInterruption);
_privateFlags.setFlag(kTSAPrivateSeenRobotWarningFlag, true);
}
break;
@@ -2439,6 +2731,65 @@ void FullTSA::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
}
}
+void FullTSA::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
+ static const TimeValue times[3][2] = {
+ { 0, 11720 },
+ { 11720, 19840 },
+ { 19840, 29960 }
+ };
+ TimeValue segmentStart = 0, segmentStop = 0;
+ bool loopSequence = false;
+ Common::Rect pushBounds;
+ NotificationFlags extraFlags;
+
+ switch (extraID) {
+ case kEasterEggJimenez:
+ case kEasterEggCastillo:
+ case kEasterEggSinclair:
+ _turnPush.getBounds(pushBounds);
+ _extraMovie.initFromMovieFile("Images/TSA/Wacky TSA.movie");
+ segmentStart = times[extraID - 1000][0];
+ segmentStop = times[extraID - 1000][1];
+ loopSequence = false;
+
+ _lastExtra = extraID;
+ _turnPush.hide();
+
+ if (!loopSequence && g_AIArea)
+ g_AIArea->lockAIOut();
+
+ extraFlags = flags;
+ _interruptionFilter = interruptionFilter;
+ // Stop the nav movie before doing anything else
+ _navMovie.stop();
+ _navMovie.stopDisplaying();
+
+ _extraMovie.setVolume(_vm->getSoundFXLevel());
+ _extraMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _extraMovie.setDisplayOrder(kNavMovieOrder + 1);
+ _extraMovie.startDisplaying();
+ _extraMovie.show();
+ _extraMovie.setFlags(0);
+ _extraMovie.setSegment(segmentStart, segmentStop);
+ _extraMovie.setTime(segmentStart);
+ if (loopSequence)
+ _extraMovie.setFlags(kLoopTimeBase);
+ else
+ extraFlags |= kNeighborhoodMovieCompletedFlag;
+ _extraMovieCallBack.cancelCallBack();
+ _extraMovieCallBack.initCallBack(&_extraMovie, kCallBackAtExtremes);
+ if (extraFlags != 0) {
+ _extraMovieCallBack.setCallBackFlag(extraFlags);
+ _extraMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+ _extraMovie.start();
+ break;
+ default:
+ Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+ break;
+ }
+}
+
void FullTSA::receiveNotification(Notification *notification, const NotificationFlags flags) {
ExtraID lastExtra = _lastExtra;
@@ -2458,12 +2809,15 @@ void FullTSA::receiveNotification(Notification *notification, const Notification
Neighborhood::receiveNotification(notification, flags);
InventoryItem *item;
+ bool doArthurSawBustMovie, doArthurRedirectedRobotsMovie;
if ((flags & kExtraCompletedFlag) != 0) {
// Only allow input if we're not in the middle of series of queue requests.
if (actionQueueEmpty())
_interruptionFilter = kFilterAllInput;
+ doArthurSawBustMovie = false;
+ doArthurRedirectedRobotsMovie = false;
switch (lastExtra) {
case kTSAGTCardSwipe:
item = (InventoryItem *)_vm->getAllItems().findItemByID(kKeyCard);
@@ -2494,21 +2848,43 @@ void FullTSA::receiveNotification(Notification *notification, const Notification
break;
case kTSA03JimenezZoomIn:
GameState.setScoringSawBust1(true);
+ doArthurSawBustMovie = true;
break;
case kTSA03CrenshawZoomIn:
GameState.setScoringSawBust2(true);
+ doArthurSawBustMovie = true;
break;
case kTSA04MatsumotoZoomIn:
GameState.setScoringSawBust3(true);
+ doArthurSawBustMovie = true;
break;
case kTSA04CastilleZoomIn:
GameState.setScoringSawBust4(true);
+ doArthurSawBustMovie = true;
break;
case kTSA05SinclairZoomIn:
GameState.setScoringSawBust5(true);
+ doArthurSawBustMovie = true;
break;
case kTSA05WhiteZoomIn:
GameState.setScoringSawBust6(true);
+ doArthurSawBustMovie = true;
+ break;
+ case kEasterEggJimenez:
+ case kEasterEggCastillo:
+ case kEasterEggSinclair:
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ doArthurSawBustMovie = true;
+ break;
+ case kTSA0AEastRobot:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA48", kArthurTSAClickedRobot1);
+ break;
+ case kTSA0AWestRobot:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA53", kArthurTSAClickedRobot2);
break;
// Command center
@@ -2616,15 +2992,20 @@ void FullTSA::receiveNotification(Notification *notification, const Notification
case kTSA0BShowGuardRobots:
startUpRobotMonitor();
// Fall through
+ case kTSA0BRobotsFromCommandCenterToFrontDoor:
+ case kTSA0BRobotsFromReadyRoomToFrontDoor:
+ doArthurRedirectedRobotsMovie = true;
case kTSA0BRobotsFromCommandCenterToReadyRoom:
case kTSA0BRobotsFromReadyRoomToCommandCenter:
- case kTSA0BRobotsFromCommandCenterToFrontDoor:
case kTSA0BRobotsFromFrontDoorToCommandCenter:
case kTSA0BRobotsFromFrontDoorToReadyRoom:
- case kTSA0BRobotsFromReadyRoomToFrontDoor:
_sprite2.setCurrentFrameIndex(kRedirectionSecuredSprite);
_sprite2.show();
break;
+ case kTSA0BAIInterruption:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA52", kArthurTSAConfinedByBaldwin);
+ break;
// TBP monitor.
case kTSA0BWestZoomIn:
@@ -2638,6 +3019,8 @@ void FullTSA::receiveNotification(Notification *notification, const Notification
}
initializeTBPMonitor(kMonitorNeutral, 0);
+ if (GameState.getTSAState() == kTSAPlayerForcedReview && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA55", kArthurTSAOpenTBPMonitor);
break;
case kTSA0BWestZoomOut:
GameState.setTSA0BZoomedIn(false);
@@ -2664,18 +3047,26 @@ void FullTSA::receiveNotification(Notification *notification, const Notification
case kTSA22RedEastZoomInSequence:
_privateFlags.setFlag(kTSAPrivateKeyVaultOpenFlag, true);
setCurrentActivation(kActivationKeyVaultOpen);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA50", kArthurTSASawJourneymanKey);
break;
case kTSA23RedWestVaultZoomInSequence:
_privateFlags.setFlag(kTSAPrivateChipVaultOpenFlag, true);
setCurrentActivation(kActivationChipVaultOpen);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA54", kArthurTSASawBiochips);
break;
case kTSA25NorthPutOnSuit:
GameState.setTSABiosuitOn(true);
GameState.setScoringGotBiosuit(true);
// Fall through...
case kTSA25NorthAlreadyHaveSuit:
- requestExtraSequence(kTSA25NorthDescending1, 0, kFilterNoInput);
+ requestExtraSequence(kTSA25NorthDescending1, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA25NorthDescending1:
requestExtraSequence(kTSA25NorthDescending2, kExtraCompletedFlag, kFilterNoInput);
+ if (GameState.getTSAState() != kTSAPlayerNeedsHistoricalLog && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA04", kArthurTSAUsedTurbolift);
break;
case kTSA25NorthDescending2:
arriveAt(kTSA26, kNorth);
@@ -2840,15 +3231,41 @@ void FullTSA::receiveNotification(Notification *notification, const Notification
case kTSA37CongratulationsToExit:
GameState.setTSAState(kPlayerFinishedWithTSA);
initializePegasusButtons(true);
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA49", kArthurTSASawBaldwinSayGo);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB22", kArthurTSASawBaldwinSayGo);
+ }
break;
default:
break;
}
+ if (g_arthurChip) {
+ if (doArthurSawBustMovie)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA21", kArthurTSASawBust);
+ else if (doArthurRedirectedRobotsMovie && GameState.getTSAState() == kRobotsAtFrontDoor)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA02", kArthurTSARedirectedRobots);
+ }
}
g_AIArea->checkMiddleArea();
}
+void FullTSA::setSoundFXLevel(const uint16 level) {
+ Neighborhood::setSoundFXLevel(level);
+ if (_extraMovie.isMovieValid())
+ _extraMovie.setVolume(level);
+}
+
+void FullTSA::setAmbienceLevel(const uint16 level) {
+ Neighborhood::setAmbienceLevel(level);
+ if (_entranceMusic.isSoundLoaded())
+ _entranceFader.setMasterVolume(level);
+ if (_solvedMusicCue.isSoundLoaded())
+ _solvedMusicCue.setVolume(level);
+}
+
void FullTSA::arriveFromPrehistoric() {
if (_vm->playerHasItemID(kHistoricalLog)) {
GameState.setScoringFinishedPrehistoric();
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.h b/engines/pegasus/neighborhood/tsa/fulltsa.h
index 7e9d5dae42..6fc71e7759 100644
--- a/engines/pegasus/neighborhood/tsa/fulltsa.h
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.h
@@ -68,6 +68,9 @@ public:
void checkContinuePoint(const RoomID, const DirectionConstant) override;
+ void setSoundFXLevel(const uint16) override;
+ void setAmbienceLevel(const uint16) override;
+
bool canSolve() override;
void doSolve() override;
@@ -99,9 +102,11 @@ protected:
void downButton(const Input &) override;
void startDoorOpenMovie(const TimeValue, const TimeValue) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
+ void showViewFrame(TimeValue) override;
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
void turnTo(const DirectionConstant) override;
CanMoveForwardReason canMoveForward(ExitTable::Entry &) override;
+ void moveForward() override;
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void bumpIntoWall() override;
void initializeTBPMonitor(const int, const ExtraID);
@@ -109,10 +114,13 @@ protected:
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void openDoor() override;
+ void doorOpened() override;
void turnRight() override;
void turnLeft() override;
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
+ void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void playExtraMovie(const ExtraTable::Entry &, const NotificationFlags, const InputBits interruptionInput) override;
+ void startTurnPush(const TurnDirection, const TimeValue, const DirectionConstant) override;
void handleInput(const Input &, const Hotspot *) override;
void arriveAtTSA25Red();
void startUpComparisonMonitor();
@@ -142,6 +150,15 @@ protected:
void checkRobotLocations(const RoomID, const DirectionConstant);
void getExtraEntry(const uint32, ExtraTable::Entry &) override;
+ Movie _extraMovie;
+ NotificationCallBack _extraMovieCallBack;
+ Movie _blankMovie;
+
+ Sound _entranceMusic;
+ SoundFader _entranceFader;
+ bool _playedSolvedMusicCue;
+ Sound _solvedMusicCue;
+
Sprite _sprite1, _sprite2, _sprite3;
FuseFunction _utilityFuse;
RipTimer _ripTimer;
diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.cpp b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
index ce0e5cfc05..42702a8627 100644
--- a/engines/pegasus/neighborhood/tsa/tinytsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
@@ -28,6 +28,7 @@
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/norad/constants.h"
@@ -189,7 +190,10 @@ Common::String TinyTSA::getEnvScanMovie() {
}
void TinyTSA::loadAmbientLoops() {
- loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+ if (_vm->isDVD()) // Updated sound in the DVD version
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.32K.AIFF");
+ else
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
}
int16 TinyTSA::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
@@ -404,6 +408,11 @@ void TinyTSA::receiveNotification(Notification *notification, const Notification
break;
}
}
+ if (((GameState.getNoradFinished() && !(GameState.getMarsFinished() || GameState.getWSCFinished())) ||
+ (GameState.getMarsFinished() && !(GameState.getNoradFinished() || GameState.getWSCFinished())) ||
+ (GameState.getWSCFinished() && !(GameState.getNoradFinished() || GameState.getMarsFinished()))) &&
+ g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB43", kArthurTSASawFirstOpMemMovie);
requestExtraSequence(kTinyTSA37OpMemReviewToMainMenu, kExtraCompletedFlag, kFilterNoInput);
break;
@@ -412,6 +421,8 @@ void TinyTSA::receiveNotification(Notification *notification, const Notification
GameState.setTSAState(kPlayerLockedInPegasus);
showMainJumpMenu();
makeContinuePoint();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA22", kArthurTSAInPegasusNoVideo);
break;
case kTinyTSA37JumpToNoradMenu:
setCurrentActivation(kActivationTinyTSAJumpToNorad);
diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp
index 329a060600..d2fc62adb1 100644
--- a/engines/pegasus/neighborhood/wsc/wsc.cpp
+++ b/engines/pegasus/neighborhood/wsc/wsc.cpp
@@ -23,10 +23,12 @@
*
*/
+#include "pegasus/cursor.h"
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/items/biochips/shieldchip.h"
#include "pegasus/neighborhood/wsc/wsc.h"
@@ -39,6 +41,12 @@ static const CanTurnReason kCantTurnWatchingDiagnosis = kCantTurnLastReason + 1;
static const CanTurnReason kCantTurnWatchingAnalysis = kCantTurnWatchingDiagnosis + 1;
static const CanTurnReason kCantTurnInMoleculeGame = kCantTurnWatchingAnalysis + 1;
+static const ExtraID kImplantNoGun = 1000;
+static const ExtraID kImplantWithGun = 1001;
+static const ExtraID kEasterEggWalchek = 1002;
+
+static const HotSpotID kBiotechImplantHotSpotID = 10000;
+
static const TimeScale kMoleculesMovieScale = 600;
static const TimeValue kMoleculeLoopTime = 4 * kMoleculesMovieScale;
static const TimeValue kMoleculeFailTime = 2 * kMoleculesMovieScale;
@@ -485,7 +493,7 @@ static const CoordType kMoleculesMovieLeft = kNavAreaLeft + 112;
static const CoordType kMoleculesMovieTop = kNavAreaTop + 40;
WSC::WSC(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "WSC", kWSCID),
- _moleculesMovie(kNoDisplayElement) {
+ _biotechImplantSpot(kBiotechImplantHotSpotID), _extraMovie(kNoDisplayElement), _moleculesMovie(kNoDisplayElement) {
_argonSprite = nullptr;
_cachedZoomSpot = nullptr;
@@ -504,6 +512,11 @@ WSC::WSC(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHan
GameState.isTakenItemID(kSinclairKey));
}
+WSC::~WSC() {
+ if (_vm->isDVD())
+ _vm->getAllHotspots().remove(&_biotechImplantSpot);
+}
+
uint16 WSC::getDateResID() const {
return kDate2310ID;
}
@@ -511,12 +524,23 @@ uint16 WSC::getDateResID() const {
void WSC::init() {
Neighborhood::init();
+ _extraMovieCallBack.setNotification(&_neighborhoodNotification);
+
_cachedZoomSpot = 0;
_argonSprite = 0;
// HACK: Fix the drag item for picking up the Sinclair Key Card
HotspotInfoTable::Entry *entry = findHotspotEntry(kWSC02SouthTakeArgonSpotID);
entry->hotspotItem = kArgonPickup;
+
+ if (_vm->isDVD()) {
+ Hotspot *aSpot = _vm->getAllHotspots().findHotspotByID(kW61TimeBendingSpotID);
+ aSpot->setArea(Common::Rect(97, 156, 275, 174));
+
+ _biotechImplantSpot.setArea(Common::Rect(kNavAreaLeft + 97, kNavAreaTop + 174, kNavAreaLeft + 275, kNavAreaTop + 182));
+ _biotechImplantSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_biotechImplantSpot);
+ }
}
void WSC::flushGameState() {
@@ -1032,27 +1056,27 @@ void WSC::getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry) {
break;
case kW61SouthScreenOnWithGun:
if (GameState.isTakenItemID(kMachineGun))
- Neighborhood::getExtraEntry(id, extraEntry);
- else
Neighborhood::getExtraEntry(kW61SouthScreenOnNoGun, extraEntry);
+ else
+ Neighborhood::getExtraEntry(id, extraEntry);
break;
case kW61SouthSmartAlloysWithGun:
if (GameState.isTakenItemID(kMachineGun))
- Neighborhood::getExtraEntry(id, extraEntry);
- else
Neighborhood::getExtraEntry(kW61SouthSmartAlloysNoGun, extraEntry);
+ else
+ Neighborhood::getExtraEntry(id, extraEntry);
break;
case kW61SouthMorphingWithGun:
if (GameState.isTakenItemID(kMachineGun))
- Neighborhood::getExtraEntry(id, extraEntry);
- else
Neighborhood::getExtraEntry(kW61SouthMorphingNoGun, extraEntry);
+ else
+ Neighborhood::getExtraEntry(id, extraEntry);
break;
case kW61SouthTimeBendingWithGun:
if (GameState.isTakenItemID(kMachineGun))
- Neighborhood::getExtraEntry(id, extraEntry);
- else
Neighborhood::getExtraEntry(kW61SouthTimeBendingNoGun, extraEntry);
+ else
+ Neighborhood::getExtraEntry(id, extraEntry);
break;
case kW98RobotHeadOpensLight:
if (GameState.getWSCCatwalkDark())
@@ -1118,6 +1142,21 @@ void WSC::bumpIntoWall() {
Neighborhood::bumpIntoWall();
}
+void WSC::spotCompleted() {
+ Neighborhood::spotCompleted();
+ if (_vm->isDVD() && GameState.getCurrentRoomAndView() == MakeRoomView(kWSC58, kSouth) && g_arthurChip) {
+ g_AIArea->checkRules();
+ if (GameState.isTakenItemID(kCrowbar)) {
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA94", kArthurWSCSawBrokenDoor);
+ } else {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA95", kArthurWSCSawBrokenDoorNoCrowBar);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurWSCSawBrokenDoorNoCrowBar);
+ }
+ }
+}
+
void WSC::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
Item *keyCard;
@@ -1164,27 +1203,43 @@ void WSC::cantOpenDoor(CanOpenDoorReason reason) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kWSC22, kWest):
playSpotSoundSync(kNakamuraNotHomeIn, kNakamuraNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC23, kEast):
playSpotSoundSync(kHernandezNotHomeIn, kHernandezNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC26, kWest):
playSpotSoundSync(kGrailisNotHomeIn, kGrailisNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC27, kEast):
playSpotSoundSync(kWashingtonNotHomeIn, kWashingtonNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC32, kWest):
playSpotSoundSync(kTheriaultNotHomeIn, kTheriaultNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC33, kEast):
playSpotSoundSync(kSullivanNotHomeIn, kSullivanNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC41, kWest):
playSpotSoundSync(kGlennerNotHomeIn, kGlennerNotHomeOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
case MakeRoomView(kWSC42, kEast):
playSpotSoundSync(kSinclairNotHomeIn, kSinclairNotHomeOut);
+ if (!GameState.isTakenItemID(kSinclairKey) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA91", kArthurWSCAttemptedSinclairDoorNoKey);
break;
case MakeRoomView(kWSC15, kWest):
case MakeRoomView(kWSC25, kWest):
@@ -1192,6 +1247,8 @@ void WSC::cantOpenDoor(CanOpenDoorReason reason) {
case MakeRoomView(kWSC41, kEast):
case MakeRoomView(kWSC46, kWest):
playSpotSoundSync(kWSCLabClosedIn, kWSCLabClosedOut);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA98", kArthurWSCAttemptedLockedDoor);
break;
default:
Neighborhood::cantOpenDoor(reason);
@@ -1338,10 +1395,87 @@ void WSC::zoomTo(const Hotspot *hotspot) {
}
void WSC::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
- if (extraID == kW61Brochure)
- loadLoopSound1("");
+ TimeValue segmentStart = 0, segmentStop = 0;
+ bool loopSequence = false;
+ Common::Rect pushBounds;
+ NotificationFlags extraFlags;
+
+ switch (extraID) {
+ case kImplantNoGun:
+ case kImplantWithGun:
+ case kEasterEggWalchek:
+ _turnPush.getBounds(pushBounds);
+
+ switch (extraID) {
+ case kImplantNoGun:
+ _extraMovie.initFromMovieFile("Images/World Science Center/W61SNF.movie");
+ break;
+ case kImplantWithGun:
+ _extraMovie.initFromMovieFile("Images/World Science Center/W61SZF.movie");
+ break;
+ case kEasterEggWalchek:
+ _extraMovie.initFromMovieFile("Images/World Science Center/W61WZF.movie");
+ break;
+ default:
+ break;
+ }
+ segmentStart = 0;
+ segmentStop = _extraMovie.getDuration();
+ loopSequence = false;
- Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+ _lastExtra = extraID;
+ _turnPush.hide();
+
+ if (!loopSequence && g_AIArea)
+ g_AIArea->lockAIOut();
+
+ extraFlags = flags;
+ _interruptionFilter = interruptionFilter;
+ // Stop the nav movie before doing anything else
+ _navMovie.stop();
+ _navMovie.stopDisplaying();
+
+ _extraMovie.setVolume(_vm->getSoundFXLevel());
+ _extraMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _extraMovie.setDisplayOrder(kNavMovieOrder + 1);
+ _extraMovie.startDisplaying();
+ _extraMovie.show();
+ _extraMovie.setFlags(0);
+ _extraMovie.setSegment(segmentStart, segmentStop);
+ _extraMovie.setTime(segmentStart);
+ if (loopSequence)
+ _extraMovie.setFlags(kLoopTimeBase);
+ else
+ extraFlags |= kNeighborhoodMovieCompletedFlag;
+ _extraMovieCallBack.cancelCallBack();
+ _extraMovieCallBack.initCallBack(&_extraMovie, kCallBackAtExtremes);
+ if (extraFlags != 0) {
+ _extraMovieCallBack.setCallBackFlag(extraFlags);
+ _extraMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+ _extraMovie.start();
+ break;
+ default:
+ switch (extraID) {
+ case kW61Brochure:
+ loadLoopSound1("");
+ break;
+ }
+ Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+ if (extraID == kWSCSpinRobot && g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA93", kArthurWSCSawAresHologram);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB08", kArthurWSCSawAresHologram);
+ }
+ break;
+ }
+}
+
+void WSC::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
+ Neighborhood::startDoorOpenMovie(startTime, stopTime);
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kWSC58, kSouth) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA19", kArthurWSCUsedCrowBar);
}
int16 WSC::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
@@ -1417,17 +1551,40 @@ void WSC::loadAmbientLoops() {
RoomID room = GameState.getCurrentRoom();
if (room >= kWSC01 && room <= kWSC04) {
- if (GameState.getWSCSeenTimeStream())
- loadLoopSound1("Sounds/World Science Center/WLabLoop.22K.AIFF", 0x100 / 2);
- } else if ((room >= kWSC06 && room <= kWSC58) || (room >= kWSC62 && room <= kWSC63))
- loadLoopSound1("Sounds/World Science Center/Organic Walls.22K.AIFF", 0x100 / 2);
- else if (room >= kWSC82 && room <= kWSC92)
- loadLoopSound1("Sounds/World Science Center/Creature Feature.22K.AIFF");
- else if ((room >= kWSC60 && room <= kWSC61West) || (room >= kWSC64 && room <= kWSC81) ||
- (room >= kWSC93 && room <= kWSC97))
- loadLoopSound1("Sounds/World Science Center/The Other Side.22K.AIFF", 0x100 / 12);
- else if (room == kWSC98)
- loadLoopSound1("Sounds/World Science Center/WCatLoop.22K.AIFF");
+ if (GameState.getWSCSeenTimeStream()) {
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/World Science Center/WLabLoop.32K.AIFF", 0x100 / 4);
+ else
+ loadLoopSound1("Sounds/World Science Center/WLabLoop.22K.AIFF", 0x100 / 2);
+ if (_vm->isDVD()) {
+ if (GameState.getWSCPoisoned())
+ loadLoopSound2("Sounds/World Science Center/Poisoned.32K.16.AIFF", 0x100 / 4);
+ else
+ loadLoopSound2("");
+ }
+ }
+ } else {
+ if ((room >= kWSC06 && room <= kWSC58) || (room >= kWSC62 && room <= kWSC63)) {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/World Science Center/Organic Walls.32K.16.AIFF", 205); // ~80%
+ else
+ loadLoopSound1("Sounds/World Science Center/Organic Walls.22K.AIFF", 0x100 / 2);
+ } else if (room >= kWSC82 && room <= kWSC92) {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/World Science Center/Creature Feature.32K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/World Science Center/Creature Feature.22K.AIFF");
+ } else if ((room >= kWSC60 && room <= kWSC61West) || (room >= kWSC64 && room <= kWSC81) ||
+ (room >= kWSC93 && room <= kWSC97)) {
+ if (_vm->isDVD()) // Updated for the DVD version
+ loadLoopSound1("Sounds/World Science Center/The Other Side.32K.16.AIFF", 51); // ~20%
+ else
+ loadLoopSound1("Sounds/World Science Center/The Other Side.22K.AIFF", 0x100 / 12);
+ } else if (room == kWSC98) {
+ loadLoopSound1("Sounds/World Science Center/WCatLoop.22K.AIFF");
+ }
+ loadLoopSound2("");
+ }
}
void WSC::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
@@ -1548,12 +1705,21 @@ void WSC::arriveAt(const RoomID room, const DirectionConstant dir) {
if (GameState.getWSCDesignedAntidote() && !GameState.getWSCPickedUpAntidote())
setCurrentActivation(kActivationReadyForSynthesis);
break;
+ case MakeRoomView(kWSC19, kWest):
+ if (!(GameState.isTakenItemID(kSinclairKey) && GameState.isTakenItemID(kArgonCanister) &&
+ GameState.isTakenItemID(kNitrogenCanister)) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA34", kArthurWSCLeftLabNoKeyOrCanisters);
+ break;
case MakeRoomView(kWSC16, kNorth):
if (getCurrentAlternate() == kAltWSCPeopleAtW19North) {
setCurrentAlternate(kAltWSCNormal);
_privateFlags.setFlag(kWSCPrivateSeenPeopleAt19NorthFlag, true);
}
break;
+ case MakeRoomView(kWSC06, kNorth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA81", kArthurWSCAtOppositeDoor);
+ break;
case MakeRoomView(kWSC07, kSouth):
case MakeRoomView(kWSC56, kNorth):
setCurrentActivation(kActivationReadyForMap);
@@ -1564,6 +1730,12 @@ void WSC::arriveAt(const RoomID room, const DirectionConstant dir) {
case MakeRoomView(kWSC42, kEast):
_privateFlags.setFlag(kWSCPrivateSinclairOfficeOpenFlag, false);
setCurrentActivation(kActivationSinclairOfficeLocked);
+ if (g_arthurChip) {
+ if (GameState.isTakenItemID(kSinclairKey))
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA99", kArthurWSCSawSinclairDoor);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA92", kArthurWSCSawSinclairDoorNoKey);
+ }
break;
case MakeRoomView(kWSC58, kSouth):
setCurrentActivation(kActivationW58SouthDoorLocked);
@@ -1572,8 +1744,14 @@ void WSC::arriveAt(const RoomID room, const DirectionConstant dir) {
case MakeRoomView(kWSC60, kEast):
GameState.setScoringEnteredSinclairOffice();
break;
+ case MakeRoomView(kWSC60East, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB03", kArthurWSCZoomedToSnake);
+ break;
case MakeRoomView(kWSC61West, kWest):
setCurrentActivation(kActivationW61MessagesOff);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB00", kArthurWSCZoomedToSinclairMessages);
break;
case MakeRoomView(kWSC61South, kSouth):
setCurrentActivation(kActivationW61SouthOff);
@@ -1581,12 +1759,21 @@ void WSC::arriveAt(const RoomID room, const DirectionConstant dir) {
case MakeRoomView(kWSC62, kSouth):
if (!GameState.getWSCDidPlasmaDodge()) {
g_AIArea->lockAIOut();
- loadLoopSound1("Sounds/World Science Center/Plasma Rock.22K.AIFF");
+
+ if (_vm->isDVD())
+ loadLoopSound1("Sounds/World Science Center/Plasma Rock.44K.16.AIFF");
+ else
+ loadLoopSound1("Sounds/World Science Center/Plasma Rock.22K.AIFF");
+
requestExtraSequence(kW62SouthPlasmaRobotAppears, 0, kFilterNoInput);
requestExtraSequence(kW62ZoomToRobot, 0, kFilterNoInput);
requestExtraSequence(kW62ZoomOutFromRobot, kExtraCompletedFlag, kFilterNoInput);
}
break;
+ case MakeRoomView(kWSC64, kSouth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB06", kArthurWSCEnteredAuditorium);
+ break;
case MakeRoomView(kWSC65Screen, kSouth):
if (!GameState.getWSCSeenSinclairLecture()) {
GameState.setWSCSeenSinclairLecture(true);
@@ -1614,11 +1801,33 @@ void WSC::arriveAt(const RoomID room, const DirectionConstant dir) {
if (getCurrentAlternate() == kAltWSCW0ZDoorOpen)
turnLeft();
break;
+ case MakeRoomView(kWSC82, kSouth):
+ case MakeRoomView(kWSC82, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB05", kArthurWSCEnteredPassage);
+ break;
+ case MakeRoomView(kWSC90, kEast):
+ case MakeRoomView(kWSC91, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA90", kArthurWSCInPassage);
+ break;
case MakeRoomView(kWSC93, kEast):
GameState.setWSCBeenAtWSC93(true);
+ case MakeRoomView(kWSC93, kNorth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA38", kArthurWSCExitedPassage);
+ break;
+ case MakeRoomView(kWSC95, kWest):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA92", kArthurWSCSawCatwalkDoor);
break;
case MakeRoomView(kWSC98, kWest):
if (!GameState.getWSCRobotDead()) {
+ if (_vm->isDVD()) {
+ _welcomeSound.initFromAIFFFile("Sounds/World Science Center/Welcome Enrique.22K.AIFF");
+ _welcomeSound.setVolume(_vm->getSoundFXLevel());
+ _welcomeSound.playSound();
+ }
scheduleEvent(kGawkAtRobotTime2, 1, kTimerEventPlayerGawkingAtRobot2);
setCurrentActivation(kActivationRobotTurning);
if (g_AIArea)
@@ -1663,6 +1872,10 @@ void WSC::turnTo(const DirectionConstant direction) {
if (GameState.getWSCDesignedAntidote() && !GameState.getWSCPickedUpAntidote())
setCurrentActivation(kActivationReadyForSynthesis);
break;
+ case MakeRoomView(kWSC06, kNorth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA81", kArthurWSCAtOppositeDoor);
+ break;
case MakeRoomView(kWSC07, kSouth):
case MakeRoomView(kWSC56, kNorth):
setCurrentActivation(kActivationReadyForMap);
@@ -1687,11 +1900,21 @@ void WSC::turnTo(const DirectionConstant direction) {
case MakeRoomView(kWSC42, kEast):
_privateFlags.setFlag(kWSCPrivateSinclairOfficeOpenFlag, false);
setCurrentActivation(kActivationSinclairOfficeLocked);
+ if (GameState.getCurrentRoom() == kWSC42 && g_arthurChip) {
+ if (GameState.isTakenItemID(kSinclairKey))
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA99", kArthurWSCSawSinclairDoor);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA92", kArthurWSCSawSinclairDoorNoKey);
+ }
break;
case MakeRoomView(kWSC58, kSouth):
setCurrentActivation(kActivationW58SouthDoorLocked);
_privateFlags.setFlag(kWSCPrivate58SouthOpenFlag, false);
break;
+ case MakeRoomView(kWSC64, kSouth):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB06", kArthurWSCEnteredAuditorium);
+ break;
case MakeRoomView(kWSC73, kWest):
setCurrentAlternate(kAltWSCNormal);
break;
@@ -1699,6 +1922,15 @@ void WSC::turnTo(const DirectionConstant direction) {
if (getCurrentAlternate() == kAltWSCW0ZDoorOpen)
startExtraSequence(kW0ZSpottedByWomen, kExtraCompletedFlag, kFilterNoInput);
break;
+ case MakeRoomView(kWSC82, kSouth):
+ case MakeRoomView(kWSC82, kEast):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB05", kArthurWSCEnteredPassage);
+ break;
+ case MakeRoomView(kWSC95, kWest):
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA92", kArthurWSCSawCatwalkDoor);
+ break;
default:
break;
}
@@ -1722,6 +1954,7 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
setCurrentActivation(kActivationShotByRobot);
GameState.setWSCPoisoned(true);
setUpPoison();
+ loadAmbientLoops();
makeContinuePoint();
break;
case kWSCDartScan2:
@@ -1729,14 +1962,18 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
GameState.setScoringRemovedDart();
GameState.setWSCRemovedDart(true);
setUpPoison();
- g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XW1WB2", false, kHintInterruption);
- // Fall through...
- case kWSCDartScanNo:
+ if (_vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XW1WB2", false, kHintInterruption);
GameState.setWSCAnsweredAboutDart(true);
startExtraSequence(kWSCDartScan3, kExtraCompletedFlag, kFilterNoInput);
break;
case kWSCDartScan3:
setCurrentActivation(kActivateHotSpotAlways);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB02", kArthurWSCRemovedDart);
+ break;
+ case kWSCDartScanNo:
+ die(kDeathDidntStopPoison);
break;
case kWSCAnalyzerPowerUp:
case kWSCAnalyzerPowerUpWithDart:
@@ -1770,10 +2007,18 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
break;
case kWSC02TurnOnMorphScreen:
setCurrentActivation(kActivationReadyForMorph);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA29", kArthurWSCLookAtMorphExperiment);
break;
case kWSC02DropToMorphExperiment:
loopExtraSequence(kWSC02MorphLoop, kExtraCompletedFlag);
setCurrentActivation(kActivationMorphLooping);
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA97", kArthurWSCStartMorphExperiment);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB04", kArthurWSCStartMorphExperiment);
+ }
break;
case kWSC02MorphLoop:
if (_privateFlags.getFlag(kWSCPrivateInterruptedMorphFlag))
@@ -1788,6 +2033,8 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
case kWSC02TurnOffMorphScreen:
setCurrentActivation(kActivationMorphScreenOff);
GameState.setWSCSawMorph(true);
+ if (!(GameState.isTakenItemID(kSinclairKey) && GameState.isTakenItemID(kArgonCanister)) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA96", kArthurWSCSawMorphExperiment);
break;
case kW03NorthActivate:
if (GameState.getWSCAnalyzedDart() && !GameState.getWSCDesignedAntidote())
@@ -1813,6 +2060,8 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
_privateFlags.setFlag(kWSCPrivateInMoleculeGameFlag, false);
GameState.setWSCDesignedAntidote(true);
GameState.setScoringBuiltAntidote();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA02", kArthurWSCDesignedAntidote);
break;
case kW03SouthCreateAntidote:
setCurrentActivation(kActivationSynthesizerLooping);
@@ -1825,9 +2074,13 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
case kWSC56SouthMap:
setCurrentActivation(kActivateHotSpotAlways);
GameState.setScoringSawWSCDirectory();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurWSCReadyForMap);
break;
case kNerdAtTheDoor1:
GameState.setWSCSeenNerd(true);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA28", kArthurWSCSeenNerd);
break;
case kNerdAtTheDoor2:
die(kDeathArrestedInWSC);
@@ -1848,6 +2101,13 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
case kW61SouthTimeBendingNoGun:
GameState.setScoringSawSinclairEntry3();
break;
+ case kImplantWithGun:
+ case kImplantNoGun:
+ case kEasterEggWalchek:
+ _extraMovie.stopDisplaying();
+ _extraMovie.releaseMovie();
+ _navMovie.startDisplaying();
+ break;
case kW61MessagesOn:
GameState.setWSCOfficeMessagesOpen(true);
setCurrentActivation(kActivationW61MessagesOn);
@@ -1864,6 +2124,8 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
case kW61SouthScreenOnNoGun:
_privateFlags.setFlag(kWSCPrivateOfficeLogOpenFlag, true);
setCurrentActivation(kActivationW61SouthOn);
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA89", kArthurWSCActivatedComputer);
break;
case kW61SouthScreenOffWithGun:
case kW61SouthScreenOffNoGun:
@@ -1877,7 +2139,6 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
case kW62ZoomOutFromRobot:
// Handle action queue before starting new movie sequences.
Neighborhood::receiveNotification(notification, flags);
- _energyDrainRate = g_energyMonitor->getEnergyDrainRate();
g_energyMonitor->setEnergyDrainRate(0);
currentEnergy = g_energyMonitor->getCurrentEnergy();
_vm->setEnergyDeathReason(kDeathHitByPlasma);
@@ -1905,12 +2166,22 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
g_energyMonitor->drainEnergy(kPlasmaEnergyNoShield);
}
- g_energyMonitor->setEnergyDrainRate(_energyDrainRate);
+ setUpPoison();
g_AIArea->unlockAI();
GameState.setScoringFinishedPlasmaDodge();
GameState.setWSCDidPlasmaDodge(true);
restoreStriding(kWSC58, kSouth, kAltWSCNormal);
loadAmbientLoops();
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA11", kArthurWSCDidPlasmaDodge);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB07", kArthurWSCDidPlasmaDodge);
+ }
+ break;
+ case kW65SouthSinclairLecture:
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB29", kArthurWSCSawSinclairLecture);
break;
case kW0ZSpottedByWomen:
die(kDeathArrestedInWSC);
@@ -1974,8 +2245,9 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
GameState.setWSCRobotDead(true);
GameState.setScoringStoppedWSCRobot();
- // Video is not present
- //g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XN59WD", false, kWarningInterruption);
+ // Video is erroneously not present in the CD version
+ if (_vm->isDVD() && _vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XN59WD", false, kWarningInterruption);
break;
case kW98RobotGassed:
item = (Item *)_vm->getAllItems().findItemByID(kArgonCanister);
@@ -1984,23 +2256,47 @@ void WSC::receiveNotification(Notification *notification, const NotificationFlag
GameState.setWSCRobotDead(true);
GameState.setScoringStoppedWSCRobot();
- // Video is not present
- //g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XN59WD", false, kWarningInterruption);
+ // Video is erroneously not present in the CD version
+ if (_vm->isDVD() && _vm->isChattyAI())
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XN59WD", false, kWarningInterruption);
break;
case kW98RobotHeadOpensLight:
case kW98RobotHeadOpensDark:
setCurrentActivation(kActivationWSCRobotHeadOpen);
_privateFlags.setFlag(kWSCPrivateRobotHeadOpenFlag, true);
+ if (g_arthurChip) {
+ switch (_vm->getRandomNumber(2)) {
+ case 0:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA36", kArthurWSCRobotHeadOpen);
+ break;
+ case 1:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA37", kArthurWSCRobotHeadOpen);
+ break;
+ case 2:
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA40", kArthurWSCRobotHeadOpen);
+ break;
+ }
+ }
break;
case kW98RobotHeadClosesDark:
case kW98RobotHeadClosesLight:
setCurrentActivation(kActivationRobotGone);
_privateFlags.setFlag(kWSCPrivateRobotHeadOpenFlag, false);
GameState.setWSCRobotGone(true);
+ if (GameState.isTakenItemID(kStunGun)) {
+ GameState.setWSCFinished(true);
+
+ if (!GameState.getWSCCatwalkDark())
+ GameState.setScoringWSCGandhi();
+
+ recallToTSASuccess();
+ }
break;
default:
break;
}
+ if ((_lastExtra == kW61WalchekEasterEgg1 || _lastExtra == kEasterEggWalchek) && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA09", kArthurWSCPlayedEasterEggMessage);
}
Neighborhood::receiveNotification(notification, flags);
@@ -2071,6 +2367,8 @@ void WSC::startMoleculeGameLevel() {
}
_moleculesMovie.start();
+ if (_moleculeGameLevel == 3 && g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA90", kArthurWSCPoisonedDuringGame);
}
void WSC::moleculeGameClick(const HotSpotID id) {
@@ -2152,6 +2450,8 @@ void WSC::moleculeGameClick(const HotSpotID id) {
_moleculesMovie.stop();
startMoleculeGameLevel();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB38", kArthurWSCFailedMolecule);
}
}
@@ -2197,27 +2497,44 @@ void WSC::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *hotspot) {
}
void WSC::activateHotspots() {
+ Input input;
+
Neighborhood::activateHotspots();
- if (GameState.getCurrentRoomAndView() == MakeRoomView(kWSC98, kWest) && _privateFlags.getFlag(kWSCPrivateRobotHeadOpenFlag)) {
- if (_privateFlags.getFlag(kWSCPrivateGotRetScanChipFlag))
- _vm->getAllHotspots().deactivateOneHotspot(kW98RetinalChipSpotID);
- else
- _vm->getAllHotspots().activateOneHotspot(kW98RetinalChipSpotID);
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC61South, kSouth):
+ if (_vm->isDVD()) {
+ InputDevice.getInput(input, kFilterAllInput);
+ if (_privateFlags.getFlag(kWSCPrivateOfficeLogOpenFlag) &&
+ JMPPPInput::isEasterEggModifierInput(input))
+ _vm->getAllHotspots().activateOneHotspot(kBiotechImplantHotSpotID);
+ }
+ break;
+ case MakeRoomView(kWSC98, kWest):
+ if (_privateFlags.getFlag(kWSCPrivateRobotHeadOpenFlag)) {
+ if (_privateFlags.getFlag(kWSCPrivateGotRetScanChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kW98RetinalChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kW98RetinalChipSpotID);
- if (_privateFlags.getFlag(kWSCPrivateGotMapChipFlag))
- _vm->getAllHotspots().deactivateOneHotspot(kW98MapChipSpotID);
- else
- _vm->getAllHotspots().activateOneHotspot(kW98MapChipSpotID);
+ if (_privateFlags.getFlag(kWSCPrivateGotMapChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kW98MapChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kW98MapChipSpotID);
- if (_privateFlags.getFlag(kWSCPrivateGotOpticalChipFlag))
- _vm->getAllHotspots().deactivateOneHotspot(kW98OpticalChipSpotID);
- else
- _vm->getAllHotspots().activateOneHotspot(kW98OpticalChipSpotID);
+ if (_privateFlags.getFlag(kWSCPrivateGotOpticalChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kW98OpticalChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kW98OpticalChipSpotID);
+ }
+ break;
}
}
void WSC::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ Movie movie(kNoDisplayElement);
+ Input movieInput;
+
if (JMPPPInput::isEasterEggModifierInput(input))
GameState.setEasterEgg(true);
@@ -2263,6 +2580,18 @@ void WSC::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
_privateFlags.setFlag(kWSCPrivateClickedCatwalkCableFlag, true);
break;
+ case kBiotechImplantHotSpotID:
+ if (GameState.isTakenItemID(kMachineGun))
+ startExtraSequence(kImplantNoGun, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kImplantWithGun, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kW61WalchekMessageSpotID:
+ if (_vm->isDVD() && GameState.getEasterEgg() && _vm->getRandomBit())
+ startExtraSequence(kEasterEggWalchek, kExtraCompletedFlag, kFilterNoInput);
+ else
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ break;
default:
Neighborhood::clickInHotspot(input, clickedSpot);
break;
@@ -2414,12 +2743,21 @@ void WSC::pickedUpItem(Item *item) {
_privateFlags.setFlag(kWSCDraggingAntidoteFlag, false);
playSpotSoundSync(kDrinkAntidoteIn, kDrinkAntidoteOut);
setUpPoison();
+ loadAmbientLoops();
if (!GameState.getWSCPickedUpAntidote()) {
GameState.setWSCPickedUpAntidote(true);
startExtraSequence(kW03SouthDeactivate, kExtraCompletedFlag, kFilterNoInput);
}
break;
+ case kMachineGun:
+ if (g_arthurChip) {
+ if (_vm->getRandomBit())
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB01", kArthurWSCGotMachineGun);
+ else
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB09", kArthurWSCGotMachineGun);
+ }
+ break;
case kArgonPickup:
_vm->removeItemFromInventory((InventoryItem *)item);
item = (Item *)_vm->getAllItems().findItemByID(kArgonCanister);
@@ -2611,6 +2949,15 @@ void WSC::doSolve() {
}
}
+void WSC::setSoundFXLevel(const uint16 level) {
+ Neighborhood::setSoundFXLevel(level);
+
+ if (_extraMovie.isMovieValid())
+ _extraMovie.setVolume(level);
+ if (_welcomeSound.isSoundLoaded())
+ _welcomeSound.setVolume(level);
+}
+
Common::String WSC::getNavMovieName() {
return "Images/World Science Center/WSC.movie";
}
diff --git a/engines/pegasus/neighborhood/wsc/wsc.h b/engines/pegasus/neighborhood/wsc/wsc.h
index 239da28633..5d36d6fcc8 100644
--- a/engines/pegasus/neighborhood/wsc/wsc.h
+++ b/engines/pegasus/neighborhood/wsc/wsc.h
@@ -42,7 +42,7 @@ static const RoomID kWSC62 = 62;
class WSC : public Neighborhood {
public:
WSC(InputHandler *, PegasusEngine *);
- ~WSC() override {}
+ ~WSC() override;
void flushGameState() override;
@@ -57,6 +57,8 @@ public:
bool canSolve() override;
void doSolve() override;
+ void setSoundFXLevel(const uint16) override;
+
void prepareForAIHint(const Common::String &) override;
void cleanUpAfterAIHint(const Common::String &) override;
@@ -126,6 +128,7 @@ protected:
void pickedUpItem(Item *) override;
void doorOpened() override;
void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
+ void startDoorOpenMovie(const TimeValue, const TimeValue) override;
void getExtraEntry(const uint32, ExtraTable::Entry &) override;
void takeItemFromRoom(Item *item) override;
void checkPeopleCrossing();
@@ -137,6 +140,7 @@ protected:
void getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) override;
void getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) override;
void bumpIntoWall() override;
+ void spotCompleted() override;
void activateHotspots() override;
void setUpAIRules() override;
Common::String getBriefingMovie() override;
@@ -153,12 +157,15 @@ protected:
FlagsArray<byte, kNumWSCPrivateFlags> _privateFlags;
const Hotspot *_cachedZoomSpot;
+ Hotspot _biotechImplantSpot;
+ Movie _extraMovie;
+ NotificationCallBack _extraMovieCallBack;
MoleculeBin _moleculeBin;
int32 _moleculeGameLevel, _numCorrect;
Movie _moleculesMovie;
uint32 _levelArray[6];
- Common::Rational _energyDrainRate;
Sprite *_argonSprite;
+ Sound _welcomeSound;
};
} // End of namespace Pegasus
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 4affc6f244..7884191bc7 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -55,6 +55,7 @@
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/itemlist.h"
#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/biochipitem.h"
#include "pegasus/items/biochips/mapchip.h"
#include "pegasus/items/biochips/opticalchip.h"
@@ -96,12 +97,20 @@ PegasusEngine::PegasusEngine(OSystem *syst, const PegasusGameDescription *gamede
_idlerHead = 0;
_currentCD = 1;
_introTimer = 0;
+ _toggleRequested = false;
+ _chattyAI = true;
+ _chattyArthur = true;
_aiSaveStream = 0;
+ _heardOverviewVoice = false;
}
PegasusEngine::~PegasusEngine() {
throwAwayEverything();
+ if (isDVD()) {
+ Arthur.destroy();
+ }
+
delete _resFork;
delete _cursor;
delete _continuePoint;
@@ -264,9 +273,13 @@ void PegasusEngine::createItems() {
void PegasusEngine::createItem(ItemID itemID, NeighborhoodID neighborhoodID, RoomID roomID, DirectionConstant direction) {
switch (itemID) {
case kInterfaceBiochip:
- // Unused in game, but still in the data and we need to create
- // it because it's saved/loaded from save files.
- new BiochipItem(itemID, neighborhoodID, roomID, direction);
+ if (isDVD()) {
+ new ArthurChip(itemID, neighborhoodID, roomID, direction);
+ } else {
+ // Unused in game, but still in the data and we need to create
+ // it because it's saved/loaded from save files.
+ new BiochipItem(itemID, neighborhoodID, roomID, direction);
+ }
break;
case kAIBiochip:
new AIChip(itemID, neighborhoodID, roomID, direction);
@@ -336,10 +349,26 @@ void PegasusEngine::runIntro() {
if (shouldQuit() || skipped)
return;
+#ifdef USE_THEORADEC
+ if (isDVD() && Common::File::exists(_introDirectory + "/BigMovie_hq.ogg")) {
+ Video::TheoraDecoder hqVideo;
+ hqVideo.setSoundType(Audio::Mixer::kPlainSoundType);
+
+ if (hqVideo.loadFile(_introDirectory + "/BigMovie_hq.ogg")) {
+ hqVideo.start();
+ playMovieScaled(&hqVideo, 0, 0);
+ return;
+ }
+ }
+#endif
+
video = new Video::QuickTimeDecoder();
if (!video->loadFile(_introDirectory + "/Big Movie.movie"))
- error("Could not load intro movie");
+ if (!video->loadFile(_introDirectory + "/BigMovie.movie"))
+ error("Could not load intro movie");
+
+ video->setVolume(MIN<uint>(getAmbienceLevel(), 0xFF));
video->setVolume(MIN<uint>(getAmbienceLevel(), 0xFF));
@@ -545,7 +574,14 @@ bool PegasusEngine::loadFromStream(Common::SeekableReadStream *stream) {
}
}
+ if (isDVD()) {
+ Arthur.resetArthurState();
+ _screenDimmer.hide();
+ _screenDimmer.stopDisplaying();
+ }
startNeighborhood();
+ if (g_arthurChip)
+ g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB24", kArthurLoadedSavedGame);
// Make a new continue point if this isn't already one
if (saveType == kNormalSave)
@@ -780,9 +816,26 @@ void PegasusEngine::introTimerExpired() {
bool skipped = false;
- Video::VideoDecoder *video = new Video::QuickTimeDecoder();
- if (!video->loadFile(_introDirectory + "/LilMovie.movie"))
- error("Failed to load little movie");
+ Video::VideoDecoder *video = 0;
+
+#ifdef USE_THEORADEC
+ if (isDVD()) {
+ video = new Video::TheoraDecoder();
+
+ if (!video->loadFile(_introDirectory + "/LilMovie_hq.ogg")) {
+ delete video;
+ video = 0;
+ }
+ }
+#endif
+
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile(_introDirectory + "/LilMovie.movie"))
+ error("Failed to load little movie");
+ }
+
+ video->setVolume(MIN<uint>(getAmbienceLevel(), 0xFF));
video->setVolume(MIN<uint>(getAmbienceLevel(), 0xFF));
@@ -880,6 +933,7 @@ void PegasusEngine::doGameMenuCommand(const GameMenuCommand command) {
_gfx->doFadeOutSync();
useMenu(new CreditsMenu());
_gfx->updateDisplay();
+ ((CreditsMenu *)_gameMenu)->startCreditsMenuLoop();
_gfx->doFadeInSync();
}
break;
@@ -924,34 +978,103 @@ void PegasusEngine::doGameMenuCommand(const GameMenuCommand command) {
_gfx->updateDisplay();
_gfx->doFadeInSync();
} else {
+ Input input;
+ if (isDVD()) {
+ InputDevice.getInput(input, kFilterAllInput);
+ if (JMPPPInput::isEasterEggModifierInput(input))
+ GameState.setEasterEgg(true);
+ }
+
_gfx->doFadeOutSync();
useMenu(0);
_gfx->enableErase();
_gfx->updateDisplay();
_gfx->disableErase();
- Video::VideoDecoder *video = new Video::QuickTimeDecoder();
- if (!video->loadFile(_introDirectory + "/Closing.movie"))
- error("Could not load closing movie");
+ Video::VideoDecoder *video = 0;
+ if (GameState.getEasterEgg()) {
+#ifdef USE_THEORADEC
+ video = new Video::TheoraDecoder();
+ if (!video->loadFile(_introDirectory + "/Closing_hq2.ogg")) {
+ delete video;
+ video = 0;
+ }
+#endif
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile(_introDirectory + "/Closing2.movie"))
+ error("Could not load alternate closing movie");
+ }
+ } else {
+#ifdef USE_THEORADEC
+ video = new Video::TheoraDecoder();
+ if (!video->loadFile(_introDirectory + "/Closing_hq1.ogg")) {
+ delete video;
+ video = 0;
+ }
+#endif
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile(_introDirectory + "/Closing.movie"))
+ error("Could not load closing movie");
+ }
+ }
video->setVolume(MIN<uint>(getSoundFXLevel(), 0xFF));
- uint16 x = (640 - video->getWidth() * 2) / 2;
- uint16 y = (480 - video->getHeight() * 2) / 2;
+ uint16 newHeight = (uint16)((640.0f / (float)video->getWidth()) * (float)video->getHeight());
+ uint16 x = 0;
+ uint16 y = (480 - newHeight) / 2;
video->start();
- playMovieScaled(video, x, y);
+ bool interrupted = playMovieScaled(video, x, y);
delete video;
+ if (isDVD() && !interrupted) {
+ // Display new post credits movie
+#ifdef USE_THEORADEC
+ video = new Video::TheoraDecoder();
+ if (!video->loadFile(_introDirectory + "/Closing_hq3.ogg")) {
+ delete video;
+ video = 0;
+ }
+#endif
+ if (!video) {
+ video = new Video::QuickTimeDecoder();
+ if (!video->loadFile(_introDirectory + "/Closing3.movie"))
+ error("Could not load closing 3 movie");
+ }
+
+ video->setVolume(MIN<uint>(getSoundFXLevel(), 0xFF));
+
+ video->start();
+ interrupted = playMovieScaled(video, 0, 0);
+ delete video;
+ }
+
if (shouldQuit())
return;
- useMenu(new MainMenu());
- _gfx->updateDisplay();
- ((MainMenu *)_gameMenu)->startMainMenuLoop();
- _gfx->doFadeInSync();
- resetIntroTimer();
+ if (isDVD()) {
+ useMenu(new CreditsMenu());
+ _gfx->updateDisplay();
+ ((CreditsMenu *)_gameMenu)->startCreditsMenuLoop();
+ if (!interrupted)
+ _gfx->doFadeInSync();
+ else
+ _gfx->enableUpdates();
+ } else {
+ useMenu(new MainMenu());
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ if (!interrupted)
+ _gfx->doFadeInSync();
+ else
+ _gfx->enableUpdates();
+ resetIntroTimer();
+ }
+ GameState.setEasterEgg(false);
}
} else {
loadFromContinuePoint();
@@ -1080,6 +1203,8 @@ void PegasusEngine::doInterfaceOverview() {
Common::Rect(542, 36, 542 + 58, 36 + 20)
};
+ static const Common::Rect hiddenSpot = Common::Rect(595, 417, 595 + 4, 417 + 5);
+
_gfx->doFadeOutSync();
useMenu(0);
@@ -1118,7 +1243,18 @@ void PegasusEngine::doInterfaceOverview() {
controllerHighlight.startDisplaying();
Movie overviewText(kNoDisplayElement);
- overviewText.initFromMovieFile("Images/Interface/Overview Mac.movie");
+
+ if (isDVD()) {
+ if (isLinux() && Common::File::exists("Images/Interface/Overview Linux.movie"))
+ overviewText.initFromMovieFile("Images/Interface/Overview Linux.movie");
+ else if (isLinux() || isWindows())
+ overviewText.initFromMovieFile("Images/Interface/Overview PC.movie");
+ else
+ overviewText.initFromMovieFile("Images/Interface/Overview ScummVM.movie");
+ } else {
+ overviewText.initFromMovieFile("Images/Interface/Overview Mac.movie");
+ }
+
overviewText.setDisplayOrder(0);
overviewText.moveElementTo(kNavAreaLeft, kNavAreaTop);
overviewText.startDisplaying();
@@ -1154,6 +1290,10 @@ void PegasusEngine::doInterfaceOverview() {
if (time == 2) {
highlight.hide();
controllerHighlight.show();
+
+ // Hidden message in the DVD version
+ if (isDVD() && hiddenSpot.contains(cursorLoc))
+ time = 12;
} else if (i != kNumOverviewSpots) {
controllerHighlight.hide();
Common::Rect r = overviewSpots[i];
@@ -1174,6 +1314,28 @@ void PegasusEngine::doInterfaceOverview() {
_gfx->updateDisplay();
_gfx->doFadeInSync();
+ Sound overviewVoice, overviewMusic;
+ SoundFader overviewMusicFader;
+
+ // In the DVD version, play the voice and some background sound
+ if (isDVD()) {
+ if (!_heardOverviewVoice) {
+ _heardOverviewVoice = true;
+ overviewVoice.initFromAIFFFile("Sounds/Overview.aiff");
+ overviewVoice.setVolume(getSoundFXLevel());
+ overviewVoice.playSound();
+ }
+
+ overviewMusic.attachFader(&overviewMusicFader);
+ overviewMusic.initFromAIFFFile("Sounds/TSA/T01NAE.NEW.32K.AIFF");
+ overviewMusicFader.setMasterVolume(getAmbienceLevel());
+ overviewMusic.loopSound();
+
+ FaderMoveSpec spec;
+ spec.makeTwoKnotFaderSpec(30, 0, 0, 30, 255);
+ overviewMusicFader.startFaderSync(spec);
+ }
+
for (;;) {
InputDevice.getInput(input, kFilterAllInput);
@@ -1195,6 +1357,10 @@ void PegasusEngine::doInterfaceOverview() {
if (time == 2) {
highlight.hide();
controllerHighlight.show();
+
+ // Hidden message in the DVD version
+ if (isDVD() && hiddenSpot.contains(cursorLoc))
+ time = 12;
} else if (i != kNumOverviewSpots) {
controllerHighlight.hide();
Common::Rect r = overviewSpots[i];
@@ -1223,6 +1389,16 @@ void PegasusEngine::doInterfaceOverview() {
highlight.hide();
_cursor->hide();
+ // Make sure we cut off the music and sound
+ overviewVoice.stopSound();
+
+ if (overviewMusic.isPlaying()) {
+ FaderMoveSpec spec;
+ spec.makeTwoKnotFaderSpec(30, 0, 255, 30, 0);
+ overviewMusicFader.startFaderSync(spec);
+ overviewMusic.stopSound();
+ }
+
_gfx->doFadeOutSync();
useMenu(new MainMenu());
_gfx->updateDisplay();
@@ -1376,6 +1552,40 @@ void PegasusEngine::cleanUpAfterAIHint(const Common::String &movieName) {
g_neighborhood->cleanUpAfterAIHint(movieName);
}
Commit: a4811f67b9eb670dc0492f5c82b7805422baaa8b
https://github.com/scummvm/scummvm/commit/a4811f67b9eb670dc0492f5c82b7805422baaa8b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2021-03-17T17:34:14+01:00
Commit Message:
NEWS: Mention recent improvements
Changed paths:
NEWS.md
diff --git a/NEWS.md b/NEWS.md
index d15ef30a47..151b068b92 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -23,6 +23,7 @@ For a more comprehensive changelog of the latest experimental code, see:
- Switched ScummVM GUI output to UTF-32.
- Updated the Roland MT-32 emulation code to the Munt project's mt32emu 2.4.2.
- Updated Dropbox Cloud Storage to use the new Dropbox OAuth workflow.
+ - Major extension to the number of supported graphics scalers.
AGOS:
- Added support for the Japanese PC-98 version of Elvira 1.
@@ -55,6 +56,9 @@ For a more comprehensive changelog of the latest experimental code, see:
- Fixed fire animation in first room when loading saves.
- Fixed MT-32 support.
+ Pegasus:
+ - Added support for DVD/GOG.com release.
+
SAGA:
- Added support for ITE GOG Mac CD v1.1.
- Added support for ITE PC-98 Japanese.
More information about the Scummvm-git-logs
mailing list