diff options
Diffstat (limited to 'engines/pegasus')
-rw-r--r-- | engines/pegasus/detection.cpp | 10 | ||||
-rw-r--r-- | engines/pegasus/elements.cpp | 2 | ||||
-rw-r--r-- | engines/pegasus/energymonitor.cpp | 2 | ||||
-rw-r--r-- | engines/pegasus/movie.cpp | 7 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/mars/reactor.cpp | 6 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/neighborhood.cpp | 8 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/norad/pressuredoor.cpp | 5 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/tsa/fulltsa.cpp | 7 | ||||
-rw-r--r-- | engines/pegasus/pegasus.cpp | 114 | ||||
-rw-r--r-- | engines/pegasus/pegasus.h | 3 | ||||
-rw-r--r-- | engines/pegasus/timers.cpp | 33 | ||||
-rw-r--r-- | engines/pegasus/timers.h | 6 |
12 files changed, 144 insertions, 59 deletions
diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp index 908005b665..ba631148d5 100644 --- a/engines/pegasus/detection.cpp +++ b/engines/pegasus/detection.cpp @@ -119,12 +119,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 +136,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/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/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/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/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/pegasus.cpp b/engines/pegasus/pegasus.cpp index 420ca39331..eedfaa7db3 100644 --- a/engines/pegasus/pegasus.cpp +++ b/engines/pegasus/pegasus.cpp @@ -33,6 +33,7 @@ #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" @@ -151,6 +152,7 @@ Common::Error PegasusEngine::run() { } // Set up input + initKeymap(); InputHandler::setInputHandler(this); allowInput(true); @@ -637,9 +639,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 +657,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 +691,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 +858,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,8 +1173,12 @@ 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); @@ -1421,6 +1466,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) @@ -2344,4 +2393,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..246414a9d0 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" @@ -195,6 +196,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 +267,7 @@ private: void doSubChase(); uint getNeighborhoodCD(const NeighborhoodID neighborhood) const; uint _currentCD; + void initKeymap(); // Menu GameMenu *_gameMenu; 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() |