aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/advancedDetector.cpp79
-rw-r--r--engines/advancedDetector.h15
-rw-r--r--engines/agi/detection.cpp8
-rw-r--r--engines/agos/detection.cpp6
-rw-r--r--engines/avalanche/detection.cpp2
-rw-r--r--engines/bbvs/detection.cpp2
-rw-r--r--engines/cge/detection.cpp2
-rw-r--r--engines/cge2/detection.cpp2
-rw-r--r--engines/cine/detection.cpp8
-rw-r--r--engines/composer/detection.cpp4
-rw-r--r--engines/cruise/detection.cpp6
-rw-r--r--engines/draci/detection.cpp2
-rw-r--r--engines/drascula/detection.cpp4
-rw-r--r--engines/dreamweb/detection.cpp4
-rw-r--r--engines/fullpipe/detection.cpp4
-rw-r--r--engines/game.cpp6
-rw-r--r--engines/game.h4
-rw-r--r--engines/gob/detection/detection.cpp10
-rw-r--r--engines/groovie/detection.cpp4
-rw-r--r--engines/hugo/detection.cpp2
-rw-r--r--engines/lab/detection.cpp23
-rw-r--r--engines/lab/processroom.cpp6
-rw-r--r--engines/lastexpress/detection.cpp4
-rw-r--r--engines/lure/detection.cpp4
-rw-r--r--engines/made/detection.cpp2
-rw-r--r--engines/mohawk/detection.cpp4
-rw-r--r--engines/mortevielle/detection.cpp2
-rw-r--r--engines/neverhood/detection.cpp6
-rw-r--r--engines/parallaction/detection.cpp2
-rw-r--r--engines/pegasus/detection.cpp2
-rw-r--r--engines/prince/detection.cpp2
-rw-r--r--engines/prince/detection.h2
-rw-r--r--engines/queen/detection.cpp14
-rw-r--r--engines/saga/detection.cpp6
-rw-r--r--engines/sci/console.cpp31
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection.cpp22
-rw-r--r--engines/sci/detection_tables.h24
-rw-r--r--engines/sci/engine/kernel.cpp2
-rw-r--r--engines/sci/engine/kgraphics.cpp9
-rw-r--r--engines/sci/engine/kgraphics32.cpp123
-rw-r--r--engines/sci/engine/script_patches.cpp33
-rw-r--r--engines/sci/engine/selector.cpp6
-rw-r--r--engines/sci/engine/selector.h4
-rw-r--r--engines/sci/engine/vm_types.cpp24
-rw-r--r--engines/sci/engine/vm_types.h4
-rw-r--r--engines/sci/engine/workarounds.cpp4
-rw-r--r--engines/sci/event.cpp38
-rw-r--r--engines/sci/event.h16
-rw-r--r--engines/sci/graphics/celobj32.cpp85
-rw-r--r--engines/sci/graphics/celobj32.h34
-rw-r--r--engines/sci/graphics/controls32.cpp433
-rw-r--r--engines/sci/graphics/controls32.h83
-rw-r--r--engines/sci/graphics/frameout.cpp129
-rw-r--r--engines/sci/graphics/frameout.h48
-rw-r--r--engines/sci/graphics/lists32.h6
-rw-r--r--engines/sci/graphics/palette.cpp88
-rw-r--r--engines/sci/graphics/palette.h21
-rw-r--r--engines/sci/graphics/palette32.cpp27
-rw-r--r--engines/sci/graphics/palette32.h12
-rw-r--r--engines/sci/graphics/plane32.cpp124
-rw-r--r--engines/sci/graphics/plane32.h58
-rw-r--r--engines/sci/graphics/remap.cpp134
-rw-r--r--engines/sci/graphics/remap.h77
-rw-r--r--engines/sci/graphics/screen_item32.cpp14
-rw-r--r--engines/sci/graphics/screen_item32.h13
-rw-r--r--engines/sci/graphics/text32.cpp119
-rw-r--r--engines/sci/graphics/text32.h280
-rw-r--r--engines/sci/graphics/view.cpp23
-rw-r--r--engines/sci/module.mk1
-rw-r--r--engines/sci/resource_audio.cpp6
-rw-r--r--engines/sci/sci.cpp18
-rw-r--r--engines/sci/sci.h7
-rw-r--r--engines/sci/sound/soundcmd.cpp2
-rw-r--r--engines/scumm/charset-fontdata.cpp31
-rw-r--r--engines/sky/detection.cpp4
-rw-r--r--engines/sword1/detection.cpp12
-rw-r--r--engines/sword25/detection.cpp2
-rw-r--r--engines/sword25/detection_tables.h5
-rw-r--r--engines/sword25/gfx/animationresource.cpp5
-rw-r--r--engines/sword25/gfx/fontresource.cpp5
-rw-r--r--engines/sword25/gfx/text.cpp3
-rw-r--r--engines/teenagent/detection.cpp2
-rw-r--r--engines/testbed/detection.cpp2
-rw-r--r--engines/tinsel/detection.cpp10
-rw-r--r--engines/toltecs/detection.cpp2
-rw-r--r--engines/toon/detection.cpp2
-rw-r--r--engines/touche/detection.cpp2
-rw-r--r--engines/tsage/detection.cpp4
-rw-r--r--engines/tucker/detection.cpp2
-rw-r--r--engines/wage/detection.cpp5
-rw-r--r--engines/wage/detection_tables.h18
-rw-r--r--engines/wintermute/base/base_engine.h2
-rw-r--r--engines/wintermute/base/base_persistence_manager.cpp12
-rw-r--r--engines/wintermute/base/base_persistence_manager.h4
-rw-r--r--engines/wintermute/base/file/base_disk_file.cpp27
-rw-r--r--engines/wintermute/detection.cpp10
-rw-r--r--engines/wintermute/detection_tables.h5
-rw-r--r--engines/wintermute/wintermute.cpp2
-rw-r--r--engines/zvision/detection.cpp2
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 {