From dc4a22ed7d1a43703b0a6f2d87480ce948bc20a8 Mon Sep 17 00:00:00 2001 From: Julien Templier Date: Tue, 26 Oct 2010 06:55:34 +0000 Subject: LASTEXPRESS: More savegame work - Implement SaveLoad::writeEntry - Implement missing saveLoadWithSerializer functions for all serialized classes & structs - Add stub for SaveLoad::computePadding svn-id: r53845 --- engines/lastexpress/entities/entity.cpp | 56 +++++++++- engines/lastexpress/entities/entity.h | 124 ++++++++++++++++++--- engines/lastexpress/entities/gendarmes.cpp | 2 +- engines/lastexpress/game/entities.cpp | 19 +++- engines/lastexpress/game/entities.h | 2 + engines/lastexpress/game/inventory.cpp | 9 +- engines/lastexpress/game/inventory.h | 15 ++- engines/lastexpress/game/object.cpp | 7 +- engines/lastexpress/game/object.h | 13 ++- engines/lastexpress/game/savegame.cpp | 83 ++++++++++++-- engines/lastexpress/game/savegame.h | 18 +-- engines/lastexpress/game/sound.cpp | 48 +++++++- engines/lastexpress/game/sound.h | 9 +- engines/lastexpress/game/state.h | 172 +++++++---------------------- 14 files changed, 391 insertions(+), 186 deletions(-) (limited to 'engines/lastexpress') diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index 502fecac84..3291b49e9b 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -42,6 +42,55 @@ namespace LastExpress { +////////////////////////////////////////////////////////////////////////// +// EntityData +////////////////////////////////////////////////////////////////////////// + +void EntityData::EntityCallData::saveLoadWithSerializer(Common::Serializer &s) { + for (uint i = 0; i < ARRAYSIZE(callbacks); i++) + s.syncAsByte(callbacks[i]); + + s.syncAsByte(currentCall); + s.syncAsUint16LE(entityPosition); + s.syncAsUint16LE(location); + s.syncAsUint16LE(car); + s.syncAsByte(field_497); + s.syncAsByte(entity); + s.syncAsByte(inventoryItem); + s.syncAsByte(direction); + s.syncAsUint16LE(field_49B); + s.syncAsUint16LE(currentFrame); + s.syncAsUint16LE(currentFrame2); + s.syncAsUint16LE(field_4A1); + s.syncAsUint16LE(field_4A3); + s.syncAsByte(clothes); + s.syncAsByte(position); + s.syncAsByte(car2); + s.syncAsByte(doProcessEntity); + s.syncAsByte(field_4A9); + s.syncAsByte(field_4AA); + s.syncAsByte(directionSwitch); + + // Sync strings +#define SYNC_STRING(varName, count) { \ + char seqName[13]; \ + memset(&seqName, 0, count); \ + if (s.isSaving()) strcpy((char *)&seqName, varName.c_str()); \ + s.syncBytes((byte *)&seqName, count); \ + if (s.isLoading()) varName = seqName; \ +} + + SYNC_STRING(sequenceName, 13); + SYNC_STRING(sequenceName2, 13); + SYNC_STRING(sequenceNamePrefix, 7); + SYNC_STRING(sequenceNameCopy, 13); + +#undef SYNC_STRING + + // Skip pointers to frame & sequences + s.skip(5 * 4); +} + ////////////////////////////////////////////////////////////////////////// // EntityData ////////////////////////////////////////////////////////////////////////// @@ -82,8 +131,11 @@ void EntityData::updateParameters(uint32 index) const { error("EntityData::updateParameters: invalid param index to update (was:%d, max:32)!", index); } -void EntityData::saveLoadWithSerializer(Common::Serializer &) { - error("EntityData::saveLoadWithSerializer: not implemented!"); +void EntityData::saveLoadWithSerializer(Common::Serializer &s) { + for (uint i = 0; i < ARRAYSIZE(_parameters); i++) + _parameters[i].saveLoadWithSerializer(s); + + _data.saveLoadWithSerializer(s); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index 75b2d34291..246b2096d9 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -44,11 +44,13 @@ struct SavePoint; class EntityData : Common::Serializable { public: - struct EntityParameters { + struct EntityParameters : Common::Serializable{ virtual ~EntityParameters() {} virtual Common::String toString() = 0; virtual void update(uint32 index) = 0; + + virtual void saveLoadWithSerializer(Common::Serializer &s) = 0; }; struct EntityParametersIIII : EntityParameters { @@ -95,6 +97,17 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncAsUint32LE(param2); + s.syncAsUint32LE(param3); + s.syncAsUint32LE(param4); + s.syncAsUint32LE(param5); + s.syncAsUint32LE(param6); + s.syncAsUint32LE(param7); + s.syncAsUint32LE(param8); + } }; struct EntityParametersSIII : EntityParameters { @@ -130,6 +143,15 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncBytes((byte *)&seq, 12); + s.syncAsUint32LE(param4); + s.syncAsUint32LE(param5); + s.syncAsUint32LE(param6); + s.syncAsUint32LE(param7); + s.syncAsUint32LE(param8); + } }; struct EntityParametersSIIS : EntityParameters { @@ -158,6 +180,13 @@ public: case 4: param5 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncBytes((byte *)&seq1, 12); + s.syncAsUint32LE(param4); + s.syncAsUint32LE(param5); + s.syncBytes((byte *)&seq2, 12); + } }; struct EntityParametersISSI : EntityParameters { @@ -186,6 +215,13 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncBytes((byte *)&seq1, 12); + s.syncBytes((byte *)&seq2, 12); + s.syncAsUint32LE(param8); + } }; struct EntityParametersISII : EntityParameters { @@ -221,6 +257,15 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncBytes((byte *)&seq, 12); + s.syncAsUint32LE(param5); + s.syncAsUint32LE(param6); + s.syncAsUint32LE(param7); + s.syncAsUint32LE(param8); + } }; struct EntityParametersSSII : EntityParameters { @@ -249,32 +294,38 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncBytes((byte *)&seq1, 12); + s.syncBytes((byte *)&seq2, 12); + s.syncAsUint32LE(param7); + s.syncAsUint32LE(param8); + } }; - struct EntityParametersSSSI : EntityParameters { + struct EntityParametersSSS : EntityParameters { char seq1[12]; char seq2[12]; - char seq3[12]; - uint param10; + char seq3[8]; - EntityParametersSSSI() { + EntityParametersSSS() { memset(&seq1, 0, 12); memset(&seq2, 0, 12); - memset(&seq3, 0, 12); - param10 = 0; + memset(&seq3, 0, 8); } Common::String toString() { - return Common::String::printf("SSSI: %s %s %s %d\n", seq1, seq2, seq3, param10); + return Common::String::printf("SSS: %s %s %s\n", seq1, seq2, seq3); } void update(uint32 index) { - switch (index) { - default: - error("EntityParametersSSSI::update: invalid index (was: %d)", index); + error("EntityParametersSSS::update: cannot update this type of parameters", index); + } - case 9: param10 = 1; break; - } + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncBytes((byte *)&seq1, 12); + s.syncBytes((byte *)&seq2, 12); + s.syncBytes((byte *)&seq3, 8); } }; @@ -304,6 +355,13 @@ public: case 1: param2 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncAsUint32LE(param2); + s.syncBytes((byte *)&seq1, 12); + s.syncBytes((byte *)&seq2, 12); + } }; struct EntityParametersIISI : EntityParameters { @@ -339,6 +397,15 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncAsUint32LE(param2); + s.syncBytes((byte *)&seq, 12); + s.syncAsUint32LE(param6); + s.syncAsUint32LE(param7); + s.syncAsUint32LE(param8); + } }; struct EntityParametersIIIS : EntityParameters { @@ -374,6 +441,15 @@ public: case 7: param8 = 1; break; } } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncAsUint32LE(param2); + s.syncAsUint32LE(param3); + s.syncBytes((byte *)&seq, 12); + s.syncAsUint32LE(param7); + s.syncAsUint32LE(param8); + } }; struct EntityParametersI5S : EntityParameters { @@ -392,9 +468,18 @@ public: param5 = 0; memset(&seq, 0, 12); } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(param1); + s.syncAsUint32LE(param2); + s.syncAsUint32LE(param3); + s.syncAsUint32LE(param4); + s.syncAsUint32LE(param5); + s.syncBytes((byte *)&seq, 12); + } }; - struct EntityCallParameters { + struct EntityCallParameters : Common::Serializable { EntityParameters *parameters[4]; EntityCallParameters() { @@ -414,9 +499,15 @@ public: parameters[i] = NULL; } } + + // Serializable + void saveLoadWithSerializer(Common::Serializer &s) { + for (uint i = 0; i < ARRAYSIZE(parameters); i++) + parameters[i]->saveLoadWithSerializer(s); + } }; - struct EntityCallData { + struct EntityCallData : Common::Serializable { byte callbacks[16]; byte currentCall; EntityPosition entityPosition; // word @@ -505,6 +596,9 @@ public: return str; } + + // Serializable + void saveLoadWithSerializer(Common::Serializer &s); }; EntityData() {} diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp index ef15326a09..620a885a60 100644 --- a/engines/lastexpress/entities/gendarmes.cpp +++ b/engines/lastexpress/entities/gendarmes.cpp @@ -111,7 +111,7 @@ IMPLEMENT_FUNCTION_II(8, Gendarmes, arrestUpdateEntity, CarIndex, EntityPosition ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) - EntityData::EntityParametersSSSI *parameters1 = (EntityData::EntityParametersSSSI*)_data->getCurrentParameters(1); + EntityData::EntityParametersSSS *parameters1 = (EntityData::EntityParametersSSS*)_data->getCurrentParameters(1); EntityData::EntityParametersISII *parameters2 = (EntityData::EntityParametersISII*)_data->getCurrentParameters(2); switch (savepoint.action) { diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index 3fd7da480b..57f9f0e050 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -244,10 +244,23 @@ int Entities::getCompartments1(int index) { ////////////////////////////////////////////////////////////////////////// // Savegame ////////////////////////////////////////////////////////////////////////// -void Entities::saveLoadWithSerializer(Common::Serializer &ser) { - _header->saveLoadWithSerializer(ser); +void Entities::saveLoadWithSerializer(Common::Serializer &s) { + _header->saveLoadWithSerializer(s); for (uint i = 1; i < _entities.size(); i++) - _entities[i]->saveLoadWithSerializer(ser); + _entities[i]->saveLoadWithSerializer(s); +} + +void Entities::savePositions(Common::Serializer &s) { + for (uint i = 0; i < _positionsCount; i++) + s.syncAsUint32LE(_positions[i]); +} + +void Entities::saveCompartments(Common::Serializer &s) { + for (uint i = 0; i < _compartmentsCount; i++) + s.syncAsUint32LE(_compartments[i]); + + for (uint i = 0; i < _compartmentsCount; i++) + s.syncAsUint32LE(_compartments1[i]); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/entities.h b/engines/lastexpress/game/entities.h index 980e26a6e8..731577d356 100644 --- a/engines/lastexpress/game/entities.h +++ b/engines/lastexpress/game/entities.h @@ -53,6 +53,8 @@ public: // Serializable void saveLoadWithSerializer(Common::Serializer &ser); + void savePositions(Common::Serializer &ser); + void saveCompartments(Common::Serializer &ser); void setup(bool isFirstChapter, EntityIndex entity); void setupChapter(ChapterIndex chapter); diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index 37020604f6..0223176cb6 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -406,8 +406,13 @@ void Inventory::setLocationAndProcess(InventoryItem item, ObjectLocation locatio ////////////////////////////////////////////////////////////////////////// // Serializable ////////////////////////////////////////////////////////////////////////// -void Inventory::saveLoadWithSerializer(Common::Serializer &) { - error("Inventory::saveLoadWithSerializer: not implemented!"); +void Inventory::saveLoadWithSerializer(Common::Serializer &s) { + for (uint i = 0; i < ARRAYSIZE(_entries); i++) + _entries[i].saveLoadWithSerializer(s); +} + +void Inventory::saveSelectedItem(Common::Serializer &s) { + s.syncAsUint32LE(_selectedItem); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/inventory.h b/engines/lastexpress/game/inventory.h index 6babe3e60e..af3478bfae 100644 --- a/engines/lastexpress/game/inventory.h +++ b/engines/lastexpress/game/inventory.h @@ -56,7 +56,7 @@ class Inventory : Common::Serializable, public EventHandler { public: // Entry - struct InventoryEntry { + struct InventoryEntry : Common::Serializable { CursorStyle cursor; SceneIndex scene; byte field_2; @@ -78,6 +78,16 @@ public: Common::String toString() { return Common::String::printf("{ %d - %d - %d - %d - %d - %d - %d }", cursor, scene, field_2, isSelectable, isPresent, manualSelect, location); } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsByte(cursor); + s.syncAsByte(scene); + s.syncAsByte(field_2); + s.syncAsByte(isSelectable); + s.syncAsByte(isPresent); + s.syncAsByte(manualSelect); + s.syncAsByte(location); + } }; Inventory(LastExpressEngine *engine); @@ -115,7 +125,8 @@ public: bool isEggHighlighted() { return _flagEggHightlighted; } // Serializable - void saveLoadWithSerializer(Common::Serializer &ser); + void saveLoadWithSerializer(Common::Serializer &s); + void saveSelectedItem(Common::Serializer &s); /** * Convert this object into a string representation. diff --git a/engines/lastexpress/game/object.cpp b/engines/lastexpress/game/object.cpp index 0b336b941f..f0e81781b6 100644 --- a/engines/lastexpress/game/object.cpp +++ b/engines/lastexpress/game/object.cpp @@ -89,8 +89,9 @@ void Objects::updateLocation2(ObjectIndex index, ObjectLocation location2) { ////////////////////////////////////////////////////////////////////////// // Serializable ////////////////////////////////////////////////////////////////////////// -void Objects::saveLoadWithSerializer(Common::Serializer &) { - error("Objects::saveLoadWithSerializer: not implemented!"); +void Objects::saveLoadWithSerializer(Common::Serializer &s) { + for (int i = 0; i < ARRAYSIZE(_objects); i++) + _objects[i].saveLoadWithSerializer(s); } ////////////////////////////////////////////////////////////////////////// @@ -99,7 +100,7 @@ void Objects::saveLoadWithSerializer(Common::Serializer &) { Common::String Objects::toString() { Common::String ret = ""; - for (int i = 0; i < kObjectMax; i++) + for (int i = 0; i < ARRAYSIZE(_objects); i++) ret += Common::String::printf("%d : %s\n", i, _objects[i].toString().c_str()); return ret; diff --git a/engines/lastexpress/game/object.h b/engines/lastexpress/game/object.h index 70eb69446e..96af4f07a6 100644 --- a/engines/lastexpress/game/object.h +++ b/engines/lastexpress/game/object.h @@ -38,7 +38,7 @@ class LastExpressEngine; class Objects : Common::Serializable { public: - struct Object { // All fields should be saved as bytes + struct Object : Common::Serializable { // All fields should be saved as bytes EntityIndex entity; ObjectLocation location; CursorStyle cursor; @@ -54,6 +54,15 @@ public: } Common::String toString(); + + // Serializable + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsByte(entity); + s.syncAsByte(location); + s.syncAsByte(cursor); + s.syncAsByte(cursor2); + s.syncAsByte(location2); + } }; Objects(LastExpressEngine *engine); @@ -63,7 +72,7 @@ public: void updateLocation2(ObjectIndex index, ObjectLocation location2); // Serializable - void saveLoadWithSerializer(Common::Serializer &ser); + void saveLoadWithSerializer(Common::Serializer &s); /** * Convert this object into a string representation. diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 37b168f7f2..53516b1347 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -25,8 +25,11 @@ #include "lastexpress/game/savegame.h" +#include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/menu.h" +#include "lastexpress/game/object.h" +#include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" #include "lastexpress/debug.h" @@ -184,11 +187,14 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { Common::Serializer ser(_savegame, NULL); entry.saveLoadWithSerializer(ser); - if (!entry.isValid() || getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) + if (!entry.isValid()) { + warning("SaveLoad::saveGame: Invalid entry. This savegame might be corrupted!"); + _savegame->seek(header.offset); + } else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) { + // Not ready to save a game, skipping! return; - - if ((type == kSavegameTypeTime || type == kSavegameTypeEvent) - && (entry.type == kSavegameTypeTickInterval && (getState()->time - entry.time) < 450)) { + } else if ((type == kSavegameTypeTime || type == kSavegameTypeEvent) + && (entry.type == kSavegameTypeTickInterval && (getState()->time - entry.time) < 450)) { _savegame->seek(header.offsetEntry); --header.count; } else { @@ -287,15 +293,64 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he return true; } -void SaveLoad::loadEntryHeader(SavegameEntryHeader *header) { - error("SaveLoad::loadEntryHeader: not implemented!"); -} - ////////////////////////////////////////////////////////////////////////// // Entries ////////////////////////////////////////////////////////////////////////// void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { - warning("SaveLoad::writeEntry: not implemented!"); +#define WRITE_ENTRY(name, func, expected) { \ + uint32 _prevPosition = _savegame->pos(); \ + func; \ + uint32 _count = _savegame->pos() - _prevPosition; \ + debugC(kLastExpressDebugSavegame, "Savegame: Writing " #name ": %d bytes", _count); \ + if (expected != 0 && _count != expected)\ + error("SaveLoad::writeEntry: Number of bytes written (%d) differ from expected count (%d)", _count, expected); \ +} + + SavegameEntryHeader header; + + header.type = type; + header.time = getState()->time; + header.chapter = getProgress().chapter; + header.value = value; + + // Save position + uint32 pos = _savegame->pos(); + + // Write header + Common::Serializer ser(NULL, _savegame); + header.saveLoadWithSerializer(ser); + + computePadding(); + + // Write game data + WRITE_ENTRY("entity index", ser.syncAsUint32LE(entity), 4); + WRITE_ENTRY("state", getState()->saveLoadWithSerializer(ser), 4 + 4 + 4 + 4 + 1 + 4 + 4); + WRITE_ENTRY("selected item", getInventory()->saveSelectedItem(ser), 4); + 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("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), 0); + WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 0); + + header.padding = computePadding(); + + // Save end position + uint32 endpos = _savegame->pos(); + + // Validate entry header + if (!header.isValid()) + error("SaveLoad::writeEntry: entry header is invalid"); + + // Save the header with the updated info + _savegame->seek(pos); + header.saveLoadWithSerializer(ser); + + // Move back to the end of the entry + _savegame->seek(endpos); } void SaveLoad::readEntry(SavegameType type, EntityIndex entity, uint32 value) { @@ -309,6 +364,16 @@ SaveLoad::SavegameEntryHeader *SaveLoad::getEntry(uint32 index) { return _gameHeaders[index]; } +uint32 SaveLoad::computePadding() { + warning("SaveLoad::computePadding: not implemented!"); + + // Hack + while (_savegame->pos() & 15) + _savegame->writeByte(0); + + return _savegame->pos(); +} + ////////////////////////////////////////////////////////////////////////// // Checks ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index ecb976b38c..33a1735d61 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -82,8 +82,8 @@ namespace LastExpress { // Savegame signatures -#define SAVEGAME_SIGNATURE 0x12001200 -#define SAVEGAME_HEADER 0xE660E660 +#define SAVEGAME_SIGNATURE 0x12001200 +#define SAVEGAME_ENTRY_SIGNATURE 0xE660E660 class LastExpressEngine; @@ -209,17 +209,17 @@ private: uint32 signature; SavegameType type; TimeValue time; - int field_C; + int padding; ChapterIndex chapter; uint32 value; int field_18; int field_1C; SavegameEntryHeader() { - signature = 0; + signature = SAVEGAME_ENTRY_SIGNATURE; type = kSavegameTypeIndex; time = kTimeNone; - field_C = 0; + padding = 0; chapter = kChapterAll; value = 0; field_18 = 0; @@ -230,7 +230,7 @@ private: s.syncAsUint32LE(signature); s.syncAsUint32LE(type); s.syncAsUint32LE(time); - s.syncAsUint32LE(field_C); + s.syncAsUint32LE(padding); s.syncAsUint32LE(chapter); s.syncAsUint32LE(value); s.syncAsUint32LE(field_18); @@ -238,7 +238,7 @@ private: } bool isValid() { - if (signature != SAVEGAME_HEADER) + if (signature != SAVEGAME_ENTRY_SIGNATURE) return false; if (type < kSavegameTypeTime || type > kSavegameTypeTickInterval) @@ -247,7 +247,7 @@ private: if (time < kTimeStartGame || time > kTimeCityConstantinople) return false; - if (field_C <= 0 || field_C >= 15) + if (padding <= 0 || padding & 15) return false; /* No check for < 0, as it cannot happen normaly */ @@ -264,12 +264,12 @@ private: // Headers static bool loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header); - void loadEntryHeader(SavegameEntryHeader *header); // Entries void writeEntry(SavegameType type, EntityIndex entity, uint32 value); void readEntry(SavegameType type, EntityIndex entity, uint32 value); SavegameEntryHeader *getEntry(uint32 index); + uint32 computePadding(); // Opening save files static Common::String getFilename(GameId id); diff --git a/engines/lastexpress/game/sound.cpp b/engines/lastexpress/game/sound.cpp index 3b47b6a405..50004bc001 100644 --- a/engines/lastexpress/game/sound.cpp +++ b/engines/lastexpress/game/sound.cpp @@ -503,8 +503,52 @@ SoundManager::SoundEntry *SoundManager::getEntry(SoundType type) { ////////////////////////////////////////////////////////////////////////// // Savegame ////////////////////////////////////////////////////////////////////////// -void SoundManager::saveLoadWithSerializer(Common::Serializer &ser) { - error("Sound::saveLoadWithSerializer: not implemented!"); +void SoundManager::saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(_state); + s.syncAsUint32LE(_currentType); + + // Compute the number of entries to save + uint32 count = 0; + if (s.isSaving()) { + for (Common::List::iterator i = _cache.begin(); i != _cache.end(); ++i) + if ((*i)->name2.matchString("NISSND?")) + ++count; + } + + s.syncAsUint32LE(count); + + // Save or load each entry data + if (s.isSaving()) { + for (Common::List::iterator i = _cache.begin(); i != _cache.end(); ++i) { + SoundEntry *entry = *i; + if (entry->name2.matchString("NISSND?") && (entry->status.status & kFlagType7) != kFlag3) { + s.syncAsUint32LE(entry->status.status); // status; + s.syncAsUint32LE(entry->type); // type; + s.syncAsUint32LE(entry->field_1C); // field_8; + s.syncAsUint32LE(entry->time); // time; + s.syncAsUint32LE(entry->field_34); // field_10; + s.syncAsUint32LE(entry->field_38); // field_14; + s.syncAsUint32LE(entry->entity); // entity; + + uint32 field_1C = entry->field_48 - _data2; + if (field_1C > kFlag8) + field_1C = 0; + s.syncAsUint32LE(field_1C); // field_1C; + + s.syncAsUint32LE(entry->field_4C); // field_20; + + char name1[16]; + strcpy((char *)&name1, entry->name1.c_str()); + s.syncBytes((byte *)&name1, 16); + + char name2[16]; + strcpy((char *)&name2, entry->name2.c_str()); + s.syncBytes((byte *)&name2, 16); + } + } + } else { + error("Sound::saveLoadWithSerializer: not implemented!"); + } } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/sound.h b/engines/lastexpress/game/sound.h index 517aa1b31c..d3b76b6dce 100644 --- a/engines/lastexpress/game/sound.h +++ b/engines/lastexpress/game/sound.h @@ -242,14 +242,14 @@ private: //int field_10; //int fileData; //int field_18; - //int field_1C; + int field_1C; uint32 time; //int field_24; //int field_28; Common::SeekableReadStream *stream; // int //int field_30; - //int field_34; - //int field_38; + int field_34; + int field_38; int field_3C; int field_40; EntityIndex entity; @@ -266,10 +266,13 @@ private: status.status = 0; type = kSoundTypeNone; + field_1C = 0; time = 0; stream = NULL; + field_34 = 0; + field_38 = 0; field_3C = 0; field_40 = 0; entity = kEntityPlayer; diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h index 07c1844efa..469f7a0ea2 100644 --- a/engines/lastexpress/game/state.h +++ b/engines/lastexpress/game/state.h @@ -28,6 +28,7 @@ #include "lastexpress/shared.h" +#include "common/serializer.h" #include "common/system.h" namespace LastExpress { @@ -40,7 +41,7 @@ class SavePoints; class State { public: - struct GameProgress { + struct GameProgress : public Common::Serializable { uint32 field_0; JacketType jacket; bool eventCorpseMovedFromFloor; @@ -313,7 +314,15 @@ public: * @return true if equal, false if not. */ bool isEqual(uint index, uint val) { - #define EXPOSE_VALUE(idx, name) case idx: return ((uint)name == val); + return getValueName(index) == val; + } + + uint32 getValueName(uint index, Common::String *name = NULL) { + #define EXPOSE_VALUE(idx, entryName) \ + case idx: { \ + if (name) (*name) = "" #entryName; \ + return (uint32)entryName; \ + } switch (index) { default: @@ -452,144 +461,26 @@ public: } Common::String toString() { -#define PRINT_VALUE(idx, name) ret += Common::String::printf("(%03d) " #name " = %d\n", idx, name); - Common::String ret = ""; - PRINT_VALUE(0, field_0); - PRINT_VALUE(1, jacket); - PRINT_VALUE(2, eventCorpseMovedFromFloor); - PRINT_VALUE(3, field_C); - PRINT_VALUE(4, eventCorpseFound); - PRINT_VALUE(5, field_14); - PRINT_VALUE(6, field_18); - PRINT_VALUE(7, portrait); - PRINT_VALUE(8, eventCorpseThrown); - PRINT_VALUE(9, field_24); - PRINT_VALUE(10, field_28); - PRINT_VALUE(11, chapter); - PRINT_VALUE(12, field_30); - PRINT_VALUE(13, eventMetAugust); - PRINT_VALUE(14, isNightTime); - PRINT_VALUE(15, field_3C); - PRINT_VALUE(16, field_40); - PRINT_VALUE(17, field_44); - PRINT_VALUE(18, field_48); - PRINT_VALUE(19, field_4C); - PRINT_VALUE(20, isTrainRunning); - PRINT_VALUE(21, field_54); - PRINT_VALUE(22, field_58); - PRINT_VALUE(23, field_5C); - PRINT_VALUE(24, field_60); - PRINT_VALUE(25, field_64); - PRINT_VALUE(26, field_68); - PRINT_VALUE(27, eventMertensAugustWaiting); - PRINT_VALUE(28, eventMertensKronosInvitation); - PRINT_VALUE(29, isEggOpen); - PRINT_VALUE(30, field_78); - PRINT_VALUE(31, field_7C); - PRINT_VALUE(32, field_80); - PRINT_VALUE(33, field_84); - PRINT_VALUE(34, field_88); - PRINT_VALUE(35, field_8C); - PRINT_VALUE(36, field_90); - PRINT_VALUE(37, field_94); - PRINT_VALUE(38, field_98); - PRINT_VALUE(39, field_9C); - PRINT_VALUE(40, field_A0); - PRINT_VALUE(41, field_A4); - PRINT_VALUE(42, field_A8); - PRINT_VALUE(43, field_AC); - PRINT_VALUE(44, field_B0); - PRINT_VALUE(45, field_B4); - PRINT_VALUE(46, field_B8); - PRINT_VALUE(47, field_BC); - PRINT_VALUE(48, field_C0); - PRINT_VALUE(49, field_C4); - PRINT_VALUE(50, field_C8); - PRINT_VALUE(51, field_CC); - PRINT_VALUE(52, eventMetBoutarel); - PRINT_VALUE(53, eventMetHadija); - PRINT_VALUE(54, eventMetYasmin); - PRINT_VALUE(55, field_DC); - PRINT_VALUE(56, field_E0); - PRINT_VALUE(57, field_E4); - PRINT_VALUE(58, field_E8); - PRINT_VALUE(59, field_EC); - PRINT_VALUE(60, field_F0); - PRINT_VALUE(61, field_F4); - PRINT_VALUE(62, field_F8); - PRINT_VALUE(63, field_FC); - PRINT_VALUE(64, field_100); - PRINT_VALUE(65, field_104); - PRINT_VALUE(66, field_108); - PRINT_VALUE(67, field_10C); - PRINT_VALUE(68, field_110); - PRINT_VALUE(69, field_114); - PRINT_VALUE(70, field_118); - PRINT_VALUE(71, field_11C); - PRINT_VALUE(72, field_120); - PRINT_VALUE(73, field_124); - PRINT_VALUE(74, field_128); - PRINT_VALUE(75, field_12C); - PRINT_VALUE(76, field_130); - PRINT_VALUE(77, field_134); - PRINT_VALUE(78, field_138); - PRINT_VALUE(79, field_13C); - PRINT_VALUE(80, field_140); - PRINT_VALUE(81, field_144); - PRINT_VALUE(82, field_148); - PRINT_VALUE(83, field_14C); - PRINT_VALUE(84, field_150); - PRINT_VALUE(85, field_154); - PRINT_VALUE(86, field_158); - PRINT_VALUE(87, field_15C); - PRINT_VALUE(88, field_160); - PRINT_VALUE(89, field_164); - PRINT_VALUE(90, field_168); - PRINT_VALUE(91, field_16C); - PRINT_VALUE(92, field_170); - PRINT_VALUE(93, field_174); - PRINT_VALUE(94, field_178); - PRINT_VALUE(95, field_17C); - PRINT_VALUE(96, field_180); - PRINT_VALUE(97, field_184); - PRINT_VALUE(98, field_188); - PRINT_VALUE(99, field_18C); - PRINT_VALUE(100, field_190); - PRINT_VALUE(101, field_194); - PRINT_VALUE(102, field_198); - PRINT_VALUE(103, field_19C); - PRINT_VALUE(104, field_1A0); - PRINT_VALUE(105, field_1A4); - PRINT_VALUE(106, field_1A8); - PRINT_VALUE(107, field_1AC); - PRINT_VALUE(108, field_1B0); - PRINT_VALUE(109, field_1B4); - PRINT_VALUE(110, field_1B8); - PRINT_VALUE(111, field_1BC); - PRINT_VALUE(112, field_1C0); - PRINT_VALUE(113, field_1C4); - PRINT_VALUE(114, field_1C8); - PRINT_VALUE(115, field_1CC); - PRINT_VALUE(116, field_1D0); - PRINT_VALUE(117, field_1D4); - PRINT_VALUE(118, field_1D8); - PRINT_VALUE(119, field_1DC); - PRINT_VALUE(120, field_1E0); - PRINT_VALUE(121, field_1E4); - PRINT_VALUE(122, field_1E8); - PRINT_VALUE(123, field_1EC); - PRINT_VALUE(124, field_1F0); - PRINT_VALUE(125, field_1F4); - PRINT_VALUE(126, field_1F8); - PRINT_VALUE(127, field_1FC); + for (uint i = 0; i < 128; i++) { + Common::String name = ""; + uint val = getValueName(i, &name); + ret += Common::String::printf("(%03d) %s = %d\n", i, name.c_str(), val); + } return ret; } + + void saveLoadWithSerializer(Common::Serializer &s) { + for (uint i = 0; i < 128; i++) { + uint32 val = getValueName(i); + s.syncAsUint32LE(val); + } + } }; - struct GameState { + struct GameState : public Common::Serializable { // Header uint32 brightness; uint32 volume; @@ -642,6 +533,21 @@ public: return ret; } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(time); + s.syncAsUint32LE(timeDelta); + s.syncAsUint32LE(timeTicks); + s.syncAsUint32LE(scene); + s.syncAsByte(sceneUseBackup); + s.syncAsUint32LE(sceneBackup); + s.syncAsUint32LE(sceneBackup2); + } + + void saveEvents(Common::Serializer &s) { + for (uint i = 0; i < ARRAYSIZE(events); i++) + s.syncAsByte(events[i]); + } }; struct Flags { -- cgit v1.2.3