Ticket #8775: saves-2.patch

File saves-2.patch, 24.1 KB (added by fingolfin, 16 years ago)

v2

  • engines/sword1/sword1.cpp

     
    169169        return kNoError;
    170170}
    171171
     172static SaveStateList Engine_SWORD1_listSaves(const char *target) {
     173        return SaveStateList();
     174}
     175
    172176REGISTER_PLUGIN(SWORD1, "Broken Sword", "Broken Sword Games (C) Revolution");
    173177
    174178namespace Sword1 {
  • engines/sword2/sword2.cpp

     
    162162        return kNoGameDataFoundError;
    163163}
    164164
     165static SaveStateList Engine_SWORD2_listSaves(const char *target) {
     166        return SaveStateList();
     167}
     168
    165169REGISTER_PLUGIN(SWORD2, "Broken Sword 2", "Broken Sword Games (C) Revolution");
    166170
    167171namespace Sword2 {
  • engines/scumm/dialogs.cpp

     
    421421Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode) {
    422422        // Get savegame descriptions
    423423        Common::StringList descriptions;
    424         char name[32];
    425424        uint i = saveMode ? 1 : 0;              //the autosave is on slot #0
    426425        bool avail_saves[81];
    427426
    428427        scumm->listSavegames(avail_saves, ARRAYSIZE(avail_saves));
    429428        for (; i < ARRAYSIZE(avail_saves); i++) {
     429                Common::String name;
    430430                if (avail_saves[i])
    431431                        scumm->getSavegameName(i, name);
    432                 else
    433                         name[0] = 0;
    434432                descriptions.push_back(name);
    435433        }
    436434
  • engines/scumm/scumm.h

     
    623623        int getKeyState(int key);
    624624
    625625public:
    626         bool getSavegameName(int slot, char *desc);
     626        bool getSavegameName(int slot, Common::String &desc);
    627627        void listSavegames(bool *marks, int num);
    628628
    629629        void requestSave(int slot, const char *name, bool temporary = false);
  • engines/scumm/saveload.cpp

     
    431431        }
    432432}
    433433
    434 bool ScummEngine::getSavegameName(int slot, char *desc) {
     434bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion);
     435
     436bool ScummEngine::getSavegameName(int slot, Common::String &desc) {
     437        Common::InSaveFile *in = 0;
     438        bool result = false;
    435439        char filename[256];
    436         Common::InSaveFile *in;
    437         SaveGameHeader hdr;
    438440
     441        desc.clear();
    439442        makeSavegameName(filename, slot, false);
    440         if (!(in = _saveFileMan->openForLoading(filename))) {
    441                 strcpy(desc, "");
    442                 return false;
     443        in = _saveFileMan->openForLoading(filename);
     444        if (in) {
     445                result = Scumm::getSavegameName(in, desc, _game.heversion);
     446                delete in;
    443447        }
     448        return result;
     449}
    444450
     451bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion) {
     452        SaveGameHeader hdr;
     453
    445454        if (!loadSaveGameHeader(in, hdr)) {
    446                 delete in;
    447                 strcpy(desc, "Invalid savegame");
     455                desc = "Invalid savegame";
    448456                return false;
    449457        }
    450         delete in;
    451458
    452459        if (hdr.ver > CURRENT_VER)
    453460                hdr.ver = TO_LE_32(hdr.ver);
    454461        if (hdr.ver < VER(7) || hdr.ver > CURRENT_VER) {
    455                 strcpy(desc, "Invalid version");
     462                desc = "Invalid version";
    456463                return false;
    457464        }
    458465
    459466        // We (deliberately) broke HE savegame compatibility at some point.
    460         if (hdr.ver < VER(57) && _game.heversion >= 60) {
    461                 strcpy(desc, "Unsupported version");
     467        if (hdr.ver < VER(57) && heversion >= 60) {
     468                desc = "Unsupported version";
    462469                return false;
    463470        }
    464471
    465         memcpy(desc, hdr.name, sizeof(hdr.name));
    466         desc[sizeof(hdr.name) - 1] = 0;
     472        hdr.name[sizeof(hdr.name) - 1] = 0;
     473        desc = hdr.name;
    467474        return true;
    468475}
    469476
  • engines/scumm/script_v5.cpp

     
    942942                        int slotSize;
    943943                        byte* slotContent;
    944944                        int savegameId;
    945                         char name[32];
    946945                        bool avail_saves[100];
    947946
    948947                        if (a == STRINGID_IQ_SERIES && b == STRINGID_IQ_SERIES) {
     
    960959
    961960                                // load savegame names
    962961                                savegameId = slot - a + 1;
     962                                Common::String name;
    963963                                if (avail_saves[savegameId] && getSavegameName(savegameId, name)) {
    964964                                        int pos;
    965                                         char *ptr = name;
     965                                        const char *ptr = name.c_str();
    966966                                        // slotContent ends with {'\0','@'} -> max. length = slotSize-2
    967967                                        for (pos = 0; pos < slotSize - 2; ++pos) {
    968968                                                if (!ptr[pos])
  • engines/scumm/detection.cpp

     
    2929#include "common/fs.h"
    3030#include "common/list.h"
    3131#include "common/md5.h"
     32#include "common/savefile.h"
     33#include "common/system.h"
    3234
    3335#include "scumm/detection.h"
    3436#include "scumm/detection_tables.h"
     
    904906        return kNoError;
    905907}
    906908
     909namespace Scumm {
     910        extern bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion);
     911}
     912
     913static SaveStateList Engine_SCUMM_listSaves(const char *target) {
     914        Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
     915        Common::StringList filenames;
     916        Common::String saveDesc;
     917        Common::String pattern = target;
     918        pattern += ".s??";
     919
     920        filenames = saveFileMan->listSavefiles(pattern.c_str());
     921        sort(filenames.begin(), filenames.end());       // Sort (hopefully ensuring we are sorted numerically..)
     922
     923        SaveStateList saveList;
     924        for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++){
     925                // Obtain the last 2 digits of the filename, since they correspond to the save slot
     926                int slotNum = atoi(file->c_str() + file->size() - 2);
     927               
     928                if (slotNum >= 0 && slotNum <= 99) {
     929                        Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
     930                        if (in) {
     931                                Scumm::getSavegameName(in, saveDesc, 0);        // FIXME: heversion?!?
     932                                saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
     933                                delete in;
     934                        }
     935                }
     936        }
     937
     938        return saveList;
     939}
     940
    907941REGISTER_PLUGIN(SCUMM, "Scumm Engine",
    908942                                "LucasArts SCUMM Games (C) LucasArts\n"
    909943                                "Humongous SCUMM Games (C) Humongous" );
  • engines/scumm/script_v8.cpp

     
    12351235                removeBlastTexts();
    12361236                break;
    12371237        case 25: {      // saveGameReadName
    1238                 char name[30];
     1238                Common::String name;
    12391239                if (getSavegameName(args[1], name)) {
    1240                         int size = resStrLen((const byte *)name) + 1;
     1240                        int size = name.size() + 1;
    12411241                        _res->nukeResource(rtString, args[2]);
    12421242
    12431243                        ArrayHeader *ah = (ArrayHeader *)_res->createResource(rtString, args[2], size + sizeof(ArrayHeader));
     
    12451245                        ah->dim1 = TO_LE_16(size + 1);
    12461246                        ah->dim2 = TO_LE_16(1);
    12471247
    1248                         memcpy(getStringAddress(args[2]), name, size);
     1248                        memcpy(getStringAddress(args[2]), name.c_str(), size);
    12491249                }
    12501250                break;
    12511251        }
  • engines/touche/detection.cpp

     
    132132        return gd != 0;
    133133}
    134134
     135static SaveStateList Engine_TOUCHE_listSaves(const char *target) {
     136        return SaveStateList();
     137}
     138
    135139ADVANCED_DETECTOR_DEFINE_PLUGIN(TOUCHE, Engine_TOUCHE_createInstance, detectionParams);
    136140
    137141REGISTER_PLUGIN(TOUCHE, "Touche Engine", "Touche: The Adventures of the 5th Musketeer (C) Clipper Software");
  • engines/agos/detection.cpp

     
    136136        return res;
    137137}
    138138
     139static SaveStateList Engine_AGOS_listSaves(const char *target) {
     140        return SaveStateList();
     141}
     142
    139143ADVANCED_DETECTOR_DEFINE_PLUGIN(AGOS, engineCreateAgos, detectionParams);
    140144
    141145REGISTER_PLUGIN(AGOS, "AGOS", "AGOS (C) Adventure Soft");
  • engines/cruise/detection.cpp

     
    131131        return gd != 0;
    132132}
    133133
     134static SaveStateList Engine_CRUISE_listSaves(const char *target) {
     135        return SaveStateList();
     136}
     137
    134138ADVANCED_DETECTOR_DEFINE_PLUGIN(CRUISE, Engine_CRUISE_createInstance, detectionParams);
    135139
    136140REGISTER_PLUGIN(CRUISE, "Cinematique evo 2 engine", "Cruise for a Corpse (C) Delphine Software");
  • engines/drascula/detection.cpp

     
    171171        return gd != 0;
    172172}
    173173
     174static SaveStateList Engine_DRASCULA_listSaves(const char *target) {
     175        return SaveStateList();
     176}
     177
    174178ADVANCED_DETECTOR_DEFINE_PLUGIN(DRASCULA, Engine_DRASCULA_createInstance, detectionParams);
    175179
    176180REGISTER_PLUGIN(DRASCULA, "Drascula Engine", "Drascula Engine (C) 2000 Alcachofa Soft, 1996 (C) Digital Dreams Multimedia, 1994 (C) Emilio de Paz");
  • engines/agi/detection.cpp

     
    22712271        return res;
    22722272}
    22732273
     2274static SaveStateList Engine_AGI_listSaves(const char *target) {
     2275        return SaveStateList();
     2276}
     2277
    22742278ADVANCED_DETECTOR_DEFINE_PLUGIN(AGI, engineCreateAgi, detectionParams);
    22752279
    22762280REGISTER_PLUGIN(AGI, "AGI preAGI + v2 + v3 Engine", "Sierra AGI Engine (C) Sierra On-Line Software");
  • engines/igor/detection.cpp

     
    119119        return gd != 0;
    120120}
    121121
     122static SaveStateList Engine_IGOR_listSaves(const char *target) {
     123        return SaveStateList();
     124}
     125
    122126ADVANCED_DETECTOR_DEFINE_PLUGIN(IGOR, Engine_IGOR_createInstance, igorDetectionParams);
    123127
    124128REGISTER_PLUGIN(IGOR, "Igor: Objective Uikokahonia", "Igor: Objective Uikokahonia (C) Pendulo Studios");
  • engines/kyra/detection.cpp

     
    469469        return res;
    470470}
    471471
     472static SaveStateList Engine_KYRA_listSaves(const char *target) {
     473        return SaveStateList();
     474}
     475
    472476ADVANCED_DETECTOR_DEFINE_PLUGIN(KYRA, engineCreateKyra, detectionParams);
    473477
    474478REGISTER_PLUGIN(KYRA, "Legend of Kyrandia Engine", "The Legend of Kyrandia (C) Westwood Studios");
  • engines/sky/sky.cpp

     
    172172        return kNoError;
    173173}
    174174
     175static SaveStateList Engine_SKY_listSaves(const char *target) {
     176        return SaveStateList();
     177}
     178
    175179REGISTER_PLUGIN(SKY, "Beneath a Steel Sky", "Beneath a Steel Sky (C) Revolution");
    176180
    177181
  • engines/gob/detection.cpp

     
    17511751        return gd != 0;
    17521752}
    17531753
     1754static SaveStateList Engine_GOB_listSaves(const char *target) {
     1755        return SaveStateList();
     1756}
     1757
    17541758ADVANCED_DETECTOR_DEFINE_PLUGIN(GOB, Engine_GOB_createInstance, detectionParams);
    17551759
    17561760REGISTER_PLUGIN(GOB, "Gob Engine", "Goblins Games (C) Coktel Vision");
  • engines/lure/detection.cpp

     
    182182        return gd != 0;
    183183}
    184184
     185static SaveStateList Engine_LURE_listSaves(const char *target) {
     186        return SaveStateList();
     187}
     188
    185189ADVANCED_DETECTOR_DEFINE_PLUGIN(LURE, Engine_LURE_createInstance, detectionParams);
    186190
    187191REGISTER_PLUGIN(LURE, "Lure of the Temptress Engine", "Lure of the Temptress (C) Revolution");
  • engines/parallaction/detection.cpp

     
    203203        return res;
    204204}
    205205
     206static SaveStateList Engine_PARALLACTION_listSaves(const char *target) {
     207        return SaveStateList();
     208}
     209
    206210ADVANCED_DETECTOR_DEFINE_PLUGIN(PARALLACTION, Engine_PARALLACTION_createInstance, detectionParams);
    207211
    208212REGISTER_PLUGIN(PARALLACTION, "Parallaction engine", "Nippon Safes Inc. (C) Dynabyte");
  • engines/saga/detection.cpp

     
    147147        return gd != 0;
    148148}
    149149
     150static SaveStateList Engine_SAGA_listSaves(const char *target) {
     151        return SaveStateList();
     152}
     153
    150154ADVANCED_DETECTOR_DEFINE_PLUGIN(SAGA, Engine_SAGA_createInstance, detectionParams);
    151155
    152156REGISTER_PLUGIN(SAGA, "SAGA Engine", "Inherit the Earth (C) Wyrmkeep Entertainment");
  • engines/queen/queen.cpp

     
    105105        return kNoError;
    106106}
    107107
     108static SaveStateList Engine_QUEEN_listSaves(const char *target) {
     109        return SaveStateList();
     110}
     111
    108112REGISTER_PLUGIN(QUEEN, "Flight of the Amazon Queen", "Flight of the Amazon Queen (C) John Passfield and Steve Stamatiadis");
    109113
    110114namespace Queen {
  • engines/cine/detection.cpp

     
    496496        return gd != 0;
    497497}
    498498
     499static SaveStateList Engine_CINE_listSaves(const char *target) {
     500        return SaveStateList();
     501}
     502
    499503ADVANCED_DETECTOR_DEFINE_PLUGIN(CINE, Engine_CINE_createInstance, detectionParams);
    500504
    501505REGISTER_PLUGIN(CINE, "Cinematique evo 1 engine", "Future Wars & Operation Stealth (C) Delphine Software");
  • base/game.h

     
    3030#include "common/array.h"
    3131#include "common/hash-str.h"
    3232
     33namespace Graphics {
     34        class Surface;
     35}
     36
    3337/**
    3438 * A simple structure used to map gameids (like "monkey", "sword1", ...) to
    3539 * nice human readable and descriptive game titles (like "The Secret of Monkey Island").
     
    6771                setVal("description", pgd.description);
    6872        }
    6973
    70         GameDescriptor(Common::String g, Common::String d, Common::Language l  = Common::UNK_LANG,
     74        GameDescriptor(const Common::String &g, const Common::String &d, Common::Language l  = Common::UNK_LANG,
    7175                     Common::Platform p = Common::kPlatformUnknown) {
    7276                setVal("gameid", g);
    7377                setVal("description", d);
     
    103107        }
    104108};
    105109
     110/**
     111 * A hashmap describing details about a given save state.
     112 * TODO
     113 * Guaranteed to contain save_slot, filename and description values.
     114 * Additional ideas: Playtime, creation date, thumbnail, ...
     115 */
     116class SaveStateDescriptor : public Common::StringMap {
     117protected:
     118        Graphics::Surface       *_thumbnail;    // can be NULL
     119public:
     120        SaveStateDescriptor() : _thumbnail(0) {
     121                setVal("save_slot", "-1");      // FIXME: default to 0 (first slot) or to -1 (invalid slot) ?
     122                setVal("description", "");
     123                setVal("filename", "");
     124        }
    106125
     126        SaveStateDescriptor(int s, const Common::String &d, const Common::String &f) : _thumbnail(0) {
     127                char buf[16];
     128                sprintf(buf, "%d", s);
     129                setVal("save_slot", buf);
     130                setVal("description", d);
     131                setVal("filename", f);
     132        }
    107133
     134        SaveStateDescriptor(const Common::String &s, const Common::String &d, const Common::String &f) : _thumbnail(0) {
     135                setVal("save_slot", s);
     136                setVal("description", d);
     137                setVal("filename", f);
     138        }
     139
     140        ~SaveStateDescriptor() {
     141                setThumbnail(0);
     142        }
     143
     144        /** The saveslot id, as it would be passed to the "-x" command line switch. */
     145        Common::String &save_slot() { return getVal("save_slot"); }
     146
     147        /** The saveslot id, as it would be passed to the "-x" command line switch (read-only variant). */
     148        const Common::String &save_slot() const { return getVal("save_slot"); }
     149
     150        /** A human readable description of the save state. */
     151        Common::String &description() { return getVal("description"); }
     152
     153        /** A human readable description of the save state (read-only variant). */
     154        const Common::String &description() const { return getVal("description"); }
     155
     156        /** The filename of the savestate, for use with the SaveFileManager API. */
     157        Common::String &filename() { return getVal("filename"); }
     158
     159        /** The filename of the savestate, for use with the SaveFileManager API (read-only variant). */
     160        const Common::String &filename() const { return getVal("filename"); }
     161
     162        /**
     163         * Return a thumbnail graphics surface representing the savestate visually
     164         * This is usually a scaled down version of the game graphics. The size
     165         * should be either 160x100 or 160x120 pixels, depending on the aspect
     166         * ratio of the game. If another ratio is required, contact the core team.
     167         *
     168         * TODO: it is probably a bad idea to read this for *all* games at once,
     169         * at least on low-end devices. So this info should probably normally only
     170         * be included optionally. I.e. only upon a query for a specific savegame...
     171         * To this end, add a getFullSaveStateInfo(target, slot) to the plugin API.
     172         */
     173        const Graphics::Surface *getThumbnail() const { return _thumbnail; }
     174
     175       
     176        void setThumbnail(Graphics::Surface *t);
     177};
     178
     179/** List of savestates. */
     180typedef Common::Array<SaveStateDescriptor> SaveStateList;
     181
     182
    108183class Plugin;
    109184
    110185namespace Base {
  • base/plugins.cpp

     
    6262                assert(_plugin->_df);
    6363                return (*_plugin->_df)(fslist);
    6464        }
     65
     66        SaveStateList listSaves(const char *target) const {
     67                assert(_plugin->_lsf);
     68                return (*_plugin->_lsf)(target);
     69        }
    6570};
    6671
    6772class StaticPluginProvider : public PluginProvider {
  • base/plugins.h

     
    5959public:
    6060        virtual ~Plugin() {}
    6161
     62//      virtual bool isLoaded() const = 0;      // TODO
    6263        virtual bool loadPlugin() = 0;
    6364        virtual void unloadPlugin() = 0;
    6465
     
    7071        virtual GameDescriptor findGame(const char *gameid) const = 0;
    7172        virtual GameList detectGames(const FSList &fslist) const = 0;
    7273
     74        virtual SaveStateList listSaves(const char *target) const = 0;
     75
    7376        virtual PluginError createInstance(OSystem *syst, Engine **engine) const = 0;
    7477};
    7578
     
    106109                        Engine_##ID##_gameIDList(), \
    107110                        Engine_##ID##_findGameID, \
    108111                        Engine_##ID##_create, \
    109                         Engine_##ID##_detectGames \
     112                        Engine_##ID##_detectGames, \
     113                        Engine_##ID##_listSaves \
    110114                        );\
    111115        } \
    112116        void dummyFuncToAllowTrailingSemicolon()
     
    119123                PLUGIN_EXPORT GameDescriptor PLUGIN_findGameID(const char *gameid) { return Engine_##ID##_findGameID(gameid); } \
    120124                PLUGIN_EXPORT PluginError PLUGIN_createEngine(OSystem *syst, Engine **engine) { return Engine_##ID##_create(syst, engine); } \
    121125                PLUGIN_EXPORT GameList PLUGIN_detectGames(const FSList &fslist) { return Engine_##ID##_detectGames(fslist); } \
     126                PLUGIN_EXPORT SaveStateList PLUGIN_listSaves(const char *target) { return Engine_##ID##_listSaves(target); } \
    122127        } \
    123128        void dummyFuncToAllowTrailingSemicolon()
    124129#endif
     
    134139        typedef GameDescriptor (*GameIDQueryFunc)(const char *gameid);
    135140        typedef PluginError (*EngineFactory)(OSystem *syst, Engine **engine);
    136141        typedef GameList (*DetectFunc)(const FSList &fslist);
     142        typedef SaveStateList (*ListSavesFunc)(const char *target);
    137143
    138144protected:
    139145        const char *_name;
     
    141147        GameIDQueryFunc _qf;
    142148        EngineFactory _ef;
    143149        DetectFunc _df;
     150        ListSavesFunc _lsf;
    144151        GameList _games;
    145152
    146153public:
    147         PluginRegistrator(const char *name, const char *copyright, GameList games, GameIDQueryFunc qf, EngineFactory ef, DetectFunc df)
    148                 : _name(name), _copyright(copyright), _qf(qf), _ef(ef), _df(df), _games(games) {}
     154        PluginRegistrator(const char *name, const char *copyright, GameList games, GameIDQueryFunc qf, EngineFactory ef, DetectFunc df, ListSavesFunc lsf)
     155                : _name(name), _copyright(copyright), _qf(qf), _ef(ef), _df(df), _lsf(lsf), _games(games) {}
    149156};
    150157#endif
    151158
  • base/commandLine.cpp

     
    567567        printf("Target               Description                                           \n"
    568568               "-------------------- ------------------------------------------------------\n");
    569569
     570#if 1
     571        // FIXME HACK
     572        g_system->initBackend();
     573#endif
     574
    570575        using namespace Common;
    571576        const ConfigManager::DomainMap &domains = ConfMan.getGameDomains();
    572         ConfigManager::DomainMap::const_iterator iter = domains.begin();
     577        ConfigManager::DomainMap::const_iterator iter;
    573578        for (iter = domains.begin(); iter != domains.end(); ++iter) {
    574579                Common::String name(iter->_key);
    575580                Common::String description(iter->_value.get("description"));
     
    585590                }
    586591
    587592                printf("%-20s %s\n", name.c_str(), description.c_str());
     593
     594#if 1
     595                // FIXME HACK: List all savegames for that target
     596
     597                // Grab the gameid from the domain
     598                Common::String gameid(iter->_value.get("gameid"));
     599                if (gameid.empty())
     600                        gameid = name;
     601                gameid.toLowercase();
     602
     603                // Find the plugin that will handle the specified gameid
     604                const Plugin *plugin = 0;
     605                GameDescriptor game = Base::findGame(gameid, &plugin);
     606
     607                if (!plugin)
     608                        continue;
     609
     610                // Query the plugin for a list of savegames
     611                SaveStateList saveList = plugin->listSaves(name.c_str());
     612
     613                //saveList = FOO;
     614                if (!saveList.empty()) {
     615                        printf("  Saves:\n");
     616                        for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
     617                                printf("    slot %-4s %s\n", x->save_slot().c_str(), x->description().c_str());
     618                                // TODO: Could also iterate over the full hashmap, printing all key-value pairs
     619                        }
     620                }
     621#endif
    588622        }
    589623}
    590624
  • base/game.cpp

     
    2525
    2626#include "base/game.h"
    2727#include "base/plugins.h"
     28#include "graphics/surface.h"
    2829
     30
    2931const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) {
    3032        const PlainGameDescriptor *g = list;
    3133        while (g->gameid) {
     
    6668        }
    6769}
    6870
     71void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
     72        if (_thumbnail && _thumbnail != t) {
     73                _thumbnail->free();
     74                delete _thumbnail;
     75        }
     76        _thumbnail = t;
     77}
     78
     79
    6980namespace Base {
    7081
    7182// TODO: Find a better name & place for this function.
  • backends/plugins/dynamic-plugin.h

     
    3636typedef GameDescriptor (*GameIDQueryFunc)(const char *gameid);
    3737typedef GameList (*GameIDListFunc)();
    3838typedef GameList (*DetectFunc)(const FSList &fslist);
     39typedef SaveStateList (*ListSavesFunc)(const char *target);
    3940
    4041
    4142class DynamicPlugin : public Plugin {
     
    4748        GameIDQueryFunc _qf;
    4849        EngineFactory _ef;
    4950        DetectFunc _df;
     51        ListSavesFunc _lsf;
    5052        GameList _games;
    5153
     54        // FIXME: We should really split the ScummVM engine plugin specific stuff
     55        // into a separate class and keep only the findSymbol function...
    5256        virtual VoidFunc findSymbol(const char *symbol) = 0;
    5357
    5458public:
    55         DynamicPlugin() : _qf(0), _ef(0), _df(0), _games() {}
     59        DynamicPlugin() : _qf(0), _ef(0), _df(0), _lsf(0), _games() {}
    5660
    5761        const char *getName() const                                     { return _name.c_str(); }
    5862        const char *getCopyright() const                        { return _copyright.c_str(); }
     
    7478                return (*_df)(fslist);
    7579        }
    7680
     81
     82        SaveStateList listSaves(const char *target) const {
     83                assert(_lsf);
     84                return (*_lsf)(fslist);
     85        }
     86
    7787        virtual bool loadPlugin() {
    7888                // Query the plugin's name
    7989                NameFunc nameFunc = (NameFunc)findSymbol("PLUGIN_name");