aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2011-10-02 20:52:09 -0400
committerMatthew Hoops2011-10-02 20:52:09 -0400
commit8c7ebc803383a87cf3199b12d5b3485b2685a873 (patch)
tree6b61f6f6ad1246f47e07631281b4932aa0bab0b1
parentb24081c781d66cdc496a14b6326574f75b083dc6 (diff)
downloadscummvm-rg350-8c7ebc803383a87cf3199b12d5b3485b2685a873.tar.gz
scummvm-rg350-8c7ebc803383a87cf3199b12d5b3485b2685a873.tar.bz2
scummvm-rg350-8c7ebc803383a87cf3199b12d5b3485b2685a873.zip
PEGASUS: Add the basic Caldoria neighborhood
Does not include the end-of-game timers and sequence yet. It's currently hooked up to the full game, but does not go beyond the first frame of the wake-up sequence right now.
-rwxr-xr-xengines/pegasus/constants.h2
-rwxr-xr-xengines/pegasus/energymonitor.h2
-rw-r--r--engines/pegasus/graphics.cpp13
-rw-r--r--engines/pegasus/graphics.h7
-rw-r--r--engines/pegasus/module.mk4
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoria.cpp1920
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoria.h509
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp369
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoria4dsystem.h78
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoriamessages.cpp115
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoriamessages.h60
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoriamirror.cpp134
-rwxr-xr-xengines/pegasus/neighborhood/caldoria/caldoriamirror.h54
-rw-r--r--engines/pegasus/neighborhood/neighborhood.h1
-rw-r--r--engines/pegasus/pegasus.cpp58
-rw-r--r--engines/pegasus/pegasus.h9
16 files changed, 3292 insertions, 43 deletions
diff --git a/engines/pegasus/constants.h b/engines/pegasus/constants.h
index 4c31b45a50..5ab2baac22 100755
--- a/engines/pegasus/constants.h
+++ b/engines/pegasus/constants.h
@@ -739,7 +739,7 @@ static const tGameMode kModeInfoScreen = kModeBiochipPick + 1;
// TODO: Remove me
static const tRoomID kTSA37 = 42;
static const tRoomID kTinyTSA37 = 0;
-static const tRoomID kCaldoria00 = 1;
+static const tRoomID kTSA00 = 0;
} // End of namespace Pegasus
diff --git a/engines/pegasus/energymonitor.h b/engines/pegasus/energymonitor.h
index cb5d4498fc..cb1170cd10 100755
--- a/engines/pegasus/energymonitor.h
+++ b/engines/pegasus/energymonitor.h
@@ -53,7 +53,7 @@ protected:
// These are in seconds.
// Max is two hours
-static const uint32 kMaxJMPEnergy = 7200;
+static const uint32 kMaxJMPEnergy = 60 * 1;
static const uint32 kCasualEnergy = kMaxJMPEnergy * 100 / 100; // 100%
static const uint32 kWorriedEnergy = kMaxJMPEnergy * 50 / 100; // 50%
diff --git a/engines/pegasus/graphics.cpp b/engines/pegasus/graphics.cpp
index 8e5c86d7b5..1e529d0e07 100644
--- a/engines/pegasus/graphics.cpp
+++ b/engines/pegasus/graphics.cpp
@@ -194,11 +194,18 @@ DisplayElement *GraphicsManager::findDisplayElement(const tDisplayElementID id)
return 0;
}
-void GraphicsManager::doFadeOutSync() {
- // TODO
+void GraphicsManager::doFadeOutSync(const TimeValue, const TimeValue, uint32 color) {
+ if (color == 0)
+ color = g_system->getScreenFormat().RGBToColor(0, 0, 0);
+
+ // HACK: Until fading out is done, white-out the screen here
+ Graphics::Surface *screen = g_system->lockScreen();
+ screen->fillRect(Common::Rect(0, 0, 640, 480), color);
+ g_system->unlockScreen();
+ g_system->updateScreen();
}
-void GraphicsManager::doFadeInSync() {
+void GraphicsManager::doFadeInSync(const TimeValue, const TimeValue, uint32) {
// TODO
}
diff --git a/engines/pegasus/graphics.h b/engines/pegasus/graphics.h
index 7aeb3c9b38..e1b339843f 100644
--- a/engines/pegasus/graphics.h
+++ b/engines/pegasus/graphics.h
@@ -32,6 +32,7 @@
#include "graphics/pict.h"
#include "graphics/surface.h"
+#include "pegasus/constants.h"
#include "pegasus/pegasus.h"
#include "pegasus/util.h"
@@ -56,8 +57,10 @@ public:
Graphics::Surface *getWorkArea() { return &_workArea; }
void clearScreen();
DisplayElement *findDisplayElement(const tDisplayElementID id);
- void doFadeOutSync();
- void doFadeInSync();
+
+ // These default to black
+ void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, uint32 color = 0);
+ void doFadeInSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, uint32 color = 0);
protected:
void markCursorAsDirty();
diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk
index 3759780b28..66cf70b2ca 100644
--- a/engines/pegasus/module.mk
+++ b/engines/pegasus/module.mk
@@ -51,6 +51,10 @@ MODULE_OBJS = \
neighborhood/turn.o \
neighborhood/view.o \
neighborhood/zoom.o \
+ neighborhood/caldoria/caldoria.o \
+ neighborhood/caldoria/caldoria4dsystem.o \
+ neighborhood/caldoria/caldoriamessages.o \
+ neighborhood/caldoria/caldoriamirror.o \
neighborhood/prehistoric/prehistoric.o
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
new file mode 100755
index 0000000000..7a5ec1b701
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -0,0 +1,1920 @@
+/* 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 "common/system.h"
+#include "video/qt_decoder.h"
+
+#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/biochipitem.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoria4dsystem.h"
+#include "pegasus/neighborhood/caldoria/caldoriamessages.h"
+#include "pegasus/neighborhood/caldoria/caldoriamirror.h"
+
+namespace Pegasus {
+
+const short kVidPhoneAngle = 30;
+const short kReplicatorAngle = 50;
+const short kDrawersAngle = -30;
+const short kCaldoria53Angle = 45;
+const short kCaldoria55Angle = -45;
+
+const TimeValue kSinclairInterruptionTime1 = 2955;
+const TimeValue kSinclairInterruptionTime2 = 6835;
+const TimeValue kSinclairInterruptionTime3 = 9835;
+const TimeValue kSinclairInterruptionTime4 = 12555;
+
+const tInputBits kPullbackInterruptFilter = kFilterAllInput;
+const tInputBits kRecalibrationInterruptFilter = kFilterAllInput;
+
+const TimeValue kCaldoriaReplicatorIntroIn = 4933;
+const TimeValue kCaldoriaReplicatorIntroOut = 6557;
+
+const TimeValue kCaldoriaReplicatorWrongChoiceIn = 6557;
+const TimeValue kCaldoriaReplicatorWrongChoiceOut = 8586;
+
+const TimeValue kCaldoriaReplicatorOJChoiceIn = 8586;
+const TimeValue kCaldoriaReplicatorOJChoiceOut = 11687;
+
+const TimeValue kCaldoriaMessagesIntroIn = 11687;
+const TimeValue kCaldoriaMessagesIntroOut = 13641;
+
+const TimeValue kCaldoriaFirstMessageIn = 13641;
+const TimeValue kCaldoriaFirstMessageOut = 14203;
+
+const TimeValue kCaldoriaSecondMessageIn = 14203;
+const TimeValue kCaldoriaSecondMessageOut = 14750;
+
+const TimeValue kCaldoriaDoorCloseIn = 14750;
+const TimeValue kCaldoriaDoorCloseOut = 15472;
+
+const TimeValue kCaldoriaElevatorCloseIn = 15472;
+const TimeValue kCaldoriaElevatorCloseOut = 16336;
+
+const TimeValue kCaldoriaShowerCloseIn = 16336;
+const TimeValue kCaldoriaShowerCloseOut = 17101;
+
+const TimeValue kCaldoriaGTDoorCloseIn = 17101;
+const TimeValue kCaldoriaGTDoorCloseOut = 18523;
+
+const TimeValue kCaldoriaNobodyHomeIn = 18523;
+const TimeValue kCaldoriaNobodyHomeOut = 21469;
+
+const TimeValue kCaldoriaNoOtherFloorIn = 21469;
+const TimeValue kCaldoriaNoOtherFloorOut = 28013;
+
+const TimeValue kCaldoria4DInstructionsIn = 28013;
+const TimeValue kCaldoria4DInstructionsOut = 29730;
+
+const TimeValue kCaldoriaDrinkOJIn = 33910;
+const TimeValue kCaldoriaDrinkOJOut = 35846;
+
+const TimeValue kCaldoriaNoOtherDestinationIn = 35846;
+const TimeValue kCaldoriaNoOtherDestinationOut = 37877;
+
+const TimeValue kCaldoriaUhghIn = 37877;
+const TimeValue kCaldoriaUhghOut = 38025;
+
+const TimeValue kCaldoriaSinclairShootsOSIn = 38025;
+const TimeValue kCaldoriaSinclairShootsOSOut = 40649;
+
+const TimeValue kCaldoriaScreamingAfterIn = 40649;
+const TimeValue kCaldoriaScreamingAfterOut = 47661;
+
+const TimeValue k4FloorTime = 0;
+
+const TimeValue k4To1Start = 40;
+const TimeValue k4To1Stop = 7720;
+
+const TimeValue k4To5Start = 7720;
+const TimeValue k4To5Stop = 10280;
+
+const TimeValue k4To2Time = 10280;
+
+const TimeValue k4To3Time = 10320;
+
+const TimeValue k1FloorTime = 10360;
+
+const TimeValue k1To4Start = 10400;
+const TimeValue k1To4Stop = 18080;
+
+const TimeValue k1To5Start = 18080;
+const TimeValue k1To5Stop = 28320;
+
+const TimeValue k1To2Time = 28320;
+
+const TimeValue k1To3Time = 28360;
+
+const TimeValue k5FloorTime = 28400;
+
+const TimeValue k5To1Start = 28440;
+const TimeValue k5To1Stop = 38680;
+
+const TimeValue k5To4Start = 38680;
+const TimeValue k5To4Stop = 41240;
+
+const TimeValue k5To2Time = 41240;
+
+const TimeValue k5To3Time = 41280;
+
+// MMFuseFunction functions...
+
+const tNotificationFlags kSinclairLoopDoneFlag = kLastNeighborhoodNotificationFlag << 1;
+
+void doorBombTimerExpiredFunction(FunctionPtr *, void *caldoria) {
+ ((Caldoria *)caldoria)->doorBombTimerExpired();
+}
+
+void sinclairTimerExpiredFunction(FunctionPtr *, void *caldoria) {
+ ((Caldoria *)caldoria)->sinclairTimerExpired();
+}
+
+Caldoria::Caldoria(InputHandler* nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Caldoria", kCaldoriaID) {
+ setIsItemTaken(kKeyCard);
+ setIsItemTaken(kOrangeJuiceGlassEmpty);
+ GameState.setTakenItemID(kOrangeJuiceGlassFull, GameState.isTakenItemID(kOrangeJuiceGlassEmpty));
+ _zoomOutSpot = 0;
+ _gunSprite = 0;
+}
+
+Caldoria::~Caldoria() {
+}
+
+void Caldoria::init() {
+ Neighborhood::init();
+
+ // We need this notification flag as well.
+ _neighborhoodNotification.notifyMe(this, kSinclairLoopDoneFlag, kSinclairLoopDoneFlag);
+
+ forceStridingStop(kCaldoria55, kSouth, kAltCaldoriaSinclairDown);
+ forceStridingStop(kCaldoria50, kNorth, kAltCaldoriaSinclairDown);
+}
+
+void Caldoria::start() {
+ g_energyMonitor->stopEnergyDraining();
+
+ if (!GameState.getCaldoriaSeenPullback()) {
+ _vm->_gfx->doFadeOutSync(kOneSecond * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
+
+ g_system->delayMillis(2 * 1000);
+
+ Video::VideoDecoder *pullbackMovie = new Video::QuickTimeDecoder();
+
+ if (!pullbackMovie->loadFile("Images/Caldoria/Pullback.movie"))
+ error("Could not load pullback movie");
+
+ bool skipped = false;
+ Input input;
+
+ _vm->_gfx->doFadeInSync(kTwoSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
+
+ bool saveAllowed = _vm->swapSaveAllowed(false);
+ bool openAllowed = _vm->swapLoadAllowed(false);
+
+ while (!_vm->shouldQuit() && !pullbackMovie->endOfVideo()) {
+ if (pullbackMovie->needsUpdate()) {
+ const Graphics::Surface *frame = pullbackMovie->decodeNextFrame();
+
+ if (frame) {
+ g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h);
+ g_system->updateScreen();
+ }
+ }
+
+ InputHandler::getCurrentInputDevice()->getInput(input, kPullbackInterruptFilter);
+ if (input.anyInput()) { // TODO: Save/Quit requests
+ skipped = true;
+ break;
+ }
+
+ g_system->delayMillis(10);
+ }
+
+ delete pullbackMovie;
+
+ _vm->swapSaveAllowed(saveAllowed);
+ _vm->swapLoadAllowed(openAllowed);
+
+ ExtraTable::Entry entry;
+
+ if (!skipped) {
+ uint32 white = g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff);
+
+ _vm->_gfx->doFadeOutSync(kThreeSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond, white);
+
+ 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, white);
+ } else {
+ getExtraEntry(kCaldoria00WakeUp1, entry);
+ _navMovie.setTime(entry.movieStart);
+ _navMovie.redrawMovieWorld();
+ _navMovie.show();
+ }
+
+ GameState.setCaldoriaSeenPullback(true);
+ }
+
+ Neighborhood::start();
+}
+
+void Caldoria::flushGameState() {
+ GameState.setCaldoriaFuseTimeLimit(_utilityFuse.getTimeRemaining());
+}
+
+void Caldoria::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ if (g_AIArea) {
+ if (GameState.allTimeZonesFinished()) {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Caldoria/X49NB1", false);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria49, kNorth));
+ AIRule *rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+#if 0
+ // TODO
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/X56EH1", false);
+ AIBombActiveCondition *activeCondition = new AIBombActiveCondition;
+ rule = new AIRule(activeCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+#endif
+ } else {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Caldoria/XAB2", false);
+ AITimerCondition *timerCondition = new AITimerCondition(kLateWarning3TimeLimit, 1, true);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria44, kEast));
+ AINotCondition *notCondition = new AINotCondition(locCondition);
+ AIAndCondition *andCondition = new AIAndCondition(timerCondition, notCondition);
+ AIRule *rule = new AIRule(andCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/XAB1", false);
+ timerCondition = new AITimerCondition(kLateWarning2TimeLimit, 1, true);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria44, kEast));
+ notCondition = new AINotCondition(locCondition);
+ andCondition = new AIAndCondition(timerCondition, notCondition);
+ rule = new AIRule(andCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/XA44EB", false);
+ locCondition = new AILocationCondition(3);
+ locCondition->addLocation(MakeRoomView(kCaldoria01, kNorth));
+ locCondition->addLocation(MakeRoomView(kCaldoria01, kEast));
+ locCondition->addLocation(MakeRoomView(kCaldoria01, kSouth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/X42WH1", false);
+ AICondition *condition = makeLocationAndDoesntHaveItemCondition(kCaldoria44, kEast, kKeyCard);
+ rule = new AIRule(condition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ AIActivateRuleAction *ruleAction = new AIActivateRuleAction(rule);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria42, kEast));
+ rule = new AIRule(locCondition, ruleAction);
+ g_AIArea->addAIRule(rule);
+ }
+ }
+}
+
+uint16 Caldoria::getDateResID() const {
+ return kDate2318ID;
+}
+
+TimeValue Caldoria::getViewTime(const tRoomID room, const tDirectionConstant direction) {
+ ExtraTable::Entry extra;
+ uint32 extraID = 0xffffffff;
+
+ switch (room) {
+ case kCaldoria00:
+ if (direction == kEast && _privateFlags.getFlag(kCaldoriaPrivate4DSystemOpenFlag))
+ extraID = k4DEnvironOpenView;
+ break;
+ case kCaldoriaDrawers:
+ if (direction == kNorth && _privateFlags.getFlag(kCaldoriaPrivateRightDrawerOpenFlag)) {
+ if (GameState.isTakenItemID(kKeyCard))
+ extraID = kRightDrawerOpenViewNoKeys;
+ else
+ extraID = kRightDrawerOpenViewWithKeys;
+ }
+ break;
+ case kCaldoria16:
+ if (direction == kSouth && GameState.getCaldoriaSeenSinclairInElevator())
+ extraID = kCaldoria16SouthViewWithElevator;
+ break;
+ case kCaldoriaReplicator:
+ if (GameState.getCaldoriaMadeOJ() && !(GameState.isTakenItemID(kOrangeJuiceGlassEmpty) || GameState.isTakenItemID(kOrangeJuiceGlassFull)))
+ extraID = kReplicatorNorthViewWithOJ;
+ break;
+ case kCaldoriaKiosk:
+ case kCaldoriaBinoculars:
+ return 0xffffffff;
+ case kCaldoria48:
+ if (direction == kNorth && GameState.getCaldoriaRoofDoorOpen())
+ extraID = kCa48NorthExplosion;
+ break;
+ }
+
+ if (extraID == 0xffffffff)
+ return Neighborhood::getViewTime(room, direction);
+
+ getExtraEntry(extraID, extra);
+ return extra.movieEnd - 1;
+}
+
+void Caldoria::startSpotOnceOnly(TimeValue startTime, TimeValue stopTime) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria13, kEast):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen13CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen13CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria14, kEast):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen14CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen14CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria18, kWest):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen18CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen18CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria23, kSouth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen23CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen23CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria33, kSouth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen33CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen33CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria36, kNorth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen36CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen36CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria41, kNorth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen41NorthCarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen41NorthCarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria41, kEast):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen41EastCarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen41EastCarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria41, kWest):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen41WestCarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen41WestCarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ default:
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ break;
+ }
+}
+
+void Caldoria::findSpotEntry(const tRoomID room, const tDirectionConstant direction, tSpotFlags flags, SpotTable::Entry &entry) {
+ Neighborhood::findSpotEntry(room, direction, flags, entry);
+
+ switch (room) {
+ case kCaldoria00:
+ if (direction == kEast && (!GameState.getCaldoriaINNAnnouncing() || GameState.getCaldoriaSeenINN()))
+ entry.clear();
+ break;
+ case kCaldoriaVidPhone:
+ if (direction == kNorth && GameState.getCaldoriaSeenMessages())
+ entry.clear();
+ break;
+ case kCaldoria44:
+ if (direction == kEast && GameState.getLastRoom() != kCaldoria42)
+ entry.clear();
+ break;
+ }
+}
+
+void Caldoria::startExitMovie(const ExitTable::Entry &exitEntry) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria05:
+ case kCaldoria07:
+ if (GameState.getCurrentDirection() == kWest)
+ closeCroppedMovie();
+ // fall through
+ case kCaldoria11:
+ if (GameState.getCurrentDirection() == kEast)
+ closeCroppedMovie();
+ break;
+ case kCaldoria13:
+ case kCaldoria14:
+ if (GameState.getCurrentDirection() == kNorth)
+ closeCroppedMovie();
+ break;
+ }
+
+ Neighborhood::startExitMovie(exitEntry);
+}
+
+void Caldoria::startZoomMovie(const ZoomTable::Entry &zoomEntry) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria12:
+ if (GameState.getCurrentDirection() == kNorth)
+ closeCroppedMovie();
+ break;
+ }
+
+ Neighborhood::startZoomMovie(zoomEntry);
+}
+
+void Caldoria::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
+ if (GameState.getCurrentRoom() == kCaldoria27 || GameState.getCurrentRoom() == kCaldoria28 || GameState.getCurrentRoom() == kCaldoria45)
+ // Must be opening elevator door.
+ closeCroppedMovie();
+
+ if (GameState.getCurrentRoom() == kCaldoria44 && GameState.getLastRoom() != kCaldoria42)
+ startExtraSequence(kArriveAtCaldoriaFromTSA, kDoorOpenCompletedFlag, false);
+ else
+ Neighborhood::startDoorOpenMovie(startTime, stopTime);
+}
+
+void Caldoria::startTurnPush(const tTurnDirection turnDirection, const TimeValue newViewTime, const tDirectionConstant destDirection) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria05:
+ case kCaldoria07:
+ if (GameState.getCurrentDirection() == kWest)
+ closeCroppedMovie();
+ break;
+ case kCaldoria11:
+ if (GameState.getCurrentDirection() == kEast)
+ closeCroppedMovie();
+ break;
+ case kCaldoria12:
+ case kCaldoria13:
+ case kCaldoria14:
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ if (GameState.getCurrentDirection() == kNorth)
+ closeCroppedMovie();
+ break;
+ case kCaldoria48:
+ if (_croppedMovie.isSurfaceValid())
+ closeCroppedMovie();
+ break;
+ }
+
+ Neighborhood::startTurnPush(turnDirection, newViewTime, destDirection);
+}
+
+void Caldoria::bumpIntoWall() {
+ requestSpotSound(kCaldoriaUhghIn, kCaldoriaUhghOut, kFilterNoInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+void Caldoria::closeDoorOffScreen(const tRoomID room, const tDirectionConstant direction) {
+ switch (room) {
+ case kCaldoria08:
+ if (direction == kNorth)
+ playSpotSoundSync(kCaldoriaShowerCloseIn, kCaldoriaShowerCloseOut);
+ else
+ playSpotSoundSync(kCaldoriaDoorCloseIn, kCaldoriaDoorCloseOut);
+ break;
+ case kCaldoria09:
+ playSpotSoundSync(kCaldoriaShowerCloseIn, kCaldoriaShowerCloseOut);
+ break;
+ case kCaldoria16:
+ case kCaldoria38:
+ case kCaldoria46:
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ playSpotSoundSync(kCaldoriaElevatorCloseIn, kCaldoriaElevatorCloseOut);
+ break;
+ case kCaldoria44:
+ case kCaldoria42:
+ if (GameState.getCurrentRoom() == kCaldoria42)
+ playSpotSoundSync(kCaldoriaGTDoorCloseIn, kCaldoriaGTDoorCloseOut);
+ break;
+ default:
+ playSpotSoundSync(kCaldoriaDoorCloseIn, kCaldoriaDoorCloseOut);
+ break;
+ }
+}
+
+int16 Caldoria::getStaticCompassAngle(const tRoomID room, const tDirectionConstant dir) {
+ int16 result = Neighborhood::getStaticCompassAngle(room, dir);
+
+ switch (room) {
+ case kCaldoriaVidPhone:
+ result += kVidPhoneAngle;
+ break;
+ case kCaldoriaReplicator:
+ result += kReplicatorAngle;
+ break;
+ case kCaldoriaDrawers:
+ result += kDrawersAngle;
+ break;
+ case kCaldoria53:
+ result += kCaldoria53Angle;
+ break;
+ case kCaldoria55:
+ result += kCaldoria55Angle;
+ break;
+ }
+
+ return result;
+}
+
+void Caldoria::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getExitCompassMove(exitEntry, compassMove);
+
+ switch (MakeRoomView(exitEntry.room, exitEntry.direction)) {
+ case MakeRoomView(kCaldoria08, kNorth):
+ case MakeRoomView(kCaldoria09, kSouth):
+ compassMove.insertFaderKnot((exitEntry.movieStart + exitEntry.movieEnd) >> 1, compassMove.getNthKnotValue(0) + 30);
+ break;
+ case MakeRoomView(kCaldoria10, kEast):
+ compassMove.insertFaderKnot(exitEntry.movieStart + 4 * kCaldoriaFrameDuration, 90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 19 * kCaldoriaFrameDuration, -90);
+ break;
+ case MakeRoomView(kCaldoria42, kWest):
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), exitEntry.movieStart, -90, exitEntry.movieEnd, 90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 3 * kCaldoriaFrameDuration, -90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 33 * kCaldoriaFrameDuration, 90);
+ break;
+ case MakeRoomView(kCaldoria54, kEast):
+ if (getCurrentAlternate() != kAltCaldoriaSinclairDown) {
+ compassMove.insertFaderKnot(exitEntry.movieStart + 16 * kCaldoriaFrameDuration, 135);
+ compassMove.insertFaderKnot(exitEntry.movieEnd, 135);
+ }
+ break;
+ case MakeRoomView(kCaldoria55, kNorth):
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), exitEntry.movieStart, 315, exitEntry.movieEnd, 270);
+ break;
+ }
+}
+
+void Caldoria::getZoomCompassMove(const ZoomTable::Entry &zoomEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getZoomCompassMove(zoomEntry, compassMove);
+
+ switch (zoomEntry.hotspot) {
+ case kCaBathroomToiletSpotID:
+ compassMove.insertFaderKnot(zoomEntry.movieStart + 4 * kCaldoriaFrameDuration, 90);
+ compassMove.insertFaderKnot(zoomEntry.movieStart + 19 * kCaldoriaFrameDuration, -90);
+ compassMove.insertFaderKnot(zoomEntry.movieEnd, -90);
+ break;
+ }
+}
+
+void Caldoria::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
+ switch (entry.extra) {
+ case kCaldoria00WakeUp1:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 90, entry.movieEnd, 180);
+ compassMove.insertFaderKnot(entry.movieStart + 1000, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 1640, 120);
+ compassMove.insertFaderKnot(entry.movieStart + 2240, 135);
+ compassMove.insertFaderKnot(entry.movieStart + 2640, 180);
+ break;
+ case kCaldoria00WakeUp2:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 180, entry.movieEnd, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 560, 90);
+ break;
+ case kCaldoria56BombStage1:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 90, entry.movieEnd, 10);
+ compassMove.insertFaderKnot(entry.movieStart + 31 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieStart + 49 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieStart + 66 * kCaldoriaFrameDuration, 10);
+ break;
+ case kCaldoria56BombStage7:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 10, entry.movieEnd, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 131 * kCaldoriaFrameDuration, 10);
+ compassMove.insertFaderKnot(entry.movieStart + 148 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieStart + 165 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieEnd - 5 * kCaldoriaFrameDuration, 90);
+ break;
+ default:
+ Neighborhood::getExtraCompassMove(entry, compassMove);
+ break;
+ }
+}
+
+void Caldoria::loadAmbientLoops() {
+ tRoomID 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);
+}
+
+void Caldoria::checkContinuePoint(const tRoomID room, const tDirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kCaldoria06, kSouth):
+ case MakeRoomView(kCaldoria13, kNorth):
+ case MakeRoomView(kCaldoria16, kSouth):
+ case MakeRoomView(kCaldoria38, kEast):
+ case MakeRoomView(kCaldoria38, kWest):
+ case MakeRoomView(kCaldoria40, kNorth):
+ case MakeRoomView(kCaldoria44, kEast):
+ case MakeRoomView(kCaldoria48, kNorth):
+ case MakeRoomView(kCaldoria49, kNorth):
+ makeContinuePoint();
+ break;
+ }
+}
+
+void Caldoria::spotCompleted() {
+ Neighborhood::spotCompleted();
+ if (GameState.getCurrentRoom() == kCaldoriaBinoculars)
+ startExtraSequence(kBinocularsZoomInOnShip, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void Caldoria::arriveAt(const tRoomID room, const tDirectionConstant direction) {
+ switch (room) {
+ case kCaldoria56:
+ if (!GameState.getCaldoriaGunAimed())
+ // Fall through...
+ case kCaldoria49:
+ case kCaldoria50:
+ case kCaldoria51:
+ case kCaldoria52:
+ case kCaldoria53:
+ case kCaldoria54:
+ case kCaldoria55:
+ if (GameState.getCaldoriaSinclairShot())
+ setCurrentAlternate(kAltCaldoriaSinclairDown);
+ break;
+ }
+
+ Neighborhood::arriveAt(room, direction);
+ Input dummy;
+
+ switch (room) {
+ case kCaldoria00:
+ arriveAtCaldoria00();
+ break;
+ case kCaldoria05:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A05 Light Loop", kCaldoriaA05LightLoopLeft, kCaldoriaA05LightLoopTop);
+ break;
+ case kCaldoria07:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A07 Light Loop", kCaldoriaA07LightLoopLeft, kCaldoriaA07LightLoopTop);
+ break;
+ case kCaldoria09:
+ _lastExtra = 0xffffffff;
+ break;
+ case kCaldoriaToilet:
+ GameState.setScoringReadPaper(true);
+ break;
+ case kCaldoriaReplicator:
+ setCurrentActivation(kActivateReplicatorReady);
+ requestSpotSound(kCaldoriaReplicatorIntroIn, kCaldoriaReplicatorIntroOut, kFilterNoInput, 0);
+ break;
+ case kCaldoria11:
+ setCurrentAlternate(kAltCaldoriaNormal);
+ if (direction == kEast && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A11 Message Machine Loop", kCaldoria11MessageLoopLeft, kCaldoria11MessageLoopTop);
+ break;
+ case kCaldoria12:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A12 Message Machine Loop", kCaldoria12MessageLoopLeft, kCaldoria12MessageLoopTop);
+ break;
+ case kCaldoriaDrawers:
+ setCurrentActivation(kActivateDrawersClosed);
+ break;
+ case kCaldoria13:
+ GameState.setCaldoriaINNAnnouncing(true);
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A13 Message Machine Loop", kCaldoria13MessageLoopLeft, kCaldoria13MessageLoopTop);
+ break;
+ case kCaldoria14:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A14 Message Machine Loop", kCaldoria14MessageLoopLeft, kCaldoria14MessageLoopTop);
+ break;
+ case kCaldoria08:
+ if (direction == kWest)
+ setCurrentActivation(kActivateMirrorReady);
+ // Fall through...
+ case kCaldoria15:
+ GameState.setCaldoriaINNAnnouncing(true);
+ break;
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ if (GameState.getCurrentDirection() == kNorth)
+ openDoor();
+ break;
+ case kCaldoriaBinoculars:
+ GameState.setScoringLookThroughTelescope(true);
+ break;
+ case kCaldoriaKiosk:
+ GameState.setScoringSawCaldoriaKiosk(true);
+ startExtraSequenceSync(kCaldoriaKioskVideo, kFilterAllInput);
+ downButton(dummy);
+ break;
+ case kCaldoria44:
+ arriveAtCaldoria44();
+ break;
+ case kCaldoria49:
+ arriveAtCaldoria49();
+ break;
+ case kCaldoria53:
+ if (direction == kEast && !GameState.getCaldoriaSinclairShot())
+ zoomToSinclair();
+ break;
+ case kCaldoria50:
+ if (direction == kNorth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria54:
+ if (direction == kSouth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria56:
+ arriveAtCaldoria56();
+ break;
+ case kCaldoriaDeathRoom:
+ arriveAtCaldoriaDeath();
+ break;
+ }
+
+ checkSinclairShootsOS();
+ setUpRoofTop();
+}
+
+void Caldoria::doAIRecalibration() {
+ GameState.setCaldoriaDidRecalibration(true);
+ 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->lowerInventoryDrawerSync();
+ g_interface->raiseBiochipDrawerSync();
+
+ 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);
+}
+
+void Caldoria::arriveAtCaldoria00() {
+ if (GameState.getCurrentDirection() == kEast) {
+ if (GameState.getCaldoriaWokenUp()) {
+ if (!GameState.getCaldoriaDidRecalibration())
+ doAIRecalibration();
+ setCurrentActivation(kActivate4DClosed);
+ } else {
+ // Good morning, sleeping beauty
+ ExtraTable::Entry extra;
+ getExtraEntry(kCaldoria00WakeUp1, extra);
+
+ if (_navMovie.getTime() != extra.movieStart) {
+ _navMovie.setTime(extra.movieStart);
+ _navMovie.redrawMovieWorld();
+ }
+
+ startExtraSequenceSync(kCaldoria00WakeUp1, kFilterNoInput);
+ GameState.setCaldoriaWokenUp(true);
+ playCroppedMovieOnce("Images/Caldoria/VidPhone.movie", kCaldoriaVidPhoneLeft, kCaldoriaVidPhoneTop, kFilterAllInput);
+ startExtraSequence(kCaldoria00WakeUp2, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
+}
+
+bool Caldoria::wantsCursor() {
+ return GameState.getCaldoriaDidRecalibration();
+}
+
+void Caldoria::arriveAtCaldoria44() {
+ if (GameState.getLastNeighborhood() != kCaldoriaID) {
+ openDoor();
+ } else {
+ setCurrentActivation(kActivateReadyForCard);
+ loopExtraSequence(kCaldoriaTransporterArrowLoop, 0);
+ }
+}
+
+void Caldoria::arriveAtCaldoria49() {
+ if (GameState.getLastRoom() == kCaldoria48)
+ setCurrentAlternate(kAltCaldoriaNormal);
+
+ // Need to force the loop to play.
+ if (GameState.getCurrentDirection() == kNorth) {
+ GameState.setCaldoriaFuseTimeLimit(kSinclairShootsTimeLimit);
+ startExtraSequence(kCa49NorthVoiceAnalysis, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void Caldoria::arriveAtCaldoria56() {
+ if (!GameState.getCaldoriaBombDisarmed()) {
+ _privateFlags.setFlag(kCaldoriaPrivateZoomingToBombFlag, true);
+
+ if (GameState.getCurrentDirection() == kNorth) {
+ turnRight();
+ } else if (GameState.getCurrentDirection() == kSouth) {
+ turnLeft();
+ } else if (GameState.getCurrentDirection() == kEast) {
+ _privateFlags.setFlag(kCaldoriaPrivateZoomingToBombFlag, false);
+ newInteraction(kCaldoriaBombInteractionID);
+ }
+ }
+}
+
+void Caldoria::arriveAtCaldoriaDeath() {
+ if (GameState.getLastRoom() == kCaldoria49) {
+ if (GameState.getCaldoriaSinclairShot()) {
+ die(kDeathNuclearExplosion);
+ } else {
+ playSpotSoundSync(kCaldoriaSinclairShootsOSIn, kCaldoriaSinclairShootsOSOut);
+ playSpotSoundSync(kCaldoriaScreamingAfterIn, kCaldoriaScreamingAfterOut);
+ die(kDeathSinclairShotDelegate);
+ }
+ } else {
+ die(kDeathShotBySinclair);
+ }
+}
+
+void Caldoria::setUpRoofTop() {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria48:
+ if (GameState.getCurrentDirection() == kNorth) {
+ if (GameState.getCaldoriaRoofDoorOpen()) {
+ setCurrentAlternate(kAltCaldoriaRoofDoorBlown);
+ } else if (GameState.getCaldoriaDoorBombed()) {
+ // Long enough for AI hints...?
+ _utilityFuse.primeFuse(kCardBombCountDownTime);
+ _utilityFuse.setFunctionPtr(&doorBombTimerExpiredFunction, (void *)this);
+ _utilityFuse.lightFuse();
+
+ loopCroppedMovie("Images/Caldoria/A48 Bomb Loop", kCaldoria48CardBombLoopLeft, kCaldoria48CardBombLoopTop);
+ } else {
+ setCurrentActivation(kActivateRoofSlotEmpty);
+ }
+ }
+ break;
+ case kCaldoria56:
+ if (GameState.getCurrentDirection() == kEast && GameState.getCaldoriaGunAimed())
+ startExtraSequence(kCa53EastShootSinclair, kExtraCompletedFlag, false);
+ else
+ // Fall through...
+ case kCaldoria49:
+ case kCaldoria50:
+ case kCaldoria51:
+ case kCaldoria52:
+ case kCaldoria53:
+ case kCaldoria54:
+ case kCaldoria55:
+ if (!GameState.getCaldoriaSinclairShot()) {
+ if (GameState.getCaldoriaSawVoiceAnalysis() && !_utilityFuse.isFuseLit()) {
+ _utilityFuse.primeFuse(GameState.getCaldoriaFuseTimeLimit());
+ _utilityFuse.setFunctionPtr(&sinclairTimerExpiredFunction, (void *)this);
+ _utilityFuse.lightFuse();
+ }
+ } else {
+ setCurrentAlternate(kAltCaldoriaSinclairDown);
+ }
+ break;
+ }
+}
+
+void Caldoria::downButton(const Input &input) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria01, kEast):
+ GameState.setCaldoriaWokenUp(true);
+ startExtraSequence(kCaldoria00SitDown, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ Neighborhood::downButton(input);
+ break;
+ }
+}
+
+void Caldoria::turnTo(const tDirectionConstant direction) {
+ Neighborhood::turnTo(direction);
+
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria00:
+ if (direction == kEast)
+ setCurrentActivation(kActivate4DClosed);
+ break;
+ case kCaldoria01:
+ if (direction == kEast) {
+ GameState.setCaldoriaWokenUp(true);
+ startExtraSequence(kCaldoria00SitDown, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCaldoria05:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A05 Light Loop", kCaldoriaA05LightLoopLeft, kCaldoriaA05LightLoopTop);
+ break;
+ case kCaldoria07:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A07 Light Loop", kCaldoriaA07LightLoopLeft, kCaldoriaA07LightLoopTop);
+ break;
+ case kCaldoria08:
+ if (direction == kWest)
+ setCurrentActivation(kActivateMirrorReady);
+ break;
+ case kCaldoria09:
+ _lastExtra = 0xffffffff;
+ break;
+ case kCaldoria11:
+ if (direction == kEast && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A11 Message Machine Loop", kCaldoria11MessageLoopLeft, kCaldoria11MessageLoopTop);
+ break;
+ case kCaldoria12:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A12 Message Machine Loop", kCaldoria12MessageLoopLeft, kCaldoria12MessageLoopTop);
+ break;
+ case kCaldoria13:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A13 Message Machine Loop", kCaldoria13MessageLoopLeft, kCaldoria13MessageLoopTop);
+ break;
+ case kCaldoria14:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A14 Message Machine Loop", kCaldoria14MessageLoopLeft, kCaldoria14MessageLoopTop);
+ break;
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ if (direction == kNorth)
+ openElevatorMovie();
+ else
+ closeCroppedMovie();
+ break;
+ case kCaldoria48:
+ if (direction == kNorth && !GameState.getCaldoriaDoorBombed())
+ setCurrentActivation(kActivateRoofSlotEmpty);
+ break;
+ case kCaldoria53:
+ if (GameState.getCurrentDirection() == kEast && !GameState.getCaldoriaSinclairShot())
+ zoomToSinclair();
+ break;
+ case kCaldoria50:
+ if (direction == kNorth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria54:
+ if (direction == kSouth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria56:
+ if (_privateFlags.getFlag(kCaldoriaPrivateZoomingToBombFlag)) {
+ _privateFlags.setFlag(kCaldoriaPrivateZoomingToBombFlag, false);
+ newInteraction(kCaldoriaBombInteractionID);
+ } else if (GameState.getCaldoriaBombDisarmed()) {
+ _vm->playEndMessage();
+ }
+ break;
+ }
+
+ checkSinclairShootsOS();
+}
+
+void Caldoria::zoomTo(const Hotspot *zoomOutSpot) {
+ // Need to set _zoomOutSpot here because we may come through
+ // this function another way, say by pressing the down arrow,
+ // that doesn't involve the ClickInHotSpot function.
+ _zoomOutSpot = zoomOutSpot;
+
+ if (zoomOutSpot->getObjectID() == kCaldoriaDrawersOutSpotID) {
+ if (_privateFlags.getFlag(kCaloriaPrivateLeftDrawerOpenFlag)) {
+ _privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, false);
+ startExtraSequence(kLeftDrawerClose, kExtraCompletedFlag, kFilterNoInput);
+ } else if (_privateFlags.getFlag(kCaldoriaPrivateRightDrawerOpenFlag)) {
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, false);
+ if (GameState.isTakenItemID(kKeyCard))
+ startExtraSequence(kRightDrawerCloseNoKeys, kExtraCompletedFlag, false);
+ else
+ startExtraSequence(kRightDrawerCloseWithKeys, kExtraCompletedFlag, false);
+ } else {
+ Neighborhood::zoomTo(zoomOutSpot);
+ }
+ } else {
+ Neighborhood::zoomTo(zoomOutSpot);
+ }
+}
+
+void Caldoria::setUpSinclairLoops() {
+ _navMovie.stop();
+ scheduleNavCallBack(kSinclairLoopDoneFlag);
+ _sinclairLoopCount = 0;
+ _numSinclairLoops = 2;
+ _navMovie.start();
+}
+
+void Caldoria::zoomToSinclair() {
+ // TODO
+}
+
+void Caldoria::receiveNotification(Notification *notification, const tNotificationFlags flags) {
+ Neighborhood::receiveNotification(notification, flags);
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ InventoryItem *item;
+ _interruptionFilter = kFilterAllInput;
+
+ switch (_lastExtra) {
+ case kCaldoria00WakeUp2:
+ makeContinuePoint();
+ // Force ArriveAt to do its thing...
+ GameState.setCurrentRoom(kNoRoomID);
+ arriveAt(kCaldoria00, kEast);
+ break;
+ case k4DEnvironOpenToINN:
+ GameState.setCaldoriaSeenINN(true);
+ GameState.setScoringSawINN(true);
+ // Fall through to k4DEnvironOpen...
+ case k4DEnvironOpen:
+ _privateFlags.setFlag(kCaldoriaPrivate4DSystemOpenFlag, true);
+ setCurrentActivation(kActivate4DOpen);
+ newInteraction(kCaldoria4DInteractionID);
+ break;
+ case kCaldoriaShowerUp:
+ GameState.setScoringTookShower(true);
+ GameState.setCaldoriaDoneHygiene(true);
+ break;
+ case kLeftDrawerClose:
+ case kRightDrawerCloseNoKeys:
+ case kRightDrawerCloseWithKeys:
+ if (_zoomOutSpot && _zoomOutSpot->getObjectID() == kCaldoriaDrawersOutSpotID) {
+ Input input;
+ clickInHotspot(input, _zoomOutSpot);
+ }
+ break;
+ case kCreateOrangeJuice:
+ setCurrentActivation(kActivateOJOnThePad);
+ requestSpotSound(kCaldoriaReplicatorOJChoiceIn, kCaldoriaReplicatorOJChoiceOut, kFilterNoInput, 0);
+ break;
+ case kCaldoria00SitDown:
+ arriveAt(kCaldoria00, kEast);
+ break;
+ case kCaldoria16ElevatorUp:
+ startExtraSequence(kCaldoria16ElevatorDown, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoria16ElevatorDown:
+ GameState.setCaldoriaSeenSinclairInElevator(true);
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ break;
+ case kCaldoriaFourthToGround:
+ case kCaldoriaRoofToGround:
+ arriveAt(kCaldoria28, GameState.getCurrentDirection());
+ break;
+ case kCaldoriaFourthToRoof:
+ case kCaldoriaGroundToRoof:
+ arriveAt(kCaldoria45, GameState.getCurrentDirection());
+ break;
+ case kCaldoriaGroundToFourth:
+ case kCaldoriaRoofToFourth:
+ arriveAt(kCaldoria27, GameState.getCurrentDirection());
+ break;
+ case kCaGTCardSwipe:
+ item = (InventoryItem *)g_allItems.findItemByID(kKeyCard);
+ _vm->addItemToInventory(item);
+ setCurrentActivation(kActivateReadyToTransport);
+ break;
+ case kCaGTFryTheFly:
+ case kCaGTGoToTSA:
+ _vm->jumpToNewEnvironment(kFullTSAID, kTSA00, kNorth);
+ break;
+ case kCaGTGoToTokyo:
+ playDeathExtra(kCaGTArriveAtTokyo, kDeathUncreatedInCaldoria);
+ break;
+ case kCaGTGoToBeach:
+ playDeathExtra(kCaGTArriveAtBeach, kDeathUncreatedInCaldoria);
+ break;
+ case kCa48NorthExplosion:
+ // Current biochip must be the shield if we got here.
+ _vm->getCurrentBiochip()->setItemState(kShieldNormal);
+ break;
+ case kBinocularsZoomInOnShip:
+ setCurrentActivation(kActivateFocusedOnShip);
+ break;
+ case kCa49NorthVoiceAnalysis:
+ _utilityFuse.primeFuse(kSinclairShootsTimeLimit);
+ _utilityFuse.setFunctionPtr(&sinclairTimerExpiredFunction, (void*) this);
+ _utilityFuse.lightFuse();
+ GameState.setCaldoriaSawVoiceAnalysis(true);
+ break;
+ case kCa53EastZoomToSinclair:
+ if (GameState.getCaldoriaSinclairShot()) {
+ delete _gunSprite;
+ _gunSprite = 0;
+ startExtraSequence(kCa53EastShootSinclair, kExtraCompletedFlag, false);
+ } else {
+ playDeathExtra(kCa53EastDeath2, kDeathSinclairShotDelegate);
+ }
+ break;
+ case kCa53EastShootSinclair:
+ _vm->addItemToInventory((InventoryItem *)g_allItems.findItemByID(kStunGun));
+ startExtraSequence(kCa53EastZoomOutFromSinclair, kExtraCompletedFlag, false);
+ GameState.setScoringStunnedSinclair(true);
+ break;
+ case kCa53EastZoomOutFromSinclair:
+ setCurrentAlternate(kAltCaldoriaSinclairDown);
+ updateViewFrame();
+ makeContinuePoint();
+ break;
+ }
+ } else if ((flags & kSpotSoundCompletedFlag) != 0) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria20:
+ case kCaldoria21:
+ case kCaldoria26:
+ case kCaldoria29:
+ case kCaldoria34:
+ case kCaldoria35:
+ updateViewFrame();
+ break;
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ updateElevatorMovie();
+ break;
+ case kCaldoriaReplicator:
+ emptyOJGlass();
+ break;
+ }
+ } else if ((flags & kSinclairLoopDoneFlag) != 0) {
+ if (++_sinclairLoopCount == _numSinclairLoops) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria50:
+ playDeathExtra(kCa50SinclairShoots, kDeathShotBySinclair);
+ break;
+ case kCaldoria54:
+ playDeathExtra(kCa54SouthDeath, kDeathShotBySinclair);
+ break;
+ }
+ } else {
+ _navMovie.stop();
+ scheduleNavCallBack(kSinclairLoopDoneFlag);
+ _navMovie.start();
+ }
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+tInputBits Caldoria::getInputFilter() {
+ tInputBits result = Neighborhood::getInputFilter();
+
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria00:
+ if (_privateFlags.getFlag(kCaldoriaPrivate4DSystemOpenFlag))
+ result &= ~kFilterAllDirections;
+ break;
+ case kCaldoriaBinoculars:
+ if (getCurrentActivation() == kActivateNotFocusedOnShip)
+ result &= ~(kFilterDownButton | kFilterDownAuto);
+ break;
+ case kCaldoria53:
+ if (_privateFlags.getFlag(kCaldoriaPrivateReadyToShootFlag) && !GameState.getCaldoriaSinclairShot())
+ result &= ~kFilterAllDirections;
+ break;
+ case kCaldoria48:
+ if (GameState.getCaldoriaDoorBombed())
+ result &= ~kFilterAllDirections;
+ }
+
+ return result;
+}
+
+void Caldoria::activateHotspots() {
+ Neighborhood::activateHotspots();
+
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoriaDrawers:
+ if (getCurrentActivation() == kActivateRightOpen)
+ if (GameState.isTakenItemID(kKeyCard)) {
+ g_allHotspots.activateOneHotspot(kCaldoriaRightDrawerNoKeysCloseSpotID);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRightDrawerWithKeysCloseSpotID);
+ } else {
+ g_allHotspots.activateOneHotspot(kCaldoriaRightDrawerWithKeysCloseSpotID);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRightDrawerNoKeysCloseSpotID);
+ }
+ case kCaldoriaReplicator:
+ if (GameState.getCaldoriaMadeOJ())
+ g_allHotspots.deactivateOneHotspot(kCaldoriaMakeOJSpotID);
+ break;
+ case kCaldoria27:
+ if (GameState.isCurrentDoorOpen()) {
+ g_allHotspots.deactivateOneHotspot(kCaldoriaFourthFloorElevator1);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaFourthFloorElevator2);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaFourthFloorElevator3);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaFourthFloorElevator4);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaFourthFloorElevator5);
+ }
+ break;
+ case kCaldoria28:
+ if (GameState.isCurrentDoorOpen()) {
+ g_allHotspots.deactivateOneHotspot(kCaldoriaGroundElevator1);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaGroundElevator2);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaGroundElevator3);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaGroundElevator4);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaGroundElevator5);
+ }
+ break;
+ case kCaldoria45:
+ if (GameState.isCurrentDoorOpen()) {
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRoofElevator1);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRoofElevator2);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRoofElevator3);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRoofElevator4);
+ g_allHotspots.deactivateOneHotspot(kCaldoriaRoofElevator5);
+ }
+ break;
+ }
+}
+
+void Caldoria::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kCa4DEnvironOpenSpotID:
+ if (!GameState.getCaldoriaINNAnnouncing() || GameState.getCaldoriaSeenINN()) {
+ startExtraSequence(k4DEnvironOpen, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ // This trick depends on the following sequences being in order in the
+ // world movie:
+ // k4DEnvironOpenToINN
+ // k4DINNInterruption
+ // k4DINNIntro
+ // k4DINNMarkJohnson
+ // k4DINNMeganLove
+ // k4DINNFadeOut
+ // k4DEnvironOpenFromINN
+ loadLoopSound1("");
+ loadLoopSound2("");
+ startExtraLongSequence(k4DEnvironOpenToINN, k4DEnvironOpenFromINN, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCa4DEnvironCloseSpotID:
+ ((Caldoria4DSystem *)_currentInteraction)->shutDown4DSystem();
+ break;
+ case kCaBathroomMirrorSpotID:
+ newInteraction(kCaldoriaMirrorInteractionID);
+ break;
+ case kCaShowerSpotID:
+ requestExtraSequence(kCaldoriaShowerTitle, 0, kFilterNoInput);
+ requestExtraSequence(kCaldoriaShowerButton, 0, kFilterNoInput);
+ requestExtraSequence(kCaldoriaShowerDown, 0, kFilterNoInput);
+ requestExtraSequence(kCaldoriaShowerUp, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaLeftDrawerOpenSpotID:
+ _privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, true);
+ setCurrentActivation(kActivateLeftOpen);
+ startExtraSequence(kLeftDrawerOpen, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaLeftDrawerCloseSpotID:
+ _privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, false);
+ setCurrentActivation(kActivateDrawersClosed);
+ startExtraSequence(kLeftDrawerClose, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRightDrawerOpenSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, true);
+ setCurrentActivation(kActivateRightOpen);
+ if (GameState.isTakenItemID(kKeyCard))
+ startExtraSequence(kRightDrawerOpenNoKeys, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kRightDrawerOpenWithKeys, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRightDrawerWithKeysCloseSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, false);
+ setCurrentActivation(kActivateDrawersClosed);
+ startExtraSequence(kRightDrawerCloseWithKeys, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRightDrawerNoKeysCloseSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, false);
+ setCurrentActivation(kActivateDrawersClosed);
+ startExtraSequence(kRightDrawerCloseNoKeys, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaMakeStickyBunsSpotID:
+ requestSpotSound(kCaldoriaReplicatorWrongChoiceIn, kCaldoriaReplicatorWrongChoiceOut, kFilterNoInput, 0);
+ break;
+ case kCaldoriaMakeOJSpotID:
+ GameState.setCaldoriaMadeOJ(true);
+ startExtraSequence(kCreateOrangeJuice, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaBedroomVidPhoneActivationSpotID:
+ newInteraction(kCaldoriaMessagesInteractionID);
+ break;
+ case kCaldoriaFourthFloorElevatorSpotID:
+ if (!GameState.getCaldoriaSeenSinclairInElevator()) {
+ startExtraSequence(kCaldoria16ElevatorUp, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ }
+ break;
+ case kCaldoriaGroundElevatorSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ break;
+ case kCaldoriaRoofElevatorSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ break;
+ case kCaldoriaFourthFloorElevator1:
+ case kCaldoriaFourthFloorElevator2:
+ case kCaldoriaFourthFloorElevator3:
+ case kCaldoriaFourthFloorElevator4:
+ case kCaldoriaFourthFloorElevator5:
+ // Assumes that elevator hot spots are consecutive.
+ takeElevator(4, spot->getObjectID() - kCaldoriaFourthFloorElevator1 + 1);
+ break;
+ case kCaldoriaGroundElevator1:
+ case kCaldoriaGroundElevator2:
+ case kCaldoriaGroundElevator3:
+ case kCaldoriaGroundElevator4:
+ case kCaldoriaGroundElevator5:
+ // Assumes that elevator hot spots are consecutive.
+ takeElevator(1, spot->getObjectID() - kCaldoriaGroundElevator1 + 1);
+ break;
+ case kCaldoriaRoofElevator1:
+ case kCaldoriaRoofElevator2:
+ case kCaldoriaRoofElevator3:
+ case kCaldoriaRoofElevator4:
+ case kCaldoriaRoofElevator5:
+ // Assumes that elevator hot spots are consecutive.
+ takeElevator(5, spot->getObjectID() - kCaldoriaRoofElevator1 + 1);
+ break;
+ case kCaldoriaGTTokyoSpotID:
+ startExtraSequence(kCaGTGoToTokyo, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaGTTSASpotID:
+ GameState.setScoringGoToTSA(true);
+ startExtraLongSequence(kCaGTFryTheFly, kCaGTGoToTSA, kExtraCompletedFlag, false);
+ break;
+ case kCaldoriaGTBeachSpotID:
+ startExtraSequence(kCaGTGoToBeach, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaGTOtherSpotID:
+ showExtraView(kCaGTOtherChoice);
+ playSpotSoundSync(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut);
+ showExtraView(kCaGTCardSwipe);
+ break;
+ case kCaldoriaZoomInOnShipSpotID:
+ startExtraSequence(kBinocularsZoomInOnShip, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRoofDoorSpotID:
+ startExtraSequence(kCa48NorthRooftopClosed, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoria20DoorbellSpotID:
+ case kCaldoria21DoorbellSpotID:
+ case kCaldoria26DoorbellSpotID:
+ case kCaldoria29DoorbellSpotID:
+ case kCaldoria34DoorbellSpotID:
+ case kCaldoria35DoorbellSpotID:
+ clickOnDoorbell(spot->getObjectID());
+ break;
+ default:
+ Neighborhood::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void Caldoria::clickOnDoorbell(const tHotSpotID doorBellSpotID) {
+ uint32 extra;
+ ExtraTable::Entry entry;
+
+ switch (doorBellSpotID) {
+ case kCaldoria20DoorbellSpotID:
+ extra = kCaldoria20Doorbell;
+ break;
+ case kCaldoria21DoorbellSpotID:
+ extra = kCaldoria21Doorbell;
+ break;
+ case kCaldoria26DoorbellSpotID:
+ extra = kCaldoria26Doorbell;
+ break;
+ case kCaldoria29DoorbellSpotID:
+ extra = kCaldoria29Doorbell;
+ break;
+ case kCaldoria34DoorbellSpotID:
+ extra = kCaldoria34Doorbell;
+ break;
+ case kCaldoria35DoorbellSpotID:
+ extra = kCaldoria35Doorbell;
+ break;
+ }
+
+ getExtraEntry(extra, entry);
+ showViewFrame(entry.movieStart);
+ requestSpotSound(kCaldoriaNobodyHomeIn, kCaldoriaNobodyHomeOut, kFilterNoInput, kSpotSoundCompletedFlag);
+}
+
+tCanOpenDoorReason Caldoria::canOpenDoor(DoorTable::Entry &entry) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria16:
+ case kCaldoria38:
+ case kCaldoria46:
+ if (GameState.getCurrentDirection() == kSouth && !_privateFlags.getFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag))
+ return kCantOpenLocked;
+ break;
+ }
+
+ return Neighborhood::canOpenDoor(entry);
+}
+
+void Caldoria::doorOpened() {
+ Neighborhood::doorOpened();
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, false);
+}
+
+GameInteraction *Caldoria::makeInteraction(const tInteractionID interactionID) {
+ switch (interactionID) {
+ case kCaldoria4DInteractionID:
+ return new Caldoria4DSystem(this);
+ break;
+ case kCaldoriaBombInteractionID:
+ // TODO
+ error("STUB: Bomb game");
+ break;
+ case kCaldoriaMessagesInteractionID:
+ return new CaldoriaMessages(this, kCaldoriaMessagesNotificationID, _vm);
+ break;
+ case kCaldoriaMirrorInteractionID:
+ return new CaldoriaMirror(this);
+ break;
+ }
+
+ return 0;
+}
+
+void Caldoria::newInteraction(const tInteractionID interactionID) {
+ Neighborhood::newInteraction(interactionID);
+
+ if (!_currentInteraction) {
+ if (_privateFlags.getFlag(kCaldoriaPrivate4DSystemOpenFlag)) {
+ _privateFlags.setFlag(kCaldoriaPrivate4DSystemOpenFlag, false);
+ setCurrentActivation(kActivate4DClosed);
+ startExtraSequence(k4DEnvironClose, kExtraCompletedFlag, kFilterNoInput);
+ } else if (GameState.getCaldoriaBombDisarmed()) {
+ turnLeft();
+ }
+ }
+}
+
+// Only called when trying to pick up an item and the player can't (because
+// the inventory is too full or because the player lets go of the item before
+// dropping it into the inventory).
+Hotspot *Caldoria::getItemScreenSpot(Item *item, DisplayElement *element) {
+ tHotSpotID destSpotID = kNoHotSpotID;
+
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ destSpotID = kCaldoriaKeyCardSpotID;
+ break;
+ case kOrangeJuiceGlassEmpty:
+ case kOrangeJuiceGlassFull:
+ destSpotID = kCaldoriaOrangeJuiceSpotID;
+ break;
+ }
+
+ if (destSpotID == kNoHotSpotID)
+ return Neighborhood::getItemScreenSpot(item, element);
+
+ return g_allHotspots.findHotspotByID(destSpotID);
+}
+
+void Caldoria::pickedUpItem(Item *item) {
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ GameState.setScoringGotKeyCard(true);
+ break;
+ case kOrangeJuiceGlassFull:
+ setCurrentActivation(kActivateReplicatorReady);
+ requestSpotSound(kCaldoriaDrinkOJIn, kCaldoriaDrinkOJOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case kStunGun:
+ GameState.setCaldoriaGunAimed(false);
+ break;
+ }
+}
+
+void Caldoria::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot->getObjectID() == kCaldoriaGTCardDropSpotID)
+ startExtraSequence(kCaGTCardSwipe, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kOrangeJuiceGlassEmpty:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot->getObjectID() == kCaldoriaOrangeJuiceDropSpotID) {
+ GameState.setCaldoriaMadeOJ(false);
+ startExtraSequence(kDisposeOrangeJuice, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCardBomb:
+ GameState.setCaldoriaDoorBombed(true);
+ setCurrentActivation(kActivateHotSpotAlways);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ // Long enough for AI hints...?
+ _utilityFuse.primeFuse(kCardBombCountDownTime);
+ _utilityFuse.setFunctionPtr(&doorBombTimerExpiredFunction, (void *)this);
+ _utilityFuse.lightFuse();
+ GameState.setCaldoriaFuseTimeLimit(kCardBombCountDownTime);
+ loopCroppedMovie("Images/Caldoria/A48 Bomb Loop", kCaldoria48CardBombLoopLeft, kCaldoria48CardBombLoopTop);
+ GameState.setScoringUsedCardBomb(true);
+ break;
+ case kStunGun:
+ GameState.setCaldoriaGunAimed(true);
+ GameState.setCaldoriaSinclairShot(true);
+ _gunSprite = item->getDragSprite(0);
+ _gunSprite->setCurrentFrameIndex(1);
+ _gunSprite->setDisplayOrder(kDragSpriteOrder);
+ _gunSprite->moveElementTo(kCaldoriaGunSpriteLeft, kCaldoriaGunSpriteTop);
+ _gunSprite->startDisplaying();
+ _gunSprite->show();
+ break;
+ default:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ }
+}
+
+void Caldoria::takeElevator(uint startFloor, uint endFloor) {
+ _croppedMovie.stop();
+ _croppedMovie.setSegment(0, _croppedMovie.getDuration());
+
+ switch (startFloor) {
+ case 1:
+ switch (endFloor) {
+ case 1:
+ // Do nothing.
+ break;
+ case 2:
+ _croppedMovie.setTime(k1To2Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 3:
+ _croppedMovie.setTime(k1To3Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 4:
+ _croppedMovie.setSegment(k1To4Start, k1To4Stop);
+ _croppedMovie.setTime(k1To4Start);
+ startExtraSequence(kCaldoriaGroundToFourth, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 5:
+ _croppedMovie.setSegment(k1To5Start, k1To5Stop);
+ _croppedMovie.setTime(k1To5Start);
+ startExtraSequence(kCaldoriaGroundToRoof, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ }
+ break;
+ case 4:
+ switch (endFloor) {
+ case 1:
+ _croppedMovie.setSegment(k4To1Start, k4To1Stop);
+ _croppedMovie.setTime(k4To1Start);
+ startExtraSequence(kCaldoriaFourthToGround, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 2:
+ _croppedMovie.setTime(k4To2Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 3:
+ _croppedMovie.setTime(k4To3Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 4:
+ // Do nothing.
+ break;
+ case 5:
+ _croppedMovie.setSegment(k4To5Start, k4To5Stop);
+ _croppedMovie.setTime(k4To5Start);
+ startExtraSequence(kCaldoriaFourthToRoof, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ }
+ break;
+ case 5:
+ switch (endFloor) {
+ case 1:
+ _croppedMovie.setSegment(k5To1Start, k5To1Stop);
+ _croppedMovie.setTime(k5To1Start);
+ startExtraSequence(kCaldoriaRoofToGround, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 2:
+ _croppedMovie.setTime(k5To2Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 3:
+ _croppedMovie.setTime(k5To3Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 4:
+ _croppedMovie.setSegment(k5To4Start, k5To4Stop);
+ _croppedMovie.setTime(k5To4Start);
+ startExtraSequence(kCaldoriaRoofToFourth, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 5:
+ // Do nothing.
+ break;
+ }
+ break;
+ };
+}
+
+void Caldoria::updateElevatorMovie() {
+ TimeValue time = 0xffffffff;
+
+ if (GameState.getCurrentDirection() == kNorth) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria27:
+ time = k4FloorTime;
+ break;
+ case kCaldoria28:
+ time = k1FloorTime;
+ break;
+ case kCaldoria45:
+ time = k5FloorTime;
+ break;
+ }
+ }
+
+ _croppedMovie.stop();
+
+ if (time == 0xffffffff) {
+ _croppedMovie.hide();
+ } else {
+ _croppedMovie.stop();
+ _croppedMovie.setSegment(0, _croppedMovie.getDuration());
+ _croppedMovie.setTime(time);
+ _croppedMovie.redrawMovieWorld();
+ _croppedMovie.show();
+
+ // *** Why do I need this?
+ // clone2727: "don't ask me!"
+ _navMovie.redrawMovieWorld();
+ }
+}
+
+void Caldoria::openElevatorMovie() {
+ if (!_croppedMovie.isSurfaceValid())
+ openCroppedMovie("Images/Caldoria/Caldoria Elevator.movie", kCaldoriaElevatorLeft, kCaldoriaElevatorTop);
+
+ updateElevatorMovie();
+}
+
+void Caldoria::emptyOJGlass() {
+ GameState.setTakenItemID(kOrangeJuiceGlassFull, false);
+ GameState.setTakenItemID(kOrangeJuiceGlassEmpty, true);
+ _vm->removeItemFromInventory((InventoryItem *)g_allItems.findItemByID(kOrangeJuiceGlassFull));
+ _vm->addItemToInventory((InventoryItem *)g_allItems.findItemByID(kOrangeJuiceGlassEmpty));
+}
+
+void Caldoria::doorBombTimerExpired() {
+ closeCroppedMovie();
+
+ if (GameState.getShieldOn()) {
+ _vm->getCurrentBiochip()->setItemState(kShieldCardBomb);
+ setCurrentAlternate(kAltCaldoriaRoofDoorBlown);
+ startExtraSequence(kCa48NorthExplosion, kExtraCompletedFlag, kFilterNoInput);
+ GameState.setScoringShieldedCardBomb(true);
+ GameState.setCaldoriaDoorBombed(false);
+ GameState.setCaldoriaRoofDoorOpen(true);
+ } else {
+ playDeathExtra(kCa48NorthExplosionDeath, kDeathCardBomb);
+ }
+}
+
+void Caldoria::sinclairTimerExpired() {
+ _privateFlags.setFlag(kCaldoriaPrivateSinclairTimerExpiredFlag, true);
+ checkSinclairShootsOS();
+}
+
+void Caldoria::checkSinclairShootsOS() {
+ if (_privateFlags.getFlag(kCaldoriaPrivateSinclairTimerExpiredFlag))
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria49, kNorth):
+ case MakeRoomView(kCaldoria49, kSouth):
+ case MakeRoomView(kCaldoria49, kEast):
+ case MakeRoomView(kCaldoria49, kWest):
+ case MakeRoomView(kCaldoria50, kSouth):
+ case MakeRoomView(kCaldoria50, kEast):
+ case MakeRoomView(kCaldoria50, kWest):
+ case MakeRoomView(kCaldoria51, kNorth):
+ case MakeRoomView(kCaldoria51, kSouth):
+ case MakeRoomView(kCaldoria51, kWest):
+ case MakeRoomView(kCaldoria52, kNorth):
+ case MakeRoomView(kCaldoria52, kSouth):
+ case MakeRoomView(kCaldoria52, kWest):
+ case MakeRoomView(kCaldoria53, kNorth):
+ case MakeRoomView(kCaldoria53, kSouth):
+ case MakeRoomView(kCaldoria53, kWest):
+ case MakeRoomView(kCaldoria54, kNorth):
+ case MakeRoomView(kCaldoria54, kEast):
+ case MakeRoomView(kCaldoria54, kWest):
+ playSpotSoundSync(kCaldoriaSinclairShootsOSIn, kCaldoriaSinclairShootsOSOut);
+ playSpotSoundSync(kCaldoriaScreamingAfterIn, kCaldoriaScreamingAfterOut);
+ die(kDeathSinclairShotDelegate);
+ break;
+ }
+}
+
+void Caldoria::checkInterruptSinclair() {
+ if (GameState.getCaldoriaSinclairShot()) {
+ _navMovie.stop();
+ _neighborhoodNotification.setNotificationFlags(kExtraCompletedFlag, kExtraCompletedFlag);
+ g_AIArea->unlockAI();
+ } else {
+ // TODO
+ }
+}
+
+Common::String Caldoria::getBriefingMovie() {
+ Common::String movieName = Neighborhood::getBriefingMovie();
+
+ if (movieName.empty()) {
+ if (GameState.allTimeZonesFinished())
+ return "Images/AI/Caldoria/XA02";
+
+ return "Images/AI/Caldoria/XA01";
+ }
+
+ return movieName;
+}
+
+Common::String Caldoria::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ tRoomID room = GameState.getCurrentRoom();
+
+ if (room >= kCaldoria00 && room <= kCaldoria14) {
+ // Inside apartment.
+ if (GameState.getCaldoriaDoneHygiene())
+ return "Images/AI/Caldoria/XAE2";
+
+ return "Images/AI/Caldoria/XAE1";
+ } else if (room >= kCaldoria15 && room <= kCaldoria48) {
+ // Wandering the halls...
+ return "Images/AI/Caldoria/XAE3";
+ } else {
+ // Must be the roof.
+ return "Images/AI/Caldoria/XAEH2";
+ }
+ }
+
+ return movieName;
+}
+
+uint Caldoria::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria44, kEast):
+ if (!GameState.isTakenItemID(kKeyCard) && GameState.getOpenDoorRoom() == kNoRoomID)
+ numHints = 1;
+ break;
+ case MakeRoomView(kCaldoria48, kNorth):
+ if (!GameState.getCaldoriaRoofDoorOpen()) {
+ if (_croppedMovie.isRunning()) // Bomb must be looping.
+ numHints = 3;
+ else if (GameState.isTakenItemID(kCardBomb))
+ numHints = 1;
+ }
+ break;
+ case MakeRoomView(kCaldoria49, kEast):
+ case MakeRoomView(kCaldoria54, kEast):
+ numHints = 1;
+ break;
+ case MakeRoomView(kCaldoria49, kNorth):
+ numHints = 1;
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String Caldoria::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria44, kEast):
+ return "Images/AI/Caldoria/X42WH2";
+ case MakeRoomView(kCaldoria48, kNorth):
+ if (_croppedMovie.isRunning()) { // Bomb must be looping.
+ if (hintNum == 1)
+ return "Images/AI/Caldoria/X48ND1";
+ else if (hintNum == 2)
+ return "Images/AI/Caldoria/X48ND2";
+ else if (GameState.isTakenItemID(kShieldBiochip))
+ return "Images/AI/Caldoria/X48ND3";
+
+ // *** Doesn't work yet, need global movies.
+ break;
+ }
+
+ return "Images/AI/Globals/XGLOB1A";
+ case MakeRoomView(kCaldoria49, kEast):
+ case MakeRoomView(kCaldoria54, kEast):
+ return "Images/AI/Caldoria/X49E";
+ case MakeRoomView(kCaldoria49, kNorth):
+ return "Images/AI/Caldoria/X49NB2";
+ }
+ }
+
+ return movieName;
+}
+
+void Caldoria::updateCursor(const Common::Point where, const Hotspot *cursorSpot) {
+ switch (cursorSpot->getObjectID()) {
+ case kCa4DEnvironCloseSpotID:
+ _vm->_cursor->setCurrentFrameIndex(2);
+ break;
+ case kCaldoriaKioskSpotID:
+ _vm->_cursor->setCurrentFrameIndex(3);
+ break;
+ default:
+ Neighborhood::updateCursor(where, cursorSpot);
+ break;
+ }
+}
+
+Common::String Caldoria::getNavMovieName() {
+ return "Images/Caldoria/Caldoria.movie";
+}
+
+Common::String Caldoria::getSoundSpotsName() {
+ return "Sounds/Caldoria/Caldoria Spots";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.h b/engines/pegasus/neighborhood/caldoria/caldoria.h
new file mode 100755
index 0000000000..f2e3775168
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.h
@@ -0,0 +1,509 @@
+/* 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_NEIGHBORHOOD_CALDORIA_CALDORIA_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+const TimeScale kCaldoriaMovieScale = 600;
+const TimeScale kCaldoriaFramesPerSecond = 15;
+const TimeScale kCaldoriaFrameDuration = 40;
+
+// Alternate IDs.
+
+const tAlternateID kAltCaldoriaNormal = 0;
+const tAlternateID kAltCaldoriaRoofDoorBlown = 2;
+const tAlternateID kAltCaldoriaSinclairDown = 3;
+
+// Room IDs.
+
+const tRoomID kCaldoria00 = 1;
+const tRoomID kCaldoria01 = 2;
+const tRoomID kCaldoria02 = 3;
+const tRoomID kCaldoria03 = 4;
+const tRoomID kCaldoria04 = 5;
+const tRoomID kCaldoria05 = 6;
+const tRoomID kCaldoria06 = 7;
+const tRoomID kCaldoria07 = 8;
+const tRoomID kCaldoria08 = 9;
+const tRoomID kCaldoria09 = 10;
+const tRoomID kCaldoria10 = 11;
+const tRoomID kCaldoriaToilet = 12;
+const tRoomID kCaldoria11 = 13;
+const tRoomID kCaldoria12 = 14;
+const tRoomID kCaldoriaVidPhone = 15;
+const tRoomID kCaldoriaReplicator = 16;
+const tRoomID kCaldoriaDrawers = 17;
+const tRoomID kCaldoria13 = 18;
+const tRoomID kCaldoria14 = 19;
+const tRoomID kCaldoria15 = 20;
+const tRoomID kCaldoria16 = 21;
+const tRoomID kCaldoria17 = 22;
+const tRoomID kCaldoria18 = 23;
+const tRoomID kCaldoria19 = 24;
+const tRoomID kCaldoria20 = 25;
+const tRoomID kCaldoria21 = 26;
+const tRoomID kCaldoria22 = 27;
+const tRoomID kCaldoria23 = 28;
+const tRoomID kCaldoria24 = 29;
+const tRoomID kCaldoria25 = 30;
+const tRoomID kCaldoria26 = 31;
+const tRoomID kCaldoria27 = 32;
+const tRoomID kCaldoria28 = 33;
+const tRoomID kCaldoria29 = 34;
+const tRoomID kCaldoria30 = 35;
+const tRoomID kCaldoria31 = 36;
+const tRoomID kCaldoria32 = 37;
+const tRoomID kCaldoria33 = 38;
+const tRoomID kCaldoria34 = 39;
+const tRoomID kCaldoria35 = 40;
+const tRoomID kCaldoria36 = 41;
+const tRoomID kCaldoria37 = 42;
+const tRoomID kCaldoria38 = 43;
+const tRoomID kCaldoria39 = 44;
+const tRoomID kCaldoria40 = 45;
+const tRoomID kCaldoria41 = 46;
+const tRoomID kCaldoriaBinoculars = 47;
+const tRoomID kCaldoria42 = 48;
+const tRoomID kCaldoriaKiosk = 49;
+const tRoomID kCaldoria44 = 50;
+const tRoomID kCaldoria45 = 51;
+const tRoomID kCaldoria46 = 52;
+const tRoomID kCaldoria47 = 53;
+const tRoomID kCaldoria48 = 54;
+const tRoomID kCaldoria49 = 55;
+const tRoomID kCaldoria50 = 56;
+const tRoomID kCaldoria51 = 57;
+const tRoomID kCaldoria52 = 58;
+const tRoomID kCaldoria53 = 59;
+const tRoomID kCaldoria54 = 60;
+const tRoomID kCaldoria55 = 61;
+const tRoomID kCaldoria56 = 62;
+const tRoomID kCaldoriaDeathRoom = 0;
+
+// Hot Spot Activation IDs.
+
+const tHotSpotActivationID kActivate4DClosed = 1;
+const tHotSpotActivationID kActivate4DOpen = 2;
+const tHotSpotActivationID kActivateMirrorReady = 3;
+const tHotSpotActivationID kActivateStylistReady = 4;
+const tHotSpotActivationID kActivateReplicatorReady = 5;
+const tHotSpotActivationID kActivateOJOnThePad = 6;
+const tHotSpotActivationID kActivateDrawersClosed = 7;
+const tHotSpotActivationID kActivateRightOpen = 8;
+const tHotSpotActivationID kActivateLeftOpen = 9;
+const tHotSpotActivationID kActivateFocusedOnShip = 10;
+const tHotSpotActivationID kActivateNotFocusedOnShip = 11;
+const tHotSpotActivationID kActivateReadyForCard = 12;
+const tHotSpotActivationID kActivateReadyToTransport = 13;
+const tHotSpotActivationID kActivateRoofSlotEmpty = 14;
+const tHotSpotActivationID kActivateZoomedOnSinclair = 15;
+
+// Hot Spot IDs.
+
+const tHotSpotID kCa4DEnvironOpenSpotID = 5000;
+const tHotSpotID kCa4DEnvironCloseSpotID = 5001;
+const tHotSpotID kCa4DVisualSpotID = 5002;
+const tHotSpotID kCa4DAudioSpotID = 5003;
+const tHotSpotID kCa4DChoice1SpotID = 5004;
+const tHotSpotID kCa4DChoice2SpotID = 5005;
+const tHotSpotID kCa4DChoice3SpotID = 5006;
+const tHotSpotID kCa4DChoice4SpotID = 5007;
+const tHotSpotID kCaBathroomMirrorSpotID = 5008;
+const tHotSpotID kCaHairStyle1SpotID = 5009;
+const tHotSpotID kCaHairStyle2SpotID = 5010;
+const tHotSpotID kCaHairStyle3SpotID = 5011;
+const tHotSpotID kCaShowerSpotID = 5012;
+const tHotSpotID kCaBathroomToiletSpotID = 5013;
+const tHotSpotID kCaldoriaVidPhoneSpotID = 5014;
+const tHotSpotID kCaldoriaReplicatorSpotID = 5015;
+const tHotSpotID kCaldoriaDrawersSpotID = 5016;
+const tHotSpotID kCaldoriaVidPhoneOutSpotID = 5017;
+const tHotSpotID kCaBedroomVidPhoneActivationSpotID = 5018;
+const tHotSpotID kCaldoriaReplicatorOutSpotID = 5019;
+const tHotSpotID kCaldoriaMakeOJSpotID = 5020;
+const tHotSpotID kCaldoriaMakeStickyBunsSpotID = 5021;
+const tHotSpotID kCaldoriaOrangeJuiceSpotID = 5022;
+const tHotSpotID kCaldoriaOrangeJuiceDropSpotID = 5023;
+const tHotSpotID kCaldoriaDrawersOutSpotID = 5024;
+const tHotSpotID kCaldoriaLeftDrawerOpenSpotID = 5025;
+const tHotSpotID kCaldoriaRightDrawerOpenSpotID = 5026;
+const tHotSpotID kCaldoriaKeyCardSpotID = 5027;
+const tHotSpotID kCaldoriaLeftDrawerCloseSpotID = 5028;
+const tHotSpotID kCaldoriaRightDrawerWithKeysCloseSpotID = 5029;
+const tHotSpotID kCaldoriaRightDrawerNoKeysCloseSpotID = 5030;
+const tHotSpotID kCaldoriaFourthFloorElevatorSpotID = 5031;
+const tHotSpotID kCaldoria20DoorbellSpotID = 5032;
+const tHotSpotID kCaldoria21DoorbellSpotID = 5033;
+const tHotSpotID kCaldoria26DoorbellSpotID = 5034;
+const tHotSpotID kCaldoriaFourthFloorElevator1 = 5035;
+const tHotSpotID kCaldoriaFourthFloorElevator2 = 5036;
+const tHotSpotID kCaldoriaFourthFloorElevator3 = 5037;
+const tHotSpotID kCaldoriaFourthFloorElevator4 = 5038;
+const tHotSpotID kCaldoriaFourthFloorElevator5 = 5039;
+const tHotSpotID kCaldoriaGroundElevator1 = 5040;
+const tHotSpotID kCaldoriaGroundElevator2 = 5041;
+const tHotSpotID kCaldoriaGroundElevator3 = 5042;
+const tHotSpotID kCaldoriaGroundElevator4 = 5043;
+const tHotSpotID kCaldoriaGroundElevator5 = 5044;
+const tHotSpotID kCaldoria29DoorbellSpotID = 5045;
+const tHotSpotID kCaldoria34DoorbellSpotID = 5046;
+const tHotSpotID kCaldoria35DoorbellSpotID = 5047;
+const tHotSpotID kCaldoriaGroundElevatorSpotID = 5048;
+const tHotSpotID kCaldoriaBinocularZoomInSpotID = 5049;
+const tHotSpotID kCaldoriaBinocularsOutSpotID = 5050;
+const tHotSpotID kCaldoriaZoomInOnShipSpotID = 5051;
+const tHotSpotID kCaldoriaKioskSpotID = 5052;
+const tHotSpotID kCaldoriaKioskOutSpotID = 5053;
+const tHotSpotID kCaldoriaKioskInfoSpotID = 5054;
+const tHotSpotID kCaldoriaGTCardDropSpotID = 5055;
+const tHotSpotID kCaldoriaGTTokyoSpotID = 5056;
+const tHotSpotID kCaldoriaGTTSASpotID = 5057;
+const tHotSpotID kCaldoriaGTBeachSpotID = 5058;
+const tHotSpotID kCaldoriaGTOtherSpotID = 5059;
+const tHotSpotID kCaldoriaRoofElevator1 = 5060;
+const tHotSpotID kCaldoriaRoofElevator2 = 5061;
+const tHotSpotID kCaldoriaRoofElevator3 = 5062;
+const tHotSpotID kCaldoriaRoofElevator4 = 5063;
+const tHotSpotID kCaldoriaRoofElevator5 = 5064;
+const tHotSpotID kCaldoriaRoofElevatorSpotID = 5065;
+const tHotSpotID kCaldoriaRoofDoorSpotID = 5066;
+const tHotSpotID kCaldoriaRoofCardDropSpotID = 5067;
+const tHotSpotID kCaldoria53EastSinclairTargetSpotID = 5068;
+
+// Extra sequence IDs.
+
+const tExtraID kCaldoriaWakeUpView1 = 0;
+const tExtraID kCaldoria00WakeUp1 = 1;
+const tExtraID kCaldoria00WakeUp2 = 2;
+const tExtraID kCaldoria00SitDown = 3;
+const tExtraID k4DEnvironOpenToINN = 4;
+const tExtraID k4DINNInterruption = 5;
+const tExtraID k4DINNIntro = 6;
+const tExtraID k4DINNMarkJohnson = 7;
+const tExtraID k4DINNMeganLove = 8;
+const tExtraID k4DINNFadeOut = 9;
+const tExtraID k4DEnvironOpenFromINN = 10;
+const tExtraID k4DEnvironOpen = 11;
+const tExtraID k4DEnvironOpenView = 12;
+const tExtraID k4DEnvironClose = 13;
+const tExtraID k4DIslandLoop = 14;
+const tExtraID k4DDesertLoop = 15;
+const tExtraID k4DMountainLoop = 16;
+const tExtraID k4DIsland1ToIsland0 = 17;
+const tExtraID k4DIsland2ToIsland0 = 18;
+const tExtraID k4DIsland0ToDesert0 = 19;
+const tExtraID k4DIsland1ToDesert0 = 20;
+const tExtraID k4DIsland2ToDesert0 = 21;
+const tExtraID k4DIsland0ToMountain0 = 22;
+const tExtraID k4DIsland1ToMountain0 = 23;
+const tExtraID k4DIsland2ToMountain0 = 24;
+const tExtraID k4DDesert0ToIsland0 = 25;
+const tExtraID k4DDesert1ToIsland0 = 26;
+const tExtraID k4DDesert2ToIsland0 = 27;
+const tExtraID k4DDesert0ToMountain0 = 28;
+const tExtraID k4DDesert1ToMountain0 = 29;
+const tExtraID k4DDesert2ToMountain0 = 30;
+const tExtraID k4DMountain0ToIsland0 = 31;
+const tExtraID k4DMountain1ToIsland0 = 32;
+const tExtraID k4DMountain2ToIsland0 = 33;
+const tExtraID k4DMountain0ToDesert0 = 34;
+const tExtraID k4DMountain1ToDesert0 = 35;
+const tExtraID k4DMountain2ToDesert0 = 36;
+const tExtraID kCaBathroomGreeting = 37;
+const tExtraID kCaBathroomBodyFat = 38;
+const tExtraID kCaBathroomStylistIntro = 39;
+const tExtraID kCaBathroomRetrothrash = 40;
+const tExtraID kCaBathroomRetrothrashReturn = 41;
+const tExtraID kCaBathroomGeoWave = 42;
+const tExtraID kCaBathroomGeoWaveReturn = 43;
+const tExtraID kCaBathroomAgencyStandard = 44;
+const tExtraID kCaldoriaShowerTitle = 45;
+const tExtraID kCaldoriaShowerButton = 46;
+const tExtraID kCaldoriaShowerDown = 47;
+const tExtraID kCaldoriaShowerUp = 48;
+const tExtraID kCaBedroomVidPhone = 49;
+const tExtraID kCaBedroomMessage1 = 50;
+const tExtraID kCaBedroomMessage2 = 51;
+const tExtraID kCreateOrangeJuice = 52;
+const tExtraID kDisposeOrangeJuice = 53;
+const tExtraID kReplicatorNorthViewWithOJ = 54;
+const tExtraID kLeftDrawerOpen = 55;
+const tExtraID kLeftDrawerClose = 56;
+const tExtraID kRightDrawerOpenWithKeys = 57;
+const tExtraID kRightDrawerCloseWithKeys = 58;
+const tExtraID kRightDrawerOpenNoKeys = 59;
+const tExtraID kRightDrawerCloseNoKeys = 60;
+const tExtraID kRightDrawerOpenViewWithKeys = 61;
+const tExtraID kRightDrawerOpenViewNoKeys = 62;
+const tExtraID kCaldoria16ElevatorUp = 63;
+const tExtraID kCaldoria16ElevatorDown = 64;
+const tExtraID kCaldoria16SouthViewWithElevator = 65;
+const tExtraID kCaldoria20Doorbell = 66;
+const tExtraID kCaldoria21Doorbell = 67;
+const tExtraID kCaldoria26Doorbell = 68;
+const tExtraID kCaldoriaFourthToGround = 69;
+const tExtraID kCaldoriaRoofToFourth = 70;
+const tExtraID kCaldoriaRoofToGround = 71;
+const tExtraID kCaldoriaGroundToFourth = 72;
+const tExtraID kCaldoriaGroundToRoof = 73;
+const tExtraID kCaldoriaFourthToRoof = 74;
+const tExtraID kCaldoria29Doorbell = 75;
+const tExtraID kCaldoria34Doorbell = 76;
+const tExtraID kCaldoria35Doorbell = 77;
+const tExtraID kBinocularsZoomInOnShip = 78;
+const tExtraID kCaldoriaKioskVideo = 79;
+const tExtraID kCaldoriaTransporterArrowLoop = 80;
+const tExtraID kArriveAtCaldoriaFromTSA = 81;
+const tExtraID kCaGTOtherChoice = 82;
+const tExtraID kCaGTCardSwipe = 83;
+const tExtraID kCaGTSelectTSA = 84;
+const tExtraID kCaGTFryTheFly = 85;
+const tExtraID kCaGTGoToTSA = 86;
+const tExtraID kCaGTSelectBeach = 87;
+const tExtraID kCaGTGoToBeach = 88;
+const tExtraID kCaGTArriveAtBeach = 89;
+const tExtraID kCaGTSelectTokyo = 90;
+const tExtraID kCaGTGoToTokyo = 91;
+const tExtraID kCaGTArriveAtTokyo = 92;
+const tExtraID kCa48NorthRooftopClosed = 93;
+const tExtraID kCa48NorthExplosion = 94;
+const tExtraID kCa48NorthExplosionDeath = 95;
+const tExtraID kCa49NorthVoiceAnalysis = 96;
+const tExtraID kCa50SinclairShoots = 97;
+const tExtraID kCa53EastZoomToSinclair = 98;
+const tExtraID kCa53EastDeath2 = 99;
+const tExtraID kCa53EastShootSinclair = 100;
+const tExtraID kCa53EastZoomOutFromSinclair = 101;
+const tExtraID kCa54SouthDeath = 102;
+const tExtraID kCaldoria56BombStage1 = 103;
+const tExtraID kCaldoria56BombStage2 = 104;
+const tExtraID kCaldoria56BombStage3 = 105;
+const tExtraID kCaldoria56BombStage4 = 106;
+const tExtraID kCaldoria56BombStage5 = 107;
+const tExtraID kCaldoria56BombStage6 = 108;
+const tExtraID kCaldoria56BombStage7 = 109;
+const tExtraID kCaldoria56BombExplodes = 110;
+
+// Caldoria interactions.
+
+const tInteractionID kCaldoria4DInteractionID = 0;
+const tInteractionID kCaldoriaBombInteractionID = 1;
+const tInteractionID kCaldoriaMessagesInteractionID = 2;
+const tInteractionID kCaldoriaMirrorInteractionID = 3;
+
+// Caldoria:
+
+const tDisplayOrder kVidPhoneOrder = kMonitorLayer;
+const tDisplayOrder k4DSpritesOrder = kMonitorLayer;
+const tDisplayOrder kCaldoriaMessagesOrder = kMonitorLayer;
+const tDisplayOrder kCaldoriaElevatorOrder = kMonitorLayer;
+const tDisplayOrder kCaldoriaA05LightLoopOrder = kMonitorLayer;
+const tDisplayOrder kCaldoriaA07LightLoopOrder = kMonitorLayer;
+const tDisplayOrder kCaldoriaBombGridOrder = kMonitorLayer;
+const tDisplayOrder kCaldoriaBombTimerOrder = kCaldoriaBombGridOrder + 1;
+
+/////////////////////////////////////////////
+//
+// Caldoria
+
+const tCoordType kCaldoriaVidPhoneLeft = kNavAreaLeft + 105;
+const tCoordType kCaldoriaVidPhoneTop = kNavAreaTop + 28;
+
+const tCoordType kCaldoria4DSpritesLeft = kNavAreaLeft + 10;
+const tCoordType kCaldoria4DSpritesTop = kNavAreaTop + 142;
+
+const tCoordType kCaldoriaMessageLeft = kNavAreaLeft + 202;
+const tCoordType kCaldoriaMessageTop = kNavAreaTop + 26;
+
+const tCoordType kCaldoriaElevatorLeft = kNavAreaLeft + 407;
+const tCoordType kCaldoriaElevatorTop = kNavAreaTop + 138;
+
+const tCoordType kCaldoriaA05LightLoopLeft = kNavAreaLeft + 213;
+const tCoordType kCaldoriaA05LightLoopTop = kNavAreaTop + 215;
+
+const tCoordType kCaldoriaA07LightLoopLeft = kNavAreaLeft + 414;
+const tCoordType kCaldoriaA07LightLoopTop = kNavAreaTop + 215;
+
+const tCoordType kCaldoriaGunSpriteLeft = kNavAreaLeft + 276;
+const tCoordType kCaldoriaGunSpriteTop = kNavAreaTop + 115;
+
+const tCoordType kCaldoria11MessageLoopLeft = kNavAreaLeft + 135;
+const tCoordType kCaldoria11MessageLoopTop = kNavAreaTop + 214;
+
+const tCoordType kCaldoria12MessageLoopLeft = kNavAreaLeft + 209;
+const tCoordType kCaldoria12MessageLoopTop = kNavAreaTop + 170;
+
+const tCoordType kCaldoria13MessageLoopLeft = kNavAreaLeft + 480;
+const tCoordType kCaldoria13MessageLoopTop = kNavAreaTop + 191;
+
+const tCoordType kCaldoria14MessageLoopLeft = kNavAreaLeft + 248;
+const tCoordType kCaldoria14MessageLoopTop = kNavAreaTop + 191;
+
+const tCoordType kCaldoria48CardBombLoopLeft = kNavAreaLeft + 337;
+const tCoordType kCaldoria48CardBombLoopTop = kNavAreaTop + 205;
+
+const tCoordType kCaldoriaBombGridLeft = kNavAreaLeft + 290;
+const tCoordType kCaldoriaBombGridTop = kNavAreaTop + 58;
+
+const tCoordType kCaldoriaBombTimerLeft = kNavAreaLeft + 58;
+const tCoordType kCaldoriaBombTimerTop = kNavAreaTop + 204;
+
+// Caldoria display IDs.
+
+const tDisplayElementID kCaldoriaVidPhoneID = kNeighborhoodDisplayID;
+const tDisplayElementID kCaldoria4DSpritesID = kCaldoriaVidPhoneID + 1;
+const tDisplayElementID kCaldoriaMessagesID = kCaldoria4DSpritesID + 1;
+const tDisplayElementID kCaldoriaUtilityID = kCaldoriaMessagesID + 1;
+const tDisplayElementID kCaldoriaBombGridID = kCaldoriaUtilityID + 1;
+const tDisplayElementID kCaldoriaBombTimerID = kCaldoriaBombGridID + 1;
+
+const TimeValue kCaldoria4DBlankChoiceIn = 29730;
+const TimeValue kCaldoria4DBlankChoiceOut = 33910;
+
+class Caldoria : public Neighborhood {
+friend void doorBombTimerExpiredFunction(FunctionPtr *, void *);
+friend void sinclairTimerExpiredFunction(FunctionPtr *, void *);
+
+public:
+ Caldoria(InputHandler *, PegasusEngine *);
+ virtual ~Caldoria();
+
+ virtual uint16 getDateResID() const;
+
+ void pickedUpItem(Item *);
+
+ virtual GameInteraction *makeInteraction(const tInteractionID);
+
+ virtual Common::String getBriefingMovie();
+ virtual Common::String getEnvScanMovie();
+ virtual uint getNumHints();
+ virtual Common::String getHintMovie(uint);
+ void loadAmbientLoops();
+ bool wantsCursor();
+ void flushGameState();
+
+ void checkContinuePoint(const tRoomID, const tDirectionConstant);
+
+protected:
+ enum {
+ kCaldoriaPrivate4DSystemOpenFlag,
+ kCaloriaPrivateLeftDrawerOpenFlag,
+ kCaldoriaPrivateRightDrawerOpenFlag,
+ kCaldoriaPrivateReadyToShootFlag,
+ kCaldoriaPrivateZoomingToBombFlag,
+ kCaldoriaPrivateCanOpenElevatorDoorFlag,
+ kCaldoriaPrivateSinclairTimerExpiredFlag,
+ kCaldoriaPrivateSeen13CarFlag,
+ kCaldoriaPrivateSeen14CarFlag,
+ kCaldoriaPrivateSeen18CarFlag,
+ kCaldoriaPrivateSeen23CarFlag,
+ kCaldoriaPrivateSeen33CarFlag,
+ kCaldoriaPrivateSeen36CarFlag,
+ kCaldoriaPrivateSeen41NorthCarFlag,
+ kCaldoriaPrivateSeen41EastCarFlag,
+ kCaldoriaPrivateSeen41WestCarFlag,
+ kNumCaldoriaPrivateFlags
+ };
+
+ void init();
+ void start();
+
+ void setUpRoofTop();
+
+ void setUpAIRules();
+ void doAIRecalibration();
+ TimeValue getViewTime(const tRoomID, const tDirectionConstant);
+ void findSpotEntry(const tRoomID, const tDirectionConstant, tSpotFlags, SpotTable::Entry &);
+ void startSpotOnceOnly(TimeValue, TimeValue);
+ void startExitMovie(const ExitTable::Entry &);
+ void startZoomMovie(const ZoomTable::Entry &);
+ void startDoorOpenMovie(const TimeValue, const TimeValue);
+ void startTurnPush(const tTurnDirection, const TimeValue, const tDirectionConstant);
+ void bumpIntoWall();
+ int16 getStaticCompassAngle(const tRoomID, const tDirectionConstant);
+ void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
+ void getZoomCompassMove(const ZoomTable::Entry &, FaderMoveSpec &);
+ void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &);
+ void spotCompleted();
+ void arriveAt(const tRoomID, const tDirectionConstant);
+ void arriveAtCaldoria00();
+ void arriveAtCaldoriaToilet();
+ void arriveAtCaldoria44();
+ void arriveAtCaldoria49();
+ void arriveAtCaldoria56();
+ void arriveAtCaldoriaDeath();
+ void turnTo(const tDirectionConstant);
+ void zoomTo(const Hotspot *);
+ void downButton(const Input &);
+ void receiveNotification(Notification *, const tNotificationFlags);
+ tInputBits getInputFilter();
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void newInteraction(const tInteractionID);
+
+ void clickOnDoorbell(const tHotSpotID);
+
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+ void dropItemIntoRoom(Item *, Hotspot *);
+ void takeElevator(uint, uint);
+ void updateElevatorMovie();
+ void openElevatorMovie();
+ void emptyOJGlass();
+ void closeDoorOffScreen(const tRoomID, const tDirectionConstant);
+ void doorBombTimerExpired();
+ void sinclairTimerExpired();
+ void checkSinclairShootsOS();
+ void setUpSinclairLoops();
+ void zoomToSinclair();
+ void playEndMessage();
+ void checkInterruptSinclair();
+
+ tCanOpenDoorReason canOpenDoor(DoorTable::Entry &);
+ void doorOpened();
+
+ void updateCursor(const Common::Point, const Hotspot *);
+
+ FlagsArray<uint16, kNumCaldoriaPrivateFlags> _privateFlags;
+
+ const Hotspot *_zoomOutSpot;
+
+ FuseFunction _utilityFuse;
+
+ long _sinclairLoopCount;
+ long _numSinclairLoops;
+
+ Sprite *_gunSprite;
+
+ Common::String getSoundSpotsName();
+ Common::String getNavMovieName();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
new file mode 100755
index 0000000000..f6fa399ed2
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
@@ -0,0 +1,369 @@
+/* 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/ai/ai_area.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoria4dsystem.h"
+
+namespace Pegasus {
+
+const TimeValue kSwitchableSlop = 3 * kCaldoriaFrameDuration;
+// Two seconds - some slop
+const TimeValue kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop;
+// Twelve frames + some slop
+const TimeValue kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop;
+
+const TimeValue kSwitchable1Start = 0;
+const TimeValue kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration;
+
+const TimeValue kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration;
+const TimeValue kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration;
+
+const TimeValue kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration;
+const TimeValue kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration;
+
+const tNotificationFlags kVidPhoneDoneFlag = 1;
+
+const TimeValue kRockMusicLoopIn = 0;
+const TimeValue kRockMusicLoopOut = 2088;
+
+const TimeValue kOrchestralMusicLoopIn = 2088;
+const TimeValue kOrchestralMusicLoopOut = 4985;
+
+const TimeValue kRhythmsMusicLoopIn = 4985;
+const TimeValue kRhythmsMusicLoopOut = 6824;
+
+const TimeValue kAcousticMusicLoopIn = 6824;
+const TimeValue kAcousticMusicLoopOut = 9387;
+
+enum {
+ k4DVideoMenu,
+ k4DAudioMenu,
+ k4DShuttingDown,
+
+ // These constants are the exact frame numbers of the sprite movie.
+ k4DRockChoice = 0,
+ k4DOrchestralChoice,
+ k4DRhythmsChoice,
+ k4DAcousticChoice,
+ k4DIslandChoice,
+ k4DDesertChoice,
+ k4DMountainChoice,
+
+ k4DFirstVideoChoice = k4DIslandChoice
+};
+
+tExtraID s_transitionExtras0[3][3] = {
+ {0xffffffff, k4DIsland0ToDesert0, k4DIsland0ToMountain0},
+ {k4DDesert0ToIsland0, 0xffffffff, k4DDesert0ToMountain0},
+ {k4DMountain0ToIsland0, k4DMountain0ToDesert0, 0xffffffff}
+};
+
+tExtraID s_transitionExtras1[3][3] = {
+ {0xffffffff, k4DIsland1ToDesert0, k4DIsland1ToMountain0},
+ {k4DDesert1ToIsland0, 0xffffffff, k4DDesert1ToMountain0},
+ {k4DMountain1ToIsland0, k4DMountain1ToDesert0, 0xffffffff}
+};
+
+tExtraID s_transitionExtras2[3][3] = {
+ {0xffffffff, k4DIsland2ToDesert0, k4DIsland2ToMountain0},
+ {k4DDesert2ToIsland0, 0xffffffff, k4DDesert2ToMountain0},
+ {k4DMountain2ToIsland0, k4DMountain2ToDesert0, 0xffffffff}
+};
+
+tExtraID s_shutDownExtras[3][3] = {
+ {0xffffffff, k4DIsland1ToIsland0, k4DIsland2ToIsland0},
+ {k4DDesert0ToIsland0, k4DDesert1ToIsland0, k4DDesert2ToIsland0},
+ {k4DMountain0ToIsland0, k4DMountain1ToIsland0, k4DMountain2ToIsland0}
+};
+
+Caldoria4DSystem::Caldoria4DSystem(Neighborhood *owner) : GameInteraction(kCaldoria4DInteractionID, owner),
+ _4DSpritesMovie(kCaldoria4DSpritesID) {
+ g_AIArea->lockAIOut();
+}
+
+Caldoria4DSystem::~Caldoria4DSystem() {
+ g_AIArea->unlockAI();
+}
+
+void Caldoria4DSystem::openInteraction() {
+ _whichMenu = k4DVideoMenu;
+ _videoChoice = k4DIslandChoice;
+ _audioChoice = k4DRockChoice;
+ _clickedHotspotID = kNoHotSpotID;
+
+ _4DSpritesMovie.initFromMovieFile("Images/Caldoria/4D Sprites", true);
+ _4DSpritesMovie.moveElementTo(kCaldoria4DSpritesLeft, kCaldoria4DSpritesTop);
+ _4DSpritesMovie.setDisplayOrder(k4DSpritesOrder);
+ _4DSpritesMovie.startDisplaying();
+ _4DSpritesMovie.show();
+
+ _4DSpritesScale = _4DSpritesMovie.getScale();
+
+ _neighborhoodNotification = _owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+
+ startIdling();
+}
+
+void Caldoria4DSystem::loopExtra(const tExtraID extraID) {
+ ExtraTable::Entry extraEntry;
+
+ _owner->getExtraEntry(extraID, extraEntry);
+ _loopStart = extraEntry.movieStart;
+ _owner->loopExtraSequence(extraID);
+}
+
+void Caldoria4DSystem::useIdleTime() {
+ if (_whichMenu == k4DShuttingDown) {
+ TimeValue movieTime = _owner->getNavMovie()->getTime() - _loopStart;
+ tExtraID extraID;
+
+ if (movieTime < kSwitchable1Stop)
+ extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][0];
+ else if (movieTime >= kSwitchable2Start && movieTime < kSwitchable2Stop)
+ extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][1];
+ else if (movieTime >= kSwitchable3Start && movieTime < kSwitchable3Stop)
+ extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][2];
+ else
+ extraID = 0xffffffff;
+
+ if (extraID != 0xffffffff) {
+ setSpritesMovie();
+ _loopStart = 0;
+ _owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
+ }
+ } else if (_clickedHotspotID != kNoHotSpotID) {
+ TimeValue movieTime = _owner->getNavMovie()->getTime() - _loopStart;
+ tExtraID extraID;
+
+ if (movieTime < kSwitchable1Stop) {
+ extraID = s_transitionExtras0[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
+ _clickedHotspotID = kNoHotSpotID;
+ } else if (movieTime >= kSwitchable2Start && movieTime < kSwitchable2Stop) {
+ extraID = s_transitionExtras1[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
+ _clickedHotspotID = kNoHotSpotID;
+ } else if (movieTime >= kSwitchable3Start && movieTime < kSwitchable3Stop) {
+ extraID = s_transitionExtras2[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
+ _clickedHotspotID = kNoHotSpotID;
+ } else
+ extraID = 0xffffffff;
+
+ if (extraID != 0xffffffff) {
+ switch (extraID) {
+ case k4DDesert0ToIsland0:
+ case k4DMountain0ToIsland0:
+ case k4DDesert1ToIsland0:
+ case k4DMountain1ToIsland0:
+ case k4DDesert2ToIsland0:
+ case k4DMountain2ToIsland0:
+ _videoChoice = k4DIslandChoice;
+ break;
+ case k4DIsland0ToDesert0:
+ case k4DMountain0ToDesert0:
+ case k4DIsland1ToDesert0:
+ case k4DMountain1ToDesert0:
+ case k4DIsland2ToDesert0:
+ case k4DMountain2ToDesert0:
+ _videoChoice = k4DDesertChoice;
+ break;
+ case k4DDesert0ToMountain0:
+ case k4DIsland0ToMountain0:
+ case k4DIsland1ToMountain0:
+ case k4DDesert1ToMountain0:
+ case k4DIsland2ToMountain0:
+ case k4DDesert2ToMountain0:
+ _videoChoice = k4DMountainChoice;
+ break;
+ }
+
+ setSpritesMovie();
+ _loopStart = 0;
+ _owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
+}
+
+void Caldoria4DSystem::initInteraction() {
+ setSpritesMovie();
+
+ _owner->loadLoopSound1("Sounds/Caldoria/Rock.aiff");
+ loopExtra(k4DIslandLoop);
+}
+
+void Caldoria4DSystem::closeInteraction() {
+ stopIdling();
+ _neighborhoodNotification->cancelNotification(this);
+ _4DSpritesMovie.releaseMovie();
+ _owner->loadAmbientLoops();
+}
+
+void Caldoria4DSystem::setSpritesMovie() {
+ if (_whichMenu == k4DShuttingDown)
+ _4DSpritesMovie.setTime(_4DSpritesScale * k4DIslandChoice);
+ else if (_whichMenu == k4DVideoMenu)
+ _4DSpritesMovie.setTime(_4DSpritesScale * _videoChoice);
+ else if (_whichMenu == k4DAudioMenu)
+ _4DSpritesMovie.setTime(_4DSpritesScale * _audioChoice);
+ _4DSpritesMovie.triggerRedraw();
+}
+
+void Caldoria4DSystem::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (input.downButtonAnyDown())
+ return;
+ if (input.anyDirectionInput())
+ shutDown4DSystem();
+ else
+ GameInteraction::handleInput(input, cursorSpot);
+}
+
+void Caldoria4DSystem::activateHotspots() {
+ GameInteraction::activateHotspots();
+ if (_whichMenu == k4DAudioMenu)
+ g_allHotspots.activateOneHotspot(kCa4DChoice4SpotID);
+}
+
+void Caldoria4DSystem::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kCa4DVisualSpotID:
+ if (_whichMenu == k4DAudioMenu) {
+ _whichMenu = k4DVideoMenu;
+ setSpritesMovie();
+ }
+ break;
+ case kCa4DAudioSpotID:
+ if (_whichMenu == k4DVideoMenu) {
+ _whichMenu = k4DAudioMenu;
+ setSpritesMovie();
+ }
+ break;
+ case kCa4DChoice1SpotID:
+ if (_whichMenu == k4DVideoMenu)
+ makeIslandChoice();
+ else if (_whichMenu == k4DAudioMenu)
+ makeRockChoice();
+ break;
+ case kCa4DChoice2SpotID:
+ if (_whichMenu == k4DVideoMenu)
+ makeDesertChoice();
+ else if (_whichMenu == k4DAudioMenu)
+ makeOrchestralChoice();
+ break;
+ case kCa4DChoice3SpotID:
+ if (_whichMenu == k4DVideoMenu)
+ makeMountainChoice();
+ else if (_whichMenu == k4DAudioMenu)
+ makeRhythmsChoice();
+ break;
+ case kCa4DChoice4SpotID:
+ if (_whichMenu == k4DAudioMenu)
+ makeAcousticChoice();
+ else
+ _owner->playSpotSoundSync(kCaldoria4DBlankChoiceIn, kCaldoria4DBlankChoiceOut);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ }
+}
+
+void Caldoria4DSystem::receiveNotification(Notification *, const tNotificationFlags) {
+ if (_whichMenu == k4DShuttingDown) {
+ _owner->requestDeleteCurrentInteraction();
+ } else {
+ uint32 extraID;
+
+ switch (_videoChoice) {
+ case k4DIslandChoice:
+ extraID = k4DIslandLoop;
+ break;
+ case k4DDesertChoice:
+ extraID = k4DDesertLoop;
+ break;
+ case k4DMountainChoice:
+ extraID = k4DMountainLoop;
+ break;
+ default:
+ extraID = 0xffffffff;
+ break;
+ }
+
+ if (extraID != 0xffffffff)
+ loopExtra(extraID);
+ }
+}
+
+void Caldoria4DSystem::makeIslandChoice() {
+ if (_videoChoice != k4DIslandChoice && _clickedHotspotID == kNoHotSpotID)
+ _clickedHotspotID = kCa4DChoice1SpotID;
+}
+
+void Caldoria4DSystem::makeDesertChoice() {
+ if (_videoChoice != k4DDesertChoice && _clickedHotspotID == kNoHotSpotID)
+ _clickedHotspotID = kCa4DChoice2SpotID;
+}
+
+void Caldoria4DSystem::makeMountainChoice() {
+ if (_videoChoice != k4DMountainChoice && _clickedHotspotID == kNoHotSpotID)
+ _clickedHotspotID = kCa4DChoice3SpotID;
+}
+
+void Caldoria4DSystem::makeRockChoice() {
+ if (_audioChoice != k4DRockChoice) {
+ _audioChoice = k4DRockChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Rock.aiff");
+ }
+}
+
+void Caldoria4DSystem::makeOrchestralChoice() {
+ if (_audioChoice != k4DOrchestralChoice) {
+ _audioChoice = k4DOrchestralChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Orchestral.aiff");
+ }
+}
+
+void Caldoria4DSystem::makeRhythmsChoice() {
+ if (_audioChoice != k4DRhythmsChoice) {
+ _audioChoice = k4DRhythmsChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Rhythms.aiff");
+ }
+}
+
+void Caldoria4DSystem::makeAcousticChoice() {
+ if (_audioChoice != k4DAcousticChoice) {
+ _audioChoice = k4DAcousticChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Acoustic.aiff");
+ }
+}
+
+void Caldoria4DSystem::shutDown4DSystem() {
+ _whichMenu = k4DShuttingDown;
+
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
new file mode 100755
index 0000000000..e0217918fa
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
@@ -0,0 +1,78 @@
+/* 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_NEIGHBORHOOD_CALDORIA_CALDORIA4DSYSTEM_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA4DSYSTEM_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Neighborhood;
+
+class Caldoria4DSystem : public GameInteraction, private Idler, public NotificationReceiver {
+public:
+ Caldoria4DSystem(Neighborhood *);
+ virtual ~Caldoria4DSystem();
+
+ void shutDown4DSystem();
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void handleInput(const Input &, const Hotspot *);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void receiveNotification(Notification *, const tNotificationFlags);
+ void setSpritesMovie();
+ void makeIslandChoice();
+ void makeRockChoice();
+ void makeMountainChoice();
+ void makeOrchestralChoice();
+ void makeDesertChoice();
+ void makeRhythmsChoice();
+ void makeAcousticChoice();
+
+ void useIdleTime();
+ void loopExtra(const tExtraID);
+
+ Movie _4DSpritesMovie;
+ TimeScale _4DSpritesScale;
+ uint _whichMenu;
+ uint _videoChoice;
+ uint _audioChoice;
+ Notification *_neighborhoodNotification;
+ TimeValue _loopStart;
+ tHotSpotID _clickedHotspotID;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
new file mode 100755
index 0000000000..bd5480de0e
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
@@ -0,0 +1,115 @@
+/* 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/gamestate.h"
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoriamessages.h"
+
+namespace Pegasus {
+
+const tNotificationFlags kMessageDoneFlag = 1;
+
+CaldoriaMessages::CaldoriaMessages(Neighborhood *owner, const tNotificationID id, NotificationManager *manager) :
+ GameInteraction(kCaldoriaMessagesInteractionID, owner), Notification(id, manager), _messageMovie(kCaldoriaMessagesID) {
+}
+
+void CaldoriaMessages::openInteraction() {
+ _neighborhoodNotification = GameInteraction::_owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+ _messageCallBack.setNotification(this);
+ notifyMe(this, kMessageDoneFlag, kMessageDoneFlag);
+ _messageCallBack.setCallBackFlag(kMessageDoneFlag);
+ _messageNumber = 1;
+}
+
+void CaldoriaMessages::initInteraction() {
+ GameInteraction::_owner->startExtraSequence(kCaBedroomVidPhone, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void CaldoriaMessages::closeInteraction() {
+ cancelNotification(this);
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void CaldoriaMessages::receiveNotification(Notification *notification, const tNotificationFlags) {
+ if (notification == _neighborhoodNotification) {
+ switch (GameInteraction::_owner->getLastExtra()) {
+ case kCaBedroomVidPhone:
+ GameInteraction::_owner->showExtraView(kCaBedroomMessage1);
+ break;
+ case kCaBedroomMessage1:
+ play1Message(1);
+ break;
+ case kCaBedroomMessage2:
+ play1Message(2);
+ break;
+ }
+ } else {
+ _messageCallBack.releaseCallBack();
+ _messageMovie.releaseMovie();
+
+ uint32 extraID = (_messageNumber == 1) ? kCaBedroomMessage1 : kCaBedroomMessage2;
+ GameInteraction::_owner->showExtraView(extraID);
+ allowInput(true);
+ }
+}
+
+void CaldoriaMessages::clickInHotspot(const Input &input, const Hotspot *spot) {
+ uint32 extraID;
+
+ switch (spot->getObjectID()) {
+ case kCaBedroomVidPhoneActivationSpotID:
+ extraID = (_messageNumber == 1) ? kCaBedroomMessage1 : kCaBedroomMessage2;
+ GameInteraction::_owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void CaldoriaMessages::play1Message(uint messageNumber) {
+ if (messageNumber == 1) {
+ _messageMovie.initFromMovieFile("Images/Caldoria/A12NVA.movie");
+ _messageNumber = 2;
+ } else {
+ _messageMovie.initFromMovieFile("Images/Caldoria/A12NVB.movie");
+ _messageNumber = 1;
+ GameState.setCaldoriaSeenMessages(true);
+ }
+
+ _messageMovie.moveElementTo(kCaldoriaMessageLeft, kCaldoriaMessageTop);
+ _messageMovie.setDisplayOrder(kCaldoriaMessagesOrder);
+ _messageMovie.startDisplaying();
+ _messageCallBack.initCallBack(&_messageMovie, kCallBackAtExtremes);
+ _messageCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ allowInput(false);
+ _messageMovie.show();
+ _messageMovie.redrawMovieWorld();
+ _messageMovie.start();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamessages.h b/engines/pegasus/neighborhood/caldoria/caldoriamessages.h
new file mode 100755
index 0000000000..1ef0ab0692
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamessages.h
@@ -0,0 +1,60 @@
+/* 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_NEIGHBORHOOD_CALDORIA_CALDORIAMESSAGES_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMESSAGES_H
+
+#include "pegasus/input.h"
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Neighborhood;
+
+class CaldoriaMessages : public GameInteraction, public Notification, public NotificationReceiver {
+public:
+ CaldoriaMessages(Neighborhood *, const tNotificationID, NotificationManager *);
+ virtual ~CaldoriaMessages() {}
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+ void receiveNotification(Notification *, const tNotificationFlags);
+ void clickInHotspot(const Input &, const Hotspot *);
+ void play1Message(uint);
+
+ Movie _messageMovie;
+ NotificationCallBack _messageCallBack;
+ Notification *_neighborhoodNotification;
+ uint _messageNumber;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
new file mode 100755
index 0000000000..4d6dc6b758
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
@@ -0,0 +1,134 @@
+/* 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/gamestate.h"
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoriamirror.h"
+
+namespace Pegasus {
+
+CaldoriaMirror::CaldoriaMirror(Neighborhood *owner) : GameInteraction(kCaldoriaMirrorInteractionID, owner) {
+}
+
+void CaldoriaMirror::openInteraction() {
+ _neighborhoodNotification = _owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+}
+
+void CaldoriaMirror::initInteraction() {
+ _owner->setCurrentActivation(kActivateMirrorReady);
+ _owner->startExtraSequence(kCaBathroomGreeting, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void CaldoriaMirror::closeInteraction() {
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void CaldoriaMirror::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_owner->getLastExtra() == (uint32)kCaBathroomAgencyStandard || !input.anyDirectionInput())
+ GameInteraction::handleInput(input, cursorSpot);
+}
+
+void CaldoriaMirror::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ switch (_owner->getLastExtra()) {
+ case kCaBathroomGreeting:
+ case kCaBathroomBodyFat:
+ case kCaBathroomRetrothrash:
+ case kCaBathroomGeoWave:
+ g_allHotspots.activateOneHotspot(kCaBathroomMirrorSpotID);
+ g_allHotspots.deactivateOneHotspot(kCaHairStyle1SpotID);
+ g_allHotspots.deactivateOneHotspot(kCaHairStyle2SpotID);
+ g_allHotspots.deactivateOneHotspot(kCaHairStyle3SpotID);
+ break;
+ case kCaBathroomStylistIntro:
+ case kCaBathroomRetrothrashReturn:
+ case kCaBathroomGeoWaveReturn:
+ g_allHotspots.activateOneHotspot(kCaHairStyle1SpotID);
+ g_allHotspots.activateOneHotspot(kCaHairStyle2SpotID);
+ g_allHotspots.activateOneHotspot(kCaHairStyle3SpotID);
+ g_allHotspots.deactivateOneHotspot(kCaBathroomMirrorSpotID);
+ break;
+ }
+}
+
+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;
+ }
+ break;
+ case kCaHairStyle1SpotID:
+ _owner->startExtraSequence(kCaBathroomRetrothrash, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaHairStyle2SpotID:
+ _owner->startExtraSequence(kCaBathroomAgencyStandard, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaHairStyle3SpotID:
+ _owner->startExtraSequence(kCaBathroomGeoWave, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void CaldoriaMirror::receiveNotification(Notification *, const tNotificationFlags) {
+ switch (_owner->getLastExtra()) {
+ case kCaBathroomRetrothrash:
+ case kCaBathroomGeoWave:
+ _owner->setCurrentActivation(kActivateMirrorReady);
+ break;
+ case kCaBathroomStylistIntro:
+ case kCaBathroomRetrothrashReturn:
+ case kCaBathroomGeoWaveReturn:
+ _owner->setCurrentActivation(kActivateStylistReady);
+ break;
+ case kCaBathroomAgencyStandard:
+ _owner->setCurrentActivation(kActivateHotSpotAlways);
+ _owner->requestDeleteCurrentInteraction();
+ GameState.setScoringFixedHair(true);
+ GameState.setCaldoriaDoneHygiene(true);
+ break;
+ }
+
+ allowInput(true);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamirror.h b/engines/pegasus/neighborhood/caldoria/caldoriamirror.h
new file mode 100755
index 0000000000..6b4339e69f
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamirror.h
@@ -0,0 +1,54 @@
+/* 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_NEIGHBORHOOD_CALDORIA_CALDORIAMIRROR_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMIRROR_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+
+namespace Pegasus {
+
+class CaldoriaMirror : public GameInteraction, public NotificationReceiver {
+public:
+ CaldoriaMirror(Neighborhood *);
+ virtual ~CaldoriaMirror() {}
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void handleInput(const Input &, const Hotspot *);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void receiveNotification(Notification *, const tNotificationFlags);
+
+ Notification *_neighborhoodNotification;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/neighborhood.h b/engines/pegasus/neighborhood/neighborhood.h
index f0e9f49ab8..e1aa814864 100644
--- a/engines/pegasus/neighborhood/neighborhood.h
+++ b/engines/pegasus/neighborhood/neighborhood.h
@@ -92,6 +92,7 @@ bool operator==(const tQueueRequest &arg1, const tQueueRequest &arg2);
bool operator!=(const tQueueRequest &arg1, const tQueueRequest &arg2);
class GameInteraction;
+class Item;
class Neighborhood;
class StriderCallBack : public TimeBaseCallBack {
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 71e4ca0f4d..7dac148f61 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -31,6 +31,7 @@
#include "common/savefile.h"
#include "common/textconsole.h"
#include "common/translation.h"
+#include "common/random.h"
#include "base/plugins.h"
#include "base/version.h"
#include "gui/saveload.h"
@@ -58,6 +59,7 @@
#include "pegasus/items/inventory/inventoryitem.h"
#include "pegasus/items/inventory/keycard.h"
#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/prehistoric/prehistoric.h"
namespace Pegasus {
@@ -85,6 +87,7 @@ PegasusEngine::~PegasusEngine() {
delete _continuePoint;
delete _gameMenu;
delete _neighborhood;
+ delete _rnd;
// NOTE: This must be deleted last!
delete _gfx;
@@ -95,6 +98,7 @@ Common::Error PegasusEngine::run() {
_gfx = new GraphicsManager(this);
_resFork = new Common::MacResManager();
_cursor = new Cursor();
+ _rnd = new Common::RandomSource("Pegasus");
if (!_resFork->open("JMP PP Resources") || !_resFork->hasResFork())
error("Could not load JMP PP Resources");
@@ -532,32 +536,6 @@ void PegasusEngine::receiveNotification(Notification *notification, const tNotif
if (&_shellNotification == notification) {
switch (flags) {
case kGameStartingFlag: {
-#if 0
- // This is just some graphical test that I wrote; I'll
- // keep it around for reference.
- Movie opening(1);
- opening.initFromMovieFile(_introDirectory + "/Big Movie.movie");
- opening.setTime(10, 1);
- opening.setStart(10, 1);
- opening.startDisplaying();
- opening.show();
- opening.start();
- opening.setFlags(kLoopTimeBase);
-
- Input input;
- InputHandler::getCurrentInputDevice()->getInput(input, kFilterAllInput);
-
- while (opening.isRunning() && !shouldQuit()) {
- checkCallBacks();
- _gfx->updateDisplay();
-
- InputHandler::getCurrentInputDevice()->getInput(input, kFilterAllInput);
- if (input.anyInput())
- break;
-
- _system->delayMillis(10);
- }
-#else
if (!isDemo())
runIntro();
else
@@ -570,7 +548,6 @@ void PegasusEngine::receiveNotification(Notification *notification, const tNotif
_gfx->invalRect(Common::Rect(0, 0, 640, 480));
_gfx->updateDisplay();
((MainMenu *)_gameMenu)->startMainMenuLoop();
-#endif
break;
}
case kPlayerDiedFlag:
@@ -638,13 +615,7 @@ void PegasusEngine::doGameMenuCommand(const tGameMenuCommand command) {
switch (command) {
case kMenuCmdStartAdventure:
GameState.setWalkthroughMode(false);
-
- // Only start the game in the demo for now
- // (until it works and I implement Caldoria)
- if (isDemo())
- startNewGame();
- else
- error("Start new game (adventure mode)");
+ startNewGame();
break;
case kMenuCmdCredits:
if (isDemo()) {
@@ -673,7 +644,7 @@ void PegasusEngine::doGameMenuCommand(const tGameMenuCommand command) {
break;
case kMenuCmdStartWalkthrough:
GameState.setWalkthroughMode(true);
- error("Start new game (walkthrough mode)");
+ startNewGame();
break;
case kMenuCmdRestore:
case kMenuCmdDeathRestore:
@@ -1371,6 +1342,9 @@ void PegasusEngine::makeNeighborhood(tNeighborhoodID neighborhoodID, Neighborhoo
// TODO: CD check
switch (neighborhoodID) {
+ case kCaldoriaID:
+ neighborhood = new Caldoria(g_AIArea, this);
+ break;
case kPrehistoricID:
neighborhood = new Prehistoric(g_AIArea, this);
break;
@@ -1869,4 +1843,18 @@ void PegasusEngine::pauseEngineIntern(bool pause) {
}
}
+uint PegasusEngine::getRandomBit() {
+ return _rnd->getRandomBit();
+}
+
+void PegasusEngine::playEndMessage() {
+ if (g_interface) {
+ allowInput(false);
+ g_interface->playEndMessage();
+ allowInput(true);
+ }
+
+ die(kPlayerWonGame);
+}
+
} // End of namespace Pegasus
diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h
index 13e975e0c8..0dd0a2abe3 100644
--- a/engines/pegasus/pegasus.h
+++ b/engines/pegasus/pegasus.h
@@ -28,9 +28,9 @@
#include "common/list.h"
#include "common/macresman.h"
+#include "common/rect.h"
#include "common/scummsys.h"
#include "common/system.h"
-#include "common/rect.h"
#include "common/util.h"
#include "engines/engine.h"
@@ -44,6 +44,10 @@
#include "pegasus/items/itemdragger.h"
#include "pegasus/neighborhood/neighborhood.h"
+namespace Common {
+ class RandomSource;
+}
+
namespace Video {
class SeekableVideoDecoder;
}
@@ -102,6 +106,7 @@ public:
void createInterface();
void setGameMode(const tGameMode);
tGameMode getGameMode() const { return _gameMode; }
+ uint getRandomBit();
// Energy
void setLastEnergyValue(const int32 value) { _savedEnergyValue = value; }
@@ -112,6 +117,7 @@ public:
tDeathReason getEnergyDeathReason() { return _deathReason; }
void resetEnergyDeathReason();
void die(const tDeathReason);
+ void playEndMessage();
// Volume
uint16 getSoundFXLevel() { return _FXLevel; }
@@ -234,6 +240,7 @@ private:
bool playMovieScaled(Video::SeekableVideoDecoder *video, uint16 x, uint16 y);
void throwAwayEverything();
void shellGameInput(const Input &input, const Hotspot *cursorSpot);
+ Common::RandomSource *_rnd;
// Menu
GameMenu *_gameMenu;