aboutsummaryrefslogtreecommitdiff
path: root/engines/lastexpress
diff options
context:
space:
mode:
authorJulien Templier2010-10-27 19:20:20 +0000
committerJulien Templier2010-10-27 19:20:20 +0000
commitcdfcaa4d48fe31afd795da787fa798054b2824e6 (patch)
tree24c73bc3aee2936d4314d926088cab910ebaf1ac /engines/lastexpress
parent5688a393b420a8f3ba83444c44bebcff47c7339a (diff)
downloadscummvm-rg350-cdfcaa4d48fe31afd795da787fa798054b2824e6.tar.gz
scummvm-rg350-cdfcaa4d48fe31afd795da787fa798054b2824e6.tar.bz2
scummvm-rg350-cdfcaa4d48fe31afd795da787fa798054b2824e6.zip
LASTEXPRESS: Implement game loading (last save entry only)
svn-id: r53883
Diffstat (limited to 'engines/lastexpress')
-rw-r--r--engines/lastexpress/debug.cpp6
-rw-r--r--engines/lastexpress/game/menu.cpp50
-rw-r--r--engines/lastexpress/game/menu.h2
-rw-r--r--engines/lastexpress/game/savegame.cpp124
-rw-r--r--engines/lastexpress/game/savegame.h13
-rw-r--r--engines/lastexpress/game/sound.cpp3
-rw-r--r--engines/lastexpress/game/state.h2
7 files changed, 131 insertions, 69 deletions
diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp
index 87daad2760..8e8c3bab2d 100644
--- a/engines/lastexpress/debug.cpp
+++ b/engines/lastexpress/debug.cpp
@@ -121,7 +121,7 @@ void Debugger::resetCommand() {
SAFE_DELETE(_command);
if (_commandParams)
- for (int i = 0; i < _numParams; i++)
+ for (int i = 0; i < _numParams; i++)
free(_commandParams[i]);
free(_commandParams);
@@ -1109,9 +1109,7 @@ bool Debugger::cmdLoadGame(int argc, const char **argv) {
if (id == 0 || id > 6)
goto error;
- if (!getSaveLoad()->loadGame((GameId)(id - 1)))
- DebugPrintf("Error loading game with id=%d", id);
-
+ getSaveLoad()->loadGame((GameId)(id - 1));
} else {
error:
DebugPrintf("Syntax: loadgame <id> (id=1-6)\n");
diff --git a/engines/lastexpress/game/menu.cpp b/engines/lastexpress/game/menu.cpp
index 1bdb9ac5ac..a6176f9658 100644
--- a/engines/lastexpress/game/menu.cpp
+++ b/engines/lastexpress/game/menu.cpp
@@ -360,7 +360,7 @@ Menu::Menu(LastExpressEngine *engine) : _engine(engine),
_gameId(kGameBlue), _hasShownStartScreen(false), _hasShownIntro(false),
_isShowingCredits(false), _isGameStarted(false), _isShowingMenu(false),
_creditsSequenceIndex(0), _checkHotspotsTicks(15), _mouseFlags(Common::EVENT_INVALID), _lastHotspot(NULL),
- _currentTime(kTimeNone), _lowerTime(kTimeNone), _time(kTimeNone), _currentIndex(0), _index(0), _savegameIndex(0), _delta(0), _handleTimeDelta(false) {
+ _currentTime(kTimeNone), _lowerTime(kTimeNone), _time(kTimeNone), _currentIndex(0), _index(0), _lastIndex(0), _delta(0), _handleTimeDelta(false) {
_clock = new Clock(_engine);
_trainLine = new TrainLine(_engine);
@@ -661,8 +661,8 @@ bool Menu::handleEvent(StartMenuAction action, Common::EventType type) {
if (_isGameStarted) {
showFrame(kOverlayEggButtons, kButtonContinue, true);
- if (_savegameIndex == _index) {
- showFrame(kOverlayTooltip, getSaveLoad()->isGameFinished(_index, _savegameIndex) ? kTooltipViewGameEnding : kTooltipContinueGame, true);
+ if (_lastIndex == _index) {
+ showFrame(kOverlayTooltip, getSaveLoad()->isGameFinished(_index, _lastIndex) ? kTooltipViewGameEnding : kTooltipContinueGame, true);
} else {
showFrame(kOverlayTooltip, kTooltipContinueRewoundGame, true);
}
@@ -830,7 +830,7 @@ bool Menu::handleEvent(StartMenuAction action, Common::EventType type) {
//////////////////////////////////////////////////////////////////////////
case kMenuForwardGame:
- if (_savegameIndex <= _index || _currentTime > _time) {
+ if (_lastIndex <= _index || _currentTime > _time) {
hideOverlays();
break;
}
@@ -1087,11 +1087,11 @@ void Menu::init(bool doSavegame, SavegameType type, uint32 value) {
}
// Init savegame & menu values
- _savegameIndex = getSaveLoad()->init(_gameId, true);
- _lowerTime = getSaveLoad()->getTime(_savegameIndex);
+ _lastIndex = getSaveLoad()->init(_gameId, true);
+ _lowerTime = getSaveLoad()->getTime(_lastIndex);
if (useSameIndex)
- _index = _savegameIndex;
+ _index = _lastIndex;
//if (!getGlobalTimer())
// _index3 = 0;
@@ -1112,26 +1112,20 @@ void Menu::init(bool doSavegame, SavegameType type, uint32 value) {
}
}
+// Start a game (or load an existing savegame)
void Menu::startGame() {
- // TODO: Clear train sequences & savegame headers
+ getSaveLoad()->clear();
- if (0 /* test for temp filename */ ) {
- if (_savegameIndex == _index)
+ if (_lastIndex == _index) {
+ setGlobalTimer(0);
+ if (_index) {
getSaveLoad()->loadGame(_gameId);
- else
- getSaveLoad()->loadGame2(_gameId);
- } else {
- if (_savegameIndex == _index) {
- setGlobalTimer(0);
- if (_index) {
- getSaveLoad()->loadGame(_gameId);
- } else {
- getLogic()->resetState();
- getEntities()->setup(true, kEntityPlayer);
- }
} else {
- getSaveLoad()->loadGame2(_gameId);
+ getLogic()->resetState();
+ getEntities()->setup(true, kEntityPlayer);
}
+ } else {
+ getSaveLoad()->loadGame(_gameId, _index);
}
}
@@ -1152,7 +1146,7 @@ void Menu::switchGame() {
_trainLine->clear();
// Clear loaded savegame data
- getSaveLoad()->clearHeaders();
+ getSaveLoad()->clear(true);
init(false, kSavegameTypeIndex, 0);
}
@@ -1367,7 +1361,7 @@ void Menu::adjustIndex(uint32 time1, uint32 time2, bool searchEntry) {
if (searchEntry) {
uint32 currentIndex = _index;
- if (_savegameIndex >= _index) {
+ if (_lastIndex >= _index) {
do {
// Calculate new delta
int32 newDelta = (uint32)getSaveLoad()->getTime(currentIndex) - time1;
@@ -1378,7 +1372,7 @@ void Menu::adjustIndex(uint32 time1, uint32 time2, bool searchEntry) {
}
++currentIndex;
- } while (currentIndex <= _savegameIndex);
+ } while (currentIndex <= _lastIndex);
}
} else {
index = _index + 1;
@@ -1409,7 +1403,7 @@ void Menu::goToTime(uint32 time) {
}
++index;
- } while (_savegameIndex >= index);
+ } while (_lastIndex >= index);
_currentIndex = entryIndex;
updateTime(getSaveLoad()->getTime(entryIndex));
@@ -1424,10 +1418,10 @@ void Menu::setTime() {
}
void Menu::forwardTime() {
- if (_savegameIndex <= _index)
+ if (_lastIndex <= _index)
return;
- _currentIndex = _savegameIndex;
+ _currentIndex = _lastIndex;
updateTime(getSaveLoad()->getTime(_currentIndex));
}
diff --git a/engines/lastexpress/game/menu.h b/engines/lastexpress/game/menu.h
index 086e7fd5df..765a611c41 100644
--- a/engines/lastexpress/game/menu.h
+++ b/engines/lastexpress/game/menu.h
@@ -183,7 +183,7 @@ private:
uint32 _currentIndex; // current savegame entry
uint32 _index;
- uint32 _savegameIndex;
+ uint32 _lastIndex;
uint32 _delta;
bool _handleTimeDelta;
diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp
index 7474245557..224d91eddd 100644
--- a/engines/lastexpress/game/savegame.cpp
+++ b/engines/lastexpress/game/savegame.cpp
@@ -61,9 +61,7 @@ SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL)
}
SaveLoad::~SaveLoad() {
- clearHeaders();
-
- SAFE_DELETE(_savegame);
+ clear(true);
//Zero passed pointers
_engine = NULL;
@@ -115,7 +113,7 @@ uint32 SaveLoad::init(GameId id, bool resetHeaders) {
// Reset cached entry headers if needed
if (resetHeaders) {
- clearHeaders();
+ clear();
SavegameEntryHeader *entryHeader = new SavegameEntryHeader();
entryHeader->time = kTimeCityParis;
@@ -156,7 +154,7 @@ void SaveLoad::loadStream(GameId id) {
error("SaveLoad::loadStream: savegame stream is invalid");
// Load all savegame data
- uint8* buf = new uint8[4096];
+ uint8* buf = new uint8[8192];
while (!save->eos() && !save->err()) {
uint32 count = save->read(buf, sizeof(buf));
if (count) {
@@ -175,11 +173,14 @@ void SaveLoad::loadStream(GameId id) {
_savegame->seek(0);
}
-void SaveLoad::clearHeaders() {
+void SaveLoad::clear(bool clearStream) {
for (uint i = 0; i < _gameHeaders.size(); i++)
SAFE_DELETE(_gameHeaders[i]);
_gameHeaders.clear();
+
+ if (clearStream)
+ SAFE_DELETE(_savegame);
}
//////////////////////////////////////////////////////////////////////////
@@ -187,19 +188,41 @@ void SaveLoad::clearHeaders() {
//////////////////////////////////////////////////////////////////////////
// Load game
-bool SaveLoad::loadGame(GameId id) {
+void SaveLoad::loadGame(GameId id) {
+ // Rewind current savegame
+ _savegame->seek(0);
- if (!SaveLoad::isSavegamePresent(id))
- return false;
+ // Validate main header
+ SavegameMainHeader header;
+ if (!loadMainHeader(_savegame, &header)) {
+ debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str());
+ return;
+ }
- //Common::InSaveFile *save = SaveLoad::openForLoading(id);
- // Validate header
+ // Load the last entry
+ _savegame->seek(header.offsetEntry);
- error("SaveLoad::loadgame: not implemented!");
+ SavegameType type = kSavegameTypeIndex;
+ EntityIndex entity = kEntityPlayer;
+ uint32 val = 0;
+ readEntry(&type, &entity, &val, header.keepIndex == 1);
+
+ // Setup last loading time
+ _gameTicksLastSavegame = getState()->timeTicks;
+
+ if (header.keepIndex) {
+ getSound()->clearQueue();
+
+ readEntry(&type, &entity, &val, false);
+ }
+
+ getEntities()->reset();
+ getEntities()->setup(false, entity);
}
-bool SaveLoad::loadGame2(GameId id) {
- error("SaveLoad::loadgame2: not implemented!");
+// Load a specific game entry
+void SaveLoad::loadGame(GameId id, uint32 index) {
+ error("SaveLoad::loadGame: not implemented! (only loading the last entry is working for now)");
}
// Save game
@@ -337,8 +360,6 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
Common::Serializer ser(NULL, _savegame);
header.saveLoadWithSerializer(ser);
- computeOffset();
-
// Write game data
WRITE_ENTRY("entity index", ser.syncAsUint32LE(entity), 4);
WRITE_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4);
@@ -346,14 +367,14 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
WRITE_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000);
WRITE_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2);
WRITE_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128);
- WRITE_ENTRY("events", getState()->saveEvents(ser), 512);
+ WRITE_ENTRY("events", getState()->syncEvents(ser), 512);
WRITE_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32);
WRITE_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128);
WRITE_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40);
WRITE_ENTRY("sound", getSound()->saveLoadWithSerializer(ser), 3 * 4 + getSound()->count() * 64);
WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 128 * 16 + 4 + getSavePoints()->count() * 16);
- header.offset = computeOffset(originalPosition);
+ header.offset = (uint32)_savegame->pos() - (originalPosition + 32);
// Add padding if necessary
while (header.offset & 0xF) {
@@ -376,8 +397,63 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
_savegame->seek(endPosition);
}
-void SaveLoad::readEntry(SavegameType type, EntityIndex entity, uint32 value) {
- warning("SaveLoad::readEntry: not implemented!");
+void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex) {
+#define LOAD_ENTRY(name, func, val) { \
+ uint32 _prevPosition = (uint32)_savegame->pos(); \
+ func; \
+ uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
+ debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \
+ if (_count != val) \
+ error("SaveLoad::readEntry: Number of bytes read (%d) differ from expected count (%d)", _count, val); \
+}
+
+#define LOAD_ENTRY_ONLY(name, func) { \
+ uint32 _prevPosition = (uint32)_savegame->pos(); \
+ func; \
+ uint32 _count = (uint32)_savegame->pos() - _prevPosition; \
+ debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \
+}
+
+ if (!type || !entity || !val)
+ error("SaveLoad::readEntry: Invalid parameters passed!");
+
+ // Load entry header
+ SavegameEntryHeader entry;
+ Common::Serializer ser(_savegame, NULL);
+ entry.saveLoadWithSerializer(ser);
+
+ if (!entry.isValid())
+ error("SaveLoad::readEntry: entry header is invalid!");
+
+ // Init type, entity & value
+ *type = entry.type;
+ *val = entry.value;
+
+ // Save position
+ uint32 originalPosition = (uint32)_savegame->pos();
+
+ // Load game data
+ LOAD_ENTRY("entity index", ser.syncAsUint32LE(*entity), 4);
+ LOAD_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4);
+ LOAD_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4);
+ LOAD_ENTRY("positions", getEntities()->savePositions(ser), 4 * 1000);
+ LOAD_ENTRY("compartments", getEntities()->saveCompartments(ser), 4 * 16 * 2);
+ LOAD_ENTRY("progress", getProgress().saveLoadWithSerializer(ser), 4 * 128);
+ LOAD_ENTRY("events", getState()->syncEvents(ser), 512);
+ LOAD_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32);
+ LOAD_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128);
+ LOAD_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40);
+ LOAD_ENTRY_ONLY("sound", getSound()->saveLoadWithSerializer(ser));
+ LOAD_ENTRY_ONLY("savepoints", getSavePoints()->saveLoadWithSerializer(ser));
+
+ // Update chapter
+ getProgress().chapter = entry.chapter;
+
+ // Skip padding
+ uint32 offset = _savegame->pos() - originalPosition;
+ if (offset & 0xF) {
+ _savegame->seek((~offset & 0xF) + 1, SEEK_SET);
+ }
}
SaveLoad::SavegameEntryHeader *SaveLoad::getEntry(uint32 index) {
@@ -387,14 +463,6 @@ SaveLoad::SavegameEntryHeader *SaveLoad::getEntry(uint32 index) {
return _gameHeaders[index];
}
-uint32 SaveLoad::computeOffset(uint32 originalPosition) {
- warning("SaveLoad::computePadding: not implemented!");
- if (!_savegame)
- error("SaveLoad::computeOffset: savegame stream is invalid");
-
- return ((uint32)_savegame->pos() - (originalPosition + 32));
-}
-
//////////////////////////////////////////////////////////////////////////
// Checks
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h
index c6a42fcb3e..d3ba5d13af 100644
--- a/engines/lastexpress/game/savegame.h
+++ b/engines/lastexpress/game/savegame.h
@@ -94,14 +94,15 @@ public:
// Init
void create(GameId id);
- void clearHeaders();
+ void clear(bool clearStream = false);
uint32 init(GameId id, bool resetHeaders);
// Save & Load
- bool loadGame(GameId id);
- bool loadGame2(GameId id);
+ void loadGame(GameId id);
+ void loadGame(GameId id, uint32 index);
void saveGame(SavegameType type, EntityIndex entity, uint32 value);
+ void loadVolumeBrightness();
void saveVolumeBrightness();
// Getting information
@@ -266,10 +267,10 @@ private:
static bool loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header);
// Entries
- void writeEntry(SavegameType type, EntityIndex entity, uint32 value);
- void readEntry(SavegameType type, EntityIndex entity, uint32 value);
+ void writeEntry(SavegameType type, EntityIndex entity, uint32 val);
+ void readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex);
+
SavegameEntryHeader *getEntry(uint32 index);
- uint32 computeOffset(uint32 originalPosition = 0);
// Opening save files
static Common::String getFilename(GameId id);
diff --git a/engines/lastexpress/game/sound.cpp b/engines/lastexpress/game/sound.cpp
index 3c87978657..0dfc38b1b0 100644
--- a/engines/lastexpress/game/sound.cpp
+++ b/engines/lastexpress/game/sound.cpp
@@ -541,7 +541,8 @@ void SoundManager::saveLoadWithSerializer(Common::Serializer &s) {
}
}
} else {
- error("Sound::saveLoadWithSerializer: not implemented!");
+ warning("Sound::saveLoadWithSerializer: not implemented!");
+ s.skip(numEntries * 64);
}
}
diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h
index 469f7a0ea2..135ee6bb4e 100644
--- a/engines/lastexpress/game/state.h
+++ b/engines/lastexpress/game/state.h
@@ -544,7 +544,7 @@ public:
s.syncAsUint32LE(sceneBackup2);
}
- void saveEvents(Common::Serializer &s) {
+ void syncEvents(Common::Serializer &s) {
for (uint i = 0; i < ARRAYSIZE(events); i++)
s.syncAsByte(events[i]);
}