diff options
Diffstat (limited to 'engines')
100 files changed, 1739 insertions, 877 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index 72629a833e..7a09f662d1 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -41,8 +41,8 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa title = g.extra; extra = ""; } else { - while (sg->gameid) { - if (!scumm_stricmp(g.gameid, sg->gameid)) + while (sg->gameId) { + if (!scumm_stricmp(g.gameId, sg->gameId)) title = sg->description; sg++; } @@ -56,7 +56,7 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa else if (g.flags & ADGF_TESTING) gsl = kTestingGame; - GameDescriptor gd(g.gameid, title, g.language, g.platform, 0, gsl); + GameDescriptor gd(g.gameId, title, g.language, g.platform, 0, gsl); gd.updateDesc(extra); return gd; } @@ -89,21 +89,38 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD return res; } +static Common::String sanitizeName(const char *name) { + Common::String res; + + while (*name) { + if (Common::isAlnum(*name)) + res += tolower(*name); + name++; + } + + return res; +} + void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const { - if (_singleid != NULL) { + if (_singleId != NULL) { desc["preferredtarget"] = desc["gameid"]; - desc["gameid"] = _singleid; + desc["gameid"] = _singleId; } if (!desc.contains("preferredtarget")) desc["preferredtarget"] = desc["gameid"]; + if (realDesc->flags & ADGF_AUTOGENTARGET) { + if (*realDesc->extra) + desc["preferredtarget"] = sanitizeName(realDesc->extra); + } + desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc); if (_flags & kADFlagUseExtraAsHint) desc["extra"] = realDesc->extra; - desc.setGUIOptions(realDesc->guioptions + _guioptions); + desc.setGUIOptions(realDesc->guiOptions + _guiOptions); desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language)); if (realDesc->flags & ADGF_ADDENGLISH) @@ -149,7 +166,7 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { // Use fallback detector if there were no matches by other means const ADGameDescription *fallbackDesc = fallbackDetect(allFiles, fslist); if (fallbackDesc != 0) { - GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameids)); + GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameIds)); updateGameDescriptor(desc, fallbackDesc); detectedGames.push_back(desc); } @@ -157,7 +174,7 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { // Otherwise use the found matches cleanupPirated(matches); for (uint i = 0; i < matches.size(); i++) { - GameDescriptor desc(toGameDescriptor(*matches[i], _gameids)); + GameDescriptor desc(toGameDescriptor(*matches[i], _gameIds)); updateGameDescriptor(desc, matches[i]); detectedGames.push_back(desc); } @@ -252,10 +269,10 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (cleanupPirated(matches)) return Common::kNoGameDataFoundError; - if (_singleid == NULL) { + if (_singleId == NULL) { // Find the first match with correct gameid. for (uint i = 0; i < matches.size(); i++) { - if (matches[i]->gameid == gameid) { + if (matches[i]->gameId == gameid) { agdDesc = matches[i]; break; } @@ -270,7 +287,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (agdDesc != 0) { // Seems we found a fallback match. But first perform a basic // sanity check: the gameid must match. - if (_singleid == NULL && agdDesc->gameid != gameid) + if (_singleId == NULL && agdDesc->gameId != gameid) agdDesc = 0; } } @@ -284,9 +301,9 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) if (agdDesc->flags & ADGF_ADDENGLISH) lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY); - Common::updateGameGUIOptions(agdDesc->guioptions + _guioptions, lang); + Common::updateGameGUIOptions(agdDesc->guiOptions + _guiOptions, lang); - GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameids); + GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameIds); bool showTestingWarning = false; @@ -407,7 +424,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons // Check which files are included in some ADGameDescription *and* are present. // Compute MD5s and file sizes for these files. - for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize) { + for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize) { g = (const ADGameDescription *)descPtr; for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { @@ -430,7 +447,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons // MD5 based matching uint i; - for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize, ++i) { + for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize, ++i) { g = (const ADGameDescription *)descPtr; bool fileMissing = false; @@ -487,7 +504,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons gotAnyMatchesWithAllFiles = true; if (!fileMissing) { - debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameid, g->extra, + debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameId, g->extra, getPlatformDescription(g->platform), getLanguageDescription(g->language), i); if (curFilesMatched > maxFilesMatched) { @@ -503,7 +520,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons } } else { - debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameid, g->extra, + debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameId, g->extra, getPlatformDescription(g->platform), getLanguageDescription(g->language), i); } } @@ -543,7 +560,7 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap & } if (!fileMissing) { - debug(4, "Matched: %s", agdesc->gameid); + debug(4, "Matched: %s", agdesc->gameId); if (numMatchedFiles > maxNumMatchedFiles) { matchedDesc = agdesc; @@ -568,27 +585,27 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap & } GameList AdvancedMetaEngine::getSupportedGames() const { - if (_singleid != NULL) { + if (_singleId != NULL) { GameList gl; - const PlainGameDescriptor *g = _gameids; - while (g->gameid) { - if (0 == scumm_stricmp(_singleid, g->gameid)) { - gl.push_back(GameDescriptor(g->gameid, g->description)); + const PlainGameDescriptor *g = _gameIds; + while (g->gameId) { + if (0 == scumm_stricmp(_singleId, g->gameId)) { + gl.push_back(GameDescriptor(g->gameId, g->description)); return gl; } g++; } - error("Engine %s doesn't have its singleid specified in ids list", _singleid); + error("Engine %s doesn't have its singleid specified in ids list", _singleId); } - return GameList(_gameids); + return GameList(_gameIds); } -GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const { +GameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const { // First search the list of supported gameids for a match. - const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, _gameids); + const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds); if (g) return GameDescriptor(*g); @@ -596,14 +613,14 @@ GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const { return GameDescriptor(); } -AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions) - : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameids(gameids), +AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions) + : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameIds(gameIds), _extraGuiOptions(extraGuiOptions) { _md5Bytes = 5000; - _singleid = NULL; + _singleId = NULL; _flags = 0; - _guioptions = GUIO_NONE; + _guiOptions = GUIO_NONE; _maxScanDepth = 1; _directoryGlobs = NULL; } diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index ad551698f6..ab3ec22bdc 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -81,6 +81,7 @@ typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Has enum ADGameFlags { ADGF_NO_FLAGS = 0, + ADGF_AUTOGENTARGET = (1 << 20), // automatically generate gameid from extra ADGF_UNSTABLE = (1 << 21), // flag to designate not yet officially-supported games that are not fit for public testing ADGF_TESTING = (1 << 22), // flag to designate not yet officially-supported games that are fit for public testing ADGF_PIRATED = (1 << 23), ///< flag to designate well known pirated versions with cracks @@ -94,7 +95,7 @@ enum ADGameFlags { }; struct ADGameDescription { - const char *gameid; + const char *gameId; const char *extra; ADGameFileDescription filesDescriptions[14]; Common::Language language; @@ -107,7 +108,7 @@ struct ADGameDescription { */ uint32 flags; - const char *guioptions; + const char *guiOptions; }; /** @@ -191,7 +192,7 @@ protected: * A list of all gameids (and their corresponding descriptions) supported * by this engine. */ - const PlainGameDescriptor *_gameids; + const PlainGameDescriptor *_gameIds; /** * A map containing all the extra game GUI options the engine supports. @@ -219,7 +220,7 @@ protected: * address a more generic problem. We should find a better way to * disambiguate gameids. */ - const char *_singleid; + const char *_singleId; /** * A bitmask of flags which can be used to configure the behavior @@ -233,7 +234,7 @@ protected: * entry in addition to per-game options. Refer to GameGUIOption * enum for the list. */ - Common::String _guioptions; + Common::String _guiOptions; /** * Maximum depth of directories to look up. @@ -251,7 +252,7 @@ protected: const char * const *_directoryGlobs; public: - AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions = 0); + AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0); /** * Returns list of targets supported by the engine. @@ -259,7 +260,7 @@ public: */ virtual GameList getSupportedGames() const; - virtual GameDescriptor findGame(const char *gameid) const; + virtual GameDescriptor findGame(const char *gameId) const; virtual GameList detectGames(const Common::FSList &fslist) const; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 7d5fd3d668..9f66d78d80 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -202,8 +202,8 @@ class AgiMetaEngine : public AdvancedMetaEngine { public: AgiMetaEngine() : AdvancedMetaEngine(Agi::gameDescriptions, sizeof(Agi::AGIGameDescription), agiGames, optionsList) { - _singleid = "agi"; - _guioptions = GUIO1(GUIO_NOSPEECH); + _singleId = "agi"; + _guiOptions = GUIO1(GUIO_NOSPEECH); } virtual const char *getName() const { @@ -567,13 +567,13 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX // Override the gameid & extra values in g_fallbackDesc.desc. This only works // until the fallback detector is called again, and while the MetaEngine instance // is alive (as else the string storage is modified/deleted). - g_fallbackDesc.desc.gameid = _gameid.c_str(); + g_fallbackDesc.desc.gameId = _gameid.c_str(); g_fallbackDesc.desc.extra = _extra.c_str(); Common::String fallbackWarning; fallbackWarning = "Your game version has been detected using fallback matching as a\n"; - fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); + fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameId, g_fallbackDesc.desc.extra); fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n"; fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n"; diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp index 82f8ad4bf2..2c89522089 100644 --- a/engines/agos/detection.cpp +++ b/engines/agos/detection.cpp @@ -94,13 +94,13 @@ using namespace AGOS; class AgosMetaEngine : public AdvancedMetaEngine { public: AgosMetaEngine() : AdvancedMetaEngine(AGOS::gameDescriptions, sizeof(AGOS::AGOSGameDescription), agosGames) { - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); + _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); + virtual GameDescriptor findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } virtual const char *getName() const { diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp index 1ea72b613a..e35c5d2cac 100644 --- a/engines/avalanche/detection.cpp +++ b/engines/avalanche/detection.cpp @@ -40,7 +40,7 @@ uint32 AvalancheEngine::getFeatures() const { } const char *AvalancheEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } static const PlainGameDescriptor avalancheGames[] = { diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp index 37b5e398df..7c0045ee73 100644 --- a/engines/bbvs/detection.cpp +++ b/engines/bbvs/detection.cpp @@ -69,7 +69,7 @@ static const char * const directoryGlobs[] = { class BbvsMetaEngine : public AdvancedMetaEngine { public: BbvsMetaEngine() : AdvancedMetaEngine(Bbvs::gameDescriptions, sizeof(ADGameDescription), bbvsGames) { - _singleid = "bbvs"; + _singleId = "bbvs"; _maxScanDepth = 3; _directoryGlobs = directoryGlobs; } diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index 95705cbebc..52168dc934 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -115,7 +115,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class CGEMetaEngine : public AdvancedMetaEngine { public: CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames, optionsList) { - _singleid = "soltys"; + _singleId = "soltys"; } virtual const char *getName() const { diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp index 3ccfffe43f..01119bb1fd 100644 --- a/engines/cge2/detection.cpp +++ b/engines/cge2/detection.cpp @@ -111,7 +111,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class CGE2MetaEngine : public AdvancedMetaEngine { public: CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games, optionsList) { - _singleid = "sfinx"; + _singleId = "sfinx"; } virtual const char *getName() const { diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp index 5e1ffadb1b..ec01e8734d 100644 --- a/engines/cine/detection.cpp +++ b/engines/cine/detection.cpp @@ -80,12 +80,12 @@ static const ADExtraGuiOptionsMap optionsList[] = { class CineMetaEngine : public AdvancedMetaEngine { public: CineMetaEngine() : AdvancedMetaEngine(Cine::gameDescriptions, sizeof(Cine::CINEGameDescription), cineGames, optionsList) { - _singleid = "cine"; - _guioptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD); + _singleId = "cine"; + _guiOptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD); } - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); + virtual GameDescriptor findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } virtual const char *getName() const { diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp index e250996371..a3ab18ae54 100644 --- a/engines/composer/detection.cpp +++ b/engines/composer/detection.cpp @@ -38,7 +38,7 @@ int ComposerEngine::getGameType() const { } const char *ComposerEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 ComposerEngine::getFeatures() const { @@ -386,7 +386,7 @@ static const char *directoryGlobs[] = { class ComposerMetaEngine : public AdvancedMetaEngine { public: ComposerMetaEngine() : AdvancedMetaEngine(Composer::gameDescriptions, sizeof(Composer::ComposerGameDescription), composerGames) { - _singleid = "composer"; + _singleId = "composer"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index 69e1bc4ad0..6f5d236173 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -35,7 +35,7 @@ struct CRUISEGameDescription { }; const char *CruiseEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } Common::Language CruiseEngine::getLanguage() const { @@ -196,8 +196,8 @@ static const CRUISEGameDescription gameDescriptions[] = { class CruiseMetaEngine : public AdvancedMetaEngine { public: CruiseMetaEngine() : AdvancedMetaEngine(Cruise::gameDescriptions, sizeof(Cruise::CRUISEGameDescription), cruiseGames) { - _singleid = "cruise"; - _guioptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); + _singleId = "cruise"; + _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); } virtual const char *getName() const { diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp index 82b6935d72..65427bd8cd 100644 --- a/engines/draci/detection.cpp +++ b/engines/draci/detection.cpp @@ -84,7 +84,7 @@ const ADGameDescription gameDescriptions[] = { class DraciMetaEngine : public AdvancedMetaEngine { public: DraciMetaEngine() : AdvancedMetaEngine(Draci::gameDescriptions, sizeof(ADGameDescription), draciGames) { - _singleid = "draci"; + _singleId = "draci"; } virtual const char *getName() const { diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index 9a2da1d732..ffec393a0a 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -310,8 +310,8 @@ SaveStateDescriptor loadMetaData(Common::ReadStream *s, int slot, bool setPlayTi class DrasculaMetaEngine : public AdvancedMetaEngine { public: DrasculaMetaEngine() : AdvancedMetaEngine(Drascula::gameDescriptions, sizeof(Drascula::DrasculaGameDescription), drasculaGames) { - _singleid = "drascula"; - _guioptions = GUIO1(GUIO_NOMIDI); + _singleId = "drascula"; + _guiOptions = GUIO1(GUIO_NOMIDI); } virtual const char *getName() const { diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index 853047ccc7..764171bcb0 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -70,8 +70,8 @@ public: AdvancedMetaEngine(DreamWeb::gameDescriptions, sizeof(DreamWeb::DreamWebGameDescription), dreamWebGames, gameGuiOptions) { - _singleid = "dreamweb"; - _guioptions = GUIO1(GUIO_NOMIDI); + _singleId = "dreamweb"; + _guiOptions = GUIO1(GUIO_NOMIDI); } virtual const char *getName() const { diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp index 99fbdc4b82..6f92f19f24 100644 --- a/engines/fullpipe/detection.cpp +++ b/engines/fullpipe/detection.cpp @@ -32,7 +32,7 @@ namespace Fullpipe { const char *FullpipeEngine::getGameId() const { - return _gameDescription->gameid; + return _gameDescription->gameId; } } @@ -76,7 +76,7 @@ static const ADGameDescription gameDescriptions[] = { class FullpipeMetaEngine : public AdvancedMetaEngine { public: FullpipeMetaEngine() : AdvancedMetaEngine(Fullpipe::gameDescriptions, sizeof(ADGameDescription), fullpipeGames) { - _singleid = "fullpipe"; + _singleId = "fullpipe"; } virtual const char *getName() const { diff --git a/engines/game.cpp b/engines/game.cpp index 85ad6fe2e8..7ff51a99cc 100644 --- a/engines/game.cpp +++ b/engines/game.cpp @@ -26,8 +26,8 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) { const PlainGameDescriptor *g = list; - while (g->gameid) { - if (0 == scumm_stricmp(gameid, g->gameid)) + while (g->gameId) { + if (0 == scumm_stricmp(gameid, g->gameId)) return g; g++; } @@ -40,7 +40,7 @@ GameDescriptor::GameDescriptor() { } GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions) { - setVal("gameid", pgd.gameid); + setVal("gameid", pgd.gameId); setVal("description", pgd.description); if (!guioptions.empty()) diff --git a/engines/game.h b/engines/game.h index a9bec8f9e0..e01e5c6885 100644 --- a/engines/game.h +++ b/engines/game.h @@ -36,7 +36,7 @@ * consisting of PlainGameDescriptors. */ struct PlainGameDescriptor { - const char *gameid; + const char *gameId; const char *description; }; @@ -108,7 +108,7 @@ public: GameList() {} GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {} GameList(const PlainGameDescriptor *g) { - while (g->gameid) { + while (g->gameId) { push_back(GameDescriptor(*g)); g++; } diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp index 3b26f63c39..b0aa78f416 100644 --- a/engines/gob/detection/detection.cpp +++ b/engines/gob/detection/detection.cpp @@ -33,7 +33,7 @@ class GobMetaEngine : public AdvancedMetaEngine { public: GobMetaEngine(); - virtual GameDescriptor findGame(const char *gameid) const; + virtual GameDescriptor findGame(const char *gameId) const; virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const; @@ -55,12 +55,12 @@ private: GobMetaEngine::GobMetaEngine() : AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) { - _singleid = "gob"; - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); + _singleId = "gob"; + _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD); } -GameDescriptor GobMetaEngine::findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); +GameDescriptor GobMetaEngine::findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp index a249b66858..b12e264a57 100644 --- a/engines/groovie/detection.cpp +++ b/engines/groovie/detection.cpp @@ -322,7 +322,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class GroovieMetaEngine : public AdvancedMetaEngine { public: GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames, optionsList) { - _singleid = "groovie"; + _singleId = "groovie"; // Use kADFlagUseExtraAsHint in order to distinguish the 11th hour from // its "Making of" as well as the Clandestiny Trailer; they all share @@ -333,7 +333,7 @@ public: // to the detection entries. In the latter case, this TODO should be // replaced with an according explanation. _flags = kADFlagUseExtraAsHint; - _guioptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT); + _guiOptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT); // Need MIDI directory to detect 11H Mac Installed _maxScanDepth = 2; diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp index c48a26b405..4e4746c002 100644 --- a/engines/hugo/detection.cpp +++ b/engines/hugo/detection.cpp @@ -41,7 +41,7 @@ uint32 HugoEngine::getFeatures() const { } const char *HugoEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp index 8d81e5f0ae..1fd3ca8944 100644 --- a/engines/lab/detection.cpp +++ b/engines/lab/detection.cpp @@ -115,7 +115,7 @@ uint32 LabEngine::getFeatures() const { class LabMetaEngine : public AdvancedMetaEngine { public: LabMetaEngine() : AdvancedMetaEngine(labDescriptions, sizeof(ADGameDescription), lab_setting) { - _singleid = "lab"; + _singleId = "lab"; _maxScanDepth = 4; _directoryGlobs = directoryGlobs; @@ -197,26 +197,7 @@ int LabMetaEngine::getMaximumSaveSlot() const { void LabMetaEngine::removeSaveState(const char *target, int slot) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); - Common::String filename = Common::String::format("%s.%03u", target, slot); - - saveFileMan->removeSavefile(filename.c_str()); - - Common::StringArray filenames; - Common::String pattern = target; - pattern += ".###"; - filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) - - for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { - // Obtain the last 3 digits of the filename, since they correspond to the save slot - int slotNum = atoi(file->c_str() + file->size() - 3); - - // Rename every slot greater than the deleted slot, - if (slotNum > slot) { - saveFileMan->renameSavefile(file->c_str(), filename.c_str()); - filename = Common::String::format("%s.%03u", target, ++slot); - } - } + saveFileMan->removeSavefile(Common::String::format("%s.%03u", target, slot)); } SaveStateDescriptor LabMetaEngine::querySaveMetaInfos(const char *target, int slot) const { diff --git a/engines/lab/processroom.cpp b/engines/lab/processroom.cpp index 44c8d65d7c..5093e8ef85 100644 --- a/engines/lab/processroom.cpp +++ b/engines/lab/processroom.cpp @@ -238,6 +238,8 @@ void LabEngine::doActions(const ActionList &actionList) { ActionList::const_iterator action; for (action = actionList.begin(); action != actionList.end(); ++action) { updateEvents(); + if (_quitLab || shouldQuit()) + return; switch (action->_actionType) { case kActionPlaySound: @@ -381,6 +383,8 @@ void LabEngine::doActions(const ActionList &actionList) { while (_system->getMillis() < targetMillis) { updateEvents(); + if (_quitLab || shouldQuit()) + return; _anim->diffNextFrame(); } } @@ -409,6 +413,8 @@ void LabEngine::doActions(const ActionList &actionList) { case kActionWaitSound: // used in scene 44 (heart of the labyrinth / ending) while (_music->isSoundEffectActive()) { updateEvents(); + if (_quitLab || shouldQuit()) + return; _anim->diffNextFrame(); waitTOF(); } diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp index d790582104..52224e4ea5 100644 --- a/engines/lastexpress/detection.cpp +++ b/engines/lastexpress/detection.cpp @@ -199,8 +199,8 @@ static const ADGameDescription gameDescriptions[] = { class LastExpressMetaEngine : public AdvancedMetaEngine { public: LastExpressMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), lastExpressGames) { - _singleid = "lastexpress"; - _guioptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOSFX); + _singleId = "lastexpress"; + _guiOptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOSFX); } const char *getName() const { diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp index d0a8ee0b4a..690a358bc3 100644 --- a/engines/lure/detection.cpp +++ b/engines/lure/detection.cpp @@ -193,12 +193,12 @@ class LureMetaEngine : public AdvancedMetaEngine { public: LureMetaEngine() : AdvancedMetaEngine(Lure::gameDescriptions, sizeof(Lure::LureGameDescription), lureGames) { _md5Bytes = 1024; - _singleid = "lure"; + _singleId = "lure"; // Use kADFlagUseExtraAsHint to distinguish between EGA and VGA versions // of italian Lure when their datafiles sit in the same directory. _flags = kADFlagUseExtraAsHint; - _guioptions = GUIO1(GUIO_NOSPEECH); + _guiOptions = GUIO1(GUIO_NOSPEECH); } virtual const char *getName() const { diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp index 7adc3e1f98..636c2d147c 100644 --- a/engines/made/detection.cpp +++ b/engines/made/detection.cpp @@ -521,7 +521,7 @@ static MadeGameDescription g_fallbackDesc = { class MadeMetaEngine : public AdvancedMetaEngine { public: MadeMetaEngine() : AdvancedMetaEngine(Made::gameDescriptions, sizeof(Made::MadeGameDescription), madeGames) { - _singleid = "made"; + _singleId = "made"; } virtual const char *getName() const { diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp index 2579712105..a64d7ff7df 100644 --- a/engines/mohawk/detection.cpp +++ b/engines/mohawk/detection.cpp @@ -54,7 +54,7 @@ struct MohawkGameDescription { }; const char* MohawkEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 MohawkEngine::getFeatures() const { @@ -178,7 +178,7 @@ static const ADExtraGuiOptionsMap optionsList[] = { class MohawkMetaEngine : public AdvancedMetaEngine { public: MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames, optionsList) { - _singleid = "mohawk"; + _singleId = "mohawk"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp index b6c27e6b12..6791707dd5 100644 --- a/engines/mortevielle/detection.cpp +++ b/engines/mortevielle/detection.cpp @@ -55,7 +55,7 @@ public: MortevielleMetaEngine() : AdvancedMetaEngine(Mortevielle::MortevielleGameDescriptions, sizeof(Mortevielle::MortevielleGameDescription), MortevielleGame) { _md5Bytes = 512; - _singleid = "mortevielle"; + _singleId = "mortevielle"; // Use kADFlagUseExtraAsHint to distinguish between original and improved versions // (i.e. use or not of the game data file). _flags = kADFlagUseExtraAsHint; diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp index c663d5d3a4..cfddc2d6b4 100644 --- a/engines/neverhood/detection.cpp +++ b/engines/neverhood/detection.cpp @@ -41,7 +41,7 @@ struct NeverhoodGameDescription { }; const char *NeverhoodEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 NeverhoodEngine::getFeatures() const { @@ -181,8 +181,8 @@ static const ExtraGuiOption neverhoodExtraGuiOption3 = { class NeverhoodMetaEngine : public AdvancedMetaEngine { public: NeverhoodMetaEngine() : AdvancedMetaEngine(Neverhood::gameDescriptions, sizeof(Neverhood::NeverhoodGameDescription), neverhoodGames) { - _singleid = "neverhood"; - _guioptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI); + _singleId = "neverhood"; + _guiOptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI); } virtual const char *getName() const { diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 0c7ebb2b05..4c52990874 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -220,7 +220,7 @@ static const PARALLACTIONGameDescription gameDescriptions[] = { class ParallactionMetaEngine : public AdvancedMetaEngine { public: ParallactionMetaEngine() : AdvancedMetaEngine(Parallaction::gameDescriptions, sizeof(Parallaction::PARALLACTIONGameDescription), parallactionGames) { - _guioptions = GUIO1(GUIO_NOLAUNCHLOAD); + _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD); } virtual const char *getName() const { diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp index 721c382d4f..161a133c8b 100644 --- a/engines/pegasus/detection.cpp +++ b/engines/pegasus/detection.cpp @@ -134,7 +134,7 @@ static const PegasusGameDescription gameDescriptions[] = { class PegasusMetaEngine : public AdvancedMetaEngine { public: PegasusMetaEngine() : AdvancedMetaEngine(Pegasus::gameDescriptions, sizeof(Pegasus::PegasusGameDescription), pegasusGames) { - _singleid = "pegasus"; + _singleId = "pegasus"; } virtual const char *getName() const { diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp index 3fe7993fdb..1c6f63aff3 100644 --- a/engines/prince/detection.cpp +++ b/engines/prince/detection.cpp @@ -29,7 +29,7 @@ int PrinceEngine::getGameType() const { } const char *PrinceEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 PrinceEngine::getFeatures() const { diff --git a/engines/prince/detection.h b/engines/prince/detection.h index 7e5bdd6b7b..3076253cf5 100644 --- a/engines/prince/detection.h +++ b/engines/prince/detection.h @@ -104,7 +104,7 @@ const static char *directoryGlobs[] = { class PrinceMetaEngine : public AdvancedMetaEngine { public: PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) { - _singleid = "prince"; + _singleId = "prince"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/queen/detection.cpp b/engines/queen/detection.cpp index 4e87b7e5c2..81e0767836 100644 --- a/engines/queen/detection.cpp +++ b/engines/queen/detection.cpp @@ -401,7 +401,7 @@ static const QueenGameDescription gameDescriptions[] = { class QueenMetaEngine : public AdvancedMetaEngine { public: QueenMetaEngine() : AdvancedMetaEngine(Queen::gameDescriptions, sizeof(Queen::QueenGameDescription), queenGames, optionsList) { - _singleid = "queen"; + _singleId = "queen"; } virtual const char *getName() const { @@ -443,25 +443,25 @@ const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles } Queen::DetectedGameVersion version; if (Queen::Resource::detectVersion(&version, &dataFile)) { - desc.gameid = "queen"; + desc.gameId = "queen"; desc.language = version.language; desc.platform = version.platform; desc.flags = ADGF_NO_FLAGS; - desc.guioptions = GUIO0(); + desc.guiOptions = GUIO0(); if (version.features & Queen::GF_DEMO) { desc.extra = "Demo"; desc.flags = ADGF_DEMO; - desc.guioptions = GUIO_NOSPEECH; + desc.guiOptions = GUIO_NOSPEECH; } else if (version.features & Queen::GF_INTERVIEW) { desc.extra = "Interview"; desc.flags = ADGF_DEMO; - desc.guioptions = GUIO_NOSPEECH; + desc.guiOptions = GUIO_NOSPEECH; } else if (version.features & Queen::GF_FLOPPY) { desc.extra = "Floppy"; - desc.guioptions = GUIO_NOSPEECH; + desc.guiOptions = GUIO_NOSPEECH; } else if (version.features & Queen::GF_TALKIE) { desc.extra = "Talkie"; - desc.guioptions = GAMEOPTION_ALT_INTRO; + desc.guiOptions = GAMEOPTION_ALT_INTRO; } return (const ADGameDescription *)&desc; } diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index e201612beb..0677e84d67 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -102,11 +102,11 @@ static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = { class SagaMetaEngine : public AdvancedMetaEngine { public: SagaMetaEngine() : AdvancedMetaEngine(Saga::gameDescriptions, sizeof(Saga::SAGAGameDescription), sagaGames) { - _singleid = "saga"; + _singleId = "saga"; } - virtual GameDescriptor findGame(const char *gameid) const { - return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable); + virtual GameDescriptor findGame(const char *gameId) const { + return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable); } virtual const char *getName() const { diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 6cd072ee8b..a092e0676d 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -141,6 +141,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), registerCmd("vpl", WRAP_METHOD(Console, cmdVisiblePlaneList)); // alias registerCmd("plane_items", WRAP_METHOD(Console, cmdPlaneItemList)); registerCmd("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias + registerCmd("visible_plane_items", WRAP_METHOD(Console, cmdVisiblePlaneItemList)); + registerCmd("vpi", WRAP_METHOD(Console, cmdVisiblePlaneItemList)); // alias registerCmd("saved_bits", WRAP_METHOD(Console, cmdSavedBits)); registerCmd("show_saved_bits", WRAP_METHOD(Console, cmdShowSavedBits)); // Segments @@ -386,6 +388,7 @@ bool Console::cmdHelp(int argc, const char **argv) { debugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n"); debugPrintf(" visible_plane_list / vpl - Shows a list of all the planes in the visible draw list (SCI2+)\n"); debugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n"); + debugPrintf(" visible_plane_items / vpi - Shows a list of all items for a plane in the visible draw list (SCI2+)\n"); debugPrintf(" saved_bits - List saved bits on the hunk\n"); debugPrintf(" show_saved_bits - Display saved bits\n"); debugPrintf("\n"); @@ -1817,6 +1820,34 @@ bool Console::cmdPlaneItemList(int argc, const char **argv) { return true; } +bool Console::cmdVisiblePlaneItemList(int argc, const char **argv) { + if (argc != 2) { + debugPrintf("Shows the list of items for a plane\n"); + debugPrintf("Usage: %s <plane address>\n", argv[0]); + return true; + } + + reg_t planeObject = NULL_REG; + + if (parse_reg_t(_engine->_gamestate, argv[1], &planeObject, false)) { + debugPrintf("Invalid address passed.\n"); + debugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + debugPrintf("Visible plane item list:\n"); + _engine->_gfxFrameout->printVisiblePlaneItemList(this, planeObject); + } else { + debugPrintf("This SCI version does not have a list of plane items\n"); + } +#else + debugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} + bool Console::cmdSavedBits(int argc, const char **argv) { SegManager *segman = _engine->_gamestate->_segMan; SegmentId id = segman->findSegmentByType(SEG_TYPE_HUNK); diff --git a/engines/sci/console.h b/engines/sci/console.h index b20f1f7251..cf85def950 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -98,6 +98,7 @@ private: bool cmdPlaneList(int argc, const char **argv); bool cmdVisiblePlaneList(int argc, const char **argv); bool cmdPlaneItemList(int argc, const char **argv); + bool cmdVisiblePlaneItemList(int argc, const char **argv); bool cmdSavedBits(int argc, const char **argv); bool cmdShowSavedBits(int argc, const char **argv); // Segments diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 985e12a7f6..c920ef10e2 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -98,8 +98,11 @@ static const PlainGameDescriptor s_sciGameTitles[] = { {"lsl6", "Leisure Suit Larry 6: Shape Up or Slip Out!"}, {"pepper", "Pepper's Adventure in Time"}, {"slater", "Slater & Charlie Go Camping"}, + {"gk1demo", "Gabriel Knight: Sins of the Fathers"}, + {"qfg4demo", "Quest for Glory IV: Shadows of Darkness"}, + {"pq4demo", "Police Quest IV: Open Season"}, // === SCI2 games ========================================================= - {"gk1", "Gabriel Knight: Sins of the Fathers"}, // demo is SCI11, full version SCI32 + {"gk1", "Gabriel Knight: Sins of the Fathers"}, {"pq4", "Police Quest IV: Open Season"}, // floppy is SCI2, CD SCI2.1 {"qfg4", "Quest for Glory IV: Shadows of Darkness"}, // floppy is SCI2, CD SCI2.1 // === SCI2.1 games ======================================================== @@ -146,6 +149,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = { { "fairytales", GID_FAIRYTALES }, { "freddypharkas", GID_FREDDYPHARKAS }, { "funseeker", GID_FUNSEEKER }, + { "gk1demo", GID_GK1DEMO }, { "gk1", GID_GK1 }, { "gk2", GID_GK2 }, { "hoyle1", GID_HOYLE1 }, @@ -183,12 +187,14 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = { { "pq2", GID_PQ2 }, { "pq3", GID_PQ3 }, { "pq4", GID_PQ4 }, + { "pq4demo", GID_PQ4DEMO }, { "pqswat", GID_PQSWAT }, { "qfg1", GID_QFG1 }, { "qfg1vga", GID_QFG1VGA }, { "qfg2", GID_QFG2 }, { "qfg3", GID_QFG3 }, { "qfg4", GID_QFG4 }, + { "qfg4demo", GID_QFG4DEMO }, { "rama", GID_RAMA }, { "sci-fanmade", GID_FANMADE }, // FIXME: Do we really need/want this? { "shivers", GID_SHIVERS }, @@ -356,7 +362,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R // qfg4 demo has less than 50 scripts if (resources.size() < 50) - return "qfg4"; + return "qfg4demo"; // Otherwise it's qfg3 return "qfg3"; @@ -473,7 +479,7 @@ static char s_fallbackGameIdBuf[256]; class SciMetaEngine : public AdvancedMetaEngine { public: SciMetaEngine() : AdvancedMetaEngine(Sci::SciGameDescriptions, sizeof(ADGameDescription), s_sciGameTitles, optionsList) { - _singleid = "sci"; + _singleId = "sci"; } virtual const char *getName() const { @@ -526,8 +532,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, s_fallbackDesc.language = Common::EN_ANY; s_fallbackDesc.flags = ADGF_NO_FLAGS; s_fallbackDesc.platform = Common::kPlatformDOS; // default to PC platform - s_fallbackDesc.gameid = "sci"; - s_fallbackDesc.guioptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); + s_fallbackDesc.gameId = "sci"; + s_fallbackDesc.guiOptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); if (allFiles.contains("resource.map") || allFiles.contains("Data1") || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) { @@ -610,7 +616,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan); strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1); s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0; // Make sure string is NULL terminated - s_fallbackDesc.gameid = s_fallbackGameIdBuf; + s_fallbackDesc.gameId = s_fallbackGameIdBuf; // Try to determine the game language // Load up text 0 and start looking for "#" characters @@ -653,7 +659,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const bool isCD = (s_fallbackDesc.flags & ADGF_CD); if (!isCD) - s_fallbackDesc.guioptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); + s_fallbackDesc.guiOptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI); if (gameId.hasSuffix("sci")) { s_fallbackDesc.extra = "SCI"; @@ -686,7 +692,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { const GameIdStrToEnum *g = s_gameIdStrToEnum; for (; g->gameidStr; ++g) { - if (0 == strcmp(desc->gameid, g->gameidStr)) { + if (0 == strcmp(desc->gameId, g->gameidStr)) { *engine = new SciEngine(syst, desc, g->gameidEnum); return true; } diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 11218142a4..d84500cc60 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -684,21 +684,23 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Gabriel Knight - English DOS CD Demo + // Gabriel Knight - English DOS Demo // SCI interpreter version 1.001.092 - {"gk1", "CD Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like gk1demo-demo + {"gk1demo", "Demo", { {"resource.map", 0, "39645952ae0ed8072c7e838f31b75464", 2490}, {"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, - // Gabriel Knight - English DOS CD Demo (from DrMcCoy) + // Gabriel Knight - English DOS Demo (from DrMcCoy) // SCI interpreter version 1.001.092 - {"gk1", "CD Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like gk1demo-demo + {"gk1demo", "Demo", { {"resource.map", 0, "8cad2a256f41463030cbb7ea1bfb2857", 2490}, {"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Gabriel Knight - English DOS Floppy @@ -2976,11 +2978,12 @@ static const struct ADGameDescription SciGameDescriptions[] = { // Police Quest 4 - English DOS Non-Interactive Demo (from FRG) // SCI interpreter version 1.001.096 - {"pq4", "Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like pq4demo-demo + {"pq4demo", "Demo", { {"resource.map", 0, "be56f87a1c4a13062a30a362df860c2f", 1472}, {"resource.000", 0, "527d5684016e6816157cd15d9071b11b", 1121310}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Police Quest 4 - English DOS CD (from the Police Quest Collection) @@ -3388,11 +3391,12 @@ static const struct ADGameDescription SciGameDescriptions[] = { // Quest for Glory 4 - English DOS Non-Interactive Demo (from FRG) // SCI interpreter version 1.001.069 (just a guess) - {"qfg4", "Demo", { + // Note: we are not using ADGF_DEMO here, to avoid a game ID like qfg4demo-demo + {"qfg4demo", "Demo", { {"resource.map", 0, "1ba7c7ae1efb315326d45cb931569b1b", 922}, {"resource.000", 0, "41ba03f0b188b029132daa3ece0d3e14", 623154}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, #ifdef ENABLE_SCI32 // Quest for Glory 4 1.1 Floppy - English DOS (supplied by markcool in bug report #2723852) diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 0df4701334..796dea2382 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -853,7 +853,7 @@ void Kernel::loadKernelNames(GameFeatures *features) { _kernelNames[0x26] = "Portrait"; else if (g_sci->getPlatform() == Common::kPlatformMacintosh) _kernelNames[0x84] = "ShowMovie"; - } else if (g_sci->getGameId() == GID_QFG4 && g_sci->isDemo()) { + } else if (g_sci->getGameId() == GID_QFG4DEMO) { _kernelNames[0x7b] = "RemapColors"; // QFG4 Demo has this SCI2 function instead of StrSplit } diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index c0a3be4c11..93d0d91b65 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -45,6 +45,7 @@ #include "sci/graphics/paint16.h" #include "sci/graphics/picture.h" #include "sci/graphics/ports.h" +#include "sci/graphics/remap.h" #include "sci/graphics/screen.h" #include "sci/graphics/text16.h" #include "sci/graphics/view.h" @@ -1248,16 +1249,16 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) { switch (operation) { case 0: { // remap by percent uint16 percent = argv[1].toUint16(); - g_sci->_gfxPalette16->resetRemapping(); - g_sci->_gfxPalette16->setRemappingPercent(254, percent); + g_sci->_gfxRemap16->resetRemapping(); + g_sci->_gfxRemap16->setRemappingPercent(254, percent); } break; case 1: { // remap by range uint16 from = argv[1].toUint16(); uint16 to = argv[2].toUint16(); uint16 base = argv[3].toUint16(); - g_sci->_gfxPalette16->resetRemapping(); - g_sci->_gfxPalette16->setRemappingRange(254, from, to, base); + g_sci->_gfxRemap16->resetRemapping(); + g_sci->_gfxRemap16->setRemappingRange(254, from, to, base); } break; case 2: // turn remapping off (unused) diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 0463b125ae..9c5d214488 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -152,12 +152,12 @@ reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { // Tests if the coordinate is on the passed object reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { - uint16 x = argv[0].toUint16(); - uint16 y = argv[1].toUint16(); - reg_t targetObject = argv[2]; - uint16 checkPixels = argv[3].getOffset(); + int16 x = argv[0].toSint16(); + int16 y = argv[1].toSint16(); + reg_t object = argv[2]; + bool checkPixel = argv[3].toSint16(); - return make_reg(0, g_sci->_gfxFrameout->kernelIsOnMe(x, y, checkPixels, targetObject)); + return g_sci->_gfxFrameout->kernelIsOnMe(object, Common::Point(x, y), checkPixel); } reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { @@ -197,16 +197,14 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { if (subop == 0) { TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode)); - reg_t out; - return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true, &out); + return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true); } else { CelInfo32 celInfo; celInfo.type = kCelTypeView; celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view)); celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel)); - reg_t out; - return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed, &out); + return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed); } } @@ -506,7 +504,6 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { } reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) { - uint32 bitmapHeaderSize = CelObjMem::getBitmapHeaderSize(); int16 width = argv[0].toSint16(); int16 height = argv[1].toSint16(); int16 skipColor = argv[2].toSint16(); @@ -515,11 +512,9 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) { int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight; bool useRemap = argc > 6 ? argv[6].toSint16() : false; - reg_t bitmapMemId = s->_segMan->allocateHunkEntry("Bitmap()", width * height + bitmapHeaderSize); - byte *bitmap = s->_segMan->getHunkPointer(bitmapMemId); - memset(bitmap + bitmapHeaderSize, backColor, width * height); - CelObjMem::buildBitmapHeader(bitmap, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap); - return bitmapMemId; + BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap); + memset(bitmap.getPixels(), backColor, width * height); + return bitmap.getObject(); } reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) { @@ -579,7 +574,37 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) { // called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894 // bitmap, text, textLeft, textTop, textRight, textBottom, foreColor, backColor, skipColor, fontNo, alignment, borderColor, dimmed - return kStubNull(s, argc + 1, argv - 1); + BitmapResource bitmap(argv[0]); + Common::String text = s->_segMan->getString(argv[1]); + Common::Rect textRect( + argv[2].toSint16(), + argv[3].toSint16(), + argv[4].toSint16() + 1, + argv[5].toSint16() + 1 + ); + int16 foreColor = argv[6].toSint16(); + int16 backColor = argv[7].toSint16(); + int16 skipColor = argv[8].toSint16(); + GuiResourceId fontId = (GuiResourceId)argv[9].toUint16(); + TextAlign alignment = (TextAlign)argv[10].toSint16(); + int16 borderColor = argv[11].toSint16(); + bool dimmed = argv[12].toUint16(); + + // NOTE: Technically the engine checks these things: + // textRect.bottom > 0 + // textRect.right > 0 + // textRect.left < bitmap.width + // textRect.top < bitmap.height + // Then clips. But this seems stupid. + textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight())); + + reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false); + Buffer bitmapBuffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels()); + CelObjMem textCel(textBitmapObject); + textCel.draw(bitmapBuffer, textRect, Common::Point(textRect.left, textRect.top), false); + s->_segMan->freeHunkEntry(textBitmapObject); + + return NULL_REG; } reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) { @@ -670,14 +695,9 @@ reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv) { // but it handles events on its own, using an internal loop, instead of using SCI // scripts for event management like kEditControl does. Called by script 64914, // DEdit::hilite(). -reg_t kEditText(EngineState *s, int argc, reg_t *argv) { - reg_t controlObject = argv[0]; - - if (!controlObject.isNull()) { - g_sci->_gfxControls32->kernelTexteditChange(controlObject); - } - return s->r_acc; +reg_t kEditText(EngineState *s, int argc, reg_t *argv) { + return g_sci->_gfxControls32->kernelEditText(argv[0]); } reg_t kAddLine(EngineState *s, int argc, reg_t *argv) { @@ -894,6 +914,8 @@ reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) { } reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { + // TODO +#if 0 uint16 operation = argv[0].toUint16(); switch (operation) { @@ -904,57 +926,57 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140) return s->r_acc; - int16 base = (argc >= 2) ? argv[1].toSint16() : 0; - if (base > 0) - warning("kRemapColors(0) called with base %d", base); - g_sci->_gfxPalette32->resetRemapping(); + int16 color = (argc >= 2) ? argv[1].toSint16() : 0; + if (color > 0) + warning("kRemapColors(0) called with base %d", color); + //g_sci->_gfxPalette32->resetRemapping(); } break; case 1: { // remap by range uint16 color = argv[1].toUint16(); uint16 from = argv[2].toUint16(); uint16 to = argv[3].toUint16(); - uint16 base = argv[4].toUint16(); - uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0; - if (unk5 > 0) - warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5); - g_sci->_gfxPalette32->setRemappingRange(color, from, to, base); + uint16 delta = argv[4].toUint16(); + uint16 depth = (argc >= 6) ? argv[5].toUint16() : 0; + if (depth > 0) + warning("kRemapColors(1) called with 6 parameters, depth is %d", depth); + //g_sci->_gfxPalette32->setRemappingRange(color, from, to, delta); } break; case 2: { // remap by percent uint16 color = argv[1].toUint16(); uint16 percent = argv[2].toUint16(); // 0 - 100 - if (argc >= 4) - warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - g_sci->_gfxPalette32->setRemappingPercent(color, percent); + uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0; + if (depth >= 0) + warning("RemapByPercent called with 4 parameters, depth is %d", depth); + //g_sci->_gfxPalette32->setRemappingPercent(color, percent); } break; case 3: { // remap to gray // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0. // In this room, it's used for the cloud before Baba Yaga appears. - int16 color = argv[1].toSint16(); - int16 percent = argv[2].toSint16(); // 0 - 100 - if (argc >= 4) - warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - g_sci->_gfxPalette32->setRemappingPercentGray(color, percent); + uint16 color = argv[1].toUint16(); + uint16 percent = argv[2].toUint16(); // 0 - 100 + uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0; + if (depth >= 0) + warning("RemapToGray called with 4 parameters, depth is %d", depth); + //g_sci->_gfxPalette32->setRemappingPercentGray(color, percent); } break; case 4: { // remap to percent gray // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200 - int16 color = argv[1].toSint16(); - int16 percent = argv[2].toSint16(); // 0 - 100 - // argv[3] is unknown (a number, e.g. 200) - start color, perhaps? + uint16 color = argv[1].toUint16(); + uint16 percent = argv[2].toUint16(); // 0 - 100 + uint16 grayPercent = argv[3].toUint16(); + uint16 depth = (argc >= 5) ? argv[4].toUint16() : 0; if (argc >= 5) - warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); - g_sci->_gfxPalette32->setRemappingPercentGray(color, percent); + warning("RemapToGrayPercent called with 5 parameters, depth is %d", depth); + //g_sci->_gfxPalette32->setRemappingPercentGray(color, percent); } break; case 5: { // don't map to range - //int16 mapping = argv[1].toSint16(); - uint16 intensity = argv[2].toUint16(); - // HACK for PQ4 - if (g_sci->getGameId() == GID_PQ4) - g_sci->_gfxPalette32->kernelSetIntensity(0, 255, intensity, true); + //uint16 start = argv[1].toSint16(); + //uint16 count = argv[2].toUint16(); kStub(s, argc, argv); } @@ -962,6 +984,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { default: break; } +#endif return s->r_acc; } diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index fc0dca5123..8039c5f282 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -813,6 +813,32 @@ static const uint16 kq5PatchWitchCageInit[] = { PATCH_END }; +// The multilingual releases of KQ5 hang right at the end during the magic battle with Mordack. +// It seems additional code was added to wait for signals, but the signals are never set and thus +// the game hangs. We disable that code, so that the battle works again. +// This also happened in the original interpreter. +// We must not change similar code, that happens before. + +// Applies to at least: French PC floppy, German PC floppy, Spanish PC floppy +// Responsible method: stingScript::changeState, dragonScript::changeState, snakeScript::changeState +static const uint16 kq5SignatureMultilingualEndingGlitch[] = { + SIG_MAGICDWORD, + 0x89, 0x57, // lsg global[57h] + 0x35, 0x00, // ldi 0 + 0x1a, // eq? + 0x18, // not + 0x30, SIG_UINT16(0x0011), // bnt [skip signal check] + SIG_ADDTOOFFSET(+8), // skip globalSound::prevSignal get code + 0x36, // push + 0x35, 0x0a, // ldi 0Ah + SIG_END +}; + +static const uint16 kq5PatchMultilingualEndingGlitch[] = { + PATCH_ADDTOOFFSET(+6), + 0x32, // change BNT into JMP + PATCH_END +}; // In the final battle, the DOS version uses signals in the music to handle // timing, while in the Windows version another method is used and the GM @@ -843,9 +869,10 @@ static const uint16 kq5PatchWinGMSignals[] = { // script, description, signature patch static const SciScriptPatcherEntry kq5Signatures[] = { - { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, - { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit }, - { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals }, + { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, + { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit }, + { true, 124, "Multilingual: Ending glitching out", 3, kq5SignatureMultilingualEndingGlitch, kq5PatchMultilingualEndingGlitch }, + { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals }, SCI_SIGNATUREENTRY_TERMINATOR }; diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index 1393e96880..ac621f58ae 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -180,6 +180,7 @@ void Kernel::mapSelectors() { FIND_SELECTOR(back); FIND_SELECTOR(skip); FIND_SELECTOR(borderColor); + FIND_SELECTOR(width); FIND_SELECTOR(fixPriority); FIND_SELECTOR(mirrored); FIND_SELECTOR(visible); @@ -192,7 +193,12 @@ void Kernel::mapSelectors() { FIND_SELECTOR(textLeft); FIND_SELECTOR(textBottom); FIND_SELECTOR(textRight); + FIND_SELECTOR(title); + FIND_SELECTOR(titleFont); + FIND_SELECTOR(titleFore); + FIND_SELECTOR(titleBack); FIND_SELECTOR(magnifier); + FIND_SELECTOR(frameOut); FIND_SELECTOR(casts); #endif } diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index a8bbbe75e3..f2d06d1cf4 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -147,6 +147,7 @@ struct SelectorCache { Selector skip; Selector dimmed; Selector borderColor; + Selector width; Selector fixPriority; Selector mirrored; @@ -155,9 +156,10 @@ struct SelectorCache { Selector useInsetRect; Selector inTop, inLeft, inBottom, inRight; Selector textTop, textLeft, textBottom, textRight; + Selector title, titleFont, titleFore, titleBack; Selector magnifier; - + Selector frameOut; Selector casts; // needed for sync'ing screen items/planes with scripts, when our save/restore code is patched in (see GfxFrameout::syncWithScripts) #endif }; diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index 53a5a5c507..d74e2b194c 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -230,6 +230,10 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { return toUint16() - right.toUint16(); else return toSint16() - right.toSint16(); +#ifdef ENABLE_SCI32 + } else if (getSciVersion() >= SCI_VERSION_2) { + return sci32Comparison(right); +#endif } else if (pointerComparisonWithInteger(right)) { return 1; } else if (right.pointerComparisonWithInteger(*this)) { @@ -238,6 +242,26 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { return lookForWorkaround(right, "comparison").toSint16(); } +#ifdef ENABLE_SCI32 +int reg_t::sci32Comparison(const reg_t right) const { + // In SCI32, MemIDs are normally indexes into the memory manager's handle + // list, but the engine reserves indexes at and above 20000 for objects + // that were created inside the engine (as opposed to inside the VM). The + // engine compares these as a tiebreaker for graphics objects that are at + // the same priority, and it is necessary to at least minimally handle + // this situation. + // This is obviously a bogus comparision, but then, this entire thing is + // bogus. For the moment, it just needs to be deterministic. + if (isNumber() && !right.isNumber()) { + return 1; + } else if (right.isNumber() && !isNumber()) { + return -1; + } + + return getOffset() - right.getOffset(); +} +#endif + bool reg_t::pointerComparisonWithInteger(const reg_t right) const { // This function handles the case where a script tries to compare a pointer // to a number. Normally, we would not want to allow that. However, SCI0 - diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h index a646478a8e..e60f52e85c 100644 --- a/engines/sci/engine/vm_types.h +++ b/engines/sci/engine/vm_types.h @@ -160,6 +160,10 @@ private: int cmp(const reg_t right, bool treatAsUnsigned) const; reg_t lookForWorkaround(const reg_t right, const char *operation) const; bool pointerComparisonWithInteger(const reg_t right) const; + +#ifdef ENABLE_SCI32 + int sci32Comparison(const reg_t right) const; +#endif }; static inline reg_t make_reg(SegmentId segment, uint16 offset) { diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 10731e270c..a4e19dc8b9 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -630,7 +630,7 @@ const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kIsObject_workarounds[] = { - { GID_GK1, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950 + { GID_GK1DEMO, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950 { GID_ISLANDBRAIN, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when going to the game options, choosing "Info" and selecting anything from the list, gets called with an invalid parameter (type "error") - bug #4989 { GID_QFG3, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when asking for something, gets called with type error parameter SCI_WORKAROUNDENTRY_TERMINATOR @@ -670,7 +670,7 @@ const SciWorkaroundEntry kReadNumber_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = { - { GID_QFG4, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947 + { GID_QFG4DEMO, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947 SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index 3322a273ae..34f1618514 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -29,6 +29,9 @@ #include "sci/console.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" +#ifdef ENABLE_SCI32 +#include "sci/graphics/frameout.h" +#endif #include "sci/graphics/screen.h" namespace Sci { @@ -133,8 +136,13 @@ static int altify(int ch) { } SciEvent EventManager::getScummVMEvent() { - SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) }; - SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) }; +#ifdef ENABLE_SCI32 + SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; + SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; +#else + SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point() }; + SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point() }; +#endif Common::EventManager *em = g_system->getEventManager(); Common::Event ev; @@ -155,7 +163,20 @@ SciEvent EventManager::getScummVMEvent() { // via pollEvent. // We also adjust the position based on the scaling of the screen. Common::Point mousePos = em->getMousePos(); - g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); + +#if ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2) { + Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); + + Common::Point mousePosSci = mousePos; + mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight)); + noEvent.mousePosSci = input.mousePosSci = mousePosSci; + } else { +#endif + g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); +#if ENABLE_SCI32 + } +#endif noEvent.mousePos = input.mousePos = mousePos; @@ -302,6 +323,11 @@ SciEvent EventManager::getScummVMEvent() { input.character = altify(input.character); if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (scummVMKeyFlags & Common::KBD_CTRL) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2 && (scummVMKeyFlags & Common::KBD_CTRL) && input.character == 'c') { + input.character = SCI_KEY_ETX; + } +#endif // If no actual key was pressed (e.g. if only a modifier key was pressed), // ignore the event @@ -329,7 +355,11 @@ void EventManager::updateScreen() { } SciEvent EventManager::getSciEvent(uint32 mask) { - SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) }; +#ifdef ENABLE_SCI32 + SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; +#else + SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point() }; +#endif EventManager::updateScreen(); diff --git a/engines/sci/event.h b/engines/sci/event.h index 0d0c550622..15a94b3e73 100644 --- a/engines/sci/event.h +++ b/engines/sci/event.h @@ -39,11 +39,18 @@ struct SciEvent { uint16 character; /** - * The mouse position at the time the event was created. - * - * These are display coordinates! + * The mouse position at the time the event was created, + * in display coordinates. */ Common::Point mousePos; + +#ifdef ENABLE_SCI32 + /** + * The mouse position at the time the event was created, + * in script coordinates. + */ + Common::Point mousePosSci; +#endif }; /*Values for type*/ @@ -59,6 +66,9 @@ struct SciEvent { #define SCI_EVENT_ANY 0x7fff /* Keycodes of special keys: */ +#ifdef ENABLE_SCI32 +#define SCI_KEY_ETX 3 +#endif #define SCI_KEY_ESC 27 #define SCI_KEY_BACKSPACE 8 #define SCI_KEY_ENTER 13 diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp index 787d295d5e..389270ec42 100644 --- a/engines/sci/graphics/celobj32.cpp +++ b/engines/sci/graphics/celobj32.cpp @@ -27,6 +27,7 @@ #include "sci/graphics/frameout.h" #include "sci/graphics/palette32.h" #include "sci/graphics/picture.h" +#include "sci/graphics/text32.h" #include "sci/graphics/view.h" namespace Sci { @@ -84,10 +85,9 @@ const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio #pragma mark CelObj void CelObj::init() { + CelObj::deinit(); _nextCacheId = 1; - delete _scaler; _scaler = new CelScaler(); - delete _cache; _cache = new CelCache; _cache->resize(100); } @@ -95,6 +95,11 @@ void CelObj::init() { void CelObj::deinit() { delete _scaler; _scaler = nullptr; + if (_cache != nullptr) { + for (CelCache::iterator it = _cache->begin(); it != _cache->end(); ++it) { + delete it->celObj; + } + } delete _cache; _cache = nullptr; } @@ -102,7 +107,7 @@ void CelObj::deinit() { #pragma mark - #pragma mark CelObj - Scalers -template <bool FLIP, typename READER> +template<bool FLIP, typename READER> struct SCALER_NoScale { const byte *_row; READER _reader; @@ -557,7 +562,7 @@ void CelObj::putCopyInCache(const int cacheIndex) const { #pragma mark - #pragma mark CelObj - Drawing -template <typename MAPPER, typename SCALER> +template<typename MAPPER, typename SCALER> struct RENDERER { MAPPER &_mapper; SCALER &_scaler; @@ -589,7 +594,7 @@ struct RENDERER { } }; -template <typename MAPPER, typename SCALER> +template<typename MAPPER, typename SCALER> void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const { MAPPER mapper; @@ -598,7 +603,7 @@ void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common renderer.draw(target, targetRect, scaledPosition); } -template <typename MAPPER, typename SCALER> +template<typename MAPPER, typename SCALER> void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const { MAPPER mapper; @@ -968,67 +973,23 @@ byte *CelObjPic::getResPointer() const { #pragma mark - #pragma mark CelObjMem -void CelObjMem::buildBitmapHeader(byte *bitmap, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool useRemap) { - const uint16 bitmapHeaderSize = getBitmapHeaderSize(); - - WRITE_SCI11ENDIAN_UINT16(bitmap + 0, width); - WRITE_SCI11ENDIAN_UINT16(bitmap + 2, height); - WRITE_SCI11ENDIAN_UINT16(bitmap + 4, (uint16)displaceX); - WRITE_SCI11ENDIAN_UINT16(bitmap + 6, (uint16)displaceY); - bitmap[8] = skipColor; - bitmap[9] = 0; - WRITE_SCI11ENDIAN_UINT16(bitmap + 10, 0); - - if (useRemap) { - bitmap[10] |= 2; - } - - WRITE_SCI11ENDIAN_UINT32(bitmap + 12, width * height); - WRITE_SCI11ENDIAN_UINT32(bitmap + 16, 0); - - if (hunkPaletteOffset) { - WRITE_SCI11ENDIAN_UINT32(bitmap + 20, hunkPaletteOffset + bitmapHeaderSize); - } else { - WRITE_SCI11ENDIAN_UINT32(bitmap + 20, 0); - } - - WRITE_SCI11ENDIAN_UINT32(bitmap + 24, bitmapHeaderSize); - WRITE_SCI11ENDIAN_UINT32(bitmap + 28, bitmapHeaderSize); - WRITE_SCI11ENDIAN_UINT32(bitmap + 32, 0); - - if (bitmapHeaderSize >= 40) { - WRITE_SCI11ENDIAN_UINT16(bitmap + 36, scaledWidth); - WRITE_SCI11ENDIAN_UINT16(bitmap + 38, scaledHeight); - } -} - -CelObjMem::CelObjMem(const reg_t bitmap) { +CelObjMem::CelObjMem(const reg_t bitmapObject) { _info.type = kCelTypeMem; - _info.bitmap = bitmap; + _info.bitmap = bitmapObject; _mirrorX = false; _compressionType = kCelCompressionNone; _celHeaderOffset = 0; _transparent = true; - const uint32 bitmapHeaderSize = getBitmapHeaderSize(); - byte *bitmapData = g_sci->getEngineState()->_segMan->getHunkPointer(bitmap); - if (bitmapData == nullptr || READ_SCI11ENDIAN_UINT32(bitmapData + 28) != bitmapHeaderSize) { - error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap)); - } - - _width = READ_SCI11ENDIAN_UINT16(bitmapData); - _height = READ_SCI11ENDIAN_UINT16(bitmapData + 2); - _displace.x = READ_SCI11ENDIAN_UINT16(bitmapData + 4); - _displace.y = READ_SCI11ENDIAN_UINT16(bitmapData + 6); - _transparentColor = bitmapData[8]; - if (bitmapHeaderSize >= 40) { - _scaledWidth = READ_SCI11ENDIAN_UINT16(bitmapData + 36); - _scaledHeight = READ_SCI11ENDIAN_UINT16(bitmapData + 38); - } else { - error("TODO: SCI2 bitmaps not implemented yet!"); - } - _hunkPaletteOffset = READ_SCI11ENDIAN_UINT16(bitmapData + 20); - _remap = (READ_SCI11ENDIAN_UINT16(bitmapData + 10) & 2) ? true : false; + BitmapResource bitmap(bitmapObject); + _width = bitmap.getWidth(); + _height = bitmap.getHeight(); + _displace = bitmap.getDisplace(); + _transparentColor = bitmap.getSkipColor(); + _scaledWidth = bitmap.getScaledWidth(); + _scaledHeight = bitmap.getScaledHeight(); + _hunkPaletteOffset = bitmap.getHunkPaletteOffset(); + _remap = bitmap.getRemap(); } CelObjMem *CelObjMem::duplicate() const { @@ -1075,4 +1036,4 @@ CelObjColor *CelObjColor::duplicate() const { byte *CelObjColor::getResPointer() const { error("Unsupported method"); } -} +} // End of namespace Sci diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h index 5707333818..8d030cfd4a 100644 --- a/engines/sci/graphics/celobj32.h +++ b/engines/sci/graphics/celobj32.h @@ -379,10 +379,10 @@ public: #pragma mark - #pragma mark CelObj - Drawing private: - template <typename MAPPER, typename SCALER> + template<typename MAPPER, typename SCALER> void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; - template <typename MAPPER, typename SCALER> + template<typename MAPPER, typename SCALER> void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const; void drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; @@ -547,34 +547,6 @@ public: */ class CelObjMem : public CelObj { public: - /** - * Writes a bitmap header to the given data buffer. - */ - static void buildBitmapHeader(byte *bitmap, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool useRemap); - - /** - * Gets the size of the bitmap header for the current - * engine version. - */ - inline static uint32 getBitmapHeaderSize() { - // TODO: These values are accurate for each engine, but there may be no reason - // to not simply just always use size 40, since SCI2.1mid does not seem to - // actually store any data above byte 40, and SCI2 did not allow bitmaps with - // scaling resolutions other than the default (320x200). Perhaps SCI3 used - // the extra bytes, or there is some reason why they tried to align the header - // size with other headers like pic headers? -// uint32 bitmapHeaderSize; -// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) { -// bitmapHeaderSize = 46; -// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) { -// bitmapHeaderSize = 40; -// } else { -// bitmapHeaderSize = 36; -// } -// return bitmapHeaderSize; - return 46; - } - CelObjMem(reg_t bitmap); virtual ~CelObjMem() override {}; @@ -605,6 +577,6 @@ public: virtual CelObjColor *duplicate() const override; virtual byte *getResPointer() const override; }; -} +} // End of namespace Sci #endif diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp index df518888a9..a877d8c276 100644 --- a/engines/sci/graphics/controls32.cpp +++ b/engines/sci/graphics/controls32.cpp @@ -23,9 +23,11 @@ #include "common/system.h" #include "sci/sci.h" +#include "sci/console.h" #include "sci/event.h" #include "sci/engine/kernel.h" #include "sci/engine/seg_manager.h" +#include "sci/engine/state.h" #include "sci/graphics/cache.h" #include "sci/graphics/compare.h" #include "sci/graphics/controls32.h" @@ -34,174 +36,321 @@ #include "sci/graphics/text32.h" namespace Sci { +GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text) : + _segMan(segMan), + _gfxCache(cache), + _gfxText32(text), + _overwriteMode(false), + _nextCursorFlashTick(0) {} -GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text) - : _segMan(segMan), _cache(cache), _text(text) { -} +reg_t GfxControls32::kernelEditText(const reg_t controlObject) { + SegManager *segMan = _segMan; -GfxControls32::~GfxControls32() { -} + TextEditor editor; + reg_t textObject = readSelector(_segMan, controlObject, SELECTOR(text)); + editor.text = _segMan->getString(textObject); + editor.foreColor = readSelectorValue(_segMan, controlObject, SELECTOR(fore)); + editor.backColor = readSelectorValue(_segMan, controlObject, SELECTOR(back)); + editor.skipColor = readSelectorValue(_segMan, controlObject, SELECTOR(skip)); + editor.fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font)); + editor.maxLength = readSelectorValue(_segMan, controlObject, SELECTOR(width)); + editor.bitmap = readSelector(_segMan, controlObject, SELECTOR(bitmap)); + editor.cursorCharPosition = 0; + editor.cursorIsDrawn = false; + editor.borderColor = readSelectorValue(_segMan, controlObject, SELECTOR(borderColor)); -void GfxControls32::kernelTexteditChange(reg_t controlObject) { - SciEvent curEvent; - uint16 maxChars = 40; //readSelectorValue(_segMan, controlObject, SELECTOR(max)); // TODO - reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text)); - GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font))); - Common::String text; - uint16 textSize; - bool textChanged = false; - bool textAddChar = false; - Common::Rect rect; + reg_t titleObject = readSelector(_segMan, controlObject, SELECTOR(title)); + + int16 titleHeight = 0; + GuiResourceId titleFontId = readSelectorValue(_segMan, controlObject, SELECTOR(titleFont)); + if (!titleObject.isNull()) { + GfxFont *titleFont = _gfxCache->getFont(titleFontId); + titleHeight += _gfxText32->scaleUpHeight(titleFont->getHeight()) + 1; + if (editor.borderColor != -1) { + titleHeight += 2; + } + } - if (textReference.isNull()) - error("kEditControl called on object that doesn't have a text reference"); - text = _segMan->getString(textReference); + int16 width = 0; + int16 height = titleHeight; - // TODO: Finish this - warning("kEditText ('%s')", text.c_str()); - return; + GfxFont *editorFont = _gfxCache->getFont(editor.fontId); + height += _gfxText32->scaleUpHeight(editorFont->getHeight()) + 1; + _gfxText32->setFont(editor.fontId); + int16 emSize = _gfxText32->getCharWidth('M', true); + width += editor.maxLength * emSize + 1; + if (editor.borderColor != -1) { + width += 4; + height += 2; + } - uint16 cursorPos = 0; - //uint16 oldCursorPos = cursorPos; - bool captureEvents = true; - EventManager* eventMan = g_sci->getEventManager(); + Common::Rect editorPlaneRect(width, height); + editorPlaneRect.translate(readSelectorValue(_segMan, controlObject, SELECTOR(x)), readSelectorValue(_segMan, controlObject, SELECTOR(y))); - while (captureEvents) { - curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK); + reg_t planeObj = readSelector(_segMan, controlObject, SELECTOR(plane)); + Plane *sourcePlane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj); + if (sourcePlane == nullptr) { + error("Could not find plane %04x:%04x", PRINT_REG(planeObj)); + } + editorPlaneRect.translate(sourcePlane->_gameRect.left, sourcePlane->_gameRect.top); - if (curEvent.type == SCI_EVENT_NONE) { - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + editor.textRect = Common::Rect(2, titleHeight + 2, width - 1, height - 1); + editor.width = width; + + if (editor.bitmap.isNull()) { + TextAlign alignment = (TextAlign)readSelectorValue(_segMan, controlObject, SELECTOR(mode)); + + if (titleObject.isNull()) { + bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed)); + editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true); } else { - textSize = text.size(); + Common::String title = _segMan->getString(titleObject); + int16 titleBackColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleBack)); + int16 titleForeColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleFore)); + editor.bitmap = _gfxText32->createTitledBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, title, titleForeColor, titleBackColor, titleFontId, true); + } + } + + drawCursor(editor); - switch (curEvent.type) { - case SCI_EVENT_MOUSE_PRESS: - // TODO: Implement mouse support for cursor change + Plane *plane = new Plane(editorPlaneRect, kPlanePicTransparent); + plane->changePic(); + g_sci->_gfxFrameout->addPlane(*plane); + + CelInfo32 celInfo; + celInfo.type = kCelTypeMem; + celInfo.bitmap = editor.bitmap; + + ScreenItem *screenItem = new ScreenItem(plane->_object, celInfo, Common::Point(), ScaleInfo()); + plane->_screenItemList.add(screenItem); + + // frameOut must be called after the screen item is + // created, and before it is updated at the end of the + // event loop, otherwise it has both created and updated + // flags set which crashes the engine (it runs updates + // before creations) + g_sci->_gfxFrameout->frameOut(true); + + EventManager *eventManager = g_sci->getEventManager(); + bool clearTextOnInput = true; + bool textChanged = false; + for (;;) { + // We peek here because the last event needs to be allowed to + // dispatch a second time to the normal event handling system. + // In the actual engine, the event is always consumed and then + // the last event just gets posted back to the event manager for + // reprocessing, but instead, we only remove the event from the + // queue *after* we have determined it is not a defocusing event + const SciEvent event = eventManager->getSciEvent(SCI_EVENT_ANY | SCI_EVENT_PEEK); + + bool focused = true; + // Original engine did not have a QUIT event but we have to handle it + if (event.type == SCI_EVENT_QUIT) { + focused = false; + break; + } else if (event.type == SCI_EVENT_MOUSE_PRESS && !editorPlaneRect.contains(event.mousePosSci)) { + focused = false; + } else if (event.type == SCI_EVENT_KEYBOARD) { + switch (event.character) { + case SCI_KEY_ESC: + case SCI_KEY_UP: + case SCI_KEY_DOWN: + case SCI_KEY_TAB: + case SCI_KEY_SHIFT_TAB: + case SCI_KEY_ENTER: + focused = false; break; - case SCI_EVENT_KEYBOARD: - switch (curEvent.character) { - case SCI_KEY_BACKSPACE: - if (cursorPos > 0) { - cursorPos--; text.deleteChar(cursorPos); - textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_DELETE: - if (cursorPos < textSize) { - text.deleteChar(cursorPos); - textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_HOME: // HOME - cursorPos = 0; textChanged = true; - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_END: // END - cursorPos = textSize; textChanged = true; - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_LEFT: // LEFT - if (cursorPos > 0) { - cursorPos--; textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_RIGHT: // RIGHT - if (cursorPos + 1 <= textSize) { - cursorPos++; textChanged = true; - } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case 3: // returned in SCI1 late and newer when Control - C is pressed - if (curEvent.modifiers & SCI_KEYMOD_CTRL) { - // Control-C erases the whole line - cursorPos = 0; text.clear(); - textChanged = true; + } + } + + if (!focused) { + break; + } + + // Consume the event now that we know it is not one of the + // defocusing events above + eventManager->getSciEvent(SCI_EVENT_ANY); + + // NOTE: In the original engine, the font and bitmap were + // reset here on each iteration through the loop, but it + // doesn't seem like this should be necessary since + // control is not yielded back to the VM until input is + // received, which means there is nothing that could modify + // the GfxText32's state with a different font in the + // meantime + + bool shouldDeleteChar = false; + bool shouldRedrawText = false; + uint16 lastCursorPosition = editor.cursorCharPosition; + if (event.type == SCI_EVENT_KEYBOARD) { + switch (event.character) { + case SCI_KEY_LEFT: + clearTextOnInput = false; + if (editor.cursorCharPosition > 0) { + --editor.cursorCharPosition; + } + break; + + case SCI_KEY_RIGHT: + clearTextOnInput = false; + if (editor.cursorCharPosition < editor.text.size()) { + ++editor.cursorCharPosition; + } + break; + + case SCI_KEY_HOME: + clearTextOnInput = false; + editor.cursorCharPosition = 0; + break; + + case SCI_KEY_END: + clearTextOnInput = false; + editor.cursorCharPosition = editor.text.size(); + break; + + case SCI_KEY_INSERT: + clearTextOnInput = false; + // Redrawing also changes the cursor rect to + // reflect the new insertion mode + shouldRedrawText = true; + _overwriteMode = !_overwriteMode; + break; + + case SCI_KEY_DELETE: + clearTextOnInput = false; + if (editor.cursorCharPosition < editor.text.size()) { + shouldDeleteChar = true; + } + break; + + case SCI_KEY_BACKSPACE: + clearTextOnInput = false; + shouldDeleteChar = true; + if (editor.cursorCharPosition > 0) { + --editor.cursorCharPosition; + } + break; + + case SCI_KEY_ETX: + editor.text.clear(); + editor.cursorCharPosition = 0; + shouldRedrawText = true; + break; + + default: { + if (event.character >= 20 && event.character < 257) { + if (clearTextOnInput) { + clearTextOnInput = false; + editor.text.clear(); } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; - case SCI_KEY_UP: - case SCI_KEY_DOWN: - case SCI_KEY_ENTER: - case SCI_KEY_ESC: - case SCI_KEY_TAB: - case SCI_KEY_SHIFT_TAB: - captureEvents = false; - break; - default: - if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.character == 'c') { - // Control-C in earlier SCI games (SCI0 - SCI1 middle) - // Control-C erases the whole line - cursorPos = 0; text.clear(); - textChanged = true; - } else if (curEvent.character > 31 && curEvent.character < 256 && textSize < maxChars) { - // insert pressed character - textAddChar = true; - textChanged = true; + + if ( + (_overwriteMode && editor.cursorCharPosition < editor.maxLength) || + (editor.text.size() < editor.maxLength && _gfxText32->getCharWidth(event.character, true) + _gfxText32->getStringWidth(editor.text) < editor.textRect.width()) + ) { + if (_overwriteMode && editor.cursorCharPosition < editor.text.size()) { + editor.text.setChar(event.character, editor.cursorCharPosition); + } else { + editor.text.insertChar(event.character, editor.cursorCharPosition); + } + + ++editor.cursorCharPosition; + shouldRedrawText = true; } - eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event - break; } - break; + } + } + } + + if (shouldDeleteChar) { + shouldRedrawText = true; + if (editor.cursorCharPosition < editor.text.size()) { + editor.text.deleteChar(editor.cursorCharPosition); } } - if (textChanged) { - rect = g_sci->_gfxCompare->getNSRect(controlObject); + if (shouldRedrawText) { + eraseCursor(editor); + _gfxText32->erase(editor.textRect, true); + _gfxText32->drawTextBox(editor.text); + drawCursor(editor); + textChanged = true; + screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); + } else if (editor.cursorCharPosition != lastCursorPosition) { + eraseCursor(editor); + drawCursor(editor); + screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); + } else { + flashCursor(editor); + screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); + } - if (textAddChar) { - const char *textPtr = text.c_str(); + g_sci->_gfxFrameout->frameOut(true); + g_sci->getSciDebugger()->onFrame(); + g_sci->getEngineState()->speedThrottler(16); + g_sci->getEngineState()->_throttleTrigger = true; + } - // We check if we are really able to add the new char - uint16 textWidth = 0; - while (*textPtr) - textWidth += font->getCharWidth((byte)*textPtr++); - textWidth += font->getCharWidth(curEvent.character); + g_sci->_gfxFrameout->deletePlane(*plane); + if (readSelectorValue(segMan, controlObject, SELECTOR(frameOut))) { + g_sci->_gfxFrameout->frameOut(true); + } - // Does it fit? - if (textWidth >= rect.width()) { - return; - } + _segMan->freeHunkEntry(editor.bitmap); - text.insertChar(curEvent.character, cursorPos++); + if (textChanged) { + editor.text.trim(); + SciString *string = _segMan->lookupString(textObject); + string->fromString(editor.text); + } - // Note: the following checkAltInput call might make the text - // too wide to fit, but SSCI fails to check that too. - } + return make_reg(0, textChanged); +} + +void GfxControls32::drawCursor(TextEditor &editor) { + if (!editor.cursorIsDrawn) { + editor.cursorRect.left = editor.textRect.left + _gfxText32->getTextWidth(editor.text, 0, editor.cursorCharPosition); - reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap)); - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject); - //texteditCursorErase(); // TODO: Cursor - - // Write back string - _segMan->strcpy(textReference, text.c_str()); - // Modify the buffer and show it - warning("kernelTexteditChange"); -#if 0 - _text->createTextBitmap(controlObject, 0, 0, hunkId); - - _text->drawTextBitmap(0, 0, nsRect, controlObject); - //texteditCursorDraw(rect, text.c_str(), cursorPos); // TODO: Cursor - g_system->updateScreen(); -#endif + const int16 scaledFontHeight = _gfxText32->scaleUpHeight(_gfxText32->_font->getHeight()); + + // NOTE: The original code branched on borderColor here but + // the two branches appeared to be identical, differing only + // because the compiler decided to be differently clever + // when optimising multiplication in each branch + if (_overwriteMode) { + editor.cursorRect.top = editor.textRect.top; + editor.cursorRect.setHeight(scaledFontHeight); } else { - // TODO: Cursor - /* - if (g_system->getMillis() >= _texteditBlinkTime) { - _paint16->invertRect(_texteditCursorRect); - _paint16->bitsShow(_texteditCursorRect); - _texteditCursorVisible = !_texteditCursorVisible; - texteditSetBlinkTime(); - } - */ + editor.cursorRect.top = editor.textRect.top + scaledFontHeight - 1; + editor.cursorRect.setHeight(1); } - textAddChar = false; - textChanged = false; - g_sci->sleep(10); - } // while + const char currentChar = editor.cursorCharPosition < editor.text.size() ? editor.text[editor.cursorCharPosition] : ' '; + editor.cursorRect.setWidth(_gfxText32->getCharWidth(currentChar, true)); + + _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true); + + editor.cursorIsDrawn = true; + } + + _nextCursorFlashTick = g_sci->getTickCount() + 30; +} + +void GfxControls32::eraseCursor(TextEditor &editor) { + if (editor.cursorIsDrawn) { + _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true); + editor.cursorIsDrawn = false; + } + + _nextCursorFlashTick = g_sci->getTickCount() + 30; } +void GfxControls32::flashCursor(TextEditor &editor) { + if (g_sci->getTickCount() > _nextCursorFlashTick) { + _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true); + + editor.cursorIsDrawn = !editor.cursorIsDrawn; + _nextCursorFlashTick = g_sci->getTickCount() + 30; + } +} } // End of namespace Sci diff --git a/engines/sci/graphics/controls32.h b/engines/sci/graphics/controls32.h index 5af7c20f16..1bb7679ddd 100644 --- a/engines/sci/graphics/controls32.h +++ b/engines/sci/graphics/controls32.h @@ -29,20 +29,95 @@ class GfxCache; class GfxScreen; class GfxText32; +struct TextEditor { + /** + * The bitmap where the editor is rendered. + */ + reg_t bitmap; + + /** + * The width of the editor, in bitmap pixels. + */ + int16 width; + + /** + * The text in the editor. + */ + Common::String text; + + /** + * The rect where text should be drawn into the editor, + * in bitmap pixels. + */ + Common::Rect textRect; + + /** + * The color of the border. -1 indicates no border. + */ + int16 borderColor; + + /** + * The text color. + */ + uint8 foreColor; + + /** + * The background color. + */ + uint8 backColor; + + /** + * The transparent color. + */ + uint8 skipColor; + + /** + * The font used to render the text in the editor. + */ + GuiResourceId fontId; + + /** + * The current position of the cursor within the editor. + */ + uint16 cursorCharPosition; + + /** + * Whether or not the cursor is currently drawn to the + * screen. + */ + bool cursorIsDrawn; + + /** + * The rectangle for drawing the input cursor, in bitmap + * pixels. + */ + Common::Rect cursorRect; + + /** + * The maximum allowed text length, in characters. + */ + uint16 maxLength; +}; + /** * Controls class, handles drawing of controls in SCI32 (SCI2, SCI2.1, SCI3) games */ class GfxControls32 { public: GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text); - ~GfxControls32(); - void kernelTexteditChange(reg_t controlObject); + reg_t kernelEditText(const reg_t controlObject); private: SegManager *_segMan; - GfxCache *_cache; - GfxText32 *_text; + GfxCache *_gfxCache; + GfxText32 *_gfxText32; + + bool _overwriteMode; + uint32 _nextCursorFlashTick; + void drawCursor(TextEditor &editor); + void eraseCursor(TextEditor &editor); + void flashCursor(TextEditor &editor); }; } // End of namespace Sci diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index ab2ed7a4a5..655e59de00 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -133,8 +133,9 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd } GfxFrameout::~GfxFrameout() { - CelObj::deinit(); clear(); + CelObj::deinit(); + free(_currentBuffer.getPixels()); } void GfxFrameout::run() { @@ -286,7 +287,7 @@ void GfxFrameout::kernelUpdateScreenItem(const reg_t object) { screenItem->update(object); } else { - warning("TODO: Magnifier view not implemented yet!"); + error("Magnifier view is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!"); } } @@ -365,6 +366,21 @@ void GfxFrameout::kernelDeletePlane(const reg_t object) { } } +void GfxFrameout::deletePlane(Plane &planeToFind) { + Plane *plane = _planes.findByObject(planeToFind._object); + if (plane == nullptr) { + error("Invalid plane passed to deletePlane"); + } + + if (plane->_created) { + _planes.erase(plane); + } else { + plane->_created = 0; + plane->_moved = 0; + plane->_deleted = getScreenCount(); + } +} + int16 GfxFrameout::kernelGetHighPlanePri() { return _planes.getTopSciPlanePriority(); } @@ -765,7 +781,7 @@ void GfxFrameout::drawScreenItemList(const DrawList &screenItemList) { mergeToShowList(drawItem.rect, _showList, _overdrawThreshold); ScreenItem &screenItem = *drawItem.screenItem; // TODO: Remove -// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), drawItem.rect.left, drawItem.rect.top, drawItem.rect.right, drawItem.rect.bottom); +// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), PRINT_RECT(drawItem.rect)); CelObj &celObj = *screenItem._celObj; celObj.draw(_currentBuffer, screenItem, drawItem.rect, screenItem._mirrorX ^ celObj._mirrorX); } @@ -1010,8 +1026,6 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co // NOTE: This is currBuffer->ptr in SCI engine byte *pixels = (byte *)_currentBuffer.getPixels(); - // TODO: Guessing that display width/height is the correct - // equivalent to screen width/height in SCI engine for (int pixelIndex = 0, numPixels = _currentBuffer.screenWidth * _currentBuffer.screenHeight; pixelIndex < numPixels; ++pixelIndex) { byte currentValue = pixels[pixelIndex]; int8 styleRangeValue = styleRanges[currentValue]; @@ -1963,73 +1977,55 @@ void GfxFrameout::kernelFrameOut(const bool shouldShowBits) { } } -uint16 GfxFrameout::kernelIsOnMe(int16 x, int16 y, uint16 checkPixels, reg_t screenObject) { - reg_t planeObject = readSelector(_segMan, screenObject, SELECTOR(plane)); - Plane *screenItemPlane = _visiblePlanes.findByObject(planeObject); // Search for plane in visible planes - ScreenItem *screenItem = nullptr; +#pragma mark - +#pragma mark Mouse cursor - if (!screenItemPlane) { - // Specified plane not found - return 0; +reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &position, bool checkPixel) const { + reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane)); + Plane *plane = _visiblePlanes.findByObject(planeObject); + if (plane == nullptr) { + return make_reg(0, 0); } - screenItem = screenItemPlane->_screenItemList.findByObject(screenObject); - if (!screenItem) { - // Specified screen object not in item list - return 0; + ScreenItem *screenItem = plane->_screenItemList.findByObject(object); + if (screenItem == nullptr) { + return make_reg(0, 0); } - // Original SCI32 seems to have made a copy (?) of the screenitem? - // there is also a "or [ebp+arg_56], 1 - not sure what that did - return isOnMe(screenItemPlane, screenItem, x, y, checkPixels); + return make_reg(0, isOnMe(*screenItem, *plane, position, checkPixel)); } -uint16 GfxFrameout::isOnMe(Plane *screenItemPlane, ScreenItem *screenItem, int16 x, int16 y, uint16 checkPixels) { - // adjust coordinate according to resolution - int32 adjustedX = x * getCurrentBuffer().screenWidth / getCurrentBuffer().scriptWidth; - int32 adjustedY = y * getCurrentBuffer().screenHeight / getCurrentBuffer().scriptHeight; - - adjustedX += screenItemPlane->_planeRect.left; - adjustedY += screenItemPlane->_planeRect.top; +bool GfxFrameout::isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const { - //warning("kIsOnMe %s %d (%d, %d -> %d, %d) mouse %d, %d", _segMan->getObjectName(screenObject), checkPixels, screenItem->_screenRect.left, screenItem->_screenRect.top, screenItem->_screenRect.right, screenItem->_screenRect.bottom, adjustedX, adjustedY); + Common::Point scaledPosition(position); + mulru(scaledPosition, Ratio(_currentBuffer.screenWidth, _currentBuffer.scriptWidth), Ratio(_currentBuffer.screenHeight, _currentBuffer.scriptHeight)); + scaledPosition.x += plane._planeRect.left; + scaledPosition.y += plane._planeRect.top; - if (!screenItem->_screenRect.contains(adjustedX, adjustedY)) { - // Specified coordinates are not within screen item - return 0; + if (!screenItem._screenRect.contains(scaledPosition)) { + return false; } - //warning("HIT!"); - if (checkPixels) { - //warning("Check Pixels"); - CelObj &screenItemCelObject = screenItem->getCelObj(); + if (checkPixel) { + CelObj &celObj = screenItem.getCelObj(); - Common::Point celAdjustedPoint(adjustedX, adjustedY); - bool celMirrored = screenItem->_mirrorX ^ screenItemCelObject._mirrorX; + bool mirrorX = screenItem._mirrorX ^ celObj._mirrorX; - celAdjustedPoint.x -= screenItem->_scaledPosition.x; - celAdjustedPoint.y -= screenItem->_scaledPosition.y; + scaledPosition.x -= screenItem._scaledPosition.x; + scaledPosition.y -= screenItem._scaledPosition.y; - Ratio celAdjustXRatio(screenItemCelObject._scaledWidth, getCurrentBuffer().screenWidth); - Ratio celAdjustYRatio(screenItemCelObject._scaledHeight, getCurrentBuffer().screenHeight); - mulru(celAdjustedPoint, celAdjustXRatio, celAdjustYRatio); + mulru(scaledPosition, Ratio(celObj._scaledWidth, _currentBuffer.screenWidth), Ratio(celObj._scaledHeight, _currentBuffer.screenHeight)); - if ((screenItem->_scale.signal) && (screenItem->_scale.x) && (screenItem->_scale.y)) { - // Apply scaling - celAdjustedPoint.x = celAdjustedPoint.x * 128 / screenItem->_scale.x; - celAdjustedPoint.y = celAdjustedPoint.y * 128 / screenItem->_scale.y; + if (screenItem._scale.signal != kScaleSignalNone && screenItem._scale.x && screenItem._scale.y) { + scaledPosition.x = scaledPosition.x * 128 / screenItem._scale.x; + scaledPosition.y = scaledPosition.y * 128 / screenItem._scale.y; } - byte coordinateColor = screenItemCelObject.readPixel(celAdjustedPoint.x, celAdjustedPoint.y, celMirrored); - byte transparentColor = screenItemCelObject._transparentColor; - - if (coordinateColor == transparentColor) { - // Coordinate is transparent - //warning("TRANSPARENT!"); - return 0; - } + uint8 pixel = celObj.readPixel(scaledPosition.x, scaledPosition.y, mirrorX); + return pixel != celObj._transparentColor; } - return 1; + + return true; } #pragma mark - @@ -2050,6 +2046,15 @@ void GfxFrameout::printVisiblePlaneList(Console *con) const { printPlaneListInternal(con, _visiblePlanes); } +void GfxFrameout::printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const { + ScreenItemList::size_type i = 0; + for (ScreenItemList::const_iterator sit = screenItemList.begin(); sit != screenItemList.end(); sit++) { + ScreenItem *screenItem = *sit; + con->debugPrintf("%2d: ", i++); + screenItem->printDebugInfo(con); + } +} + void GfxFrameout::printPlaneItemList(Console *con, const reg_t planeObject) const { Plane *p = _planes.findByObject(planeObject); @@ -2058,12 +2063,18 @@ void GfxFrameout::printPlaneItemList(Console *con, const reg_t planeObject) cons return; } - ScreenItemList::size_type i = 0; - for (ScreenItemList::iterator sit = p->_screenItemList.begin(); sit != p->_screenItemList.end(); sit++) { - ScreenItem *screenItem = *sit; - con->debugPrintf("%2d: ", i++); - screenItem->printDebugInfo(con); + printPlaneItemListInternal(con, p->_screenItemList); +} + +void GfxFrameout::printVisiblePlaneItemList(Console *con, const reg_t planeObject) const { + Plane *p = _visiblePlanes.findByObject(planeObject); + + if (p == nullptr) { + con->debugPrintf("Plane does not exist"); + return; } + + printPlaneItemListInternal(con, p->_screenItemList); } } // End of namespace Sci diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index f172997704..f864abc5bc 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -259,6 +259,13 @@ private: PlaneList _planes; /** + * Updates an existing plane with properties from the + * given VM object. + */ + void updatePlane(Plane &plane); + +public: + /** * Creates and adds a new plane to the plane list, or * cancels deletion and updates an already-existing * plane if a plane matching the given plane VM object @@ -270,15 +277,19 @@ private: void addPlane(Plane &plane); /** - * Updates an existing plane with properties from the - * given VM object. + * Deletes a plane within the current plane list. + * + * @note This method is on Screen in SCI engine, but it + * is only ever called on `GraphicsMgr.screen`. */ - void updatePlane(Plane &plane); + void deletePlane(Plane &plane); -public: const PlaneList &getPlanes() const { return _planes; } + const PlaneList &getVisiblePlanes() const { + return _visiblePlanes; + } void kernelAddPlane(const reg_t object); void kernelUpdatePlane(const reg_t object); void kernelDeletePlane(const reg_t object); @@ -423,13 +434,6 @@ private: void drawScreenItemList(const DrawList &screenItemList); /** - * Updates the internal screen buffer for the next - * frame. If `shouldShowBits` is true, also sends the - * buffer to hardware. - */ - void frameOut(const bool shouldShowBits, const Common::Rect &rect = Common::Rect()); - - /** * Adds a new rectangle to the list of regions to write * out to the hardware. The provided rect may be merged * into an existing rectangle to reduce the number of @@ -469,6 +473,13 @@ public: void kernelFrameOut(const bool showBits); /** + * Updates the internal screen buffer for the next + * frame. If `shouldShowBits` is true, also sends the + * buffer to hardware. + */ + void frameOut(const bool shouldShowBits, const Common::Rect &rect = Common::Rect()); + + /** * Modifies the raw pixel data for the next frame with * new palette indexes based on matched style ranges. */ @@ -491,8 +502,17 @@ public: return 1; }; - uint16 kernelIsOnMe(int16 x, int16 y, uint16 checkPixels, reg_t screenObject); - uint16 isOnMe(Plane *screenItemPlane, ScreenItem *screenItem, int16 x, int16 y, uint16 checkPixels); +#pragma mark - +#pragma mark Mouse cursor +private: + /** + * Determines whether or not the point given by + * `position` is inside of the given screen item. + */ + bool isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const; + +public: + reg_t kernelIsOnMe(const reg_t object, const Common::Point &position, const bool checkPixel) const; #pragma mark - #pragma mark Debugging @@ -501,6 +521,8 @@ public: void printVisiblePlaneList(Console *con) const; void printPlaneListInternal(Console *con, const PlaneList &planeList) const; void printPlaneItemList(Console *con, const reg_t planeObject) const; + void printVisiblePlaneItemList(Console *con, const reg_t planeObject) const; + void printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const; }; } // End of namespace Sci diff --git a/engines/sci/graphics/lists32.h b/engines/sci/graphics/lists32.h index bb990e17ca..4f74c77325 100644 --- a/engines/sci/graphics/lists32.h +++ b/engines/sci/graphics/lists32.h @@ -36,7 +36,7 @@ namespace Sci { * calling `erase` or when destroying the * StablePointerArray. */ -template <class T, uint N> +template<class T, uint N> class StablePointerArray { uint _size; T *_items[N]; @@ -178,7 +178,7 @@ public: } }; -template <typename T> +template<typename T> class FindByObject { const reg_t &_object; public: @@ -188,5 +188,5 @@ public: } }; -} +} // End of namespace Sci #endif diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 6f6e0b672e..1514ad838f 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -32,6 +32,7 @@ #include "sci/graphics/cache.h" #include "sci/graphics/maciconbar.h" #include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" #include "sci/graphics/screen.h" #include "sci/graphics/view.h" @@ -103,9 +104,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen) default: error("GfxPalette: Unknown view type"); } - - _remapOn = false; - resetRemapping(); } GfxPalette::~GfxPalette() { @@ -336,79 +334,6 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) { } } -byte GfxPalette::remapColor(byte remappedColor, byte screenColor) { - assert(_remapOn); - if (_remappingType[remappedColor] == kRemappingByRange) - return _remappingByRange[screenColor]; - else if (_remappingType[remappedColor] == kRemappingByPercent) - return _remappingByPercent[screenColor]; - else - error("remapColor(): Color %d isn't remapped", remappedColor); - - return 0; // should never reach here -} - -void GfxPalette::resetRemapping() { - _remapOn = false; - _remappingPercentToSet = 0; - - for (int i = 0; i < 256; i++) { - _remappingType[i] = kRemappingNone; - _remappingByPercent[i] = i; - _remappingByRange[i] = i; - } -} - -void GfxPalette::setRemappingPercent(byte color, byte percent) { - _remapOn = true; - - // We need to defer the setup of the remapping table every time the screen - // palette is changed, so that kernelFindColor() can find the correct - // colors. Set it once here, in case the palette stays the same and update - // it on each palette change by copySysPaletteToScreen(). - _remappingPercentToSet = percent; - - for (int i = 0; i < 256; i++) { - byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100; - byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100; - byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100; - _remappingByPercent[i] = kernelFindColor(r, g, b); - } - - _remappingType[color] = kRemappingByPercent; -} - -void GfxPalette::setRemappingPercentGray(byte color, byte percent) { - _remapOn = true; - - // We need to defer the setup of the remapping table every time the screen - // palette is changed, so that kernelFindColor() can find the correct - // colors. Set it once here, in case the palette stays the same and update - // it on each palette change by copySysPaletteToScreen(). - _remappingPercentToSet = percent; - - // Note: This is not what the original does, but the results are the same visually - for (int i = 0; i < 256; i++) { - byte rComponent = (byte)(_sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100); - byte gComponent = (byte)(_sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100); - byte bComponent = (byte)(_sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100); - byte luminosity = rComponent + gComponent + bComponent; - _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity); - } - - _remappingType[color] = kRemappingByPercent; -} - -void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) { - _remapOn = true; - - for (int i = from; i <= to; i++) { - _remappingByRange[i] = i + base; - } - - _remappingType[color] = kRemappingByRange; -} - bool GfxPalette::insert(Palette *newPalette, Palette *destPalette) { bool paletteChanged = false; @@ -589,15 +514,8 @@ void GfxPalette::copySysPaletteToScreen() { } } - // Check if we need to reset remapping by percent with the new colors. - if (_remappingPercentToSet) { - for (int i = 0; i < 256; i++) { - byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100; - byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100; - byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100; - _remappingByPercent[i] = kernelFindColor(r, g, b); - } - } + if (g_sci->_gfxRemap16) + g_sci->_gfxRemap16->updateRemapping(); g_system->getPaletteManager()->setPalette(bpal, 0, 256); } diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 61a8d36cb9..7335dc59d0 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -35,12 +35,6 @@ class GfxScreen; #define SCI_PALETTE_MATCH_PERFECT 0x8000 #define SCI_PALETTE_MATCH_COLORMASK 0xFF -enum ColorRemappingType { - kRemappingNone = 0, - kRemappingByRange = 1, - kRemappingByPercent = 2 -}; - /** * Palette class, handles palette operations like changing intensity, setting up the palette, merging different palettes */ @@ -64,15 +58,6 @@ public: void getSys(Palette *pal); uint16 getTotalColorCount() const { return _totalScreenColors; } - void resetRemapping(); - void setRemappingPercent(byte color, byte percent); - void setRemappingPercentGray(byte color, byte percent); - void setRemappingRange(byte color, byte from, byte to, byte base); - bool isRemapped(byte color) const { - return _remapOn && (_remappingType[color] != kRemappingNone); - } - byte remapColor(byte remappedColor, byte screenColor); - void setOnScreen(); void copySysPaletteToScreen(); @@ -138,12 +123,6 @@ protected: int _palVarySignal; uint16 _totalScreenColors; - bool _remapOn; - ColorRemappingType _remappingType[256]; - byte _remappingByPercent[256]; - byte _remappingByRange[256]; - uint16 _remappingPercentToSet; - void loadMacIconBarPalette(); byte *_macClut; }; diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp index 9204e4bf96..82e8d779f1 100644 --- a/engines/sci/graphics/palette32.cpp +++ b/engines/sci/graphics/palette32.cpp @@ -55,7 +55,9 @@ GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen) _cyclers(), _cycleMap() { _varyPercent = _varyTargetPercent; - memset(_fadeTable, 100, sizeof(_fadeTable)); + for (int i = 0, len = ARRAYSIZE(_fadeTable); i < len; ++i) { + _fadeTable[i] = 100; + } // NOTE: In SCI engine, the palette manager constructor loads // the default palette, but in ScummVM this initialisation // is performed by SciEngine::run; see r49523 for details @@ -68,7 +70,7 @@ GfxPalette32::~GfxPalette32() { } inline void mergePaletteInternal(Palette *const to, const Palette *const from) { - for (int i = 0; i < ARRAYSIZE(to->colors); ++i) { + for (int i = 0, len = ARRAYSIZE(to->colors); i < len; ++i) { if (from->colors[i].used) { to->colors[i] = from->colors[i]; } @@ -695,14 +697,8 @@ void GfxPalette32::cycleAllOn() { } void GfxPalette32::cycleAllPause() { - // TODO: The SCI SQ6 cycleAllPause function does not seem to perform - // nullptr checking?? This would definitely cause null pointer - // dereference in SCI code. I have not seen anything actually call - // this function yet, so it is possible it is just unused and broken - // in SCI SQ6. This assert exists so that if this function is called, - // it is noticed and can be rechecked in the actual engine. - // Obviously this code *does* do nullptr checks instead of crashing. :) - assert(0); + // NOTE: The original engine did not check for null pointers in the + // palette cyclers pointer array. for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { PalCycler *cycler = _cyclers[i]; if (cycler != nullptr) { @@ -795,7 +791,7 @@ void GfxPalette32::applyCycles() { // the last palette entry is intentionally left unmodified, or if this is a bug // in the engine. It certainly seems confused because all other places that accept // color ranges typically receive values in the range of 0–255. -void GfxPalette32::setFade(uint8 percent, uint8 fromColor, uint16 numColorsToFade) { +void GfxPalette32::setFade(uint16 percent, uint8 fromColor, uint16 numColorsToFade) { if (fromColor > numColorsToFade) { return; } @@ -817,9 +813,10 @@ void GfxPalette32::applyFade() { Color &color = _nextPalette.colors[i]; - color.r = (int16)color.r * _fadeTable[i] / 100; - color.g = (int16)color.g * _fadeTable[i] / 100; - color.b = (int16)color.b * _fadeTable[i] / 100; + color.r = MIN(255, (uint16)color.r * _fadeTable[i] / 100); + color.g = MIN(255, (uint16)color.g * _fadeTable[i] / 100); + color.b = MIN(255, (uint16)color.b * _fadeTable[i] / 100); } } -} + +} // End of namespace Sci diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h index 9da217bf31..b8388d11ea 100644 --- a/engines/sci/graphics/palette32.h +++ b/engines/sci/graphics/palette32.h @@ -265,13 +265,19 @@ private: * The fade table records the expected intensity level of each pixel * in the palette that will be displayed on the next frame. */ - byte _fadeTable[256]; + uint16 _fadeTable[256]; public: - void setFade(const uint8 percent, const uint8 fromColor, const uint16 toColor); + /** + * Sets the intensity level for a range of palette + * entries. An intensity of zero indicates total + * darkness. Intensity may be set to over 100 percent. + */ + void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor); void fadeOff(); void applyFade(); }; -} + +} // End of namespace Sci #endif diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp index 52dde4b465..4487070948 100644 --- a/engines/sci/graphics/plane32.cpp +++ b/engines/sci/graphics/plane32.cpp @@ -43,10 +43,10 @@ void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) { #pragma mark Plane uint16 Plane::_nextObjectId = 20000; -Plane::Plane(const Common::Rect &gameRect) : +Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) : _width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), _height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), -_pictureId(kPlanePicColored), +_pictureId(pictureId), _mirrored(false), _back(0), _priorityChanged(0), @@ -55,6 +55,7 @@ _redrawAllCount(g_sci->_gfxFrameout->getScreenCount()), _created(g_sci->_gfxFrameout->getScreenCount()), _updated(0), _deleted(0), +_moved(0), _gameRect(gameRect) { convertGameRectToPlaneRect(); _priority = MAX(10000, g_sci->_gfxFrameout->getPlanes().getTopPlanePriority() + 1); @@ -296,7 +297,7 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList ScreenItemList::size_type planeItemCount = _screenItemList.size(); ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size(); - for (PlaneList::size_type i = 0; i < planeItemCount; ++i) { + for (ScreenItemList::size_type i = 0; i < planeItemCount; ++i) { ScreenItem *vitem = nullptr; // NOTE: The original engine used an array without bounds checking // so could just get the visible screen item directly; we need to @@ -311,13 +312,15 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList if (i < _screenItemList.size() && item != nullptr) { if (item->_deleted) { // add item's rect to erase list - if (i < visiblePlane._screenItemList.size() && vitem != nullptr) { - if (!vitem->_screenRect.isEmpty()) { - if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps? - mergeToRectList(vitem->_screenRect, eraseList); - } else { - eraseList.add(vitem->_screenRect); - } + if ( + i < visiblePlane._screenItemList.size() && + vitem != nullptr && + !vitem->_screenRect.isEmpty() + ) { + if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps? + mergeToRectList(vitem->_screenRect, eraseList); + } else { + eraseList.add(vitem->_screenRect); } } } else if (item->_created) { @@ -350,7 +353,11 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList drawList.add(item, item->_screenRect); mergeToRectList(item->_screenRect, eraseList); } - if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) { + if ( + i < visiblePlaneItemCount && + vitem != nullptr && + !vitem->_screenRect.isEmpty() + ) { mergeToRectList(vitem->_screenRect, eraseList); } } else { @@ -358,10 +365,11 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList // and item to draw list // TODO: This was changed from disasm, verify please! - Common::Rect extendedScreenItem = vitem->_screenRect; - extendedScreenItem.extend(item->_screenRect); + Common::Rect extendedScreenRect = vitem->_screenRect; + extendedScreenRect.extend(item->_screenRect); + drawList.add(item, item->_screenRect); - mergeToRectList(extendedScreenItem, eraseList); + mergeToRectList(extendedScreenRect, eraseList); } } else { // if no active remaps, just add item to draw list and old rect @@ -369,7 +377,11 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList if (!item->_screenRect.isEmpty()) { drawList.add(item, item->_screenRect); } - if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) { + if ( + i < visiblePlaneItemCount && + vitem != nullptr && + !vitem->_screenRect.isEmpty() + ) { eraseList.add(vitem->_screenRect); } } @@ -381,6 +393,10 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList breakEraseListByPlanes(eraseList, planeList); breakDrawListByPlanes(drawList, planeList); + // We store the current size of the drawlist, as we want to loop + // over the currently inserted entries later. + DrawList::size_type drawListSizePrimary = drawList.size(); + // NOTE: Setting this to true fixes the menu bars in GK1 if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"???? _screenItemList.sort(); @@ -428,31 +444,42 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList for (RectList::size_type i = 0; i < eraseList.size(); ++i) { for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) { ScreenItem *item = _screenItemList[j]; - if (item != nullptr && !item->_updated && !item->_deleted && !item->_created && eraseList[i]->intersects(item->_screenRect)) { + if ( + item != nullptr && + !item->_created && !item->_updated && !item->_deleted && + eraseList[i]->intersects(item->_screenRect) + ) { drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect)); } } } } + if (/* TODO: g_Remap_numActiveRemaps == 0 */ true) { // no remaps active? // Add all items that overlap with items in the drawlist and have higher - // priority - for (DrawList::size_type i = 0; i < drawList.size(); ++i) { + // priority. + + // We only loop over "primary" items in the draw list, skipping + // those that were added because of the erase list in the previous loop, + // or those to be added in this loop. + for (DrawList::size_type i = 0; i < drawListSizePrimary; ++i) { DrawItem *dli = drawList[i]; - for (PlaneList::size_type j = 0; j < planeItemCount; ++j) { + for (ScreenItemList::size_type j = 0; j < planeItemCount; ++j) { ScreenItem *sli = _screenItemList[j]; - if (i < drawList.size() && dli) { - if (j < _screenItemList.size() && sli) { - if (!sli->_updated && !sli->_deleted && !sli->_created) { - ScreenItem *item = dli->screenItem; - if (sli->_priority > item->_priority /* TODO: || (sli->_priority == item->_priority && sli->_object > item->_object)*/) { - if (dli->rect.intersects(sli->_screenRect)) { - drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect)); - } - } - } + if ( + i < drawList.size() && dli != nullptr && + j < _screenItemList.size() && sli != nullptr && + !sli->_created && !sli->_updated && !sli->_deleted + ) { + ScreenItem *item = dli->screenItem; + + if ( + (sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) && + dli->rect.intersects(sli->_screenRect) + ) { + drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect)); } } } @@ -491,8 +518,7 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force if (item->_created) { item->_created--; if (visiblePlane != nullptr) { - ScreenItem *n = new ScreenItem(*item); - visiblePlane->_screenItemList.add(n); + visiblePlane->_screenItemList.add(new ScreenItem(*item)); } } @@ -582,14 +608,13 @@ void Plane::filterUpEraseRects(DrawList &drawList, RectList &eraseList) const { } } -void Plane::mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const { +void Plane::mergeToDrawList(const ScreenItemList::size_type index, const Common::Rect &rect, DrawList &drawList) const { RectList rects; - Common::Rect r = _screenItemList[index]->_screenRect; + ScreenItem *item = _screenItemList[index]; + Common::Rect r = item->_screenRect; r.clip(rect); - rects.add(r); - ScreenItem *item = _screenItemList[index]; for (RectList::size_type i = 0; i < rects.size(); ++i) { r = *rects[i]; @@ -778,6 +803,17 @@ void Plane::update(const reg_t object) { #pragma mark - #pragma mark PlaneList +void PlaneList::add(Plane *plane) { + for (iterator it = begin(); it != end(); ++it) { + if ((*it)->_priority > plane->_priority) { + insert(it, plane); + return; + } + } + + push_back(plane); +} + void PlaneList::clear() { for (iterator it = begin(); it != end(); ++it) { delete *it; @@ -795,6 +831,11 @@ void PlaneList::erase(Plane *plane) { } } +PlaneList::iterator PlaneList::erase(iterator it) { + delete *it; + return PlaneListBase::erase(it); +} + int PlaneList::findIndexByObject(const reg_t object) const { for (size_type i = 0; i < size(); ++i) { if ((*this)[i] != nullptr && (*this)[i]->_object == object) { @@ -837,15 +878,8 @@ int16 PlaneList::getTopSciPlanePriority() const { return priority; } -void PlaneList::add(Plane *plane) { - for (iterator it = begin(); it != end(); ++it) { - if ((*it)->_priority < plane->_priority) { - insert(it, plane); - return; - } - } - - push_back(plane); +void PlaneList::remove_at(size_type index) { + delete PlaneListBase::remove_at(index); } -} +} // End of namespace Sci diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h index be6f71464a..d844919c9e 100644 --- a/engines/sci/graphics/plane32.h +++ b/engines/sci/graphics/plane32.h @@ -133,7 +133,7 @@ private: * synchronised to another plane (which calls * changePic). */ - bool _pictureChanged; // ? + bool _pictureChanged; // TODO: Are these ever actually used? int _field_34, _field_38; // probably a point or ratio @@ -241,30 +241,28 @@ public: */ static void init(); - Plane(const Common::Rect &gameRect); + // NOTE: This constructor signature originally did not accept a + // picture ID, but some calls to construct planes with this signature + // immediately set the picture ID and then called setType again, so + // it made more sense to just make the picture ID a parameter instead. + Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId = kPlanePicColored); + Plane(const reg_t object); + Plane(const Plane &other); + void operator=(const Plane &other); + inline bool operator<(const Plane &other) const { - // TODO: In SCI engine, _object is actually a uint16 and can either - // contain a MemID (a handle to MemoryMgr, similar to reg_t) or - // a serial (Plane::_nextObjectId). These numbers can be compared - // directly in the real engine and the lowest MemID wins, but in - // ScummVM reg_t pointers are not comparable so we have to use a - // different strategy when two planes generated by scripts conflict. - // For now we just don't check if the priority is below 0, since - // that priority is used to represent hidden planes and is guaranteed - // to generate conflicts with script-generated planes. If there are - // other future conflicts with script-generated planes then we need - // to come up with a solution that works, similar to - // reg_t::pointerComparisonWithInteger used by SCI16. - // - // For now, we check the object offsets, as this will likely work - // like in the original SCI engine, without comparing objects. - // However, this whole comparison is quite ugly, and if it still - // fails, we should try to change it to something equivalent, to avoid - // adding loads of workarounds just for this - return _priority < other._priority || (_priority == other._priority && _priority > -1 && _object.getOffset() < other._object.getOffset()); + if (_priority < other._priority) { + return true; + } + + if (_priority == other._priority) { + return _object < other._object; + } + + return false; } /** @@ -318,12 +316,6 @@ private: inline void addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX); /** - * If the plane is a picture plane, re-adds all cels - * from its picture resource to the plane. - */ - void changePic(); - - /** * Marks all screen items to be deleted that are within * this plane and match the given picture ID. */ @@ -352,6 +344,13 @@ public: */ void addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX); + /** + * If the plane is a picture plane, re-adds all cels + * from its picture resource to the plane. Otherwise, + * just clears the _pictureChanged flag. + */ + void changePic(); + #pragma mark - #pragma mark Plane - Rendering private: @@ -459,13 +458,14 @@ public: void add(Plane *plane); void clear(); - using PlaneListBase::erase; + iterator erase(iterator it); void erase(Plane *plane); inline void sort() { Common::sort(begin(), end(), sortHelper); } + void remove_at(size_type index); }; -} +} // End of namespace Sci #endif diff --git a/engines/sci/graphics/remap.cpp b/engines/sci/graphics/remap.cpp new file mode 100644 index 0000000000..1f1ae4da0e --- /dev/null +++ b/engines/sci/graphics/remap.cpp @@ -0,0 +1,134 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "sci/sci.h" +#include "sci/resource.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" +#include "sci/graphics/screen.h" + +namespace Sci { + +#pragma mark - +#pragma mark SCI16 remapping (QFG4 demo) + +GfxRemap::GfxRemap(GfxScreen *screen, GfxPalette *palette) + : _screen(screen), _palette(palette) { + _remapOn = false; + resetRemapping(); +} + +GfxRemap::~GfxRemap() { +} + +byte GfxRemap::remapColor(byte remappedColor, byte screenColor) { + assert(_remapOn); + if (_remappingType[remappedColor] == kRemappingByRange) + return _remappingByRange[screenColor]; + else if (_remappingType[remappedColor] == kRemappingByPercent) + return _remappingByPercent[screenColor]; + else + error("remapColor(): Color %d isn't remapped", remappedColor); + + return 0; // should never reach here +} + +void GfxRemap::resetRemapping() { + _remapOn = false; + _remappingPercentToSet = 0; + + for (int i = 0; i < 256; i++) { + _remappingType[i] = kRemappingNone; + _remappingByPercent[i] = i; + _remappingByRange[i] = i; + } +} + +void GfxRemap::setRemappingPercent(byte color, byte percent) { + _remapOn = true; + + // We need to defer the setup of the remapping table every time the screen + // palette is changed, so that kernelFindColor() can find the correct + // colors. Set it once here, in case the palette stays the same and update + // it on each palette change by copySysPaletteToScreen(). + _remappingPercentToSet = percent; + + for (int i = 0; i < 256; i++) { + byte r = _palette->_sysPalette.colors[i].r * _remappingPercentToSet / 100; + byte g = _palette->_sysPalette.colors[i].g * _remappingPercentToSet / 100; + byte b = _palette->_sysPalette.colors[i].b * _remappingPercentToSet / 100; + _remappingByPercent[i] = _palette->kernelFindColor(r, g, b); + } + + _remappingType[color] = kRemappingByPercent; +} + +void GfxRemap::setRemappingRange(byte color, byte from, byte to, byte base) { + _remapOn = true; + + for (int i = from; i <= to; i++) { + _remappingByRange[i] = i + base; + } + + _remappingType[color] = kRemappingByRange; +} + +void GfxRemap::updateRemapping() { + // Check if we need to reset remapping by percent with the new colors. + if (_remappingPercentToSet) { + for (int i = 0; i < 256; i++) { + byte r = _palette->_sysPalette.colors[i].r * _remappingPercentToSet / 100; + byte g = _palette->_sysPalette.colors[i].g * _remappingPercentToSet / 100; + byte b = _palette->_sysPalette.colors[i].b * _remappingPercentToSet / 100; + _remappingByPercent[i] = _palette->kernelFindColor(r, g, b); + } + } +} + +#pragma mark - +#pragma mark SCI32 remapping + +#if 0 +// TODO +void GfxRemap32::setRemappingPercentGray(byte color, byte percent) { + _remapOn = true; + + // We need to defer the setup of the remapping table every time the screen + // palette is changed, so that kernelFindColor() can find the correct + // colors. Set it once here, in case the palette stays the same and update + // it on each palette change by copySysPaletteToScreen(). + _remappingPercentToSet = percent; + + // Note: This is not what the original does, but the results are the same visually + for (int i = 0; i < 256; i++) { + byte rComponent = (byte)(_sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100); + byte gComponent = (byte)(_sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100); + byte bComponent = (byte)(_sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100); + byte luminosity = rComponent + gComponent + bComponent; + _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity); + } + + _remappingType[color] = kRemappingByPercent; +} +#endif + +} // End of namespace Sci diff --git a/engines/sci/graphics/remap.h b/engines/sci/graphics/remap.h new file mode 100644 index 0000000000..e92eaffad2 --- /dev/null +++ b/engines/sci/graphics/remap.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SCI_GRAPHICS_REMAP_H +#define SCI_GRAPHICS_REMAP_H + +#include "common/array.h" +#include "sci/graphics/helpers.h" + +namespace Sci { + +class GfxScreen; + +enum ColorRemappingType { + kRemappingNone = 0, + kRemappingByRange = 1, + kRemappingByPercent = 2 +}; + +/** + * Remap class, handles color remapping + */ +class GfxRemap { +public: + GfxRemap(GfxScreen *screen, GfxPalette *_palette); + ~GfxRemap(); + void resetRemapping(); + void setRemappingPercent(byte color, byte percent); + void setRemappingRange(byte color, byte from, byte to, byte base); + bool isRemapped(byte color) const { + return _remapOn && (_remappingType[color] != kRemappingNone); + } + byte remapColor(byte remappedColor, byte screenColor); + void updateRemapping(); + +private: + GfxScreen *_screen; + GfxPalette *_palette; + + bool _remapOn; + ColorRemappingType _remappingType[256]; + byte _remappingByPercent[256]; + byte _remappingByRange[256]; + uint16 _remappingPercentToSet; +}; + +#ifdef ENABLE_SCI32 +class GfxRemap32 { +public: + GfxRemap32(GfxScreen *screen, GfxPalette *_palette) {} + ~GfxRemap32() {} + //void setRemappingPercentGray(byte color, byte percent); +}; +#endif + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp index a07dacee83..4a42221875 100644 --- a/engines/sci/graphics/screen_item32.cpp +++ b/engines/sci/graphics/screen_item32.cpp @@ -83,7 +83,7 @@ _mirrorX(false) { } } -ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect, const ScaleInfo &scaleInfo) : +ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo) : _plane(plane), _scale(scaleInfo), _useInsetRect(false), @@ -91,7 +91,7 @@ _z(0), _celInfo(celInfo), _celObj(nullptr), _fixPriority(false), -_position(rect.left, rect.top), +_position(position), _object(make_reg(0, _nextObjectId++)), _pictureId(-1), _created(g_sci->_gfxFrameout->getScreenCount()), @@ -126,6 +126,10 @@ void ScreenItem::operator=(const ScreenItem &other) { _scaledPosition = other._scaledPosition; } +ScreenItem::~ScreenItem() { + delete _celObj; +} + void ScreenItem::init() { _nextObjectId = 20000; } @@ -395,7 +399,7 @@ void ScreenItem::calcRects(const Plane &plane) { } } -CelObj &ScreenItem::getCelObj() { +CelObj &ScreenItem::getCelObj() const { if (_celObj == nullptr) { switch (_celInfo.type) { case kCelTypeView: @@ -417,7 +421,7 @@ CelObj &ScreenItem::getCelObj() { } void ScreenItem::printDebugInfo(Console *con) const { - con->debugPrintf("%x:%x (%s), prio %d, x %d, y %d, z: %d, scaledX: %d, scaledY: %d flags: %d\n", + con->debugPrintf("%04x:%04x (%s), prio %d, x %d, y %d, z: %d, scaledX: %d, scaledY: %d flags: %d\n", _object.getSegment(), _object.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(_object), _priority, @@ -523,4 +527,4 @@ void ScreenItemList::unsort() { } } -} +} // End of namespace Sci diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h index 0ca840a13a..52782acc56 100644 --- a/engines/sci/graphics/screen_item32.h +++ b/engines/sci/graphics/screen_item32.h @@ -125,7 +125,7 @@ public: * item. This member is populated by calling * `getCelObj`. */ - CelObj *_celObj; + mutable CelObj *_celObj; /** * If set, the priority for this screen item is fixed @@ -213,8 +213,9 @@ public: ScreenItem(const reg_t screenItem); ScreenItem(const reg_t plane, const CelInfo32 &celInfo); ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect); - ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect, const ScaleInfo &scaleInfo); + ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo); ScreenItem(const ScreenItem &other); + ~ScreenItem(); void operator=(const ScreenItem &); inline bool operator<(const ScreenItem &other) const { @@ -228,9 +229,7 @@ public: } if (_position.y + _z == other._position.y + other._z) { - return false; - // TODO: Failure in SQ6 room 220 -// return _object < other._object; + return _object < other._object; } } @@ -251,7 +250,7 @@ public: * screen item. If a cel object does not already exist, * one will be created and assigned. */ - CelObj &getCelObj(); + CelObj &getCelObj() const; void printDebugInfo(Console *con) const; @@ -277,6 +276,6 @@ public: void sort(); void unsort(); }; -} +} // End of namespace Sci #endif diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 8e3222f580..fa19047a4c 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -40,10 +40,9 @@ namespace Sci { int16 GfxText32::_defaultFontId = 0; -GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) : +GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) : _segMan(segMan), _cache(fonts), - _screen(screen), _scaledWidth(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), _scaledHeight(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), // Not a typo, the original engine did not initialise height, only width @@ -60,7 +59,7 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) : _font = _cache->getFont(_defaultFontId); } -reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling, reg_t *outBitmapObject) { +reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling) { _field_22 = 0; _borderColor = borderColor; @@ -98,10 +97,8 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect _textRect = Common::Rect(); } - _bitmap = _segMan->allocateHunkEntry("FontBitmap()", _width * _height + CelObjMem::getBitmapHeaderSize()); - - byte *bitmap = _segMan->getHunkPointer(_bitmap); - CelObjMem::buildBitmapHeader(bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); + BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); + _bitmap = bitmap.getObject(); erase(bitmapRect, false); @@ -110,12 +107,10 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect } drawTextBox(); - - *outBitmapObject = _bitmap; return _bitmap; } -reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, reg_t *outBitmapObject) { +reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed) { _field_22 = 0; _borderColor = borderColor; _text = text; @@ -143,11 +138,9 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect & _textRect = Common::Rect(); } - _bitmap = _segMan->allocateHunkEntry("FontBitmap()", _width * _height + CelObjMem::getBitmapHeaderSize()); - byte *bitmap = _segMan->getHunkPointer(_bitmap); - CelObjMem::buildBitmapHeader(bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); - - Buffer buffer(_width, _height, bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28)); + BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); + _bitmap = bitmap.getObject(); + Buffer buffer(_width, _height, bitmap.getPixels()); // NOTE: The engine filled the bitmap pixels with 11 here, which is silly // because then it just erased the bitmap using the skip color. So we don't @@ -175,10 +168,14 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect & } } - *outBitmapObject = _bitmap; return _bitmap; } +reg_t GfxText32::createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling) { + warning("TODO: createTitledBitmap incomplete !"); + return createFontBitmap(width, height, textRect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, false, doScaling); +} + void GfxText32::setFont(const GuiResourceId fontId) { // NOTE: In SCI engine this calls FontMgr::BuildFontTable and then a font // table is built on the FontMgr directly; instead, because we already have @@ -193,16 +190,35 @@ void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint Common::Rect targetRect = doScaling ? scaleRect(rect) : rect; byte *bitmap = _segMan->getHunkPointer(_bitmap); - byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); + byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28) + rect.top * _width + rect.left; // NOTE: Not fully disassembled, but this should be right - // TODO: Implement variable frame size - assert(size == 1); - Buffer buffer(_width, _height, pixels); - buffer.frameRect(targetRect, color); + int16 rectWidth = targetRect.width(); + int16 sidesHeight = targetRect.height() - size * 2; + int16 centerWidth = rectWidth - size * 2; + int16 stride = _width - rectWidth; + + for (int16 y = 0; y < size; ++y) { + memset(pixels, color, rectWidth); + pixels += _width; + } + for (int16 y = 0; y < sidesHeight; ++y) { + for (int16 x = 0; x < size; ++x) { + *pixels++ = color; + } + pixels += centerWidth; + for (int16 x = 0; x < size; ++x) { + *pixels++ = color; + } + pixels += stride; + } + for (int16 y = 0; y < size; ++y) { + memset(pixels, color, rectWidth); + pixels += _width; + } } -void GfxText32::drawChar(const uint8 charIndex) { +void GfxText32::drawChar(const char charIndex) { byte *bitmap = _segMan->getHunkPointer(_bitmap); byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); @@ -210,7 +226,7 @@ void GfxText32::drawChar(const uint8 charIndex) { _drawPosition.x += _font->getCharWidth(charIndex); } -uint16 GfxText32::getCharWidth(const uint8 charIndex, const bool doScaling) const { +uint16 GfxText32::getCharWidth(const char charIndex, const bool doScaling) const { uint16 width = _font->getCharWidth(charIndex); if (doScaling) { width = scaleUpWidth(width); @@ -253,6 +269,11 @@ void GfxText32::drawTextBox() { } } +void GfxText32::drawTextBox(const Common::String &text) { + _text = text; + drawTextBox(); +} + void GfxText32::drawText(const uint index, uint length) { assert(index + length <= _text.size()); @@ -309,6 +330,51 @@ void GfxText32::drawText(const uint index, uint length) { } } +void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) { + Common::Rect targetRect = rect; + if (doScaling) { + bitmapStride = bitmapStride * _scaledWidth / g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + targetRect = scaleRect(rect); + } + + byte *bitmapData = _segMan->getHunkPointer(bitmap); + + // NOTE: SCI code is super weird here; it seems to be trying to look at the + // entire size of the bitmap including the header, instead of just the pixel + // data size. We just look at the pixel size. This function generally is an + // odd duck since the stride dimension for a bitmap is built in to the bitmap + // header, so perhaps it was once an unheadered bitmap format and this + // function was never updated to match? Or maybe they exploit the + // configurable stride length somewhere else to do stair stepping inverts... + uint32 invertSize = targetRect.height() * bitmapStride + targetRect.width(); + uint32 bitmapSize = READ_SCI11ENDIAN_UINT32(bitmapData + 12); + + if (invertSize >= bitmapSize) { + error("InvertRect too big: %u >= %u", invertSize, bitmapSize); + } + + // NOTE: Actual engine just added the bitmap header size hardcoded here + byte *pixel = bitmapData + READ_SCI11ENDIAN_UINT32(bitmapData + 28) + bitmapStride * targetRect.top + targetRect.left; + + int16 stride = bitmapStride - targetRect.width(); + int16 targetHeight = targetRect.height(); + int16 targetWidth = targetRect.width(); + + for (int16 y = 0; y < targetHeight; ++y) { + for (int16 x = 0; x < targetWidth; ++x) { + if (*pixel == foreColor) { + *pixel = backColor; + } else if (*pixel == backColor) { + *pixel = foreColor; + } + + ++pixel; + } + + pixel += stride; + } +} + uint GfxText32::getLongest(uint *charIndex, const int16 width) { assert(width > 0); @@ -543,7 +609,7 @@ Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth, } void GfxText32::erase(const Common::Rect &rect, const bool doScaling) { - Common::Rect targetRect = doScaling ? rect : scaleRect(rect); + Common::Rect targetRect = doScaling ? scaleRect(rect) : rect; byte *bitmap = _segMan->getHunkPointer(_bitmap); byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); @@ -556,10 +622,7 @@ void GfxText32::erase(const Common::Rect &rect, const bool doScaling) { } int16 GfxText32::getStringWidth(const Common::String &text) { - // TODO: The fact that this double-scales the text makes it - // seem pretty unlikely that this is ever called in real life - error("Called weirdo getStringWidth (FontMgr::StringWidth)"); - return scaleUpWidth(getTextWidth(text, 0, 10000)); + return getTextWidth(text, 0, 10000); } } // End of namespace Sci diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h index 5de54d318f..472d5e0956 100644 --- a/engines/sci/graphics/text32.h +++ b/engines/sci/graphics/text32.h @@ -34,6 +34,200 @@ enum TextAlign { kTextAlignRight = 2 }; +enum BitmapFlags { + kBitmapRemap = 2 +}; + +#define BITMAP_PROPERTY(size, property, offset)\ +inline uint##size get##property() const {\ + return READ_SCI11ENDIAN_UINT##size(_bitmap + (offset));\ +}\ +inline void set##property(uint##size value) {\ + WRITE_SCI11ENDIAN_UINT##size(_bitmap + (offset), (value));\ +} + +/** + * A convenience class for creating and modifying in-memory + * bitmaps. + */ +class BitmapResource { + byte *_bitmap; + reg_t _object; + + /** + * Gets the size of the bitmap header for the current + * engine version. + */ + static inline uint16 getBitmapHeaderSize() { + // TODO: These values are accurate for each engine, but there may be no reason + // to not simply just always use size 40, since SCI2.1mid does not seem to + // actually store any data above byte 40, and SCI2 did not allow bitmaps with + // scaling resolutions other than the default (320x200). Perhaps SCI3 used + // the extra bytes, or there is some reason why they tried to align the header + // size with other headers like pic headers? +// uint32 bitmapHeaderSize; +// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) { +// bitmapHeaderSize = 46; +// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) { +// bitmapHeaderSize = 40; +// } else { +// bitmapHeaderSize = 36; +// } +// return bitmapHeaderSize; + return 46; + } + + /** + * Gets the byte size of a bitmap with the given width + * and height. + */ + static inline uint32 getBitmapSize(const uint16 width, const uint16 height) { + return width * height + getBitmapHeaderSize(); + } + +public: + /** + * Create a bitmap resource for an existing bitmap. + * Ownership of the bitmap is retained by the caller. + */ + inline BitmapResource(reg_t bitmap) : + _bitmap(g_sci->getEngineState()->_segMan->getHunkPointer(bitmap)), + _object(bitmap) { + if (_bitmap == nullptr || getUncompressedDataOffset() != getBitmapHeaderSize()) { + error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap)); + } + } + + /** + * Allocates and initialises a new bitmap in the given + * segment manager. + */ + inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool remap) { + + _object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height)); + _bitmap = segMan->getHunkPointer(_object); + + const uint16 bitmapHeaderSize = getBitmapHeaderSize(); + + setWidth(width); + setHeight(height); + setDisplace(Common::Point(displaceX, displaceY)); + setSkipColor(skipColor); + _bitmap[9] = 0; + WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, 0); + setRemap(remap); + setDataSize(width * height); + WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0); + setHunkPaletteOffset(hunkPaletteOffset); + setDataOffset(bitmapHeaderSize); + setUncompressedDataOffset(bitmapHeaderSize); + setControlOffset(0); + setScaledWidth(scaledWidth); + setScaledHeight(scaledHeight); + } + + reg_t getObject() const { + return _object; + } + + BITMAP_PROPERTY(16, Width, 0); + BITMAP_PROPERTY(16, Height, 2); + + inline Common::Point getDisplace() const { + return Common::Point( + (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 4), + (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 6) + ); + } + + inline void setDisplace(const Common::Point &displace) { + WRITE_SCI11ENDIAN_UINT16(_bitmap + 4, (uint16)displace.x); + WRITE_SCI11ENDIAN_UINT16(_bitmap + 6, (uint16)displace.y); + } + + inline uint8 getSkipColor() const { + return _bitmap[8]; + } + + inline void setSkipColor(const uint8 skipColor) { + _bitmap[8] = skipColor; + } + + inline bool getRemap() const { + return READ_SCI11ENDIAN_UINT16(_bitmap + 10) & kBitmapRemap; + } + + inline void setRemap(const bool remap) { + uint16 flags = READ_SCI11ENDIAN_UINT16(_bitmap + 10); + if (remap) { + flags |= kBitmapRemap; + } else { + flags &= ~kBitmapRemap; + } + WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, flags); + } + + BITMAP_PROPERTY(32, DataSize, 12); + + inline uint32 getHunkPaletteOffset() const { + return READ_SCI11ENDIAN_UINT32(_bitmap + 20); + } + + void setHunkPaletteOffset(uint32 hunkPaletteOffset) { + if (hunkPaletteOffset) { + hunkPaletteOffset += getBitmapHeaderSize(); + } + + WRITE_SCI11ENDIAN_UINT32(_bitmap + 20, hunkPaletteOffset); + } + + BITMAP_PROPERTY(32, DataOffset, 24); + + // NOTE: This property is used as a "magic number" for + // validating that a block of memory is a valid bitmap, + // and so is always set to the size of the header. + BITMAP_PROPERTY(32, UncompressedDataOffset, 28); + + // NOTE: This property always seems to be zero + BITMAP_PROPERTY(32, ControlOffset, 32); + + inline uint16 getScaledWidth() const { + if (getDataOffset() >= 40) { + return READ_SCI11ENDIAN_UINT16(_bitmap + 36); + } + + // SCI2 bitmaps did not have scaling ability + return 320; + } + + inline void setScaledWidth(uint16 scaledWidth) { + if (getDataOffset() >= 40) { + WRITE_SCI11ENDIAN_UINT16(_bitmap + 36, scaledWidth); + } + } + + inline uint16 getScaledHeight() const { + if (getDataOffset() >= 40) { + return READ_SCI11ENDIAN_UINT16(_bitmap + 38); + } + + // SCI2 bitmaps did not have scaling ability + return 200; + } + + inline void setScaledHeight(uint16 scaledHeight) { + if (getDataOffset() >= 40) { + WRITE_SCI11ENDIAN_UINT16(_bitmap + 38, scaledHeight); + } + } + + inline byte *getPixels() { + return _bitmap + getUncompressedDataOffset(); + } +}; + +class GfxFont; + /** * This class handles text calculation and rendering for * SCI32 games. The text calculation system in SCI32 is @@ -45,7 +239,6 @@ class GfxText32 { private: SegManager *_segMan; GfxCache *_cache; - GfxScreen *_screen; /** * The resource ID of the default font used by the game. @@ -111,11 +304,6 @@ private: */ TextAlign _alignment; - /** - * The memory handle of the currently active bitmap. - */ - reg_t _bitmap; - int16 _field_20; /** @@ -133,18 +321,10 @@ private: Common::Point _drawPosition; void drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling); - void drawTextBox(); - void erase(const Common::Rect &rect, const bool doScaling); - void drawChar(const uint8 charIndex); - uint16 getCharWidth(const uint8 charIndex, const bool doScaling) const; + void drawChar(const char charIndex); void drawText(const uint index, uint length); - inline int scaleUpWidth(int value) const { - const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; - return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth; - } - /** * Gets the length of the longest run of text available * within the currently loaded text, starting from the @@ -162,24 +342,23 @@ private: */ int16 getTextWidth(const uint index, uint length) const; - /** - * Gets the pixel width of a substring of the currently - * loaded text, with scaling. - */ - int16 getTextWidth(const Common::String &text, const uint index, const uint length); - inline Common::Rect scaleRect(const Common::Rect &rect) { Common::Rect scaledRect(rect); int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; Ratio scaleX(_scaledWidth, scriptWidth); Ratio scaleY(_scaledHeight, scriptHeight); - mul(scaledRect, scaleX, scaleY); + mulinc(scaledRect, scaleX, scaleY); return scaledRect; } public: - GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen); + GfxText32(SegManager *segMan, GfxCache *fonts); + + /** + * The memory handle of the currently active bitmap. + */ + reg_t _bitmap; /** * The size of the x-dimension of the coordinate system @@ -206,12 +385,52 @@ public: * Creates a plain font bitmap with a flat color * background. */ - reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling, reg_t *outBitmapObject); + reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling); /** * Creates a font bitmap with a view background. */ - reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, reg_t *outBitmapObject); + reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed); + + /** + * Creates a font bitmap with a title. + */ + reg_t createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling); + + inline int scaleUpWidth(int value) const { + const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth; + } + + inline int scaleUpHeight(int value) const { + const int scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + return (value * scriptHeight + _scaledHeight - 1) / _scaledHeight; + } + + /** + * Draws the text to the bitmap. + */ + void drawTextBox(); + + /** + * Draws the given text to the bitmap. + * + * @note The original engine holds a reference to a + * shared string which lets the text be updated from + * outside of the font manager. Instead, we give this + * extra signature to send the text to draw. + * + * TODO: Use shared string instead? + */ + void drawTextBox(const Common::String &text); + + /** + * Erases the given rect by filling with the background + * color. + */ + void erase(const Common::Rect &rect, const bool doScaling); + + void invertRect(const reg_t bitmap, const int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling); /** * Sets the font to be used for rendering and @@ -220,11 +439,22 @@ public: void setFont(const GuiResourceId fontId); /** + * Gets the width of a character. + */ + uint16 getCharWidth(const char charIndex, const bool doScaling) const; + + /** * Retrieves the width and height of a block of text. */ Common::Rect getTextSize(const Common::String &text, const int16 maxWidth, bool doScaling); /** + * Gets the pixel width of a substring of the currently + * loaded text, with scaling. + */ + int16 getTextWidth(const Common::String &text, const uint index, const uint length); + + /** * Retrieves the width of a line of text. */ int16 getStringWidth(const Common::String &text); diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index 4116eda876..ff3fc70619 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -25,6 +25,7 @@ #include "sci/engine/state.h" #include "sci/graphics/screen.h" #include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" #include "sci/graphics/coordadjuster.h" #include "sci/graphics/view.h" @@ -842,12 +843,11 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const const int y2 = clipRectTranslated.top + y; if (!upscaledHires) { if (priority >= _screen->getPriority(x2, y2)) { - if (!_palette->isRemapped(palette->mapping[color])) { - _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); - } else { - byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2)); - _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0); - } + byte outputColor = palette->mapping[color]; + // SCI16 remapping (QFG4 demo) + if (g_sci->_gfxRemap16 && g_sci->_gfxRemap16->isRemapped(outputColor)) + outputColor = g_sci->_gfxRemap16->remapColor(outputColor, _screen->getVisual(x2, y2)); + _screen->putPixel(x2, y2, drawMask, outputColor, priority, 0); } } else { // UpscaledHires means view is hires and is supposed to @@ -957,12 +957,11 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const int x2 = clipRectTranslated.left + x; const int y2 = clipRectTranslated.top + y; if (color != clearKey && priority >= _screen->getPriority(x2, y2)) { - if (!_palette->isRemapped(palette->mapping[color])) { - _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0); - } else { - byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2)); - _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0); - } + byte outputColor = palette->mapping[color]; + // SCI16 remapping (QFG4 demo) + if (g_sci->_gfxRemap16 && g_sci->_gfxRemap16->isRemapped(outputColor)) + outputColor = g_sci->_gfxRemap16->remapColor(outputColor, _screen->getVisual(x2, y2)); + _screen->putPixel(x2, y2, drawMask, outputColor, priority, 0); } } } diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 963b65742d..a02147e4d0 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -57,6 +57,7 @@ MODULE_OBJS := \ graphics/picture.o \ graphics/portrait.o \ graphics/ports.o \ + graphics/remap.o \ graphics/screen.o \ graphics/text16.o \ graphics/transitions.o \ diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 82099413cb..5717a09121 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -688,6 +688,12 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers channel->data = resource->data + dataOffset; channel->size = READ_LE_UINT16(data + 4); + + if (dataOffset + channel->size > resource->size) { + warning("Invalid size inside sound resource %d: track %d, channel %d", resourceNr, trackNr, channelNr); + channel->size = resource->size - dataOffset; + } + channel->curPos = 0; channel->number = *channel->data; diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 52188db0fb..6bc6650245 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -58,6 +58,7 @@ #include "sci/graphics/picture.h" #include "sci/graphics/ports.h" #include "sci/graphics/palette.h" +#include "sci/graphics/remap.h" #include "sci/graphics/screen.h" #include "sci/graphics/text16.h" #include "sci/graphics/transitions.h" @@ -163,6 +164,7 @@ SciEngine::~SciEngine() { delete _gfxText32; delete _robotDecoder; delete _gfxFrameout; + delete _gfxRemap32; #endif delete _gfxMenu; delete _gfxControls16; @@ -175,6 +177,7 @@ SciEngine::~SciEngine() { delete _gfxPorts; delete _gfxCache; delete _gfxPalette16; + delete _gfxRemap16; delete _gfxCursor; delete _gfxScreen; @@ -238,13 +241,7 @@ Common::Error SciEngine::run() { // Only DOS+Windows switch (_gameId) { case GID_KQ6: - if (isCD()) - _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); - break; case GID_GK1: - if ((isCD()) && (!isDemo())) - _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); - break; case GID_PQ4: if (isCD()) _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); @@ -666,6 +663,7 @@ void SciEngine::initGraphics() { _gfxPaint = 0; _gfxPaint16 = 0; _gfxPalette16 = 0; + _gfxRemap16 = 0; _gfxPorts = 0; _gfxText16 = 0; _gfxTransitions = 0; @@ -676,6 +674,7 @@ void SciEngine::initGraphics() { _gfxFrameout = 0; _gfxPaint32 = 0; _gfxPalette32 = 0; + _gfxRemap32 = 0; #endif if (hasMacIconBar()) @@ -685,9 +684,12 @@ void SciEngine::initGraphics() { if (getSciVersion() >= SCI_VERSION_2) { _gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen); _gfxPalette16 = _gfxPalette32; + _gfxRemap32 = new GfxRemap32(_gfxScreen, _gfxPalette32); } else { #endif _gfxPalette16 = new GfxPalette(_resMan, _gfxScreen); + if (getGameId() == GID_QFG4DEMO) + _gfxRemap16 = new GfxRemap(_gfxScreen, _gfxPalette16); #ifdef ENABLE_SCI32 } #endif @@ -705,7 +707,7 @@ void SciEngine::initGraphics() { _gfxPaint = _gfxPaint32; _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32); - _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); + _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache); _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); _gfxFrameout->run(); } else { @@ -834,7 +836,7 @@ Console *SciEngine::getSciDebugger() { } const char *SciEngine::getGameIdStr() const { - return _gameDescription->gameid; + return _gameDescription->gameId; } Common::Language SciEngine::getLanguage() const { diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 3945e68e33..2474db81d9 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -71,6 +71,8 @@ class GfxPaint16; class GfxPaint32; class GfxPalette; class GfxPalette32; +class GfxRemap; +class GfxRemap32; class GfxPorts; class GfxScreen; class GfxText16; @@ -128,6 +130,7 @@ enum SciGameId { GID_FAIRYTALES, GID_FREDDYPHARKAS, GID_FUNSEEKER, + GID_GK1DEMO, // We have a separate ID for GK1 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1) GID_GK1, GID_GK2, GID_HOYLE1, @@ -165,12 +168,14 @@ enum SciGameId { GID_PQ2, GID_PQ3, GID_PQ4, + GID_PQ4DEMO, // We have a separate ID for PQ4 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1) GID_PQSWAT, GID_QFG1, GID_QFG1VGA, GID_QFG2, GID_QFG3, GID_QFG4, + GID_QFG4DEMO, // We have a separate ID for QFG4 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1) GID_RAMA, GID_SHIVERS, //GID_SHIVERS2, // Not SCI @@ -349,6 +354,8 @@ public: GfxMenu *_gfxMenu; // Menu for 16-bit gfx GfxPalette *_gfxPalette16; GfxPalette32 *_gfxPalette32; // Palette for 32-bit gfx + GfxRemap *_gfxRemap16; // Remapping for the QFG4 demo + GfxRemap32 *_gfxRemap32; // Remapping for 32-bit gfx GfxPaint *_gfxPaint; GfxPaint16 *_gfxPaint16; // Painting in 16-bit gfx GfxPaint32 *_gfxPaint32; // Painting in 32-bit gfx diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index ee5903fda2..e7b25eb1fc 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -44,7 +44,7 @@ SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segM // resource number, but it's totally unrelated to the menu music). // The GK1 demo (very late SCI1.1) does the same thing // TODO: Check the QFG4 demo - _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1 || ConfMan.getBool("prefer_digitalsfx")); + _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1DEMO || ConfMan.getBool("prefer_digitalsfx")); _music = new SciMusic(_soundVersion, _useDigitalSFX); _music->init(); diff --git a/engines/scumm/charset-fontdata.cpp b/engines/scumm/charset-fontdata.cpp index 23e89b1878..a1e92a9950 100644 --- a/engines/scumm/charset-fontdata.cpp +++ b/engines/scumm/charset-fontdata.cpp @@ -591,35 +591,40 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language) _fontHeight = 8; _curId = 0; - const byte *replacementData = NULL; + const byte *replacementMap = NULL, *replacementData = NULL; int replacementChars = 0; switch (language) { case Common::DE_DEU: if (_vm->_game.version == 0) { - replacementData = germanCharsetDataV0; + replacementMap = germanCharsetDataV0; replacementChars = sizeof(germanCharsetDataV0) / 2; } else { - replacementData = germanCharsetDataV2; + replacementMap = germanCharsetDataV2; replacementChars = sizeof(germanCharsetDataV2) / 2; } + replacementData = specialCharsetData; break; case Common::FR_FRA: - replacementData = frenchCharsetDataV2; + replacementMap = frenchCharsetDataV2; replacementChars = sizeof(frenchCharsetDataV2) / 2; + replacementData = specialCharsetData; break; case Common::IT_ITA: - replacementData = italianCharsetDataV2; + replacementMap = italianCharsetDataV2; replacementChars = sizeof(italianCharsetDataV2) / 2; + replacementData = specialCharsetData; break; case Common::ES_ESP: - replacementData = spanishCharsetDataV2; + replacementMap = spanishCharsetDataV2; replacementChars = sizeof(spanishCharsetDataV2) / 2; + replacementData = specialCharsetData; break; case Common::RU_RUS: if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) { - replacementData = russCharsetDataV2; + replacementMap = russCharsetDataV2; replacementChars = sizeof(russCharsetDataV2) / 2; + replacementData = russianCharsetDataV2; } else { _fontPtr = russianCharsetDataV2; } @@ -629,20 +634,16 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language) break; } - if (replacementData) { + if (replacementMap && replacementData) { _fontPtr = new byte[sizeof(englishCharsetDataV2)]; _deleteFontPtr = true; memcpy(const_cast<byte *>(_fontPtr), englishCharsetDataV2, sizeof(englishCharsetDataV2)); for (int i = 0; i < replacementChars; i++) { - int ch1 = replacementData[2 * i]; - int ch2 = replacementData[2 * i + 1]; + int ch1 = replacementMap[2 * i]; + int ch2 = replacementMap[2 * i + 1]; - if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) { - memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, russianCharsetDataV2 + 8 * ch2, 8); - } else { - memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, specialCharsetData + 8 * ch2, 8); - } + memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, replacementData + 8 * ch2, 8); } } else _deleteFontPtr = false; diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp index d85299cc24..4b91f50a61 100644 --- a/engines/sky/detection.cpp +++ b/engines/sky/detection.cpp @@ -136,7 +136,7 @@ const ExtraGuiOptions SkyMetaEngine::getExtraGuiOptions(const Common::String &ta } GameDescriptor SkyMetaEngine::findGame(const char *gameid) const { - if (0 == scumm_stricmp(gameid, skySetting.gameid)) + if (0 == scumm_stricmp(gameid, skySetting.gameId)) return skySetting; return GameDescriptor(); } @@ -175,7 +175,7 @@ GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const { // Match found, add to list of candidates, then abort inner loop. // The game detector uses US English by default. We want British // English to match the recorded voices better. - GameDescriptor dg(skySetting.gameid, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown); + GameDescriptor dg(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown); const SkyVersion *sv = skyVersions; while (sv->dinnerTableEntries) { if (dinnerTableEntries == sv->dinnerTableEntries && diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp index 3eac95cdf2..0edf856125 100644 --- a/engines/sword1/detection.cpp +++ b/engines/sword1/detection.cpp @@ -128,17 +128,17 @@ GameList SwordMetaEngine::getSupportedGames() const { } GameDescriptor SwordMetaEngine::findGame(const char *gameid) const { - if (0 == scumm_stricmp(gameid, sword1FullSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1FullSettings.gameId)) return sword1FullSettings; - if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameId)) return sword1DemoSettings; - if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameId)) return sword1MacFullSettings; - if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameId)) return sword1MacDemoSettings; - if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameId)) return sword1PSXSettings; - if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameid)) + if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameId)) return sword1PSXDemoSettings; return GameDescriptor(); } diff --git a/engines/sword25/detection.cpp b/engines/sword25/detection.cpp index 175261a89e..4ca565c972 100644 --- a/engines/sword25/detection.cpp +++ b/engines/sword25/detection.cpp @@ -52,7 +52,7 @@ static const ExtraGuiOption sword25ExtraGuiOption = { class Sword25MetaEngine : public AdvancedMetaEngine { public: Sword25MetaEngine() : AdvancedMetaEngine(Sword25::gameDescriptions, sizeof(ADGameDescription), sword25Game) { - _guioptions = GUIO1(GUIO_NOMIDI); + _guiOptions = GUIO1(GUIO_NOMIDI); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/sword25/detection_tables.h b/engines/sword25/detection_tables.h index fa79bde4d5..927060bf18 100644 --- a/engines/sword25/detection_tables.h +++ b/engines/sword25/detection_tables.h @@ -132,11 +132,14 @@ static const ADGameDescription gameDescriptions[] = { // Distributed by ScummVM // Contains all language packs, English voice-overs and Hungarian version + // Mark it as Unknown Language since it contains multiple languages. If we + // mark it as English, then changing the language in-game causes the detection + // to fail the next time we try to start the engine. { "sword25", "Latest version", AD_ENTRY1s("data.b25c", "880a8a67faf4a4e7ab62cf114b771428", 827397764), - Common::EN_ANY, + Common::UNK_LANG, Common::kPlatformUnknown, ADGF_NO_FLAGS, GUIO1(GUIO_NOASPECT) diff --git a/engines/sword25/gfx/animationresource.cpp b/engines/sword25/gfx/animationresource.cpp index 431d466658..423a2b86b4 100644 --- a/engines/sword25/gfx/animationresource.cpp +++ b/engines/sword25/gfx/animationresource.cpp @@ -211,8 +211,9 @@ bool AnimationResource::precacheAllFrames() const { error("Could not precache \"%s\".", (*iter).fileName.c_str()); return false; } -#else - Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName); +#else + Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName); + pResource->release(); //unlock precached resource #endif } diff --git a/engines/sword25/gfx/fontresource.cpp b/engines/sword25/gfx/fontresource.cpp index c4d4c3c52e..1d7aedcb6e 100644 --- a/engines/sword25/gfx/fontresource.cpp +++ b/engines/sword25/gfx/fontresource.cpp @@ -103,8 +103,9 @@ bool FontResource::parserCallback_font(ParserNode *node) { if (!_pKernel->getResourceManager()->precacheResource(_bitmapFileName)) { error("Could not precache \"%s\".", _bitmapFileName.c_str()); } -#else - _pKernel->getResourceManager()->requestResource(_bitmapFileName); +#else + Resource *pResource = _pKernel->getResourceManager()->requestResource(_bitmapFileName); + pResource->release(); //unlock precached resource #endif return true; diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp index d409c538c0..769c9b1162 100644 --- a/engines/sword25/gfx/text.cpp +++ b/engines/sword25/gfx/text.cpp @@ -77,7 +77,8 @@ bool Text::setFont(const Common::String &font) { return false; } #else - getResourceManager()->requestResource(font); + Resource *pResource = getResourceManager()->requestResource(font); + pResource->release(); //unlock precached resource _font = font; updateFormat(); forceRefresh(); diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp index cefc1a89d3..caa7bdbec9 100644 --- a/engines/teenagent/detection.cpp +++ b/engines/teenagent/detection.cpp @@ -88,7 +88,7 @@ enum { class TeenAgentMetaEngine : public AdvancedMetaEngine { public: TeenAgentMetaEngine() : AdvancedMetaEngine(teenAgentGameDescriptions, sizeof(ADGameDescription), teenAgentGames) { - _singleid = "teenagent"; + _singleId = "teenagent"; } virtual const char *getName() const { diff --git a/engines/testbed/detection.cpp b/engines/testbed/detection.cpp index 348ade62b0..7aff7a1805 100644 --- a/engines/testbed/detection.cpp +++ b/engines/testbed/detection.cpp @@ -49,7 +49,7 @@ class TestbedMetaEngine : public AdvancedMetaEngine { public: TestbedMetaEngine() : AdvancedMetaEngine(testbedDescriptions, sizeof(ADGameDescription), testbed_setting) { _md5Bytes = 512; - _singleid = "testbed"; + _singleId = "testbed"; } virtual const char *getName() const { diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 0c7d0b0665..2fde6e788a 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -85,7 +85,7 @@ static const PlainGameDescriptor tinselGames[] = { class TinselMetaEngine : public AdvancedMetaEngine { public: TinselMetaEngine() : AdvancedMetaEngine(Tinsel::gameDescriptions, sizeof(Tinsel::TinselGameDescription), tinselGames) { - _singleid = "tinsel"; + _singleId = "tinsel"; } virtual const char *getName() const { @@ -228,8 +228,8 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile // Check which files are included in some dw2 ADGameDescription *and* present // in fslist without a '1' suffix character. Compute MD5s and file sizes for these files. - for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) { - if (strcmp(g->desc.gameid, "dw2") != 0) + for (g = &Tinsel::gameDescriptions[0]; g->desc.gameId != 0; ++g) { + if (strcmp(g->desc.gameId, "dw2") != 0) continue; for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) { @@ -265,8 +265,8 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile int maxFilesMatched = 0; // MD5 based matching - for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) { - if (strcmp(g->desc.gameid, "dw2") != 0) + for (g = &Tinsel::gameDescriptions[0]; g->desc.gameId != 0; ++g) { + if (strcmp(g->desc.gameId, "dw2") != 0) continue; bool fileMissing = false; diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp index 145d9544f2..7c707895e6 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -206,7 +206,7 @@ static const ExtraGuiOption toltecsExtraGuiOption = { class ToltecsMetaEngine : public AdvancedMetaEngine { public: ToltecsMetaEngine() : AdvancedMetaEngine(Toltecs::gameDescriptions, sizeof(Toltecs::ToltecsGameDescription), toltecsGames) { - _singleid = "toltecs"; + _singleId = "toltecs"; } virtual const char *getName() const { diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index 2ca2bce2ee..5d2e0a9bca 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -127,7 +127,7 @@ static const char * const directoryGlobs[] = { class ToonMetaEngine : public AdvancedMetaEngine { public: ToonMetaEngine() : AdvancedMetaEngine(Toon::gameDescriptions, sizeof(ADGameDescription), toonGames) { - _singleid = "toon"; + _singleId = "toon"; _maxScanDepth = 3; _directoryGlobs = directoryGlobs; } diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp index 1d0e136d69..dcb58ffae6 100644 --- a/engines/touche/detection.cpp +++ b/engines/touche/detection.cpp @@ -128,7 +128,7 @@ class ToucheMetaEngine : public AdvancedMetaEngine { public: ToucheMetaEngine() : AdvancedMetaEngine(Touche::gameDescriptions, sizeof(ADGameDescription), toucheGames) { _md5Bytes = 4096; - _singleid = "touche"; + _singleId = "touche"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp index 7784a3de1a..fe555f2fdb 100644 --- a/engines/tsage/detection.cpp +++ b/engines/tsage/detection.cpp @@ -40,7 +40,7 @@ struct tSageGameDescription { }; const char *TSageEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 TSageEngine::getGameID() const { @@ -75,7 +75,7 @@ enum { class TSageMetaEngine : public AdvancedMetaEngine { public: TSageMetaEngine() : AdvancedMetaEngine(TsAGE::gameDescriptions, sizeof(TsAGE::tSageGameDescription), tSageGameTitles) { - _singleid = "tsage"; + _singleId = "tsage"; } virtual const char *getName() const { diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp index a2878f4cc8..2447e15d6b 100644 --- a/engines/tucker/detection.cpp +++ b/engines/tucker/detection.cpp @@ -116,7 +116,7 @@ class TuckerMetaEngine : public AdvancedMetaEngine { public: TuckerMetaEngine() : AdvancedMetaEngine(tuckerGameDescriptions, sizeof(ADGameDescription), tuckerGames) { _md5Bytes = 512; - _singleid = "tucker"; + _singleId = "tucker"; } virtual const char *getName() const { diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp index 35e33cd7bc..fcecb8d2b0 100644 --- a/engines/wage/detection.cpp +++ b/engines/wage/detection.cpp @@ -41,6 +41,7 @@ static const PlainGameDescriptor wageGames[] = { {"afm", "Another Fine Mess"}, {"amot", "A Mess O' Trouble"}, {"cantitoe", "Camp Cantitoe"}, + {"raysmaze", "Ray's Maze"}, {"scepters", "Enchanted Scepters"}, {"twisted", "Twisted!"}, {"wage", "WAGE"}, @@ -52,8 +53,8 @@ static const PlainGameDescriptor wageGames[] = { class WageMetaEngine : public AdvancedMetaEngine { public: WageMetaEngine() : AdvancedMetaEngine(Wage::gameDescriptions, sizeof(ADGameDescription), wageGames) { - _singleid = "wage"; - _guioptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); + _singleId = "wage"; + _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI); } virtual const char *getName() const { diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h index 2df16f13b5..fcd03d3e05 100644 --- a/engines/wage/detection_tables.h +++ b/engines/wage/detection_tables.h @@ -23,7 +23,7 @@ namespace Wage { #define ADGF_DEFAULT (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM) -#define ADGF_GENERIC (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_USEEXTRAASTITLE) +#define ADGF_GENERIC (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_USEEXTRAASTITLE|ADGF_AUTOGENTARGET) #define FANGAME(n,m,s) { "wage",n,AD_ENTRY1s(n,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()} #define FANGAMEN(n,f,m,s) { "wage",n,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()} @@ -44,18 +44,34 @@ static const ADGameDescription gameDescriptions[] = { // Polygons with ignored byte 1 FANGAME("Double Trouble", "5e9ee13d09ac54918ed111fa9727ac1c", 557184), FANGAME("Eidisi I", "299d1de4baccf1c66118396519953652", 180480), + // Problems(?) with text on the first screen + FANGAMEN("Enchanted Pencils", "Enchanted Pencils 0.99 (PG)", "35514583fe7ab36fad2569fc87bd887b", 414464), FANGAME("Escape from School!", "a854be48d4af20126d18a9cad93a969b", 51840), FANGAME("Exploration Zeta!", "b9fbb704017d7ea9613b0160f86527bb", 370944), + // Crash in console rendering on the first scene + FANGAME("Fantasy Quest", "599f0b2c7ecce65c39646c05f2c19c1b", 782848), + FANGAME("Find the Heart", "7ae36ffa295651cd6d2d56981d6b5ff7", 108928), // From Joshua's Worlds 1.0 FANGAME("Lost Crystal", "4f21ba8ee64f8d655b9eeb1e3ffd50f7", 792064), FANGAME("Magic Rings", "6e0d1dd561d3dad8f9a7a20ed1f09b16", 112000), FANGAME("Midnight Snack", "346982a32fc701f53bb19771d72063d0", 69504), + FANGAME("Puzzle Piece Search", "51885fe2effeaa14b2b8b08a53931805", 252928), // From Joshua's Worlds 1.0 + // Empty(?) first scene + FANGAME("Pyramid of No Return", "48a9c668ce69206f57e11e1a85970d02", 392192), FANGAME("Queen Quest", "730605d312efedb5e3ff108522fcac18", 59776), + // Crash in console rendering on the initial scene + FANGAME("Quest for the Dark Sword", "7e4e712d151f6c686f6024b0dedf5d34", 590720), + FANGAME("Quest for the Dark Sword", "308cf0fdfa129fa46b325b307f7e88c6", 590720), // Alteranative version + BIGGAME("raysmaze", "v1.5", "Ray's Maze1.5", "e5a3e25dddfffbed461bca3c26073117", 1437184), BIGGAME("scepters", "", "Scepters", "b80bff315897776dda7689cdf829fab4", 360832), // ??? problems with dog bitmap? FANGAMEN("Space Adventure", "SpaceAdventure", "e5b0d8ad6d235ede2f08583342642dfa", 158720), + FANGAME("Star Trek", "2395856df8dbefe9c0609caa985edf73", 55296), + // Crash in bitmap drawing on the first scene + FANGAME("Strange Disappearance", "f9eba5b315853a5599927db2a73c87d3", 781312), FANGAME("Time Bomb", "2df84b636237686b624e736a698a16c4", 66432), // Invalid rect in scene "Access Tube 1" FANGAMEN("The Phoenix v1.2", "The Phoenix", "7fa2a2ac740f22572516843922b7c630", 434560), + FANGAME("The Sultan's Palace", "589aebf6c14bb5c63d9b4b2c37f31e16", 468096), // Admission for on 3rd screen is messed up FANGAME("The Tower", "75eba57a12ed181e07f34eaf6aa9d2c4", 568320), // Doesn't go past first scene diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index 0f4a6b0775..cbf5d92d00 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -74,7 +74,7 @@ public: static const Timer *getTimer(); static const Timer *getLiveTimer(); static void LOG(bool res, const char *fmt, ...); - const char *getGameTargetName() const { return _targetName.c_str(); } + Common::String getGameTargetName() const { return _targetName; } Common::String getGameId() const { return _gameId; } Common::Language getLanguage() const { return _language; } WMETargetExecutable getTargetExecutable() const { diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index bb5e0c4091..39462f7a15 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -56,7 +56,7 @@ namespace Wintermute { #define SAVE_MAGIC_3 0x12564154 ////////////////////////////////////////////////////////////////////////// -BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool deleteSingleton) { +BasePersistenceManager::BasePersistenceManager(const Common::String &savePrefix, bool deleteSingleton) { _saving = false; _offset = 0; _saveStream = nullptr; @@ -91,7 +91,7 @@ BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool dele _thumbnailDataSize = 0; _thumbnailData = nullptr; - if (savePrefix) { + if (savePrefix != "") { _savePrefix = savePrefix; } else if (_gameRef) { _savePrefix = _gameRef->getGameTargetName(); @@ -215,8 +215,8 @@ bool BasePersistenceManager::getSaveExists(int slot) { } ////////////////////////////////////////////////////////////////////////// -bool BasePersistenceManager::initSave(const char *desc) { - if (!desc) { +bool BasePersistenceManager::initSave(const Common::String &desc) { + if (desc == "") { return STATUS_FAILED; } @@ -297,11 +297,11 @@ bool BasePersistenceManager::initSave(const char *desc) { uint32 dataOffset = _offset + sizeof(uint32) + // data offset - sizeof(uint32) + strlen(desc) + 1 + // description + sizeof(uint32) + strlen(desc.c_str()) + 1 + // description sizeof(uint32); // timestamp putDWORD(dataOffset); - putString(desc); + putString(desc.c_str()); g_system->getTimeAndDate(_savedTimestamp); putTimeDate(_savedTimestamp); diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index 373d1580de..760b45c907 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -63,7 +63,7 @@ public: uint32 getMaxUsedSlot(); bool getSaveExists(int slot); bool initLoad(const Common::String &filename); - bool initSave(const char *desc); + bool initSave(const Common::String &desc); bool getBytes(byte *buffer, uint32 size); bool putBytes(byte *buffer, uint32 size); uint32 _offset; @@ -86,7 +86,7 @@ public: bool transferCharPtr(const char *name, char **val); bool transferString(const char *name, Common::String *val); bool transferVector2(const char *name, Vector2 *val); - BasePersistenceManager(const char *savePrefix = nullptr, bool deleteSingleton = false); + BasePersistenceManager(const Common::String &savePrefix = "", bool deleteSingleton = false); virtual ~BasePersistenceManager(); bool checkVersion(byte verMajor, byte verMinor, byte verBuild); diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 82a9e24dfb..d0c51616f4 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -113,13 +113,28 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { Common::String fixedFilename = filename; correctSlashes(fixedFilename); - // Absolute path: TODO: Add specific fallbacks here. + // HACK: There are a few games around which mistakenly refer to absolute paths in the scripts. + // The original interpreter on Windows usually simply ignores them when it can't find them. + // We try to turn the known ones into relative paths. if (fixedFilename.contains(':')) { - if (fixedFilename.hasPrefix("c:/windows/fonts/")) { // East Side Story refers to "c:\windows\fonts\framd.ttf" - fixedFilename = filename.c_str() + 14; - } else if (fixedFilename.hasPrefix("c:/carol6/svn/data/")) { // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" - fixedFilename = fixedFilename.c_str() + 19; - } else { + const char* const knownPrefixes[] = { // Known absolute paths + "c:/windows/fonts/", // East Side Story refers to "c:\windows\fonts\framd.ttf" + "c:/carol6/svn/data/", // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" + "f:/dokument/spel 5/demo/data/" // Carol Reed 5 (non-demo) refers to "f:\dokument\spel 5\demo\data\scenes\credits\op_cred_00\op_cred_00.jpg" + }; + + bool matched = false; + + for (uint i = 0; i < ARRAYSIZE(knownPrefixes); i++) { + if (fixedFilename.hasPrefix(knownPrefixes[i])) { + fixedFilename = fixedFilename.c_str() + strlen(knownPrefixes[i]); + matched = true; + } + } + + if (!matched) { + // fixedFilename is unchanged and thus still broken, none of the above workarounds worked. + // We can only bail out error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str()); } } diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index aca682ae99..f77eb5c64d 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -75,8 +75,8 @@ static const char *directoryGlobs[] = { class WintermuteMetaEngine : public AdvancedMetaEngine { public: WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { - _singleid = "wintermute"; - _guioptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS); + _singleId = "wintermute"; + _guiOptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } @@ -94,8 +94,8 @@ public: s_fallbackDesc.language = Common::UNK_LANG; s_fallbackDesc.flags = ADGF_UNSTABLE; s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows - s_fallbackDesc.gameid = "wintermute"; - s_fallbackDesc.guioptions = GUIO0(); + s_fallbackDesc.gameId = "wintermute"; + s_fallbackDesc.guiOptions = GUIO0(); if (allFiles.contains("data.dcp")) { Common::String name, caption; @@ -109,7 +109,7 @@ public: // Prefix to avoid collisions with actually known games name = "wmeunk-" + name; Common::strlcpy(s_fallbackGameIdBuf, name.c_str(), sizeof(s_fallbackGameIdBuf) - 1); - s_fallbackDesc.gameid = s_fallbackGameIdBuf; + s_fallbackDesc.gameId = s_fallbackGameIdBuf; if (caption != name) { caption += " (unknown version) "; char *offset = s_fallbackGameIdBuf + name.size() + 1; diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index 25a01766e4..ca30204462 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -181,10 +181,13 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY1s("data.dcp", "b3f8b09bb4b05ee3e9d14697525257f9", 59296246), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 4 - East Side Story WME_WINENTRY("carolreed4", "", - WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), + WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 5 - The Colour of Murder WME_WINENTRY("carolreed5", "", WME_ENTRY1s("data.dcp", "3fcfca44209545d0e26774156427b494", 603660415), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), + // Carol Reed 5 - The Colour of Murder (1.0 Demo) + WME_WINENTRY("carolreed5", "Demo", + WME_ENTRY1s("data.dcp", "27b3efc018ade5ee8f4adf08b4e3c0dd", 92019500), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 6 - Black Circle WME_WINENTRY("carolreed6", "", WME_ENTRY1s("data.dcp", "0e4c532beecf23d85012168753f41189", 456258147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index e35bb60c3d..955f2dc1c2 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -133,7 +133,7 @@ Common::Error WintermuteEngine::run() { } int WintermuteEngine::init() { - BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameid, _gameDescription->adDesc.language, _gameDescription->targetExecutable); + BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameId, _gameDescription->adDesc.language, _gameDescription->targetExecutable); _game = new AdGame(_targetName); if (!_game) { return 1; diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp index 8b47590861..cc967070d9 100644 --- a/engines/zvision/detection.cpp +++ b/engines/zvision/detection.cpp @@ -61,7 +61,7 @@ public: ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), ZVision::zVisionGames, ZVision::optionsList) { _maxScanDepth = 2; _directoryGlobs = ZVision::directoryGlobs; - _singleid = "zvision"; + _singleId = "zvision"; } virtual const char *getName() const { |