Skip to content

Commit

Permalink
PEGASUS: Stub off loading/saving games
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Hoops committed Sep 16, 2011
1 parent ecde872 commit 2ae8a97
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 5 deletions.
17 changes: 17 additions & 0 deletions engines/pegasus/constants.h
Expand Up @@ -26,6 +26,8 @@
#ifndef PEGASUS_CONSTANTS_H
#define PEGASUS_CONSTANTS_H

#include "common/endian.h"

#include "pegasus/types.h"

namespace Pegasus {
Expand Down Expand Up @@ -247,6 +249,21 @@ const tNotificationFlags kNeighborhoodFlags = kNeighborhoodMovieCompletedFlag |
kActionRequestCompletedFlag |
kDeathExtraCompletedFlag;

const uint32 kPegasusPrimeCreator = MKTAG('J', 'P', 'P', 'P');
const uint32 kPegasusPrimeContinueType = MKTAG('P', 'P', 'C', 'T');

const uint32 kPegasusPrimeDisk1GameType = MKTAG('P', 'P', 'G', '1');
const uint32 kPegasusPrimeDisk2GameType = MKTAG('P', 'P', 'G', '2');
const uint32 kPegasusPrimeDisk3GameType = MKTAG('P', 'P', 'G', '3');
const uint32 kPegasusPrimeDisk4GameType = MKTAG('P', 'P', 'G', '4');

// We only support one of the save versions; the rest are from betas
// and we are not supporting them.
const uint32 kPegasusPrimeVersion = 0x00009019;

const char kNormalSave = 0;
const char kContinueSave = 1;

} // End of namespace Pegasus

#endif
40 changes: 39 additions & 1 deletion engines/pegasus/detection.cpp
Expand Up @@ -25,6 +25,7 @@
#include "engines/advancedDetector.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/savefile.h"

#include "pegasus/pegasus.h"

Expand All @@ -36,7 +37,9 @@ struct PegasusGameDescription {

bool PegasusEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL);
(f == kSupportsRTL)
|| (f == kSupportsLoadingDuringRuntime)
|| (f == kSupportsSavingDuringRuntime);
}

bool PegasusEngine::isDemo() const {
Expand Down Expand Up @@ -98,9 +101,44 @@ class PegasusMetaEngine : public AdvancedMetaEngine {
return "The Journeyman Project: Pegasus Prime (C) Presto Studios";
}

virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const { return 999; }
virtual void removeSaveState(const char *target, int slot) const;
};

bool PegasusMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves)
|| (f == kSupportsDeleteSave);
}

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");

SaveStateList saveList;
for (uint32 i = 0; i < filenames.size(); i++) {
// Isolate the description from the file name
Common::String desc = filenames[i].c_str() + 8;
for (int j = 0; j < 4; j++)
desc.deleteLastChar();

saveList.push_back(SaveStateDescriptor(i, desc));
}

return saveList;
}

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());
}

bool PegasusMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
const Pegasus::PegasusGameDescription *gd = (const Pegasus::PegasusGameDescription *)desc;

Expand Down
148 changes: 148 additions & 0 deletions engines/pegasus/pegasus.cpp
Expand Up @@ -25,6 +25,8 @@
#include "common/events.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/memstream.h"
#include "common/savefile.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "base/plugins.h"
Expand All @@ -36,6 +38,7 @@
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/timers.h"
#include "pegasus/items/itemlist.h"
#include "pegasus/items/biochips/biochipitem.h"
#include "pegasus/items/inventory/inventoryitem.h"

Expand All @@ -49,6 +52,8 @@
namespace Pegasus {

PegasusEngine::PegasusEngine(OSystem *syst, const PegasusGameDescription *gamedesc) : Engine(syst), InputHandler(0), _gameDescription(gamedesc) {
_continuePoint = 0;
_saveAllowed = _loadAllowed = true;
}

PegasusEngine::~PegasusEngine() {
Expand All @@ -59,6 +64,7 @@ PegasusEngine::~PegasusEngine() {
delete _biochipLid;
delete _console;
delete _cursor;
delete _continuePoint;
}

Common::Error PegasusEngine::run() {
Expand Down Expand Up @@ -340,4 +346,146 @@ void PegasusEngine::removeTimeBase(TimeBase *timeBase) {
_timeBases.remove(timeBase);
}

bool PegasusEngine::loadFromStream(Common::ReadStream *stream) {
// TODO: Dispose currently running stuff (neighborhood, etc.)

// Signature
uint32 creator = stream->readUint32BE();
if (creator != kPegasusPrimeCreator) {
warning("Bad save creator '%s'", tag2str(creator));
return false;
}

uint32 gameType = stream->readUint32BE();
int saveType;

switch (gameType) {
case kPegasusPrimeDisk1GameType:
case kPegasusPrimeDisk2GameType:
case kPegasusPrimeDisk3GameType:
case kPegasusPrimeDisk4GameType:
saveType = kNormalSave;
break;
case kPegasusPrimeContinueType:
saveType = kContinueSave;
break;
default:
// There are five other possible game types on the Pippin
// version, but hopefully we don't see any of those here
warning("Unhandled pegasus game type '%s'", tag2str(gameType));
return false;
}

uint32 version = stream->readUint32BE();
if (version != kPegasusPrimeVersion) {
warning("Where did you get this save? It's a beta (v%04x)!", version & 0x7fff);
return false;
}

// Game State
GameState.readGameState(stream);

// TODO: Energy
stream->readUint32BE();

// TODO: Death reason
stream->readByte();

// TODO: This is as far as we can go right now
return true;

// Items
g_allItems.readFromStream(stream);

// TODO: Player Inventory
// TODO: Player BioChips
// TODO: Disc check
// TODO: Jump to environment
// TODO: AI rules

// Make a new continue point if this isn't already one
if (saveType == kNormalSave)
makeContinuePoint();

return true;
}

bool PegasusEngine::writeToStream(Common::WriteStream *stream, int saveType) {
// Not ready yet! :P
return false;

// Signature
stream->writeUint32BE(kPegasusPrimeCreator);

if (saveType == kNormalSave) {
// TODO: Disc check
stream->writeUint32BE(kPegasusPrimeDisk1GameType);
} else { // Continue
stream->writeUint32BE(kPegasusPrimeContinueType);
}

stream->writeUint32BE(kPegasusPrimeVersion);

// Game State
GameState.writeGameState(stream);

// TODO: Energy
stream->writeUint32BE(0);

// TODO: Death reason
stream->writeByte(0);

// Items
g_allItems.writeToStream(stream);

// TODO: Player Inventory
// TODO: Player BioChips
// TODO: Jump to environment
// TODO: AI rules
return true;
}

void PegasusEngine::makeContinuePoint() {
delete _continuePoint;

Common::MemoryWriteStreamDynamic newPoint(DisposeAfterUse::NO);
writeToStream(&newPoint, kContinueSave);
_continuePoint = new Common::MemoryReadStream(newPoint.getData(), newPoint.size(), DisposeAfterUse::YES);
}

void PegasusEngine::loadFromContinuePoint() {
// Failure to load a continue point is fatal

if (!_continuePoint)
error("Attempting to load from non-existant continue point");

if (!loadFromStream(_continuePoint))
error("Failed loading continue point");
}

Common::Error PegasusEngine::loadGameState(int slot) {
Common::StringArray filenames = _saveFileMan->listSavefiles("pegasus-*.sav");
Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filenames[slot]);
if (!loadFile)
return Common::kUnknownError;

bool valid = loadFromStream(loadFile);
warning("pos = %d", loadFile->pos());
delete loadFile;

return valid ? Common::kNoError : Common::kUnknownError;
}

Common::Error PegasusEngine::saveGameState(int slot, const Common::String &desc) {
Common::String output = Common::String::format("pegasus-%s.sav", desc.c_str());
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(output);
if (!saveFile)
return Common::kUnknownError;

bool valid = writeToStream(saveFile, kNormalSave);
delete saveFile;

return valid ? Common::kNoError : Common::kUnknownError;
}

} // End of namespace Pegasus
23 changes: 19 additions & 4 deletions engines/pegasus/pegasus.h
Expand Up @@ -72,22 +72,29 @@ friend class InputHandler;
public:
PegasusEngine(OSystem *syst, const PegasusGameDescription *gamedesc);
virtual ~PegasusEngine();


// Engine stuff
const PegasusGameDescription *_gameDescription;
bool hasFeature(EngineFeature f) const;
GUI::Debugger *getDebugger();

bool canLoadGameStateCurrently() { return _loadAllowed; }
bool canSaveGameStateCurrently() { return _saveAllowed; }
Common::Error loadGameState(int slot);
Common::Error saveGameState(int slot, const Common::String &desc);

// Base classes
VideoManager *_video;
GraphicsManager *_gfx;
Common::MacResManager *_resFork, *_inventoryLid, *_biochipLid;

// Misc.
bool isDemo() const;

void addIdler(Idler *idler);
void removeIdler(Idler *idler);

void addTimeBase(TimeBase *timeBase);
void removeTimeBase(TimeBase *timeBase);
void swapSaveAllowed(bool allow) { _saveAllowed = allow; }
void swapLoadAllowed(bool allow) { _loadAllowed = allow; }

protected:
Common::Error run();
Expand Down Expand Up @@ -148,6 +155,14 @@ friend class InputHandler;

// TimeBases
Common::List<TimeBase *> _timeBases;

// Save/Load
bool loadFromStream(Common::ReadStream *stream);
bool writeToStream(Common::WriteStream *stream, int saveType);
void makeContinuePoint();
void loadFromContinuePoint();
Common::ReadStream *_continuePoint;
bool _saveAllowed, _loadAllowed; // It's so nice that this was in the original code already :P
};

} // End of namespace Pegasus
Expand Down

0 comments on commit 2ae8a97

Please sign in to comment.