Ticket #8473: kyra-md5detect.patch

File kyra-md5detect.patch, 15.1 KB (added by vinterstum, 15 years ago)

Kyra md5 game detection

  • kyra/kyra.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvmcvs/kyra/kyra.cpp scummvm/kyra/kyra.cpp
    old new  
    2929#include "common/config-manager.h"
    3030#include "common/file.h"
    3131#include "common/system.h"
     32#include "common/md5.h"
    3233
    3334#include "sound/mixer.h"
    3435#include "sound/mididrv.h"
     
    4849
    4950using namespace Kyra;
    5051
     52enum {
     53        // We only compute MD5 of the first megabyte of our data files.
     54        kMD5FileSizeLimit = 1024 * 1024
     55};
     56
     57// Kyra MD5 detection brutally ripped from the Gobliins engine.
    5158struct KyraGameSettings {
    5259        const char *name;
    5360        const char *description;
     61        byte id;
    5462        uint32 features;
    55         const char *detectName;
     63        const char *md5sum;
     64        const char *checkFile;
    5665        GameSettings toGameSettings() const {
    5766                GameSettings dummy = { name, description, features };
    5867                return dummy;
    5968        }
    6069};
    6170
    62 static const KyraGameSettings kyra_settings[] = {
    63         { "kyra1", "Legend of Kyrandia (Floppy)", GF_FLOPPY | GF_KYRA1, "INTRO.SND" },
    64         { "kyra1cd", "Legend of Kyrandia (CD)",  GF_TALKIE | GF_KYRA1,  "CHAPTER1.VRM" },
    65         { "kyra1demo", "Legend of Kyrandia (Demo)", GF_DEMO | GF_FLOPPY | GF_KYRA1, "DEMO1.WSA" },
    66 //      { "kyra2", "Hand of Fate (Floppy)", GF_FLOPPY | GF_KYRA2, 0 },
    67 //      { "kyra2cd", "Hand of Fate (CD)", GF_TALKIE | GF_KYRA2, "AUDIO.PAK" },
    68 //      { "kyra3", "Malcolm's Revenge", GF_TALKIE | GF_KYRA3, "K3INTRO0.VQA" },
    69         { 0, 0, 0, 0 }
     71static const KyraGameSettings kyra_games[] = {
     72        { "kyra1", "Legend of Kyrandia (Floppy, English)", GI_KYRA1, GF_ENGLISH | GF_FLOPPY  | GF_KYRA1,
     73                                                                                "796e44863dd22fa635b042df1bf16673", "GEMCUT.EMC" },
     74        { "kyra1", "Legend of Kyrandia (Floppy, French)",  GI_KYRA1, GF_FRENCH  | GF_FLOPPY  | GF_KYRA1,
     75                                                                                "abf8eb360e79a6c2a837751fbd4d3d24", "GEMCUT.EMC" },
     76        { "kyra1", "Legend of Kyrandia (Floppy, German)",  GI_KYRA1, GF_GERMAN  | GF_FLOPPY  | GF_KYRA1,
     77                                                                                "82aea70ef26f41fa963dfae270994e49", "GEMCUT.EMC"},
     78        { "kyra1", "Legend of Kyrandia (CD)",              GI_KYRA1, GF_ENGLISH | GF_TALKIE  | GF_KYRA1,
     79                                                                                "fac399fe62f98671e56a005c5e94e39f", "GEMCUT.PAK" },
     80        { "kyra1", "Legend of Kyrandia (Demo)",            GI_KYRA1, GF_DEMO | GF_KYRA1,
     81                                                                                "fb722947d94897512b13b50cc84fd648", "DEMO1.WSA" },
     82        {0, 0, 0, 0, 0, 0}
     83};
     84
     85// Keep list of different supported games
     86static const struct KyraGameList {
     87        const char *name;
     88        const char *description;
     89        uint32 features;
     90        GameSettings toGameSettings() const {
     91                GameSettings dummy = { name, description, features };
     92                return dummy;
     93        }
     94} kyra_list[] = {
     95        {"kyra1", "Legend of Kyrandia", GF_KYRA1},
     96        {0, 0, 0}
    7097};
    7198
    7299GameList Engine_KYRA_gameList() {
    73100        GameList games;
    74         const KyraGameSettings *g = kyra_settings;
     101        const KyraGameList *g = kyra_list;
     102
    75103        while (g->name) {
    76104                games.push_back(g->toGameSettings());
    77105                g++;
     
    80108}
    81109
    82110DetectedGameList Engine_KYRA_detectGames(const FSList &fslist) {
    83         const KyraGameSettings *game;
    84111        DetectedGameList detectedGames;
     112        const KyraGameSettings *g;
     113        FSList::const_iterator file;
    85114
    86         for (game = kyra_settings; game->name; ++game) {
    87                 if (game->detectName == NULL)
     115        // Iterate over all files in the given directory
     116        bool isFound = false;
     117        for (file = fslist.begin(); file != fslist.end(); file++) {
     118                if (file->isDirectory())
    88119                        continue;
    89120
    90                 for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
    91                         if (!file->isDirectory()) {
    92                                 const char *name = file->displayName().c_str();
    93                                 if ((!scumm_stricmp(game->detectName, name))) {
    94                                         detectedGames.push_back(game->toGameSettings());
    95                                         break;
    96                                 }
    97                         }
     121                for (g = kyra_games; g->name; g++) {
     122                        if (scumm_stricmp(file->displayName().c_str(), g->checkFile) == 0)
     123                                isFound = true;
    98124                }
     125                if (isFound)
     126                        break;
    99127        }
    100128
     129        if (file == fslist.end())
     130                return detectedGames;
     131
     132        uint8 md5sum[16];
     133        char md5str[32 + 1];
     134
     135        if (Common::md5_file(file->path().c_str(), md5sum, NULL, kMD5FileSizeLimit)) {
     136                for (int i = 0; i < 16; i++) {
     137                        sprintf(md5str + i * 2, "%02x", (int)md5sum[i]);
     138                }
     139                for (g = kyra_games; g->name; g++) {
     140                        if (strcmp(g->md5sum, (char *)md5str) == 0) {
     141                                detectedGames.push_back(g->toGameSettings());
     142                        }
     143                }
     144                if (detectedGames.isEmpty()) {
     145                        printf("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5str);
     146
     147                        const KyraGameList *g1 = kyra_list;
     148                        while (g1->name) {
     149                                detectedGames.push_back(g1->toGameSettings());
     150                                g1++;
     151                        }
     152                }
     153        }
    101154        return detectedGames;
    102155}
    103156
     
    121174        _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
    122175        _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
    123176
    124         // gets the game
    125         if (detector->_game.features & GF_KYRA1) {
    126                 if (detector->_game.features & GF_DEMO) {
    127                         _game = KYRA1DEMO;
    128                 } else if (detector->_game.features & GF_FLOPPY) {
    129                         _game = KYRA1;
    130                 } else {
    131                         _game = KYRA1CD;
    132                 }
    133         } else if (detector->_game.features & GF_KYRA2) {
    134                 if (detector->_game.features & GF_FLOPPY) {
    135                         _game = KYRA2;
    136                 } else {
    137                         _game = KYRA2CD;
     177        // Detect game features based on MD5. Again brutally ripped from Gobliins.
     178        uint8 md5sum[16];
     179        char md5str[32 + 1];
     180
     181        const KyraGameSettings *g;
     182        bool found = false;
     183
     184        // TODO
     185        // Fallback. Maybe we will be able to determine game type from game
     186        // data contents
     187        _features = GF_KYRA1;
     188
     189        for (g = kyra_games; g->name; g++) {
     190                if (!Common::File::exists(g->checkFile))
     191                        continue;
     192
     193                if (Common::md5_file(g->checkFile, md5sum, ConfMan.get("path").c_str(), kMD5FileSizeLimit)) {
     194                        for (int j = 0; j < 16; j++) {
     195                                sprintf(md5str + j*2, "%02x", (int)md5sum[j]);
     196                        }
     197                } else
     198                        continue;
     199
     200                if (strcmp(g->md5sum, (char *)md5str) == 0) {
     201                        _features = g->features;
     202                        _game = g->id;
     203
     204                        if (g->description)
     205                                g_system->setWindowCaption(g->description);
     206
     207                        found = true;
     208                        break;
    138209                }
    139         } else if (detector->_game.features & GF_KYRA3) {
    140                 _game = KYRA3;
    141         } else {
    142                 error("unknown game");
     210        }
     211
     212        if (!found) {
     213                printf("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5str);
    143214        }
    144215}
    145216
     
    204275        _quitFlag = false;
    205276        uint32 sz;
    206277
    207         if (_game == KYRA1) {
     278        if (_features & GF_FLOPPY) {
    208279                _screen->loadFont(Screen::FID_6_FNT, _res->fileData("6.FNT", &sz));
    209280        }
    210281        _screen->loadFont(Screen::FID_8_FNT, _res->fileData("8FAT.FNT", &sz));
     
    212283
    213284        _abortIntroFlag = false;
    214285
    215         if (_game == KYRA1DEMO) {
     286        if (_features & GF_DEMO) {
    216287                seq_demo();
    217288        } else {
    218289                seq_intro();
     
    321392        _screen->clearPage(10);
    322393
    323394        // Loading GUI bitmap
    324         if (_game == KYRA1CD) {
     395        if (_features & GF_ENGLISH && _features & GF_TALKIE)
    325396                loadBitmap("MAIN_ENG.CPS", 10, 10, 0);
    326         } else {
     397        else if(_features & GF_FRENCH )
     398                loadBitmap("MAIN_FRE.CPS", 10, 10, 0);
     399        else if(_features & GF_GERMAN )
     400                loadBitmap("MAIN_GER.CPS", 10, 10, 0);
     401        else
    327402                loadBitmap("MAIN15.CPS", 10, 10, 0);
    328         }
    329403
    330404        // Loading main room background
    331405        strncpy(buf, _rooms[roomID].filename, 8);
     
    663737
    664738void KyraEngine::seq_intro() {
    665739        debug(9, "KyraEngine::seq_intro()");
    666         if (_game == KYRA1CD) {
     740        if (_features & GF_TALKIE) {
    667741                        _res->loadPakFile("INTRO.VRM");
    668742        }
    669743        static const IntroProc introProcTable[] = {
     
    686760        waitTicks(30);
    687761        _seq->setCopyViewOffs(false);
    688762        _midi->stopMusic();
    689         if (_game == KYRA1CD) {
     763        if (_features & GF_TALKIE) {
    690764                        _res->unloadPakFile("INTRO.VRM");
    691765        }
    692766}
     
    702776        _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200);
    703777        _screen->fadeFromBlack();
    704778       
    705         if (_game == KYRA1) {
     779        if (_features & GF_FLOPPY) {
    706780                if (_seq->playSequence(_seq_floppyData_WestwoodLogo, _skipIntroFlag)) {
    707781                        _screen->fadeToBlack();
    708782                        _screen->clearPage(0);
     
    714788                        _screen->clearPage(0);
    715789                        return;
    716790                }
    717         } else if (_game == KYRA1CD) {
     791        } else if (_features & GF_TALKIE) {
    718792                if (_seq->playSequence(_seq_cdromData_WestwoodLogo, _skipIntroFlag)) {
    719793                        _screen->fadeToBlack();
    720794                        _screen->clearPage(0);
     
    750824                waitTicks(1);
    751825        } while (y2 >= 64);
    752826
    753         if (_game == KYRA1) {
     827        if (_features & GF_FLOPPY) {
    754828                _seq->playSequence(_seq_floppyData_Forest, true);
    755         } else if (_game == KYRA1CD) {
     829        } else if (_features & GF_TALKIE) {
    756830                _seq->playSequence(_seq_cdromData_Forest, true);
    757831        }
    758832}
     
    768842        debug(9, "KyraEngine::seq_introMalcomTree()");
    769843        _screen->_curPage = 0;
    770844        _screen->clearPage(3);
    771         if (_game == KYRA1) {
     845        if (_features & GF_FLOPPY) {
    772846                _seq->playSequence(_seq_floppyData_MalcomTree, true);
    773         } else if (_game == KYRA1CD) {
     847        } else if (_features & GF_TALKIE) {
    774848                _seq->playSequence(_seq_cdromData_MalcomTree, true);
    775849        }
    776850}
     
    781855        _screen->setAnimBlockPtr(5060);
    782856        _screen->_charWidth = -2;
    783857        _screen->clearPage(3);
    784         if (_game == KYRA1) {
     858        if (_features & GF_FLOPPY) {
    785859                _seq->playSequence(_seq_floppyData_KallakWriting, true);
    786         } else if (_game == KYRA1CD) {
     860        } else if (_features & GF_TALKIE) {
    787861                _seq->playSequence(_seq_cdromData_KallakWriting, true);
    788862        }
    789863        _seq->freeHandShapes();
     
    792866void KyraEngine::seq_introKallakMalcom() {
    793867        debug(9, "KyraEngine::seq_introKallakMalcom()");
    794868        _screen->clearPage(3);
    795         if (_game == KYRA1) {
     869        if (_features & GF_FLOPPY) {
    796870                _seq->playSequence(_seq_floppyData_KallakMalcom, true);
    797         } else if (_game == KYRA1CD) {
     871        } else if (_features & GF_TALKIE) {
    798872                _seq->playSequence(_seq_cdromData_KallakMalcom, true);
    799873        }
    800874}
  • kyra/kyra.h

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvmcvs/kyra/kyra.h scummvm/kyra/kyra.h
    old new  
    2525#include "base/engine.h"
    2626#include "common/rect.h"
    2727#include "sound/mixer.h"
     28#include "common/file.h"
    2829
    2930class AudioStream;
    3031
     
    3940        GF_KYRA2   = 1 << 3,
    4041        GF_KYRA3   = 1 << 4,
    4142        GF_AUDIOCD = 1 << 5,  // FM-Towns versions seems to use audio CD
    42         GF_DEMO    = 1 << 6
     43        GF_DEMO    = 1 << 6,
     44        GF_ENGLISH = 1 << 7,
     45        GF_FRENCH  = 1 << 8,
     46        GF_GERMAN  = 1 << 9
     47
    4348};
    4449
    4550enum {
    46         KYRA1     = 0,
    47         KYRA1CD   = 1,
    48         KYRA1DEMO = 2,
    49         KYRA2     = 3,
    50         KYRA2CD   = 4,
    51         KYRA3     = 5
     51        GI_KYRA1 = 0
    5252};
    5353
    5454struct Character {
     
    157157
    158158        void waitTicks(int ticks);
    159159
     160        uint32 _features;
     161
    160162protected:
    161163
    162164        int go();
  • kyra/resource.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvmcvs/kyra/resource.cpp scummvm/kyra/resource.cpp
    old new  
    3030        _engine = engine;
    3131
    3232        // No PAK files in the demo version
    33         if (_engine->game() == KYRA1DEMO)
     33        if (_engine->_features & GF_DEMO)
    3434                return;
    3535
    3636        // prefetches all PAK Files
     
    6363
    6464        const char** usedFilelist = 0;
    6565
    66         if (_engine->game() == KYRA1)
     66        if (_engine->_features & GF_FLOPPY)
    6767                usedFilelist = kyra1Filelist;
    68         else if (_engine->game() == KYRA1CD)
     68        else if (_engine->_features & GF_TALKIE)
    6969                usedFilelist = kyra1CDFilelist;
    7070        else
    7171                error("no filelist found for this game");
     
    155155                       
    156156                        if (!(*size))
    157157                                continue;
    158 
     158                        debug("file: '%s'", file);
    159159                        buffer = new uint8[*size];
    160160                        assert(buffer);
    161161                       
  • kyra/screen.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvmcvs/kyra/screen.cpp scummvm/kyra/screen.cpp
    old new  
    549549        DrawShapePlotPixelCallback plotPixel = _drawShapePlotPixelTable[ppc];
    550550       
    551551        const uint8 *src = shapeData;
    552         if (_vm->game() == KYRA1CD) {
     552        if (_vm->_features & GF_TALKIE) {
    553553                src += 2;
    554554        }
    555555        uint16 shapeFlags = READ_LE_UINT16(src); src += 2;
  • kyra/seqplayer.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvmcvs/kyra/seqplayer.cpp scummvm/kyra/seqplayer.cpp
    old new  
    6060        uint16 numShapes = READ_LE_UINT16(data);
    6161        if (shape < numShapes) {
    6262                uint32 offs = 0;
    63                 if (_vm->game() == KYRA1CD) {
     63                if (_vm->_features & GF_TALKIE) {
    6464                        offs = READ_LE_UINT32(data + 2 + shape * 4);
    6565                } else {
    6666                        offs = READ_LE_UINT16(data + 2 + shape * 2);
     
    9898        assert(wsaObj < ARRAYSIZE(_seqMovies));
    9999        uint8 offscreenDecode = *_seqData++;
    100100        _seqWsaCurDecodePage = _seqMovies[wsaObj].page = (offscreenDecode == 0) ? 0 : 3;                               
    101         if (_vm->game() == KYRA1DEMO) {
     101        if (_vm->_features & GF_DEMO) {
    102102                _seqMovies[wsaObj].wsa = _vm->wsa_open(KyraEngine::_seq_demo_WSATable[wsaObj], offscreenDecode, 0);
    103103        } else {
    104104                _seqMovies[wsaObj].wsa = _vm->wsa_open(KyraEngine::_seq_WSATable[wsaObj], offscreenDecode, 0);
     
    212212        uint8 colNum = *_seqData++;
    213213        uint32 fileSize;
    214214        uint8 *srcData;
    215         if (_vm->game() == KYRA1DEMO) {
     215        if (_vm->_features & GF_DEMO) {
    216216                srcData = _res->fileData(KyraEngine::_seq_demo_COLTable[colNum], &fileSize);
    217217        } else {
    218218                srcData = _res->fileData(KyraEngine::_seq_COLTable[colNum], &fileSize);
     
    306306void SeqPlayer::s1_copyRegionSpecial() {
    307307        static const uint8 colorMap[] = { 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0 };
    308308        const char *copyStr = 0;
    309         if (_vm->game() == KYRA1 || _vm->game() == KYRA1DEMO) {
     309        if (_vm->_features & GF_FLOPPY || _vm->_features & GF_DEMO) {
    310310                copyStr = "Copyright (c) 1992 Westwood Studios";
    311         } else if (_vm->game() == KYRA1CD) {
     311        } else if (_vm->_features & GF_TALKIE) {
    312312                copyStr = "Copyright (c) 1992,1993 Westwood Studios";
    313313        }
    314314       
     
    364364
    365365void SeqPlayer::s1_soundUnk2() {
    366366        uint8 msg = *_seqData++;
    367         if (_vm->game() == KYRA1 || _vm->game() == KYRA1DEMO) {
     367        if (_vm->_features & GF_FLOPPY || _vm->_features & GF_DEMO) {
    368368                switch (msg) {
    369369                case 0:
    370370                        // nothing to do here...
     
    385385                        warning("Unknown seq. message: %.02d", msg);
    386386                        break;
    387387                }
    388         } else if (_vm->game() == KYRA1CD) {
     388        } else if (_vm->_features & GF_TALKIE) {
    389389                if (msg == 1) {
    390390                        _midi->beginFadeOut();
    391391                } else {
     
    395395}
    396396
    397397void SeqPlayer::s1_allocTempBuffer() {
    398         if (_vm->game() == KYRA1DEMO) {
     398        if (_vm->_features & GF_DEMO) {
    399399                _seqQuitFlag = true;
    400400        } else {
    401401                // allocate offscreen buffer, not needed
     
    532532
    533533        debug(9, "SeqPlayer::seq_playSequence(0x%X, %d)", seqData, skipSeq);
    534534
    535         if (_vm->game() == KYRA1 || _vm->game() == KYRA1DEMO) {
     535        if (_vm->_features & GF_FLOPPY || _vm->_features & GF_DEMO) {
    536536                commands = floppySeqProcs;
    537537                numCommands = ARRAYSIZE(floppySeqProcs);
    538         } else if (_vm->game() == KYRA1CD) {
     538        } else if (_vm->_features & GF_TALKIE) {
    539539                commands = cdromSeqProcs;
    540540                numCommands = ARRAYSIZE(cdromSeqProcs);
    541541        } else {
  • kyra/wsamovie.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvmcvs/kyra/wsamovie.cpp scummvm/kyra/wsamovie.cpp
    old new  
    4141        wsa->deltaBufferSize = READ_LE_UINT16(wsaData); wsaData += 2;
    4242        wsa->offscreenBuffer = NULL;
    4343        wsa->flags = 0;
    44         if (_game == KYRA1CD) {
     44        if (_features & GF_TALKIE) {
    4545                flags = READ_LE_UINT16(wsaData); wsaData += 2;
    4646        }
    4747