Ticket #8939: sword1-savegames.patch

File sword1-savegames.patch, 21.4 KB (added by bluegr, 15 years ago)

Broken Sword 1 save/load overhaul

  • control.cpp

     
    2323 *
    2424 */
    2525
     26#include <time.h>       // for extended infos
    2627
    2728#include "common/file.h"
    2829#include "common/util.h"
     
    3132#include "common/system.h"
    3233#include "common/config-manager.h"
    3334
     35#include "graphics/thumbnail.h"
    3436#include "gui/message.h"
    3537
    3638#include "sword1/control.h"
     
    509511}
    510512
    511513void Control::setupSaveRestorePanel(bool saving) {
     514        readSavegameDescriptions();
     515
    512516        FrameHeader *savePanel = _resMan->fetchFrame(_resMan->openFetchRes(SR_WINDOW), 0);
    513517        uint16 panelX = (640 - _resMan->getUint16(savePanel->width)) / 2;
    514518        uint16 panelY = (480 - _resMan->getUint16(savePanel->height)) / 2;
     
    690694
    691695void Control::handleSaveKey(Common::KeyState kbd) {
    692696        if (_selectedSavegame < 255) {
    693                 uint8 len = strlen((char*)_saveNames[_selectedSavegame]);
     697                uint8 len = _saveNames[_selectedSavegame].size();
    694698                if ((kbd.keycode == Common::KEYCODE_BACKSPACE) && len)  // backspace
    695                         _saveNames[_selectedSavegame][len - 1] = '\0';
     699                        _saveNames[_selectedSavegame].deleteLastChar();
    696700                else if (keyAccepted(kbd.ascii) && (len < 31)) {
    697                         _saveNames[_selectedSavegame][len] = kbd.ascii;
    698                         _saveNames[_selectedSavegame][len + 1] = '\0';
     701                        _saveNames[_selectedSavegame].insertChar(kbd.ascii, len);
    699702                }
    700703                showSavegameNames();
    701704        }
    702705}
    703706
    704707bool Control::saveToFile(void) {
    705         if ((_selectedSavegame == 255) || !strlen((char*)_saveNames[_selectedSavegame]))
     708        if ((_selectedSavegame == 255) || _saveNames[_selectedSavegame].size() == 0)
    706709                return false; // no saveslot selected or no name entered
    707710        saveGameToFile(_selectedSavegame);
    708         writeSavegameDescriptions();
    709711        return true;
    710712}
    711713
     
    717719}
    718720
    719721void Control::readSavegameDescriptions(void) {
    720         Common::InSaveFile *inf;
    721         inf = _saveFileMan->openForLoading("SAVEGAME.INF");
    722         _saveScrollPos = _saveFiles = 0;
     722        char saveName[40];
     723        Common::String pattern = ConfMan.get("gameid") + ".???";
     724        Common::StringList filenames = _saveFileMan->listSavefiles(pattern.c_str());
     725        sort(filenames.begin(), filenames.end());       // Sort (hopefully ensuring we are sorted numerically..)
     726
     727        int num = 0;
     728        int slotNum = 0;
     729        for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
     730                // Obtain the last 3 digits of the filename, since they correspond to the save slot
     731                slotNum = atoi(file->c_str() + file->size() - 3);
     732               
     733                while (num < slotNum) {
     734                        _saveNames.push_back("");
     735                        num++;
     736                }
     737
     738                if (slotNum >= 0 && slotNum <= 999) {
     739                        num++;
     740                        Common::InSaveFile *in = _saveFileMan->openForLoading(file->c_str());
     741                        if (in) {
     742                                in->readUint32LE();     // header
     743                                in->read(saveName, 40);
     744                                _saveNames.push_back(saveName);
     745                                delete in;
     746                        }
     747                }
     748        }
     749
     750        for (int i = _saveNames.size(); i < 1000; i++)
     751                _saveNames.push_back("");
     752
     753        _saveScrollPos = 0;
    723754        _selectedSavegame = 255;
    724         for (uint8 cnt = 0; cnt < 64; cnt++) {
    725                 memset(_saveNames[cnt], 0, sizeof(_saveNames[cnt]));
    726         }
    727         if (inf) {
    728                 uint8 curFileNum = 0;
    729                 uint8 ch;
    730                 do {
    731                         uint8 pos = 0;
    732                         do {
    733                                 ch = inf->readByte();
    734                                 if (pos < sizeof(_saveNames[curFileNum]) - 1) {
    735                                         if ((ch == 10) || (ch == 255) || (inf->eos()))
    736                                                 _saveNames[curFileNum][pos++] = '\0';
    737                                         else if (ch >= 32)
    738                                                 _saveNames[curFileNum][pos++] = ch;
    739                                 }
    740                         } while ((ch != 10) && (ch != 255) && (!inf->eos()));
    741                         curFileNum++;
    742                 } while ((ch != 255) && (!inf->eos()));
    743                 _saveFiles = curFileNum;
    744                 _numSaves = _saveFiles;
    745         }
    746         delete inf;
     755        _saveFiles = _numSaves = _saveNames.size();
    747756}
    748757
    749758int Control::displayMessage(const char *altButton, const char *message, ...) {
     
    760769        return result;
    761770}
    762771
    763 void Control::writeSavegameDescriptions(void) {
    764         Common::OutSaveFile *outf;
    765         outf = _saveFileMan->openForSaving("SAVEGAME.INF");
     772bool Control::savegamesExist(void) {
     773        Common::String pattern = ConfMan.get("gameid") + ".???";
     774        Common::StringList saveNames = _saveFileMan->listSavefiles(pattern.c_str());
     775        return saveNames.size() > 0;
     776}
    766777
    767         if (!outf) {
    768                 // Display an error message, and do nothing
    769                 displayMessage(0, "Can't create SAVEGAME.INF. (%s)", _saveFileMan->popErrorDesc().c_str());
     778void Control::checkForOldSaveGames() {
     779        Common::InSaveFile *inf = _saveFileMan->openForLoading("SAVEGAME.INF");
     780
     781        if (!inf) {
     782                delete inf;
    770783                return;
    771784        }
    772785
    773         // if the player accidently clicked the last slot and then deselected it again,
    774         // we'd still have _saveFiles == 64, so get rid of the empty end.
    775         while (strlen((char*)_saveNames[_saveFiles - 1]) == 0)
    776                 _saveFiles--;
    777         for (uint8 cnt = 0; cnt < _saveFiles; cnt++) {
    778                 int len = strlen((char*)_saveNames[cnt]);
    779                 if (len > 0)
    780                         outf->write(_saveNames[cnt], len);
    781                 if (cnt < _saveFiles - 1)
    782                         outf->writeByte(10);
    783                 else
    784                         outf->writeByte(255);
     786        GUI::MessageDialog dialog0(
     787                "ScummVM found that you have old savefiles for Broken Sword 1 that should be converted.\n"
     788                "The old save game format is no longer supported, so you will not be able to load your games if you don't convert them.\n\n"
     789                "Press OK to convert them now, otherwise you will be asked again the next time you start the game.\n", "OK", "Cancel");
     790
     791        int choice = dialog0.runModal();
     792        if (choice == 0) {
     793                // user pressed cancel
     794                return;
    785795        }
    786         outf->finalize();
    787         if (outf->ioFailed())
    788                 displayMessage(0, "Can't write to SAVEGAME.INF. Device full? (%s)", _saveFileMan->popErrorDesc().c_str());
    789         delete outf;
    790 }
    791796
    792 bool Control::savegamesExist(void) {
    793         bool retVal = false;
    794         Common::InSaveFile *inf;
    795         inf = _saveFileMan->openForLoading("SAVEGAME.INF");
    796         if (inf)
    797                 retVal = true;
    798         delete inf;
    799         return retVal;
     797        // Convert every save slot we find in the index file to the new format
     798        uint8 saveName[32];
     799        uint8 slot = 0;
     800        uint8 ch;
     801
     802        memset(saveName, 0, sizeof(saveName));
     803
     804        do {
     805                uint8 pos = 0;
     806                do {
     807                        ch = inf->readByte();
     808                        if (pos < sizeof(saveName) - 1) {
     809                                if ((ch == 10) || (ch == 255) || (inf->eos()))
     810                                        saveName[pos++] = '\0';
     811                                else if (ch >= 32)
     812                                        saveName[pos++] = ch;
     813                        }
     814                } while ((ch != 10) && (ch != 255) && (!inf->eos()));
     815
     816                if (pos > 1)    // if the slot has a description
     817                        convertSaveGame(slot, (char*)saveName);
     818                slot++;
     819        } while ((ch != 255) && (!inf->eos()));
     820
     821        delete inf;     
     822
     823        // Delete index file
     824        _saveFileMan->removeSavefile("SAVEGAME.INF");
    800825}
    801826
    802827void Control::showSavegameNames(void) {
     
    805830                uint8 textMode = TEXT_LEFT_ALIGN;
    806831                uint16 ycoord = _saveButtons[cnt].y + 2;
    807832                uint8 str[40];
    808                 sprintf((char*)str, "%d. %s", cnt + _saveScrollPos + 1, _saveNames[cnt + _saveScrollPos]);
     833                sprintf((char*)str, "%d. %s", cnt + _saveScrollPos + 1, _saveNames[cnt + _saveScrollPos].c_str());
    809834                if (cnt + _saveScrollPos == _selectedSavegame) {
    810835                        textMode |= TEXT_RED_FONT;
    811836                        ycoord += 2;
     
    821846        _buttons[id - BUTTON_SAVE_SELECT1]->setSelected(1);
    822847        uint8 num = (id - BUTTON_SAVE_SELECT1) + _saveScrollPos;
    823848        if (saving && (_selectedSavegame != 255)) // the player may have entered something, clear it again
    824                 strcpy((char*)_saveNames[_selectedSavegame], (char*)_oldName);
     849                _saveNames[_selectedSavegame] = _oldName;
    825850        if (num < _saveFiles) {
    826851                _selectedSavegame = num;
    827                 strcpy((char*)_oldName, (char*)_saveNames[num]); // save for later
     852                _oldName = _saveNames[num]; // save for later
    828853        } else {
    829854                if (!saving)
    830855                        _buttons[id - BUTTON_SAVE_SELECT1]->setSelected(0); // no save in slot, deselect it
     
    832857                        if (_saveFiles <= num)
    833858                                _saveFiles = num + 1;
    834859                        _selectedSavegame = num;
    835                         _oldName[0] = '\0';
     860                        _oldName.clear();
    836861                }
    837862        }
    838863        if (_selectedSavegame < 255)
     
    950975void Control::saveGameToFile(uint8 slot) {
    951976        char fName[15];
    952977        uint16 cnt;
    953         sprintf(fName, "SAVEGAME.%03d", slot);
     978        sprintf(fName, "%s.%03d", ConfMan.get("gameid").c_str(), slot);
    954979        uint16 liveBuf[TOTAL_SECTIONS];
    955980        Common::OutSaveFile *outf;
    956981        outf = _saveFileMan->openForSaving(fName);
     
    960985                return;
    961986        }
    962987
     988        outf->writeUint32LE(SAVEGAME_HEADER);
     989        outf->write(_saveNames[slot].c_str(), 40);
     990        outf->writeByte(SAVEGAME_VERSION);
     991
     992        // FIXME: at this point, we can't save a thumbnail of the game screen, as the save menu is shown
     993#if 0
     994        outf->writeByte(HAS_THUMBNAIL);
     995
     996        // Thumbnail
     997        Graphics::saveThumbnail(*outf);
     998#else
     999        outf->writeByte(NO_THUMBNAIL);
     1000#endif
     1001
     1002        // Date / time
     1003        tm curTime;
     1004        _system->getTimeAndDate(curTime);
     1005
     1006        uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | (curTime.tm_year + 1900) & 0xFFFF;
     1007        uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | (curTime.tm_min) & 0xFF;
     1008
     1009        outf->writeUint32BE(saveDate);
     1010        outf->writeUint16BE(saveTime);
     1011        // TODO: played time
     1012
    9631013        _objMan->saveLiveList(liveBuf);
    9641014        for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
    9651015                outf->writeUint16LE(liveBuf[cnt]);
     
    9871037bool Control::restoreGameFromFile(uint8 slot) {
    9881038        char fName[15];
    9891039        uint16 cnt;
    990         sprintf(fName, "SAVEGAME.%03d", slot);
     1040        sprintf(fName, "%s.%03d", ConfMan.get("gameid").c_str(), slot);
    9911041        Common::InSaveFile *inf;
    9921042        inf = _saveFileMan->openForLoading(fName);
    9931043        if (!inf) {
     
    9961046                return false;
    9971047        }
    9981048
     1049        uint saveHeader = inf->readUint32LE();
     1050        if (saveHeader != SAVEGAME_HEADER) {
     1051                // Display an error message, and do nothing
     1052                displayMessage(0, "Save game '%s' is corrupt", fName);
     1053                return false;           
     1054        }
     1055
     1056        inf->skip(40);          // skip description
     1057        uint8 saveVersion = inf->readByte();
     1058
     1059        if (saveVersion != SAVEGAME_VERSION) {
     1060                warning("Different save game version");
     1061                return false;
     1062        }
     1063       
     1064        bool hasThumbnail = inf->readByte();
     1065
     1066        if (hasThumbnail) {
     1067                // We don't need the thumbnail here, so just read it and discard it
     1068                Graphics::Surface *thumbnail = new Graphics::Surface();
     1069                assert(thumbnail);
     1070                Graphics::loadThumbnail(*inf, *thumbnail);
     1071                delete thumbnail;
     1072                thumbnail = 0;
     1073        }
     1074
     1075        inf->readUint32BE();    // save date
     1076        inf->readUint16BE();    // save time
     1077        // TODO: played time
     1078
    9991079        _restoreBuf = (uint8*)malloc(
    10001080                TOTAL_SECTIONS * 2 +
    10011081                NUM_SCRIPT_VARS * 4 +
     
    10261106        return true;
    10271107}
    10281108
     1109bool Control::convertSaveGame(uint8 slot, char* desc) {
     1110        char oldFileName[15];
     1111        char newFileName[40];
     1112        sprintf(oldFileName, "SAVEGAME.%03d", slot);
     1113        sprintf(newFileName, "%s.%03d", ConfMan.get("gameid").c_str(), slot);
     1114        uint8 *saveData;
     1115        int dataSize;
     1116
     1117        // Check if the new file already exists
     1118        if (Common::File::exists(newFileName)) {
     1119                char msg[200];
     1120                sprintf(msg, "Target new save game already exists!\n"
     1121                                         "Would you like to keep the old save game (%s) or the new one (%s)?\n",
     1122                                         oldFileName, newFileName);
     1123                GUI::MessageDialog dialog0(msg, "Keep the old one", "Keep the new one");
     1124
     1125                int choice = dialog0.runModal();
     1126                if (choice == 1) {
     1127                        // User chose to keep the new game, so delete the old one
     1128                        _saveFileMan->removeSavefile(oldFileName);
     1129                        return true;
     1130                }
     1131        }
     1132
     1133        Common::InSaveFile *oldSave = _saveFileMan->openForLoading(oldFileName);
     1134        if (!oldSave) {
     1135                // Display a warning message and do nothing
     1136                warning("Can't open file '%s'", oldFileName);
     1137                return false;
     1138        }
     1139
     1140        // Read data from old type of save game
     1141        dataSize = oldSave->size();
     1142        saveData = new uint8[dataSize];
     1143        oldSave->read(saveData, dataSize);
     1144        delete oldSave;
     1145
     1146        // Now write the save data to a new type of save game
     1147        Common::OutSaveFile *newSave;
     1148        newSave = _saveFileMan->openForSaving(newFileName);
     1149        if (!newSave) {
     1150                // Display a warning message and do nothing
     1151                warning("Unable to create file '%s'. (%s)", newFileName);
     1152                free(saveData);
     1153                saveData = NULL;
     1154                return false;
     1155        }       
     1156
     1157        newSave->writeUint32LE(SAVEGAME_HEADER);
     1158        newSave->write(desc, 40);
     1159        newSave->writeByte(SAVEGAME_VERSION);
     1160        newSave->writeByte(NO_THUMBNAIL);
     1161
     1162        // Date / time
     1163        tm curTime;
     1164        _system->getTimeAndDate(curTime);
     1165
     1166        uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | (curTime.tm_year + 1900) & 0xFFFF;
     1167        uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | (curTime.tm_min) & 0xFF;
     1168
     1169        newSave->writeUint32BE(saveDate);
     1170        newSave->writeUint16BE(saveTime);
     1171        // TODO: played time
     1172
     1173        newSave->write(saveData, dataSize);
     1174
     1175        newSave->finalize();
     1176        if (newSave->ioFailed())
     1177                warning("Couldn't write to file '%s'. Device full?", newFileName);
     1178        delete newSave;
     1179
     1180        // Delete old save
     1181        _saveFileMan->removeSavefile(oldFileName);
     1182
     1183        // Cleanup
     1184        free(saveData);
     1185        saveData = NULL;
     1186        return true;
     1187}
     1188
    10291189void Control::doRestore(void) {
    10301190        uint8 *bufPos = _restoreBuf;
    10311191        _objMan->loadLiveList((uint16*)bufPos);
  • control.h

     
    4343class Music;
    4444class Sound;
    4545
     46#define SAVEGAME_HEADER MKID_BE('BS_1')
     47#define SAVEGAME_VERSION 1
     48#define HAS_THUMBNAIL 1
     49#define NO_THUMBNAIL 0
     50
    4651#define MAX_BUTTONS 16
    4752
    4853#define CONTROL_NOTHING_DONE 0
     
    8792        void doRestore(void);
    8893        void askForCd(void);
    8994        bool savegamesExist(void);
     95        void readSavegameDescriptions(void);
     96        void saveGameToFile(uint8 slot);
    9097        bool restoreGameFromFile(uint8 slot);
     98        void checkForOldSaveGames();
     99
     100        void setSaveDescription(int slot, const char *desc) {
     101                _saveNames[slot] = desc;
     102        }
     103
    91104private:
    92105        int displayMessage(const char *altButton, const char *message, ...);
    93106
    94         void saveGameToFile(uint8 slot);
    95         void readSavegameDescriptions(void);
    96         void writeSavegameDescriptions(void);
     107        bool convertSaveGame(uint8 slot, char* desc);
    97108        void showSavegameNames(void);
    98109        void deselectSaveslots(void);
    99110        uint8 *_restoreBuf;
     
    101112        uint8 _numSaves;
    102113        uint8 _saveScrollPos;
    103114        uint8 _selectedSavegame;
    104         uint8 _saveNames[64][32];
    105         uint8 _oldName[32];
     115        Common::StringList _saveNames;
     116        Common::String _oldName;
    106117        uint8 _cursorTick;
    107118        bool _cursorVisible;
    108119
  • detection.cpp

     
    2424 */
    2525
    2626#include "sword1/sword1.h"
     27#include "sword1/control.h"
    2728
    2829#include "base/plugins.h"
    2930#include "common/config-manager.h"
    3031#include "common/file.h"
    3132#include "common/fs.h"
    3233#include "common/savefile.h"
     34#include "graphics/thumbnail.h"
    3335
    3436#include "engines/metaengine.h"
    3537
     
    8183        virtual GameList detectGames(const Common::FSList &fslist) const;
    8284        virtual SaveStateList listSaves(const char *target) const;
    8385        virtual int getMaximumSaveSlot() const;
     86        virtual void removeSaveState(const char *target, int slot) const;
     87        SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
    8488
    8589        virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
    8690};
     
    8892bool SwordMetaEngine::hasFeature(MetaEngineFeature f) const {
    8993        return
    9094                (f == kSupportsListSaves) ||
    91                 (f == kSupportsLoadingDuringStartup);
     95                (f == kSupportsLoadingDuringStartup) ||
     96                (f == kSupportsDeleteSave) ||
     97                (f == kSavesSupportMetaInfo) ||
     98                (f == kSavesSupportThumbnail) ||
     99                (f == kSavesSupportCreationDate);
    92100}
    93101
    94102bool Sword1::SwordEngine::hasFeature(EngineFeature f) const {
     
    184192
    185193SaveStateList SwordMetaEngine::listSaves(const char *target) const {
    186194        Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
     195        Common::String pattern = target;
     196        pattern += ".???";
    187197        SaveStateList saveList;
     198        char saveName[40];
    188199
    189         Common::String pattern = "SAVEGAME.???";
    190200        Common::StringList filenames = saveFileMan->listSavefiles(pattern.c_str());
    191         sort(filenames.begin(), filenames.end());
    192         Common::StringList::const_iterator file = filenames.begin();
     201        sort(filenames.begin(), filenames.end());       // Sort (hopefully ensuring we are sorted numerically..)
    193202
    194         Common::InSaveFile *in = saveFileMan->openForLoading("SAVEGAME.INF");
     203        int slotNum = 0;
     204        for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
     205                // Obtain the last 3 digits of the filename, since they correspond to the save slot
     206                slotNum = atoi(file->c_str() + file->size() - 3);
     207               
     208                if (slotNum >= 0 && slotNum <= 999) {
     209                        Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
     210                        if (in) {
     211                                in->readUint32LE();     // header
     212                                in->read(saveName, 40);
     213                                saveList.push_back(SaveStateDescriptor(slotNum, saveName));
     214                                delete in;
     215                        }
     216                }
     217        }
    195218
     219        return saveList;
     220}
     221
     222int SwordMetaEngine::getMaximumSaveSlot() const { return 999; }
     223
     224void SwordMetaEngine::removeSaveState(const char *target, int slot) const {
     225        char extension[6];
     226        snprintf(extension, sizeof(extension), ".%03d", slot);
     227
     228        Common::String filename = target;
     229        filename += extension;
     230
     231        g_system->getSavefileManager()->removeSavefile(filename.c_str());
     232}
     233
     234SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
     235        static char fileName[40];
     236        sprintf(fileName, "%s.%03d", target, slot);
     237        char name[40];
     238
     239        Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
     240
    196241        if (in) {
    197                 Common::Array<uint32> offsets;
    198                 uint8 stop = 0;
    199                 int slotsInFile = 0;
     242                in->skip(4);            // header
     243                in->read(name, sizeof(name));
     244                in->skip(1);            // version
    200245
    201                 // Find the offset for each savegame name in the file.
    202                 while (stop != 255 && !in->eos()) {
    203                         offsets.push_back(in->pos());
    204                         slotsInFile++;
    205                         stop = 0;
    206                         while (stop != 10 && stop != 255 && !in->eos())
    207                                 stop = in->readByte();
     246                SaveStateDescriptor desc(slot, name);
     247
     248                desc.setDeletableFlag(true);
     249                desc.setWriteProtectedFlag(false);
     250
     251                bool hasThumbnail = in->readByte();
     252                if (hasThumbnail) {
     253                        Graphics::Surface *thumbnail = new Graphics::Surface();
     254                        assert(thumbnail);
     255                        if (!Graphics::loadThumbnail(*in, *thumbnail)) {
     256                                delete thumbnail;
     257                                thumbnail = 0;
     258                        }
     259
     260                        desc.setThumbnail(thumbnail);
    208261                }
    209262
    210                 // Match the savegames to the save slot names.
    211                 while (file != filenames.end()) {
    212                         char saveDesc[32];
     263                uint32 saveDate = in->readUint32BE();
     264                uint16 saveTime = in->readUint16BE();
    213265
    214                         if (file->compareToIgnoreCase("SAVEGAME.INF") == 0) {
    215                                 file++;
    216                                 continue;
    217                         }
     266                int day = (saveDate >> 24) & 0xFF;
     267                int month = (saveDate >> 16) & 0xFF;
     268                int year = saveDate & 0xFFFF;
     269
     270                desc.setSaveDate(year, month, day);
    218271                       
    219                         // Obtain the last 3 digits of the filename, since they correspond to the save slot
    220                         int slotNum = atoi(file->c_str() + file->size() - 3);
     272                int hour = (saveTime >> 8) & 0xFF;
     273                int minutes = saveTime & 0xFF;
    221274
    222                         if (slotNum >= 0 && slotNum < slotsInFile) {
    223                                 in->seek(offsets[slotNum]);
     275                desc.setSaveTime(hour, minutes);
    224276
    225                                 uint pos = 0;
    226                                 do {
    227                                         stop = in->readByte();
    228                                         if (pos < sizeof(saveDesc) - 1) {
    229                                                 if (stop == 10 || stop == 255 || in->eos())
    230                                                         saveDesc[pos++] = '\0';
    231                                                 else if (stop >= 32)
    232                                                         saveDesc[pos++] = stop;
    233                                         }
    234                                 } while (stop != 10 && stop != 255 && !in->eos());
    235                         }
     277                // TODO: played time
    236278
    237                         if (saveDesc[0] == 0)
    238                                 strcpy(saveDesc, "Unnamed savegame");
     279                delete in;
    239280
    240                         // FIXME: The in-game dialog shows the first save slot as 1, not 0,
    241                         // but if we change the numbering here, the launcher won?t set
    242                         // "save_slot" correctly.
    243                         saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
    244                         file++;
    245                 }
     281                return desc;
    246282        }
    247 
    248         delete in;
    249 
    250         return saveList;
     283       
     284        return SaveStateDescriptor();
    251285}
    252286
    253 int SwordMetaEngine::getMaximumSaveSlot() const { return 999; }
    254 
    255287#if PLUGIN_ENABLED_DYNAMIC(SWORD1)
    256288        REGISTER_PLUGIN_DYNAMIC(SWORD1, PLUGIN_TYPE_ENGINE, SwordMetaEngine);
    257289#else
    258290        REGISTER_PLUGIN_STATIC(SWORD1, PLUGIN_TYPE_ENGINE, SwordMetaEngine);
    259291#endif
     292
     293namespace Sword1 {
     294
     295// FIXME: Loading a game through the GMM crashes the game
     296#if 0
     297Common::Error SwordEngine::loadGameState(int slot) {
     298        _systemVars.forceRestart = false;
     299        _systemVars.controlPanelMode = CP_NORMAL;
     300        _control->restoreGameFromFile(slot);
     301        reinitialize();
     302        _control->doRestore();
     303        return Common::kNoError;        // TODO: return success/failure
     304}
     305
     306Common::Error SwordEngine::saveGameState(int slot, const char *desc) {
     307        _control->setSaveDescription(slot, desc);
     308        _control->saveGameToFile(slot);
     309        return Common::kNoError;        // TODO: return success/failure
     310}
     311
     312bool SwordEngine::canLoadGameStateCurrently() {
     313        return mouseIsActive();
     314}
     315
     316bool SwordEngine::canSaveGameStateCurrently() {
     317        return mouseIsActive();
     318}
     319#endif
     320
     321} // End of namespace Sword1
  • sword1.cpp

     
    484484}
    485485
    486486Common::Error SwordEngine::go() {
     487        _control->checkForOldSaveGames();
     488
    487489        uint16 startPos = ConfMan.getInt("boot_param");
     490        _control->readSavegameDescriptions();
    488491        if (startPos) {
    489492                _logic->startPositions(startPos);
    490493        } else {
     
    660663        } while (_system->getMillis() < start + amount);
    661664}
    662665
     666bool SwordEngine::mouseIsActive() {
     667        return Logic::_scriptVars[MOUSE_STATUS] & 1;
     668}
     669
    663670} // End of namespace Sword1
  • sword1.h

     
    7979        void reinitialize(void);
    8080
    8181        uint32 _features;
     82
     83        bool mouseIsActive();
     84
    8285protected:
    8386        // Engine APIs
    8487        virtual Common::Error init();
    8588        virtual Common::Error go();
    8689        virtual bool hasFeature(EngineFeature f) const;
    8790        virtual void syncSoundSettings();
     91        // FIXME: Loading a game through the GMM crashes the game
     92#if 0
     93        Common::Error loadGameState(int slot);
     94        Common::Error saveGameState(int slot, const char *desc);
     95        bool canLoadGameStateCurrently();
     96        bool canSaveGameStateCurrently();
     97#endif
    8898
    8999private:
    90100        void delay(int32 amount);