aboutsummaryrefslogtreecommitdiff
path: root/engines/pegasus
diff options
context:
space:
mode:
Diffstat (limited to 'engines/pegasus')
-rw-r--r--engines/pegasus/cursor.cpp28
-rw-r--r--engines/pegasus/detection.cpp56
-rw-r--r--engines/pegasus/elements.cpp2
-rw-r--r--engines/pegasus/energymonitor.cpp2
-rw-r--r--engines/pegasus/interface.cpp30
-rw-r--r--engines/pegasus/interface.h3
-rw-r--r--engines/pegasus/items/inventorypicture.h1
-rw-r--r--engines/pegasus/menu.cpp10
-rw-r--r--engines/pegasus/movie.cpp7
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria.cpp7
-rw-r--r--engines/pegasus/neighborhood/mars/mars.cpp16
-rw-r--r--engines/pegasus/neighborhood/mars/reactor.cpp6
-rw-r--r--engines/pegasus/neighborhood/neighborhood.cpp8
-rw-r--r--engines/pegasus/neighborhood/norad/delta/globegame.cpp10
-rw-r--r--engines/pegasus/neighborhood/norad/pressuredoor.cpp5
-rw-r--r--engines/pegasus/neighborhood/prehistoric/prehistoric.cpp56
-rw-r--r--engines/pegasus/neighborhood/tsa/fulltsa.cpp7
-rw-r--r--engines/pegasus/neighborhood/wsc/wsc.cpp18
-rw-r--r--engines/pegasus/pegasus.cpp156
-rw-r--r--engines/pegasus/pegasus.h7
-rw-r--r--engines/pegasus/sound.cpp3
-rw-r--r--engines/pegasus/surface.cpp12
-rw-r--r--engines/pegasus/surface.h2
-rw-r--r--engines/pegasus/timers.cpp33
-rw-r--r--engines/pegasus/timers.h6
25 files changed, 390 insertions, 101 deletions
diff --git a/engines/pegasus/cursor.cpp b/engines/pegasus/cursor.cpp
index 5babdf34af..897d31d7bd 100644
--- a/engines/pegasus/cursor.cpp
+++ b/engines/pegasus/cursor.cpp
@@ -82,8 +82,14 @@ void Cursor::setCurrentFrameIndex(int32 index) {
_index = index;
if (index != -1) {
loadCursorImage(_info[index]);
- CursorMan.replaceCursorPalette(_info[index].palette, 0, _info[index].colorCount);
- CursorMan.replaceCursor((byte *)_info[index].surface->pixels, _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, 0);
+
+ if (_info[index].surface->format.bytesPerPixel == 1) {
+ CursorMan.replaceCursorPalette(_info[index].palette, 0, _info[index].colorCount);
+ CursorMan.replaceCursor(_info[index].surface->pixels, _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, 0);
+ } else {
+ CursorMan.replaceCursor(_info[index].surface->pixels, _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, _info[index].surface->format.RGBToColor(0xFF, 0xFF, 0xFF), false, &_info[index].surface->format);
+ }
+
((PegasusEngine *)g_engine)->_gfx->markCursorAsDirty();
}
}
@@ -135,9 +141,25 @@ void Cursor::loadCursorImage(CursorInfo &cursorInfo) {
if (cursorInfo.surface)
return;
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (vm->isDVD()) {
+ // The DVD version has some higher color PICT images for its cursors
+ Common::SeekableReadStream *pictStream = vm->_resFork->getResource(MKTAG('P', 'I', 'C', 'T'), cursorInfo.tag + 1000);
+
+ if (pictStream) {
+ Graphics::PICTDecoder pict;
+ if (!pict.loadStream(*pictStream))
+ error("Failed to decode cursor PICT %d", cursorInfo.tag + 1000);
+
+ cursorInfo.surface = pict.getSurface()->convertTo(g_system->getScreenFormat());
+ delete pictStream;
+ return;
+ }
+ }
+
cursorInfo.surface = new Graphics::Surface();
- PegasusEngine *vm = (PegasusEngine *)g_engine;
Common::SeekableReadStream *cicnStream = vm->_resFork->getResource(MKTAG('c', 'i', 'c', 'n'), cursorInfo.tag);
if (!cicnStream)
diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp
index 908005b665..721c382d4f 100644
--- a/engines/pegasus/detection.cpp
+++ b/engines/pegasus/detection.cpp
@@ -35,6 +35,10 @@ struct PegasusGameDescription {
ADGameDescription desc;
};
+enum {
+ GF_DVD = (1 << 1)
+};
+
bool PegasusEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL)
@@ -46,6 +50,22 @@ bool PegasusEngine::isDemo() const {
return (_gameDescription->desc.flags & ADGF_DEMO) != 0;
}
+bool PegasusEngine::isDVD() const {
+ return (_gameDescription->desc.flags & GF_DVD) != 0;
+}
+
+bool PegasusEngine::isDVDDemo() const {
+ return isDemo() && isDVD();
+}
+
+bool PegasusEngine::isOldDemo() const {
+ return isDemo() && !isDVD();
+}
+
+bool PegasusEngine::isWindows() const {
+ return _gameDescription->desc.platform == Common::kPlatformWindows;
+}
+
} // End of namespace Pegasus
static const PlainGameDescriptor pegasusGames[] = {
@@ -76,7 +96,31 @@ static const PegasusGameDescription gameDescriptions[] = {
AD_ENTRY1s("JMP PP Resources", "d13a602d2498010d720a6534f097f88b", 360129),
Common::EN_ANY,
Common::kPlatformMacintosh,
- ADGF_MACRESFORK|ADGF_DEMO,
+ ADGF_MACRESFORK | ADGF_DEMO,
+ GUIO1(GUIO_NOLAUNCHLOAD)
+ },
+ },
+
+ {
+ {
+ "pegasus",
+ "DVD Demo",
+ AD_ENTRY1s("JMP PP Resources", "d0fcda50dc75c7a81ae314e6a813f4d2", 93495),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_MACRESFORK | ADGF_DEMO | GF_DVD,
+ GUIO1(GUIO_NOLAUNCHLOAD)
+ },
+ },
+
+ {
+ {
+ "pegasus",
+ "DVD Demo",
+ AD_ENTRY1s("JMP PP Resources", "d0fcda50dc75c7a81ae314e6a813f4d2", 93495),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_MACRESFORK | ADGF_DEMO | GF_DVD,
GUIO1(GUIO_NOLAUNCHLOAD)
},
},
@@ -119,12 +163,12 @@ SaveStateList PegasusMetaEngine::listSaves(const char *target) const {
// The original had no pattern, so the user must rename theirs
// Note that we ignore the target because saves are compatible between
// all versions
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("pegasus-*.sav");
+ Common::StringArray fileNames = Pegasus::PegasusEngine::listSaveFiles();
SaveStateList saveList;
- for (uint32 i = 0; i < filenames.size(); i++) {
+ for (uint32 i = 0; i < fileNames.size(); i++) {
// Isolate the description from the file name
- Common::String desc = filenames[i].c_str() + 8;
+ Common::String desc = fileNames[i].c_str() + 8;
for (int j = 0; j < 4; j++)
desc.deleteLastChar();
@@ -136,8 +180,8 @@ SaveStateList PegasusMetaEngine::listSaves(const char *target) const {
void PegasusMetaEngine::removeSaveState(const char *target, int slot) const {
// See listSaves() for info on the pattern
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("pegasus-*.sav");
- g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
+ Common::StringArray fileNames = Pegasus::PegasusEngine::listSaveFiles();
+ g_system->getSavefileManager()->removeSavefile(fileNames[slot].c_str());
}
bool PegasusMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/pegasus/elements.cpp b/engines/pegasus/elements.cpp
index c84d555444..87fb69a557 100644
--- a/engines/pegasus/elements.cpp
+++ b/engines/pegasus/elements.cpp
@@ -259,8 +259,8 @@ void FrameSequence::openFrameSequence() {
_frameTimes.clear();
for (uint32 i = 0; i < _numFrames; i++) {
TimeValue time = res->readUint32BE();
- _duration += time;
_frameTimes.push_back(_duration);
+ _duration += time;
}
setScale(scale);
diff --git a/engines/pegasus/energymonitor.cpp b/engines/pegasus/energymonitor.cpp
index 8aa77eb341..be9d205360 100644
--- a/engines/pegasus/energymonitor.cpp
+++ b/engines/pegasus/energymonitor.cpp
@@ -262,9 +262,9 @@ void EnergyMonitor::calibrateEnergyBar() {
_energyLight.setCurrentFrameIndex(0);
_energyLight.hide();
- show();
setEnergyValue(0);
setEnergyDrainRate(-(int32)kMaxJMPEnergy / 2);
+ show();
// Make sure warning light is hidden...
_energyLight.hide();
diff --git a/engines/pegasus/interface.cpp b/engines/pegasus/interface.cpp
index d9d3865192..f2429bf36a 100644
--- a/engines/pegasus/interface.cpp
+++ b/engines/pegasus/interface.cpp
@@ -186,6 +186,11 @@ void Interface::validateInventoryPanel() {
_inventoryLid.setDisplayOrder(kInventoryLidOrder);
_inventoryLid.startDisplaying();
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _inventoryOpenSound.initFromAIFFFile("Sounds/Items/Inventory Panel Open.aif");
+ _inventoryCloseSound.initFromAIFFFile("Sounds/Items/Inventory Panel Close.aif");
+ }
+
_inventoryPushCallBack.initCallBack(&_inventoryPush, kCallBackAtExtremes);
_inventoryLidCallBack.initCallBack(&_inventoryLid, kCallBackAtExtremes);
@@ -231,6 +236,11 @@ void Interface::validateBiochipPanel() {
_biochipLid.setDisplayOrder(kBiochipLidOrder);
_biochipLid.startDisplaying();
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _biochipOpenSound.initFromAIFFFile("Sounds/Items/Biochip Panel Open.aif");
+ _biochipCloseSound.initFromAIFFFile("Sounds/Items/Biochip Panel Close.aif");
+ }
+
_biochipPushCallBack.initCallBack(&_biochipPush, kCallBackAtExtremes);
_biochipLidCallBack.initCallBack(&_biochipLid, kCallBackAtExtremes);
@@ -385,6 +395,11 @@ void Interface::raiseInventoryDrawer(const bool doCallBacks) {
_inventoryLid.show();
_inventoryPush.show();
_inventoryLid.start();
+
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _inventoryCloseSound.stopSound();
+ _inventoryOpenSound.playSound();
+ }
}
void Interface::playEndMessage() {
@@ -446,6 +461,11 @@ void Interface::lowerInventoryDrawer(const bool doCallBacks) {
FaderMoveSpec moveSpec;
moveSpec.makeTwoKnotFaderSpec(60, 0, 1000, 15, 0);
_inventoryPush.startFader(moveSpec);
+
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _inventoryOpenSound.stopSound();
+ _inventoryCloseSound.playSound();
+ }
}
}
@@ -487,6 +507,11 @@ void Interface::raiseBiochipDrawer(const bool doCallBacks) {
_biochipLid.show();
_biochipPush.show();
_biochipLid.start();
+
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _biochipCloseSound.stopSound();
+ _biochipOpenSound.playSound();
+ }
}
void Interface::biochipLidOpen(const bool doCallBacks) {
@@ -521,6 +546,11 @@ void Interface::lowerBiochipDrawer(const bool doCallBacks) {
FaderMoveSpec moveSpec;
moveSpec.makeTwoKnotFaderSpec(60, 0, 1000, 9, 0);
_biochipPush.startFader(moveSpec);
+
+ if (((PegasusEngine *)g_engine)->isDVD()) {
+ _biochipOpenSound.stopSound();
+ _biochipCloseSound.playSound();
+ }
}
}
diff --git a/engines/pegasus/interface.h b/engines/pegasus/interface.h
index a65d9a595a..5f04f98df0 100644
--- a/engines/pegasus/interface.h
+++ b/engines/pegasus/interface.h
@@ -29,6 +29,7 @@
#include "pegasus/hotspot.h"
#include "pegasus/input.h"
#include "pegasus/notification.h"
+#include "pegasus/sound.h"
#include "pegasus/surface.h"
#include "pegasus/transition.h"
#include "pegasus/items/inventorypicture.h"
@@ -125,6 +126,7 @@ protected:
NotificationCallBack _inventoryLidCallBack;
InventoryItemsPicture _inventoryPanel;
bool _inventoryUp, _inventoryRaised;
+ Sound _inventoryOpenSound, _inventoryCloseSound;
Push _biochipPush;
SpriteSequence _biochipLid;
@@ -132,6 +134,7 @@ protected:
NotificationCallBack _biochipLidCallBack;
BiochipPicture _biochipPanel;
bool _biochipUp, _biochipRaised;
+ Sound _biochipOpenSound, _biochipCloseSound;
Hotspot _currentItemSpot;
Hotspot _currentBiochipSpot;
diff --git a/engines/pegasus/items/inventorypicture.h b/engines/pegasus/items/inventorypicture.h
index 88a4a4ba75..9eba25bc3a 100644
--- a/engines/pegasus/items/inventorypicture.h
+++ b/engines/pegasus/items/inventorypicture.h
@@ -106,7 +106,6 @@ protected:
virtual TimeValue getItemPanelTime(Item *);
void loopCurrentItem();
- InputHandler *_previousHandler;
bool _isLooping;
};
diff --git a/engines/pegasus/menu.cpp b/engines/pegasus/menu.cpp
index deaa460188..e55c006f86 100644
--- a/engines/pegasus/menu.cpp
+++ b/engines/pegasus/menu.cpp
@@ -149,10 +149,14 @@ MainMenu::MainMenu() : GameMenu(kMainMenuID), _menuBackground(0), _overviewButto
bool isDemo = ((PegasusEngine *)g_engine)->isDemo();
- if (isDemo)
- _menuBackground.initFromPICTFile("Images/Demo/DemoMenu.pict");
- else
+ if (isDemo) {
+ if (((PegasusEngine *)g_engine)->isWindows())
+ _menuBackground.initFromPICTFile("Images/Demo/DemoMenuPC.pict");
+ else
+ _menuBackground.initFromPICTFile("Images/Demo/DemoMenu.pict");
+ } else {
_menuBackground.initFromPICTFile("Images/Main Menu/MainMenu.mac");
+ }
_menuBackground.setDisplayOrder(0);
_menuBackground.startDisplaying();
_menuBackground.show();
diff --git a/engines/pegasus/movie.cpp b/engines/pegasus/movie.cpp
index 75c287c7a6..59814a753d 100644
--- a/engines/pegasus/movie.cpp
+++ b/engines/pegasus/movie.cpp
@@ -161,9 +161,10 @@ void Movie::setTime(const TimeValue time, const TimeScale scale) {
}
void Movie::setRate(const Common::Rational rate) {
- if (rate != 1 && rate != 0) {
- warning("Cannot set movie rate");
- start();
+ if (_video) {
+ _video->setRate(rate);
+
+ TimeBase::setRate(_video->getRate());
return;
}
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
index 140e6e8093..9a378a6728 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -1291,6 +1291,7 @@ void Caldoria::activateHotspots() {
_vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRightDrawerNoKeysCloseSpotID);
}
}
+ break;
case kCaldoriaReplicator:
if (GameState.getCaldoriaMadeOJ())
_vm->getAllHotspots().deactivateOneHotspot(kCaldoriaMakeOJSpotID);
@@ -1640,10 +1641,12 @@ void Caldoria::takeElevator(uint startFloor, uint endFloor) {
break;
case 2:
_croppedMovie.setTime(k1To2Time);
+ _croppedMovie.redrawMovieWorld();
requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case 3:
_croppedMovie.setTime(k1To3Time);
+ _croppedMovie.redrawMovieWorld();
requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case 4:
@@ -1670,10 +1673,12 @@ void Caldoria::takeElevator(uint startFloor, uint endFloor) {
break;
case 2:
_croppedMovie.setTime(k4To2Time);
+ _croppedMovie.redrawMovieWorld();
requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case 3:
_croppedMovie.setTime(k4To3Time);
+ _croppedMovie.redrawMovieWorld();
requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case 4:
@@ -1697,10 +1702,12 @@ void Caldoria::takeElevator(uint startFloor, uint endFloor) {
break;
case 2:
_croppedMovie.setTime(k5To2Time);
+ _croppedMovie.redrawMovieWorld();
requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case 3:
_croppedMovie.setTime(k5To3Time);
+ _croppedMovie.redrawMovieWorld();
requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
break;
case 4:
diff --git a/engines/pegasus/neighborhood/mars/mars.cpp b/engines/pegasus/neighborhood/mars/mars.cpp
index 34c9e3d0f8..775221589a 100644
--- a/engines/pegasus/neighborhood/mars/mars.cpp
+++ b/engines/pegasus/neighborhood/mars/mars.cpp
@@ -1035,7 +1035,6 @@ void Mars::checkContinuePoint(const RoomID room, const DirectionConstant directi
case MakeRoomView(kMars51, kEast):
case MakeRoomView(kMars56, kEast):
case MakeRoomView(kMars60, kWest):
- case MakeRoomView(kMarsMaze004, kWest):
case MakeRoomView(kMarsMaze009, kWest):
case MakeRoomView(kMarsMaze012, kWest):
case MakeRoomView(kMarsMaze037, kWest):
@@ -1059,6 +1058,11 @@ void Mars::checkContinuePoint(const RoomID room, const DirectionConstant directi
case MakeRoomView(kMarsMaze199, kWest):
makeContinuePoint();
break;
+ case MakeRoomView(kMarsMaze004, kWest):
+ // WORKAROUND: See Mars::arriveAt() for more details.
+ if (GameState.isTakenItemID(kCardBomb))
+ makeContinuePoint();
+ break;
case MakeRoomView(kMars05, kEast):
case MakeRoomView(kMars06, kEast):
case MakeRoomView(kMars07, kEast):
@@ -1393,6 +1397,13 @@ void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
case MakeRoomView(kMarsRobotShuttle, kEast):
setCurrentActivation(kActivationRobotHeadClosed);
break;
+ case MakeRoomView(kMarsMaze004, kWest):
+ // WORKAROUND: You're not supposed to continue through the maze without the
+ // bomb or the game will not be completable. We're using the previously unused
+ // bomb death here to prevent progress (you didn't find the bomb, after all).
+ if (!GameState.isTakenItemID(kCardBomb))
+ didntFindBomb();
+ break;
case MakeRoomView(kMarsMaze007, kNorth):
launchMaze007Robot();
break;
@@ -2459,6 +2470,7 @@ void Mars::doCanyonChase() {
playSpotSoundSync(kShuttleCockpitIn, kShuttleCockpitOut);
_centerShuttleMovie.setTime(kShuttleCenterCheckTime);
+ _centerShuttleMovie.redrawMovieWorld();
playSpotSoundSync(kShuttleOnboardIn, kShuttleOnboardOut);
_shuttleEnergyMeter.initShuttleEnergyMeter();
@@ -2643,7 +2655,7 @@ void Mars::startUpFromSpaceChase() {
// Open the spot sounds movie again...
_spotSounds.initFromQuickTime(getSoundSpotsName());
- _spotSounds.setVolume(_vm->getSoundFXLevel());;
+ _spotSounds.setVolume(_vm->getSoundFXLevel());
initOnePicture(&_shuttleInterface1, "Images/Mars/MCmain1.pict", kShuttleBackgroundOrder, kShuttle1Left,
kShuttle1Top, true);
diff --git a/engines/pegasus/neighborhood/mars/reactor.cpp b/engines/pegasus/neighborhood/mars/reactor.cpp
index 334fb98879..3a7ef9d7eb 100644
--- a/engines/pegasus/neighborhood/mars/reactor.cpp
+++ b/engines/pegasus/neighborhood/mars/reactor.cpp
@@ -244,9 +244,9 @@ void ReactorHistory::draw(const Common::Rect &) {
static const CoordType kColorTops[5] = {
0,
kColorHeights[0],
- kColorHeights[0] + kColorHeights[1],
- kColorHeights[0] + kColorHeights[1] + kColorHeights[2],
- kColorHeights[0] + kColorHeights[1] + kColorHeights[2] + kColorHeights[3],
+ (CoordType)(kColorHeights[0] + kColorHeights[1]),
+ (CoordType)(kColorHeights[0] + kColorHeights[1] + kColorHeights[2]),
+ (CoordType)(kColorHeights[0] + kColorHeights[1] + kColorHeights[2] + kColorHeights[3]),
};
if (_colors.isSurfaceValid() && _digits.isSurfaceValid()) {
diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp
index 07be62c957..38366c4ba2 100644
--- a/engines/pegasus/neighborhood/neighborhood.cpp
+++ b/engines/pegasus/neighborhood/neighborhood.cpp
@@ -1761,10 +1761,10 @@ void Neighborhood::pauseTimer() {
}
void Neighborhood::resumeTimer() {
- // NOTE: Yes, this function calls pauseFuse!
- // Looks like an original game bug, will need
- // to investigate how this affects gameplay.
- _eventTimer.pauseFuse();
+ // NOTE: The original calls pauseFuse() here, which causes a bug with the robot
+ // in WSC on the catwalk, causing him never to come after you if you don't act
+ // against him.
+ _eventTimer.resumeFuse();
}
bool Neighborhood::timerPaused() {
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
index 06e40c2b3a..1416c51c8d 100644
--- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
@@ -64,6 +64,10 @@ void GlobeTracker::setTrackParameters(const Hotspot *trackSpot, GlobeTrackDirect
_globeMovie->setSegment(start, start + kDurationPerRow);
+ // Clip new time so we don't go past the end of the segment
+ if (newTime >= start + kDurationPerRow)
+ newTime = start + kDurationPerRow - 1;
+
if (newTime != time) {
_globeMovie->setTime(newTime);
_globeMovie->redrawMovieWorld();
@@ -84,6 +88,10 @@ void GlobeTracker::setTrackParameters(const Hotspot *trackSpot, GlobeTrackDirect
_globeMovie->setSegment(start, start + kDurationPerRow);
+ // Clip new time so we don't go past the end of the segment
+ if (newTime >= start + kDurationPerRow)
+ newTime = start + kDurationPerRow - 1;
+
if (newTime != time) {
_globeMovie->setTime(newTime);
_globeMovie->redrawMovieWorld();
@@ -621,6 +629,7 @@ void GlobeGame::receiveNotification(Notification *notification, const Notificati
_monitorMovie.stop();
_monitorMovie.setSegment(0, _monitorMovie.getDuration());
_monitorMovie.setTime(kSplash2End * scale - 1);
+ _monitorMovie.redrawMovieWorld();
_monitorMovie.setFlags(0);
_owner->requestDelay(1, 2, kFilterNoInput, 0);
@@ -643,6 +652,7 @@ void GlobeGame::receiveNotification(Notification *notification, const Notificati
_monitorMovie.stop();
_monitorMovie.setSegment(0, _monitorMovie.getDuration());
_monitorMovie.setTime(kNewLaunchSiloTime * scale);
+ _monitorMovie.redrawMovieWorld();
_owner->requestSpotSound(kNewLaunchSiloIn, kNewLaunchSiloOut, kFilterNoInput,
kSpotSoundCompletedFlag);
_gameState = kPlayingNewSilo1;
diff --git a/engines/pegasus/neighborhood/norad/pressuredoor.cpp b/engines/pegasus/neighborhood/norad/pressuredoor.cpp
index d1378567d3..a12e971d10 100644
--- a/engines/pegasus/neighborhood/norad/pressuredoor.cpp
+++ b/engines/pegasus/neighborhood/norad/pressuredoor.cpp
@@ -323,7 +323,8 @@ void PressureDoor::receiveNotification(Notification *notification, const Notific
_robotState = kRobotDead;
_levelsMovie.stop();
_levelsMovie.setSegment((kNormalSubRoomPressure + kPressureBase) * _levelsScale,
- (GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
+ (GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale + 1);
+ _levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
_pressureCallBack.setCallBackFlag(kPressureDroppingFlag);
_pressureCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
_typeMovie.stop();
@@ -335,7 +336,7 @@ void PressureDoor::receiveNotification(Notification *notification, const Notific
_downButton.setCurrentFrameIndex(1);
_gameState = kGameOver;
allowInput(false);
- _levelsMovie.setRate(Common::Rational(0x5555, 0x10000) - 1); // Should match door tracker.
+ _levelsMovie.setRate(Common::Rational(-4, 3)); // Should match door tracker.
break;
case kRobotDead:
allowInput(true);
diff --git a/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp b/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
index 814d7717de..d62b069e46 100644
--- a/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
+++ b/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
@@ -125,6 +125,13 @@ void Prehistoric::setUpAIRules() {
AIRule *rule = new AIRule(hasLogCondition, doneAction);
g_AIArea->addAIRule(rule);
} else {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP25W", false);
+ AIHasItemCondition *hasLogCondition = new AIHasItemCondition(kHistoricalLog);
+ AIRule *rule = new AIRule(hasLogCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+ }
+
+ if (!_vm->isOldDemo()) {
AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP1NB", false);
AILocationCondition *locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kPrehistoric16, kNorth));
@@ -159,11 +166,6 @@ void Prehistoric::setUpAIRules() {
AITimerCondition *timerCondition = new AITimerCondition(kPrehistoricWarningTimeLimit, 1, true);
rule = new AIRule(timerCondition, messageAction);
g_AIArea->addAIRule(rule);
-
- messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP25W", false);
- AIHasItemCondition *hasLogCondition = new AIHasItemCondition(kHistoricalLog);
- rule = new AIRule(hasLogCondition, messageAction);
- g_AIArea->addAIRule(rule);
}
}
}
@@ -402,9 +404,10 @@ void Prehistoric::loadAmbientLoops() {
switch (room) {
case kPrehistoric02:
// 1/4 volume.
- if (GameState.getPrehistoricSeenTimeStream())
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 64);
- break;
+ if (!GameState.getPrehistoricSeenTimeStream())
+ break;
+
+ // Fall through
case kPrehistoric01:
case kPrehistoric03:
case kPrehistoric04:
@@ -419,7 +422,10 @@ void Prehistoric::loadAmbientLoops() {
case kPrehistoric19:
case kPrehistoric20:
// 1/4 volume.
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 64);
+ if (_vm->isDVD()) // Updated sound for the DVD version
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.32k.AIFF", 64);
+ else
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 64);
break;
case kPrehistoric08:
case kPrehistoric10:
@@ -429,11 +435,17 @@ void Prehistoric::loadAmbientLoops() {
case kPrehistoric18:
case kPrehistoric21:
// 3/16 volume.
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 48);
+ if (_vm->isDVD()) // Updated sound for the DVD version
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.32k.AIFF", 48);
+ else
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 48);
break;
case kPrehistoric25:
// 1/8 volume.
- loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 32);
+ if (_vm->isDVD()) // Updated sound for the DVD version
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.32k.AIFF", 32);
+ else
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 32);
break;
case kPrehistoric22:
case kPrehistoric22North:
@@ -470,19 +482,29 @@ void Prehistoric::loadAmbientLoops() {
break;
case kPrehistoric01:
case kPrehistoric25:
- loadLoopSound2("Sounds/Prehistoric/VolcLoop.22K.AIFF", 64);
+ if (_vm->isDVD())
+ loadLoopSound2("Sounds/Prehistoric/VolcLoop.32K.AIFF", 64);
+ else
+ loadLoopSound2("Sounds/Prehistoric/VolcLoop.22K.AIFF", 64);
break;
case kPrehistoric18:
- if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag))
- loadLoopSound2("Sounds/Prehistoric/P18EAL00.22k.AIFF", 0x100, 0, 0);
- else
+ if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
+ if (_vm->isDVD()) // Updated sound for the DVD version
+ loadLoopSound2("Sounds/Prehistoric/P18EAL00.44K.aiff", 0x100, 0, 0);
+ else
+ loadLoopSound2("Sounds/Prehistoric/P18EAL00.22k.AIFF", 0x100, 0, 0);
+ } else {
loadLoopSound2("");
+ }
break;
case kPrehistoric23:
case kPrehistoric24:
case kPrehistoric22:
case kPrehistoric22North:
- loadLoopSound2("Sounds/Prehistoric/P24NAL00.22k.AIFF", 64);
+ if (_vm->isDVD()) // Updated sound for the DVD version
+ loadLoopSound2("Sounds/Prehistoric/P24NAL00.32k.AIFF", 64);
+ else
+ loadLoopSound2("Sounds/Prehistoric/P24NAL00.22k.AIFF", 64);
break;
}
}
@@ -575,7 +597,7 @@ Common::String Prehistoric::getEnvScanMovie() {
Common::String movieName = Neighborhood::getEnvScanMovie();
if (movieName.empty()) {
- if (!_vm->isDemo()) {
+ if (!_vm->isOldDemo()) {
switch (GameState.getCurrentRoom()) {
case kPrehistoric16:
case kPrehistoric23:
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
index b598841b45..9b843da5d6 100644
--- a/engines/pegasus/neighborhood/tsa/fulltsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
@@ -622,6 +622,13 @@ void RipTimer::draw(const Common::Rect &updateRect) {
}
void RipTimer::timeChanged(const TimeValue newTime) {
+ // WORKAROUND: If the timer isn't running, don't run the following code.
+ // Fixes use of the code when it shouldn't be running (since this is an
+ // IdlerAnimation, this is called on useIdleTime() but this specific
+ // timer only makes sense when used as an actual timer).
+ if (!isRunning())
+ return;
+
Common::Rect bounds;
getBounds(bounds);
diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp
index f3bf113333..50b7774da4 100644
--- a/engines/pegasus/neighborhood/wsc/wsc.cpp
+++ b/engines/pegasus/neighborhood/wsc/wsc.cpp
@@ -646,11 +646,13 @@ uint WSC::getNumHints() {
return 1;
break;
case MakeRoomView(kWSC03, kNorth):
- if (inSynthesizerGame() || (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
- !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
- !GameState.getWSCDesignedAntidote()))
- return 3;
- break;
+ // WORKAROUND: The original game is missing the first two hint movies and
+ // just plays nothing in its stead. We'll just return that we have one
+ // hint available.
+ if (inSynthesizerGame())
+ return 1;
+
+ // fall through
case MakeRoomView(kWSC01, kNorth):
case MakeRoomView(kWSC01, kSouth):
case MakeRoomView(kWSC01, kEast):
@@ -779,10 +781,12 @@ Common::String WSC::getHintMovie(uint hintNum) {
}
break;
case MakeRoomView(kWSC03, kNorth):
+ // WORKAROUND: The original game is missing the first two hint movies and
+ // just plays nothing in its stead. We just make it the first hint.
if (inSynthesizerGame())
- return Common::String::format("Images/AI/WSC/XW03NH%d", hintNum);
+ return "Images/AI/WSC/XW03NH3";
- return Common::String::format("Images/AI/WSC/XWPH%d", hintNum);
+ // fall through
case MakeRoomView(kWSC01, kNorth):
case MakeRoomView(kWSC01, kSouth):
case MakeRoomView(kWSC01, kEast):
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 81e8058628..463e81e52e 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -33,9 +33,11 @@
#include "common/textconsole.h"
#include "common/translation.h"
#include "common/random.h"
+#include "backends/keymapper/keymapper.h"
#include "base/plugins.h"
#include "base/version.h"
#include "gui/saveload.h"
+#include "video/theora_decoder.h"
#include "video/qt_decoder.h"
#include "pegasus/console.h"
@@ -151,6 +153,7 @@ Common::Error PegasusEngine::run() {
}
// Set up input
+ initKeymap();
InputHandler::setInputHandler(this);
allowInput(true);
@@ -237,6 +240,9 @@ bool PegasusEngine::detectOpeningClosingDirectory() {
void PegasusEngine::createItems() {
Common::SeekableReadStream *res = _resFork->getResource(MKTAG('N', 'I', 't', 'm'), 0x80);
+ if (!res)
+ error("Couldn't find neighborhood items resource");
+
uint16 entryCount = res->readUint16BE();
for (uint16 i = 0; i < entryCount; i++) {
@@ -614,7 +620,7 @@ void PegasusEngine::loadFromContinuePoint() {
// Failure to load a continue point is fatal
if (!_continuePoint)
- error("Attempting to load from non-existant continue point");
+ error("Attempting to load from non-existent continue point");
_continuePoint->seek(0);
@@ -637,9 +643,15 @@ void PegasusEngine::writeContinueStream(Common::WriteStream *stream) {
delete[] data;
}
+Common::StringArray PegasusEngine::listSaveFiles() {
+ Common::StringArray fileNames = g_system->getSavefileManager()->listSavefiles("pegasus-*.sav");
+ Common::sort(fileNames.begin(), fileNames.end());
+ return fileNames;
+}
+
Common::Error PegasusEngine::loadGameState(int slot) {
- Common::StringArray filenames = _saveFileMan->listSavefiles("pegasus-*.sav");
- Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filenames[slot]);
+ Common::StringArray fileNames = listSaveFiles();
+ Common::InSaveFile *loadFile = _saveFileMan->openForLoading(fileNames[slot]);
if (!loadFile)
return Common::kUnknownError;
@@ -649,7 +661,23 @@ Common::Error PegasusEngine::loadGameState(int slot) {
return valid ? Common::kNoError : Common::kUnknownError;
}
+static bool isValidSaveFileChar(char c) {
+ // Limit it to letters, digits, and a few other characters that should be safe
+ return Common::isAlnum(c) || c == ' ' || c == '_' || c == '+' || c == '-' || c == '.';
+}
+
+static bool isValidSaveFileName(const Common::String &desc) {
+ for (uint32 i = 0; i < desc.size(); i++)
+ if (!isValidSaveFileChar(desc[i]))
+ return false;
+
+ return true;
+}
+
Common::Error PegasusEngine::saveGameState(int slot, const Common::String &desc) {
+ if (!isValidSaveFileName(desc))
+ return Common::Error(Common::kCreatingFileFailed, _("Invalid save file name"));
+
Common::String output = Common::String::format("pegasus-%s.sav", desc.c_str());
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(output, false);
if (!saveFile)
@@ -667,19 +695,35 @@ void PegasusEngine::receiveNotification(Notification *notification, const Notifi
case kGameStartingFlag: {
useMenu(new MainMenu());
- if (!isDemo()) {
+ if (isDemo()) {
+ // Start playing the music earlier here
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+
+ // Show the intro splash screen
+ showTempScreen("Images/Demo/NGsplashScrn.pict");
+
+ if (shouldQuit()) {
+ useMenu(0);
+ return;
+ }
+
+ // Fade out and then back in with the main menu
+ _gfx->doFadeOutSync();
+ _gfx->updateDisplay();
+ _gfx->doFadeInSync();
+ } else {
+ // Display the intro
runIntro();
resetIntroTimer();
- } else {
- showTempScreen("Images/Demo/NGsplashScrn.pict");
- }
- if (shouldQuit())
- return;
+ if (shouldQuit())
+ return;
- _gfx->invalRect(Common::Rect(0, 0, 640, 480));
- _gfx->updateDisplay();
- ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ // Now display the main menu
+ _gfx->invalRect(Common::Rect(0, 0, 640, 480));
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ }
break;
}
case kPlayerDiedFlag:
@@ -818,7 +862,8 @@ void PegasusEngine::doGameMenuCommand(const GameMenuCommand command) {
case kMenuCmdDeathQuitDemo:
if (isDemo())
showTempScreen("Images/Demo/NGquitScrn.pict");
- _system->quit();
+ _gfx->doFadeOutSync();
+ quitGame();
break;
case kMenuCmdOverview:
stopIntroTimer();
@@ -1132,10 +1177,15 @@ void PegasusEngine::doInterfaceOverview() {
controllerHighlight.hide();
}
- overviewText.setTime(time * 3 + 2, 15);
- overviewText.redrawMovieWorld();
+ // The original just constantly redraws the frame, but that
+ // doesn't actually need to be done.
+ if ((time * 3 + 2) * 40 != overviewText.getTime()) {
+ overviewText.setTime(time * 3 + 2, 15);
+ overviewText.redrawMovieWorld();
+ }
refreshDisplay();
+ _system->delayMillis(10);
}
if (shouldQuit())
@@ -1313,8 +1363,14 @@ bool PegasusEngine::playMovieScaled(Video::VideoDecoder *video, uint16 x, uint16
if (video->needsUpdate()) {
const Graphics::Surface *frame = video->decodeNextFrame();
- if (frame)
- drawScaledFrame(frame, x, y);
+ if (frame) {
+ if (frame->w <= 320 && frame->h <= 240) {
+ drawScaledFrame(frame, x, y);
+ } else {
+ _system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ _system->updateScreen();
+ }
+ }
}
Input input;
@@ -1338,6 +1394,19 @@ void PegasusEngine::die(const DeathReason reason) {
}
void PegasusEngine::doDeath() {
+#ifdef USE_THEORADEC
+ // The updated demo has a new Theora video for the closing
+ if (isDVDDemo() && _deathReason == kPlayerWonGame) {
+ Video::TheoraDecoder decoder;
+
+ if (decoder.loadFile("Images/Demo TSA/DemoClosing.ogg")) {
+ throwAwayEverything();
+ decoder.start();
+ playMovieScaled(&decoder, 0, 0);
+ }
+ }
+#endif
+
_gfx->doFadeOutSync();
throwAwayEverything();
useMenu(new DeathMenu(_deathReason));
@@ -1420,6 +1489,10 @@ void PegasusEngine::switchGameMode(const GameMode newMode, const GameMode oldMod
}
bool PegasusEngine::canSwitchGameMode(const GameMode newMode, const GameMode oldMode) {
+ // WORKAROUND: Don't allow game mode switches when the interface is not set up.
+ // Prevents segfaults when pressing 'i' when in the space chase.
+ if (!g_interface)
+ return false;
if (newMode == kModeInventoryPick && oldMode == kModeBiochipPick)
return false;
if (newMode == kModeBiochipPick && oldMode == kModeInventoryPick)
@@ -1538,6 +1611,18 @@ void PegasusEngine::startNewGame() {
GameState.setPrehistoricSeenFlyer2(false);
GameState.setPrehistoricSeenBridgeZoom(false);
GameState.setPrehistoricBreakerThrown(false);
+
+#ifdef USE_THEORADEC
+ if (isDVD()) {
+ // The updated demo has a new Theora video for the closing
+ Video::TheoraDecoder decoder;
+
+ if (decoder.loadFile("Images/Demo TSA/DemoOpening.ogg")) {
+ decoder.start();
+ playMovieScaled(&decoder, 0, 0);
+ }
+ }
+#endif
} else {
jumpToNewEnvironment(kCaldoriaID, kCaldoria00, kEast);
}
@@ -2343,4 +2428,41 @@ uint PegasusEngine::getNeighborhoodCD(const NeighborhoodID neighborhood) const {
return 1;
}
+void PegasusEngine::initKeymap() {
+#ifdef ENABLE_KEYMAPPER
+ static const char *const kKeymapName = "pegasus";
+ Common::Keymapper *const mapper = _eventMan->getKeymapper();
+
+ // Do not try to recreate same keymap over again
+ if (mapper->getKeymap(kKeymapName) != 0)
+ return;
+
+ Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+
+ // Since the game has multiple built-in keys for each of these anyway,
+ // this just attempts to remap one of them.
+ const Common::KeyActionEntry keyActionEntries[] = {
+ { Common::KEYCODE_UP, "UP", _("Up/Zoom In/Move Forward/Open Doors") },
+ { Common::KEYCODE_DOWN, "DWN", _("Down/Zoom Out") },
+ { Common::KEYCODE_LEFT, "TL", _("Turn Left") },
+ { Common::KEYCODE_RIGHT, "TR", _("Turn Right") },
+ { Common::KEYCODE_BACKQUOTE, "TIV", _("Display/Hide Inventory Tray") },
+ { Common::KEYCODE_BACKSPACE, "TBI", _("Display/Hide Biochip Tray") },
+ { Common::KEYCODE_RETURN, "ENT", _("Action/Select") },
+ { Common::KEYCODE_t, "TMA", _("Toggle Center Data Display") },
+ { Common::KEYCODE_i, "TIN", _("Display/Hide Info Screen") },
+ { Common::KEYCODE_ESCAPE, "PM", _("Display/Hide Pause Menu") },
+ { Common::KEYCODE_e, "WTF", _("???") } // easter egg key (without being completely upfront about it)
+ };
+
+ for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
+ Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
+ act->addKeyEvent(keyActionEntries[i].ks);
+ }
+
+ mapper->addGameKeymap(engineKeyMap);
+ mapper->pushKeymap(kKeymapName, true);
+#endif
+}
+
} // End of namespace Pegasus
diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h
index 2a8ba22470..07e6d8f761 100644
--- a/engines/pegasus/pegasus.h
+++ b/engines/pegasus/pegasus.h
@@ -30,6 +30,7 @@
#include "common/macresman.h"
#include "common/rect.h"
#include "common/scummsys.h"
+#include "common/str-array.h"
#include "common/system.h"
#include "common/util.h"
@@ -94,6 +95,10 @@ public:
// Misc.
bool isDemo() const;
+ bool isDVD() const;
+ bool isDVDDemo() const;
+ bool isOldDemo() const;
+ bool isWindows() const;
void addIdler(Idler *idler);
void removeIdler(Idler *idler);
void addTimeBase(TimeBase *timeBase);
@@ -195,6 +200,7 @@ public:
bool saveRequested() const { return _saveRequested; }
void requestLoad() { _loadRequested = true; }
bool loadRequested() const { return _loadRequested; }
+ static Common::StringArray listSaveFiles();
protected:
Common::Error run();
@@ -265,6 +271,7 @@ private:
void doSubChase();
uint getNeighborhoodCD(const NeighborhoodID neighborhood) const;
uint _currentCD;
+ void initKeymap();
// Menu
GameMenu *_gameMenu;
diff --git a/engines/pegasus/sound.cpp b/engines/pegasus/sound.cpp
index bf15858e80..5b437b81d4 100644
--- a/engines/pegasus/sound.cpp
+++ b/engines/pegasus/sound.cpp
@@ -87,6 +87,9 @@ void Sound::playSound() {
stopSound();
+ // Make sure the sound is back at the beginning before we play it
+ _stream->rewind();
+
if (_fader)
setVolume(_fader->getFaderValue());
diff --git a/engines/pegasus/surface.cpp b/engines/pegasus/surface.cpp
index e9e0958f9d..cdcb3c6e79 100644
--- a/engines/pegasus/surface.cpp
+++ b/engines/pegasus/surface.cpp
@@ -85,7 +85,8 @@ void Surface::getImageFromPICTFile(const Common::String &fileName) {
if (!pict.open(fileName))
error("Could not open picture '%s'", fileName.c_str());
- getImageFromPICTStream(&pict);
+ if (!getImageFromPICTStream(&pict))
+ error("Failed to load PICT '%s'", fileName.c_str());
}
void Surface::getImageFromPICTResource(Common::MacResManager *resFork, uint16 id) {
@@ -93,19 +94,22 @@ void Surface::getImageFromPICTResource(Common::MacResManager *resFork, uint16 id
if (!res)
error("Could not open PICT resource %d from '%s'", id, resFork->getBaseFileName().c_str());
- getImageFromPICTStream(res);
+ if (!getImageFromPICTStream(res))
+ error("Failed to load PICT resource %d from '%s'", id, resFork->getBaseFileName().c_str());
+
delete res;
}
-void Surface::getImageFromPICTStream(Common::SeekableReadStream *stream) {
+bool Surface::getImageFromPICTStream(Common::SeekableReadStream *stream) {
Graphics::PICTDecoder pict;
if (!pict.loadStream(*stream))
- error("Failed to load PICT image");
+ return false;
_surface = pict.getSurface()->convertTo(g_system->getScreenFormat(), pict.getPalette());
_ownsSurface = true;
_bounds = Common::Rect(0, 0, _surface->w, _surface->h);
+ return true;
}
void Surface::getImageFromMovieFrame(Video::VideoDecoder *video, TimeValue time) {
diff --git a/engines/pegasus/surface.h b/engines/pegasus/surface.h
index 4588146fb4..47e3ef538c 100644
--- a/engines/pegasus/surface.h
+++ b/engines/pegasus/surface.h
@@ -84,7 +84,7 @@ protected:
Common::Rect _bounds;
private:
- void getImageFromPICTStream(Common::SeekableReadStream *stream);
+ bool getImageFromPICTStream(Common::SeekableReadStream *stream);
uint32 getGlowColor(uint32 color) const;
bool isTransparent(uint32 color) const;
diff --git a/engines/pegasus/timers.cpp b/engines/pegasus/timers.cpp
index 3b875038cc..50cc9bc6d8 100644
--- a/engines/pegasus/timers.cpp
+++ b/engines/pegasus/timers.cpp
@@ -73,13 +73,8 @@ TimeBase::TimeBase(const TimeScale preferredScale) {
}
TimeBase::~TimeBase() {
- if (_master)
- _master->_slaves.remove(this);
-
((PegasusEngine *)g_engine)->removeTimeBase(this);
disposeAllCallBacks();
-
- // TODO: Remove slaves? Make them remove themselves?
}
void TimeBase::setTime(const TimeValue time, const TimeScale scale) {
@@ -88,20 +83,23 @@ void TimeBase::setTime(const TimeValue time, const TimeScale scale) {
}
TimeValue TimeBase::getTime(const TimeScale scale) {
+ // HACK: Emulate the master TimeBase code here for the one case that needs it in the
+ // game. Note that none of the master TimeBase code in this file should actually be
+ // used as a reference for anything ever.
+ if (_master)
+ return _master->getTime(scale);
+
return _time.getNumerator() * ((scale == 0) ? _preferredScale : scale) / _time.getDenominator();
}
void TimeBase::setRate(const Common::Rational rate) {
_rate = rate;
+ _lastMillis = 0;
if (_rate == 0)
_paused = false;
}
-Common::Rational TimeBase::getEffectiveRate() const {
- return _rate * ((_master == 0) ? 1 : _master->getEffectiveRate());
-}
-
void TimeBase::start() {
if (_paused)
_pausedRate = 1;
@@ -192,18 +190,15 @@ TimeValue TimeBase::getDuration(const TimeScale scale) const {
}
void TimeBase::setMasterTimeBase(TimeBase *tb) {
- // TODO: We're just ignoring the master (except for effective rate)
- // for now to simplify things
- if (_master)
- _master->_slaves.remove(this);
-
_master = tb;
-
- if (_master)
- _master->_slaves.push_back(this);
}
void TimeBase::updateTime() {
+ if (_master) {
+ _master->updateTime();
+ return;
+ }
+
if (_lastMillis == 0) {
_lastMillis = g_system->getMillis();
} else {
@@ -211,7 +206,7 @@ void TimeBase::updateTime() {
if (_lastMillis == curTime) // No change
return;
- _time += Common::Rational(curTime - _lastMillis, 1000) * getEffectiveRate();
+ _time += Common::Rational(curTime - _lastMillis, 1000) * getRate();
_lastMillis = curTime;
}
}
@@ -233,8 +228,6 @@ void TimeBase::checkCallBacks() {
else if (_time <= startTime)
_time = startTime;
- // TODO: Update the slaves?
-
Common::Rational time = Common::Rational(getTime(), getScale());
// Check if we've triggered any callbacks
diff --git a/engines/pegasus/timers.h b/engines/pegasus/timers.h
index bcdca6e860..944930d21b 100644
--- a/engines/pegasus/timers.h
+++ b/engines/pegasus/timers.h
@@ -26,7 +26,6 @@
#ifndef PEGASUS_TIMERS_H
#define PEGASUS_TIMERS_H
-#include "common/list.h"
#include "common/rational.h"
#include "common/func.h"
@@ -122,11 +121,6 @@ protected:
Common::Rational _time;
uint32 _lastMillis, _pauseStart;
-
-private:
- Common::Rational getEffectiveRate() const;
-
- Common::List<TimeBase *> _slaves;
};
// Type passed to initCallBack()