aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorAlejandro Marzini2010-08-06 03:21:21 +0000
committerAlejandro Marzini2010-08-06 03:21:21 +0000
commit33e40e1a20c4cc60031854c87d6da5e461f9eb73 (patch)
treef76425d516e75d147ffbbacbec3fad49297da1b1 /engines
parentf97809a9a62a2d8840229facb2c2b6f75e37bad3 (diff)
parent6c8bcd2ba1cad1312f0a588ca284110bbbb81ccc (diff)
downloadscummvm-rg350-33e40e1a20c4cc60031854c87d6da5e461f9eb73.tar.gz
scummvm-rg350-33e40e1a20c4cc60031854c87d6da5e461f9eb73.tar.bz2
scummvm-rg350-33e40e1a20c4cc60031854c87d6da5e461f9eb73.zip
Merged from trunk, from r51495 to r51775
svn-id: r51776
Diffstat (limited to 'engines')
-rw-r--r--engines/advancedDetector.cpp13
-rw-r--r--engines/advancedDetector.h7
-rw-r--r--engines/draci/detection.cpp10
-rw-r--r--engines/gob/videoplayer.cpp2
-rw-r--r--engines/kyra/detection.cpp3
-rw-r--r--engines/kyra/kyra_hof.cpp5
-rw-r--r--engines/kyra/kyra_lok.h2
-rw-r--r--engines/kyra/kyra_mr.cpp4
-rw-r--r--engines/kyra/kyra_v1.cpp4
-rw-r--r--engines/kyra/kyra_v2.cpp1
-rw-r--r--engines/kyra/kyra_v2.h1
-rw-r--r--engines/kyra/lol.cpp4
-rw-r--r--engines/kyra/resource.h1
-rw-r--r--engines/kyra/saveload.cpp2
-rw-r--r--engines/kyra/scene_lol.cpp2
-rw-r--r--engines/kyra/screen_lol.cpp62
-rw-r--r--engines/kyra/screen_lol.h1
-rw-r--r--engines/kyra/screen_v2.cpp69
-rw-r--r--engines/kyra/screen_v2.h2
-rw-r--r--engines/kyra/sound_intern.h43
-rw-r--r--engines/kyra/sound_lok.cpp6
-rw-r--r--engines/kyra/sound_lol.cpp2
-rw-r--r--engines/kyra/sound_towns.cpp4347
-rw-r--r--engines/kyra/staticres.cpp2
-rw-r--r--engines/kyra/text_hof.cpp3
-rw-r--r--engines/kyra/text_lok.cpp15
-rw-r--r--engines/kyra/text_mr.cpp3
-rw-r--r--engines/kyra/timer_hof.cpp3
-rw-r--r--engines/kyra/timer_lok.cpp3
-rw-r--r--engines/mohawk/video.cpp4
-rw-r--r--engines/queen/queen.cpp2
-rw-r--r--engines/sci/console.cpp50
-rw-r--r--engines/sci/console.h6
-rw-r--r--engines/sci/detection.cpp8
-rw-r--r--engines/sci/detection_tables.h1076
-rw-r--r--engines/sci/engine/features.cpp38
-rw-r--r--engines/sci/engine/features.h2
-rw-r--r--engines/sci/engine/kernel.cpp58
-rw-r--r--engines/sci/engine/kernel.h9
-rw-r--r--engines/sci/engine/kernel_tables.h21
-rw-r--r--engines/sci/engine/kfile.cpp14
-rw-r--r--engines/sci/engine/kgraphics.cpp45
-rw-r--r--engines/sci/engine/kmath.cpp14
-rw-r--r--engines/sci/engine/kmisc.cpp77
-rw-r--r--engines/sci/engine/kmovement.cpp14
-rw-r--r--engines/sci/engine/kscripts.cpp1
-rw-r--r--engines/sci/engine/ksound.cpp12
-rw-r--r--engines/sci/engine/kvideo.cpp11
-rw-r--r--engines/sci/engine/message.cpp4
-rw-r--r--engines/sci/engine/savegame.cpp97
-rw-r--r--engines/sci/engine/seg_manager.cpp6
-rw-r--r--engines/sci/engine/seg_manager.h2
-rw-r--r--engines/sci/engine/segment.h3
-rw-r--r--engines/sci/engine/selector.cpp1
-rw-r--r--engines/sci/engine/selector.h2
-rw-r--r--engines/sci/engine/state.h8
-rw-r--r--engines/sci/engine/static_selectors.cpp103
-rw-r--r--engines/sci/engine/vm.cpp61
-rw-r--r--engines/sci/engine/vm_types.h6
-rw-r--r--engines/sci/engine/workarounds.cpp112
-rw-r--r--engines/sci/engine/workarounds.h8
-rw-r--r--engines/sci/graphics/animate.cpp91
-rw-r--r--engines/sci/graphics/frameout.cpp33
-rw-r--r--engines/sci/graphics/paint.cpp4
-rw-r--r--engines/sci/graphics/paint.h4
-rw-r--r--engines/sci/graphics/paint16.cpp28
-rw-r--r--engines/sci/graphics/paint16.h2
-rw-r--r--engines/sci/graphics/ports.cpp105
-rw-r--r--engines/sci/graphics/ports.h6
-rw-r--r--engines/sci/graphics/screen.cpp16
-rw-r--r--engines/sci/graphics/screen.h5
-rw-r--r--engines/sci/graphics/text16.cpp73
-rw-r--r--engines/sci/graphics/text16.h2
-rw-r--r--engines/sci/graphics/view.cpp59
-rw-r--r--engines/sci/graphics/view.h8
-rw-r--r--engines/sci/resource.cpp137
-rw-r--r--engines/sci/resource.h17
-rw-r--r--engines/sci/resource_audio.cpp43
-rw-r--r--engines/sci/resource_intern.h28
-rw-r--r--engines/sci/sci.cpp35
-rw-r--r--engines/sci/sci.h4
-rw-r--r--engines/sci/sound/midiparser_sci.cpp3
-rw-r--r--engines/sci/sound/music.cpp5
-rw-r--r--engines/sci/sound/soundcmd.cpp20
-rw-r--r--engines/sci/sound/soundcmd.h3
-rw-r--r--engines/sci/video/seq_decoder.cpp5
-rw-r--r--engines/sci/video/seq_decoder.h2
-rw-r--r--engines/sci/video/vmd_decoder.cpp4
-rw-r--r--engines/sci/video/vmd_decoder.h2
-rw-r--r--engines/scumm/player_nes.cpp3
-rw-r--r--engines/scumm/saveload.cpp4
-rw-r--r--engines/scumm/scumm.cpp2
-rw-r--r--engines/sword1/control.cpp3
93 files changed, 2000 insertions, 5253 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index 315763a6da..f4af4a8500 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -209,6 +209,9 @@ static void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *
desc.setGUIOptions(realDesc->guioptions | params.guioptions);
desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
+
+ if (realDesc->flags & ADGF_ADDENGLISH)
+ desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
}
GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
@@ -306,7 +309,12 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
// If the GUI options were updated, we catch this here and update them in the users config
// file transparently.
- Common::updateGameGUIOptions(agdDesc->guioptions | params.guioptions, getGameGUIOptionsDescriptionLanguage(agdDesc->language));
+ Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc->language);
+ if (agdDesc->flags & ADGF_ADDENGLISH)
+ lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY);
+
+ Common::updateGameGUIOptions(agdDesc->guioptions | params.guioptions, lang);
+
debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str());
if (!createInstance(syst, engine, agdDesc))
@@ -455,7 +463,8 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
// Do not even bother to look at entries which do not have matching
// language and platform (if specified).
- if ((language != Common::UNK_LANG && g->language != Common::UNK_LANG && g->language != language) ||
+ if ((language != Common::UNK_LANG && g->language != Common::UNK_LANG && g->language != language
+ && !(language == Common::EN_ANY && (g->flags & ADGF_ADDENGLISH))) ||
(platform != Common::kPlatformUnknown && g->platform != Common::kPlatformUnknown && g->platform != platform)) {
continue;
}
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index de4fc3bbf8..1e59df04bf 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -38,11 +38,14 @@ struct ADGameFileDescription {
int32 fileSize; // Optional. Set to -1 to ignore.
};
-#define AD_ENTRY1(f, x) {{ f, 0, x, -1}, {NULL, 0, NULL, 0}}
-#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, {NULL, 0, NULL, 0}}
+#define AD_LISTEND {NULL, 0, NULL, 0}
+
+#define AD_ENTRY1(f, x) {{ f, 0, x, -1}, AD_LISTEND}
+#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, AD_LISTEND}
enum ADGameFlags {
ADGF_NO_FLAGS = 0,
+ ADGF_ADDENGLISH = (1 << 24), // always add English as language option
ADGF_MACRESFORK = (1 << 25), // the md5 for this entry will be calculated from the resource fork
ADGF_USEEXTRAASTITLE = (1 << 26), // Extra field value will be used as main game title, not gameid
ADGF_KEEPMATCH = (1 << 27), // this entry is kept even when there are matched entries with more files
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index e1025e698a..07a9928cfa 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -71,6 +71,16 @@ const ADGameDescription gameDescriptions[] = {
GUIO_NONE
},
+ {
+ "draci",
+ 0,
+ AD_ENTRY1s("INIT.DFW", "9a7115b91cdea361bcaff3e046ac7ded", 906),
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO_NONE
+ },
+
AD_TABLE_END_MARKER
};
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index 125edd4307..51bc1b88a5 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -73,7 +73,7 @@ bool VideoPlayer::Video::open(const char *fileName, Type which, int16 width, int
return false;
}
- if (!_video->load(*_stream)) {
+ if (!_video->load(_stream)) {
warning("While loading video \"%s\"", fileName);
close();
return false;
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index f3e6c7c8cc..135a9ae7b2 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -105,7 +105,8 @@ bool Kyra::KyraEngine_v1::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime);
+ (f == kSupportsSavingDuringRuntime) ||
+ (f == kSupportsSubtitleOptions);
}
bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 2716f0b285..0fafaa15ce 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -679,7 +679,7 @@ void KyraEngine_HoF::updateWithText() {
restorePage3();
drawAnimObjects();
- if (textEnabled() && _chatText) {
+ if (_chatTextEnabled && _chatText) {
int pageBackUp = _screen->_curPage;
_screen->_curPage = 2;
objectChatPrintText(_chatText, _chatObject);
@@ -1996,9 +1996,10 @@ void KyraEngine_HoF::writeSettings() {
}
void KyraEngine_HoF::readSettings() {
+ KyraEngine_v2::readSettings();
+
int talkspeed = ConfMan.getInt("talkspeed");
_configTextspeed = (talkspeed*95)/255 + 2;
- KyraEngine_v1::readSettings();
}
} // End of namespace Kyra
diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h
index b37a14bad4..50f36d7b71 100644
--- a/engines/kyra/kyra_lok.h
+++ b/engines/kyra/kyra_lok.h
@@ -319,7 +319,7 @@ protected:
// chat
// -> process
void characterSays(int vocFile, const char *chatStr, int8 charNum, int8 chatDuration);
- void waitForChatToFinish(int vocFile, int16 chatDuration, const char *str, uint8 charNum);
+ void waitForChatToFinish(int vocFile, int16 chatDuration, const char *str, uint8 charNum, const bool printText);
// -> initialization
int initCharacterChat(int8 charNum);
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp
index 61bc3708c3..2169e5283f 100644
--- a/engines/kyra/kyra_mr.cpp
+++ b/engines/kyra/kyra_mr.cpp
@@ -1127,7 +1127,7 @@ void KyraEngine_MR::updateWithText() {
restorePage3();
drawAnimObjects();
- if (textEnabled() && _chatText) {
+ if (_chatTextEnabled && _chatText) {
int curPage = _screen->_curPage;
_screen->_curPage = 2;
objectChatPrintText(_chatText, _chatObject);
@@ -1490,7 +1490,7 @@ void KyraEngine_MR::writeSettings() {
}
void KyraEngine_MR::readSettings() {
- KyraEngine_v1::readSettings();
+ KyraEngine_v2::readSettings();
_configStudio = ConfMan.getBool("studio_audience");
_configSkip = ConfMan.getBool("skip_support");
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index 5db2c360d6..1c27716a67 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -625,6 +625,10 @@ uint8 KyraEngine_v1::getVolume(kVolumeEntry vol) {
void KyraEngine_v1::syncSoundSettings() {
Engine::syncSoundSettings();
+ // We need to use this here to allow the subtitle options to be changed
+ // through the GMM's options dialog.
+ readSettings();
+
if (_sound)
_sound->updateVolumeSettings();
}
diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp
index 34284a8e20..53c57c21cd 100644
--- a/engines/kyra/kyra_v2.cpp
+++ b/engines/kyra/kyra_v2.cpp
@@ -63,6 +63,7 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi
_chatVocLow = -1;
_chatText = 0;
_chatObject = -1;
+ _chatTextEnabled = false;
memset(_hiddenItems, -1, sizeof(_hiddenItems));
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 6aaa8c3687..6414040344 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -350,6 +350,7 @@ protected:
int _chatObject;
uint32 _chatEndTime;
int _chatVocHigh, _chatVocLow;
+ bool _chatTextEnabled;
EMCData _chatScriptData;
EMCState _chatScriptState;
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 5a066e5d0c..98f0e31b69 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -810,8 +810,8 @@ void LoLEngine::startup() {
pal.fill(0, 1, 0x3F);
pal.fill(2, 126, 0x3F);
pal.fill(192, 4, 0x3F);
- _screen->generateOverlay(pal, _screen->_paletteOverlay1, 1, 96);
- _screen->generateOverlay(pal, _screen->_paletteOverlay2, 144, 65);
+ _screen->generateOverlay(pal, _screen->_paletteOverlay1, 1, 96, 254);
+ _screen->generateOverlay(pal, _screen->_paletteOverlay2, 144, 65, 254);
_screen->copyPalette(0, 1);
}
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index 7983be9a68..d572c1ac54 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -209,6 +209,7 @@ enum KyraResources {
k1CreditsStrings,
+ k1TownsMusicFadeTable,
k1TownsSFXwdTable,
k1TownsSFXbtTable,
k1TownsCDATable,
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index 959d89f0ad..56e1c73d0a 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -122,7 +122,7 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
header.thumbnail = 0;
}
} else {
- Graphics::skipThumbnailHeader(*in);
+ Graphics::skipThumbnail(*in);
}
}
diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp
index ddc6e41bec..bf3320486a 100644
--- a/engines/kyra/scene_lol.cpp
+++ b/engines/kyra/scene_lol.cpp
@@ -468,7 +468,7 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight
for (int i = 0; i < 7; i++) {
weight = 100 - (i * _lastSpecialColorWeight);
weight = (weight > 0) ? (weight * 255) / 100 : 0;
- _screen->generateLevelOverlay(tpal, _screen->getLevelOverlay(i), _lastSpecialColor, weight);
+ _screen->generateOverlay(tpal, _screen->getLevelOverlay(i), _lastSpecialColor, weight);
int l = _flags.use16ColorMode ? 256 : 128;
uint8 *levelOverlay = _screen->getLevelOverlay(i);
diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp
index e350d2c977..be3dbe5b21 100644
--- a/engines/kyra/screen_lol.cpp
+++ b/engines/kyra/screen_lol.cpp
@@ -183,68 +183,6 @@ void Screen_LoL::generateGrayOverlay(const Palette &srcPal, uint8 *grayOverlay,
grayOverlay[i] = findLeastDifferentColor(tmpPal.getData() + 3 * i, srcPal, 0, lastColor, skipSpecialColors);
}
-uint8 *Screen_LoL::generateLevelOverlay(const Palette &srcPal, uint8 *ovl, int opColor, int weight) {
- if (!ovl)
- return ovl;
-
- if (weight > 255)
- weight = 255;
-
- const uint8 *srt = srcPal.getData();
-
- uint16 r = srt[opColor * 3];
- uint16 g = srt[opColor * 3 + 1];
- uint16 b = srt[opColor * 3 + 2];
-
- uint8 *d = ovl;
- *d++ = 0;
-
- for (int i = 1; i != 256; i++) {
- uint16 a = srt[i * 3];
- uint8 dr = a - ((((a - r) * (weight >> 1)) << 1) >> 8);
- a = srt[i * 3 + 1];
- uint8 dg = a - ((((a - g) * (weight >> 1)) << 1) >> 8);
- a = srt[i * 3 + 2];
- uint8 db = a - ((((a - b) * (weight >> 1)) << 1) >> 8);
-
- int l = opColor;
- int m = _use16ColorMode ? 0xffff : 0x7fff;
- int ii = _use16ColorMode ? 255 : 127;
- int x = 1;
- const uint8 *s = srt + 3;
-
- do {
- if (!_use16ColorMode && i == x) {
- s += 3;
- } else {
- int t = *s++ - dr;
- int c = t * t;
- t = *s++ - dg;
- c += (t * t);
- t = *s++ - db;
- c += (t * t);
-
- if (!c) {
- l = x;
- break;
- }
-
- if (c <= m) {
- if (!_use16ColorMode || (x == opColor || i != x)) {
- m = c;
- l = x;
- }
- }
- }
- x++;
- } while (--ii);
-
- *d++ = l & 0xff;
- }
-
- return ovl;
-}
-
void Screen_LoL::createTransparencyTablesIntern(const uint8 *ovl, int a, const uint8 *fxPal1, const uint8 *fxPal2, uint8 *outTable1, uint8 *outTable2, int b) {
Palette screenPal(256);
screenPal.copy(fxPal2, 0, 256);
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
index cdd18f98f6..52e66df1ec 100644
--- a/engines/kyra/screen_lol.h
+++ b/engines/kyra/screen_lol.h
@@ -79,7 +79,6 @@ public:
Palette **generateFadeTable(Palette **dst, Palette *src1, Palette *src2, int numTabs);
void generateGrayOverlay(const Palette &Pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors);
- uint8 *generateLevelOverlay(const Palette &Pal, uint8 *ovl, int opColor, int weight);
uint8 *getLevelOverlay(int index) { return _levelOverlays[index]; }
void createTransparencyTablesIntern(const uint8 *ovl, int a, const uint8 *fxPal1, const uint8 *fxPal2, uint8 *outTable1, uint8 *outTable2, int b);
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index 919b9086f3..3907f844cb 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -38,38 +38,67 @@ Screen_v2::~Screen_v2() {
delete[] _wsaFrameAnimBuffer;
}
-uint8 *Screen_v2::generateOverlay(const Palette &pal, uint8 *buffer, int startColor, uint16 factor) {
+uint8 *Screen_v2::generateOverlay(const Palette &pal, uint8 *buffer, int opColor, uint weight, int maxColor) {
if (!buffer)
return buffer;
- factor = MIN<uint16>(255, factor);
- factor >>= 1;
- factor &= 0xFF;
+ weight = MIN<uint>(weight, 255) >> 1;
- const byte col1 = pal[startColor * 3 + 0];
- const byte col2 = pal[startColor * 3 + 1];
- const byte col3 = pal[startColor * 3 + 2];
+ const byte opR = pal[opColor * 3 + 0];
+ const byte opG = pal[opColor * 3 + 1];
+ const byte opB = pal[opColor * 3 + 2];
uint8 *dst = buffer;
*dst++ = 0;
- for (int i = 1; i != 255; ++i) {
- uint8 processedPalette[3];
- byte col;
+ int maxIndex = maxColor;
+ if (maxIndex == -1) {
+ if (_vm->gameFlags().gameID == GI_LOL) {
+ if (_use16ColorMode)
+ maxIndex = 255;
+ else
+ maxIndex = 127;
+ } else {
+ maxIndex = 255;
+ }
+ }
+
+ for (int i = 1; i != 256; ++i) {
+ const byte curR = pal[i * 3 + 0] - ((((pal[i * 3 + 0] - opR) * weight) >> 7) & 0x7F);
+ const byte curG = pal[i * 3 + 1] - ((((pal[i * 3 + 1] - opG) * weight) >> 7) & 0x7F);
+ const byte curB = pal[i * 3 + 2] - ((((pal[i * 3 + 2] - opB) * weight) >> 7) & 0x7F);
+
+ uint16 idxSum = _use16ColorMode ? 0xFFFF : 0x7FFF;
+ byte index = opColor;
+
+ for (int curIdx = 1; curIdx <= maxIndex; ++curIdx) {
+ if (!_use16ColorMode && i == curIdx)
+ continue;
- col = pal[i * 3 + 0];
- col -= ((((col - col1) * factor) << 1) >> 8) & 0xFF;
- processedPalette[0] = col;
+ int diff = 0;
+ uint16 sum = 0;
- col = pal[i * 3 + 1];
- col -= ((((col - col2) * factor) << 1) >> 8) & 0xFF;
- processedPalette[1] = col;
+ diff = pal[curIdx * 3 + 0] - curR;
+ sum += diff * diff;
+ diff = pal[curIdx * 3 + 1] - curG;
+ sum += diff * diff;
+ diff = pal[curIdx * 3 + 2] - curB;
+ sum += diff * diff;
- col = pal[i * 3 + 2];
- col -= ((((col - col3) * factor) << 1) >> 8) & 0xFF;
- processedPalette[2] = col;
+ if (!sum) {
+ index = curIdx;
+ break;
+ }
+
+ if (sum <= idxSum) {
+ if (!_use16ColorMode || (curIdx == opColor || curIdx != i)) {
+ idxSum = sum;
+ index = curIdx;
+ }
+ }
+ }
- *dst++ = findLeastDifferentColor(processedPalette, pal, 1, 255) + 1;
+ *dst++ = index;
}
return buffer;
diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h
index 7be68e7b6d..92aeb3525d 100644
--- a/engines/kyra/screen_v2.h
+++ b/engines/kyra/screen_v2.h
@@ -40,7 +40,7 @@ public:
void checkedPageUpdate(int srcPage, int dstPage);
// palette handling
- uint8 *generateOverlay(const Palette &pal, uint8 *buffer, int color, uint16 factor);
+ uint8 *generateOverlay(const Palette &pal, uint8 *buffer, int color, uint weight, int maxColor = -1);
void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay);
int findLeastDifferentColor(const uint8 *paletteEntry, const Palette &pal, uint8 firstColor, uint16 numColors, bool skipSpecialColors = false);
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index a229dc310d..f8738bc791 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -31,7 +31,9 @@
#include "common/mutex.h"
-#include "sound/softsynth/ym2612.h"
+#include "sound/softsynth/fmtowns_pc98/towns_pc98_driver.h"
+#include "sound/softsynth/fmtowns_pc98/towns_euphony.h"
+
#include "sound/softsynth/emumidi.h"
#include "sound/midiparser.h"
@@ -99,10 +101,7 @@ private:
Common::Mutex _mutex;
};
-class Towns_EuphonyDriver;
-class TownsPC98_OpnDriver;
-
-class SoundTowns : public MidiDriver, public Sound {
+class SoundTowns : public Sound {
public:
SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer);
~SoundTowns();
@@ -119,43 +118,35 @@ public:
void haltTrack();
void playSoundEffect(uint8);
+ void stopAllSoundEffects();
void beginFadeOut();
- //MidiDriver interface implementation
- int open();
- void close();
- void send(uint32 b);
- void metaEvent(byte type, byte *data, uint16 length) {}
-
- void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
- uint32 getBaseTempo();
-
- //Channel allocation functions
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
- static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey,
- uint32 sampleRate, uint32 outputRate, int32 pitchWheel);
+ void updateVolumeSettings();
private:
bool loadInstruments();
void playEuphonyTrack(uint32 offset, int loop);
- static void onTimer(void *data);
+ void fadeOutSoundEffects();
int _lastTrack;
Audio::AudioStream *_currentSFX;
Audio::SoundHandle _sfxHandle;
+ uint8 *_musicTrackData;
+
uint _sfxFileIndex;
uint8 *_sfxFileData;
+ uint8 _sfxChannel;
- Towns_EuphonyDriver * _driver;
- MidiParser * _parser;
-
+ TownsEuphonyDriver *_driver;
+
Common::Mutex _mutex;
+ bool _cdaPlaying;
+
+ const uint8 *_musicFadeTable;
const uint8 *_sfxBTTable;
const uint8 *_sfxWDTable;
};
@@ -186,7 +177,7 @@ protected:
int _lastTrack;
uint8 *_musicTrackData;
uint8 *_sfxTrackData;
- TownsPC98_OpnDriver *_driver;
+ TownsPC98_AudioDriver *_driver;
};
class SoundTownsPC98_v2 : public Sound {
@@ -218,7 +209,7 @@ protected:
uint8 *_musicTrackData;
uint8 *_sfxTrackData;
- TownsPC98_OpnDriver *_driver;
+ TownsPC98_AudioDriver *_driver;
};
// PC Speaker MIDI driver
diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp
index 1d0b334a09..40daa0b5bd 100644
--- a/engines/kyra/sound_lok.cpp
+++ b/engines/kyra/sound_lok.cpp
@@ -49,16 +49,14 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) {
_lastMusicCommand = -1;
if (_flags.platform == Common::kPlatformFMTowns) {
- if (command == 1) {
- _sound->beginFadeOut();
- } else if (command >= 35 && command <= 38) {
+ if (command >= 35 && command <= 38) {
snd_playSoundEffect(command - 20);
} else if (command >= 2) {
if (_lastMusicCommand != command)
// the original does -2 here we handle this inside _sound->playTrack()
_sound->playTrack(command);
} else {
- _sound->haltTrack();
+ _sound->beginFadeOut();
}
_lastMusicCommand = command;
} else if (_flags.platform == Common::kPlatformPC98) {
diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index 1bcb77c89d..c233987120 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -225,7 +225,7 @@ void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
for (int i = 3; i > 0; i--) {
int dir = calcMonsterDirection(cbl & 0x1f, cbl >> 5, block & 0x1f, block >> 5);
- cbl += blockShiftTable[dir];
+ cbl = (cbl + blockShiftTable[dir]) & 0x3ff;
if (cbl != block) {
if (testWallFlag(cbl, 0, 1))
_environmentSfxVol >>= 1;
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 32fbbdf1e7..8d01d47262 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -35,3889 +35,39 @@
#include "common/util.h"
-#define EUPHONY_FADEOUT_TICKS 600
-
namespace Kyra {
-enum EnvelopeState { s_ready, s_attacking, s_decaying, s_sustaining, s_releasing };
-
-class Towns_EuphonyChannel : public MidiChannel {
-public:
- Towns_EuphonyChannel() {}
- virtual ~Towns_EuphonyChannel() {}
-
- virtual void nextTick(int32 *outbuf, int buflen) = 0;
- virtual void rate(uint16 r) = 0;
-
-protected:
- uint16 _rate;
-};
-
-class Towns_EuphonyFmChannel : public Towns_EuphonyChannel {
-public:
- Towns_EuphonyFmChannel();
- virtual ~Towns_EuphonyFmChannel();
-
- void nextTick(int32 *outbuf, int buflen);
- void rate(uint16 r);
-
- // MidiChannel interface
- MidiDriver *device() { return 0; }
- byte getNumber() { return 0; }
- void release() { }
- void send(uint32) { }
- void noteOff(byte note);
- void noteOn(byte note, byte onVelo);
- void programChange(byte) {}
- void pitchBend(int16 value);
- void controlChange(byte control, byte value);
- void pitchBendFactor(byte) { }
- void sysEx_customInstrument(uint32 unused, const byte *instr);
-
-protected:
- Voice2612 *_voice;
-};
-
-class Towns_EuphonyPcmChannel : public Towns_EuphonyChannel {
-public:
- void nextTick(int32 *outbuf, int buflen);
- void rate(uint16 r);
-
- Towns_EuphonyPcmChannel();
- virtual ~Towns_EuphonyPcmChannel();
-
- // MidiChannel interface
- MidiDriver *device() { return 0; }
- byte getNumber() { return 0; }
- void release() { }
- void send(uint32 b) { }
- void noteOff(byte note);
- void noteOn(byte note, byte onVelo);
- void programChange(byte program) {}
- void pitchBend(int16 value);
- void controlChange(byte control, byte value);
- void pitchBendFactor(byte value) { }
- void sysEx_customInstrument(uint32 type, const byte *instr);
-
-protected:
- void velocity(int velo);
- void panPosition(int8 pan);
- void evpNextTick();
-
- int _ctrl7_volume;
- int16 _velocity;
- int16 _note;
- int32 _frequencyOffs;
- float _phase;
- int8 _current;
-
- struct Voice {
- char name[9];
- uint16 split[8];
- uint32 id[8];
- struct Snd {
- char name[9];
- int32 id;
- int32 numSamples;
- int32 loopStart;
- int32 loopLength;
- int32 samplingRate;
- int32 keyOffset;
- int32 keyNote;
- const int8 *_samples;
- } *_snd[8];
- struct Env {
- EnvelopeState state;
- int32 currentLevel;
- int32 rate;
- int32 tickCount;
- int32 totalLevel;
- int32 attackRate;
- int32 decayRate;
- int32 sustainLevel;
- int32 sustainRate;
- int32 releaseLevel;
- int32 releaseRate;
- int32 rootKeyOffset;
- int32 size;
- } *_env[8];
- } *_voice;
-};
-
-class Towns_EuphonyTrackQueue {
-public:
- Towns_EuphonyTrackQueue(Towns_EuphonyDriver *driver, Towns_EuphonyTrackQueue *last);
- ~Towns_EuphonyTrackQueue() {}
-
- Towns_EuphonyTrackQueue *release();
- void initDriver();
- void loadDataToCurrentPosition(uint8 *trackdata, uint32 size, bool loop = 0);
- void loadDataToEndOfQueue(uint8 *trackdata, uint32 size, bool loop = 0);
- void setPlayBackStatus(bool playing);
- bool isPlaying() const {return _playing; }
- uint8 *trackData() {return _trackData; }
-
- bool _loop;
- Towns_EuphonyTrackQueue *_next;
-
-private:
- uint8 *_trackData;
- uint8 *_used;
- uint8 *_fchan;
- uint8 *_wchan;
- bool _playing;
- Towns_EuphonyDriver *_driver;
- Towns_EuphonyTrackQueue *_last;
-};
-
-class Towns_EuphonyParser : public MidiParser {
-public:
- Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue);
- bool loadMusic (byte *data, uint32 size);
- int32 calculateTempo(int16 val);
-
-protected:
- void parseNextEvent (EventInfo &info);
- void resetTracking();
- void setup();
-
- byte *_enable;
- byte *_mode;
- byte *_channel;
- byte *_adjVelo;
- int8 *_adjNote;
-
- uint8 _firstBaseTickStep;
- uint8 _nextBaseTickStep;
- uint32 _initialTempo;
- uint32 _baseTick;
-
- byte _tempo[3];
- Towns_EuphonyTrackQueue *_queue;
-};
-
-class Towns_EuphonyDriver : public MidiDriver_Emulated {
-public:
- Towns_EuphonyDriver(Audio::Mixer *mixer);
- virtual ~Towns_EuphonyDriver();
-
- int open();
- void close();
- void send(uint32 b);
- void send(byte channel, uint32 b);
- uint32 property(int prop, uint32 param) { return 0; }
-
- void setPitchBendRange(byte channel, uint range) { }
- void loadFmInstruments(const byte *instr);
- void loadWaveInstruments(const byte *instr);
-
- Towns_EuphonyTrackQueue *queue() { return _queue; }
-
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
- void assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber);
- void assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber);
- void removeChannel(uint8 midiChannelNumber);
-
- void setVolume(int val = -1) { if (val >= 0) _volume = val; }
- int getVolume(int val = -1) { return _volume; }
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _mixer->getOutputRate(); }
-
- void fading(bool status = true);
-
-protected:
- void nextTick(int16 *buf1, int buflen);
- void rate(uint16 r);
-
- void generateSamples(int16 *buf, int len);
-
- Towns_EuphonyFmChannel *_fChannel[6];
- Towns_EuphonyPcmChannel *_wChannel[8];
- Towns_EuphonyChannel *_channel[16];
- Towns_EuphonyTrackQueue *_queue;
-
- int _volume;
- bool _fading;
- int16 _fadestate;
-
- uint8 *_fmInstruments;
- uint8 *_waveInstruments;
- int8 * _waveSounds[10];
-};
-
-Towns_EuphonyFmChannel::Towns_EuphonyFmChannel() {
- _voice = new Voice2612;
-}
-
-Towns_EuphonyFmChannel::~Towns_EuphonyFmChannel() {
- delete _voice;
-}
-
-void Towns_EuphonyFmChannel::noteOn(byte note, byte onVelo) {
- _voice->noteOn(note, onVelo);
-}
-
-void Towns_EuphonyFmChannel::noteOff(byte note) {
- _voice->noteOff(note);
-}
-
-void Towns_EuphonyFmChannel::controlChange(byte control, byte value) {
- if (control == 121) {
- // Reset controller
- delete _voice;
- _voice = new Voice2612;
- } else if (control == 10) {
- // pan position
- } else {
- _voice->setControlParameter(control, value);
- }
-}
-
-void Towns_EuphonyFmChannel::sysEx_customInstrument(uint32, const byte *fmInst) {
- _voice->_rate = _rate;
- _voice->setInstrument(fmInst);
-}
-
-void Towns_EuphonyFmChannel::pitchBend(int16 value) {
- _voice->pitchBend(value);
-}
-
-void Towns_EuphonyFmChannel::nextTick(int32 *outbuf, int buflen) {
- _voice->nextTick((int *)outbuf, buflen);
-}
-
-void Towns_EuphonyFmChannel::rate(uint16 r) {
- _rate = r;
- _voice->_rate = r;
-}
-
-Towns_EuphonyPcmChannel::Towns_EuphonyPcmChannel() {
- _voice = new Voice;
- for (uint8 i = 0; i < 8; i++) {
- _voice->_env[i] = new Voice::Env;
- _voice->_snd[i] = 0;
- }
-
- _ctrl7_volume = 127;
- velocity(0);
- _frequencyOffs = 0x2000;
- _current = -1;
-}
-
-Towns_EuphonyPcmChannel::~Towns_EuphonyPcmChannel() {
- for (uint8 i = 0; i < 8; i++) {
- if (_voice->_snd[i])
- delete _voice->_snd[i];
- delete _voice->_env[i];
- }
- delete _voice;
-}
-
-void Towns_EuphonyPcmChannel::noteOn(byte note, byte onVelo) {
- _note = note;
- velocity(onVelo);
- _phase = 0;
-
- for (_current = 0; _current < 7; _current++) {
- if (note <= _voice->split[_current])
- break;
- }
-
- _voice->_env[_current]->state = s_attacking;
- _voice->_env[_current]->currentLevel = 0;
- _voice->_env[_current]->rate = _rate;
- _voice->_env[_current]->tickCount = 0;
-}
-
-void Towns_EuphonyPcmChannel::noteOff(byte note) {
- if (_current == -1)
- return;
- if (_voice->_env[_current]->state == s_ready)
- return;
-
- _voice->_env[_current]->state = s_releasing;
- _voice->_env[_current]->releaseLevel = _voice->_env[_current]->currentLevel;
- _voice->_env[_current]->tickCount = 0;
-}
-
-void Towns_EuphonyPcmChannel::controlChange(byte control, byte value) {
- switch (control) {
- case 0x07:
- // volume
- _ctrl7_volume = value;
- break;
- case 0x0A:
- // pan position
- break;
- case 0x79:
- // Reset controller
- for (uint8 i = 0; i < 8; i++) {
- if (_voice->_snd[i])
- delete _voice->_snd[i];
- delete _voice->_env[i];
- }
- delete _voice;
- _voice = new Voice;
- for (uint8 i = 0; i < 8; i++) {
- _voice->_env[i] = new Voice::Env;
- _voice->_snd[i] = 0;
- }
- break;
- case 0x7B:
- noteOff(_note);
- break;
- default:
- break;
- }
-}
-
-void Towns_EuphonyPcmChannel::sysEx_customInstrument(uint32 type, const byte *fmInst) {
- if (type == 0x80) {
- for (uint8 i = 0; i < 8; i++) {
- const byte * const *pos = (const byte * const *)fmInst;
- for (uint8 ii = 0; ii < 10; ii++) {
- if (_voice->id[i] == *(pos[ii] + 8)) {
- if (!_voice->_snd[i])
- _voice->_snd[i] = new Voice::Snd;
- memset(_voice->_snd[i]->name, 0, 9);
- memcpy(_voice->_snd[i]->name, (const char *)pos[ii], 8);
- _voice->_snd[i]->id = READ_LE_UINT32(pos[ii] + 8);
- _voice->_snd[i]->numSamples = READ_LE_UINT32(pos[ii] + 12);
- _voice->_snd[i]->loopStart = READ_LE_UINT32(pos[ii] + 16);
- _voice->_snd[i]->loopLength = READ_LE_UINT32(pos[ii] + 20);
- _voice->_snd[i]->samplingRate = READ_LE_UINT16(pos[ii] + 24);
- _voice->_snd[i]->keyOffset = READ_LE_UINT16(pos[ii] + 26);
- _voice->_snd[i]->keyNote = *(const uint8 *)(pos[ii] + 28);
- _voice->_snd[i]->_samples = (const int8 *)(pos[ii] + 32);
- }
- }
- }
- } else {
- memset(_voice->name, 0, 9);
- memcpy(_voice->name, (const char *)fmInst, 8);
-
- for (uint8 i = 0; i < 8; i++) {
- _voice->split[i] = READ_LE_UINT16(fmInst + 16 + 2 * i);
- _voice->id[i] = READ_LE_UINT32(fmInst + 32 + 4 * i);
- _voice->_snd[i] = 0;
- _voice->_env[i]->state = s_ready;
- _voice->_env[i]->currentLevel = 0;
- _voice->_env[i]->totalLevel = *(fmInst + 64 + 8 * i);
- _voice->_env[i]->attackRate = *(fmInst + 65 + 8 * i) * 10;
- _voice->_env[i]->decayRate = *(fmInst + 66 + 8 * i) * 10;
- _voice->_env[i]->sustainLevel = *(fmInst + 67 + 8 * i);
- _voice->_env[i]->sustainRate = *(fmInst + 68 + 8 * i) * 20;
- _voice->_env[i]->releaseRate = *(fmInst + 69 + 8 * i) * 10;
- _voice->_env[i]->rootKeyOffset = *(fmInst + 70 + 8 * i);
- }
- }
-}
-
-void Towns_EuphonyPcmChannel::pitchBend(int16 value) {
- _frequencyOffs = value;
-}
-
-void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) {
- if (_current == -1 || !_voice->_snd[_current] || !_voice->_env[_current]->state || !_velocity) {
- velocity(0);
- _current = -1;
- return;
- }
-
- float phaseStep = SoundTowns::calculatePhaseStep(_note, _voice->_snd[_current]->keyNote -
- _voice->_env[_current]->rootKeyOffset, _voice->_snd[_current]->samplingRate, _rate, _frequencyOffs);
-
- int32 looplength = _voice->_snd[_current]->loopLength;
- int32 numsamples = _voice->_snd[_current]->numSamples;
- const int8 * samples = _voice->_snd[_current]->_samples;
-
- for (int i = 0; i < buflen; i++) {
- if (looplength > 0) {
- while (_phase >= numsamples)
- _phase -= looplength;
- } else {
- if (_phase >= numsamples) {
- velocity(0);
- _current = -1;
- break;
- }
- }
-
- int32 output;
-
- int32 phase0 = int32(_phase);
- int32 phase1 = int32(_phase + 1);
- if (phase1 >= numsamples)
- phase1 -= looplength;
- float weight0 = _phase - phase0;
- float weight1 = phase1 - _phase;
- output = int32(samples[phase0] * weight0 + samples[phase1] * weight1);
-
- output *= _velocity;
- output <<= 1;
-
- evpNextTick();
- output *= _voice->_env[_current]->currentLevel;
- output >>= 7;
- output *= _ctrl7_volume;
- output >>= 7;
-
- output *= 185;
- output >>= 8;
- outbuf[i] += output;
- _phase += phaseStep;
- }
-}
-
-void Towns_EuphonyPcmChannel::evpNextTick() {
- switch (_voice->_env[_current]->state) {
- case s_ready:
- _voice->_env[_current]->currentLevel = 0;
- return;
-
- case s_attacking:
- if (_voice->_env[_current]->attackRate == 0)
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel;
- else if (_voice->_env[_current]->attackRate >= 1270)
- _voice->_env[_current]->currentLevel = 0;
- else
- _voice->_env[_current]->currentLevel = (_voice->_env[_current]->totalLevel *
- _voice->_env[_current]->tickCount++ * 1000) /
- (_voice->_env[_current]->attackRate * _voice->_env[_current]->rate);
-
- if (_voice->_env[_current]->currentLevel >= _voice->_env[_current]->totalLevel) {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel;
- _voice->_env[_current]->state = s_decaying;
- _voice->_env[_current]->tickCount = 0;
- }
- break;
-
- case s_decaying:
- if (_voice->_env[_current]->decayRate == 0) {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel;
- } else if (_voice->_env[_current]->decayRate >= 1270) {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel;
- } else {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel;
- _voice->_env[_current]->currentLevel -= ((_voice->_env[_current]->totalLevel -
- _voice->_env[_current]->sustainLevel) * _voice->_env[_current]->tickCount++ * 1000) /
- (_voice->_env[_current]->decayRate * _voice->_env[_current]->rate);
- }
-
- if (_voice->_env[_current]->currentLevel <= _voice->_env[_current]->sustainLevel) {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel;
- _voice->_env[_current]->state = s_sustaining;
- _voice->_env[_current]->tickCount = 0;
- }
- break;
-
- case s_sustaining:
- if (_voice->_env[_current]->sustainRate == 0) {
- _voice->_env[_current]->currentLevel = 0;
- } else if (_voice->_env[_current]->sustainRate >= 2540) {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel;
- } else {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel;
- _voice->_env[_current]->currentLevel -= (_voice->_env[_current]->sustainLevel *
- _voice->_env[_current]->tickCount++ * 1000) / (_voice->_env[_current]->sustainRate *
- _voice->_env[_current]->rate);
- }
-
- if (_voice->_env[_current]->currentLevel <= 0) {
- _voice->_env[_current]->currentLevel = 0;
- _voice->_env[_current]->state = s_ready;
- _voice->_env[_current]->tickCount = 0;
- }
- break;
-
- case s_releasing:
- if (_voice->_env[_current]->releaseRate == 0) {
- _voice->_env[_current]->currentLevel = 0;
- } else if (_voice->_env[_current]->releaseRate >= 1270) {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->releaseLevel;
- } else {
- _voice->_env[_current]->currentLevel = _voice->_env[_current]->releaseLevel;
- _voice->_env[_current]->currentLevel -= (_voice->_env[_current]->releaseLevel *
- _voice->_env[_current]->tickCount++ * 1000) / (_voice->_env[_current]->releaseRate *
- _voice->_env[_current]->rate);
- }
-
- if (_voice->_env[_current]->currentLevel <= 0) {
- _voice->_env[_current]->currentLevel = 0;
- _voice->_env[_current]->state = s_ready;
- }
- break;
-
- default:
- break;
- }
-}
-
-void Towns_EuphonyPcmChannel::rate(uint16 r) {
- _rate = r;
-}
-
-void Towns_EuphonyPcmChannel::velocity(int velo) {
- _velocity = velo;
-}
-
-Towns_EuphonyDriver::Towns_EuphonyDriver(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
- _volume = 255;
- _fadestate = EUPHONY_FADEOUT_TICKS;
- _queue = 0;
-
- MidiDriver_YM2612::createLookupTables();
-
- for (uint8 i = 0; i < 6; i++)
- _channel[i] = _fChannel[i] = new Towns_EuphonyFmChannel;
- for (uint8 i = 0; i < 8; i++)
- _channel[i + 6] = _wChannel[i] = new Towns_EuphonyPcmChannel;
- _channel[14] = _channel[15] = 0;
-
- _fmInstruments = _waveInstruments = 0;
- memset(_waveSounds, 0, sizeof(uint8 *)* 10);
-
- rate(getRate());
- fading(0);
-
- _queue = new Towns_EuphonyTrackQueue(this, 0);
-}
-
-Towns_EuphonyDriver::~Towns_EuphonyDriver() {
- for (int i = 0; i < 6; i++)
- delete _fChannel[i];
- for (int i = 0; i < 8; i++)
- delete _wChannel[i];
-
- MidiDriver_YM2612::removeLookupTables();
-
- delete[] _fmInstruments;
- _fmInstruments = 0;
-
- delete[] _waveInstruments;
- _waveInstruments = 0;
-
- for (int i = 0; i < 10; i++) {
- delete[] _waveSounds[i];
- _waveSounds[i] = 0;
- }
-
- if (_queue) {
- _queue->release();
- delete _queue;
- _queue = 0;
- }
-}
-
-int Towns_EuphonyDriver::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
-
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle,
- this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- return 0;
-}
-
-void Towns_EuphonyDriver::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
- _mixer->stopHandle(_mixerSoundHandle);
-}
-
-void Towns_EuphonyDriver::send(uint32 b) {
- send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void Towns_EuphonyDriver::send(byte chan, uint32 b) {
- byte param2 = (byte) ((b >> 16) & 0xFF);
- byte param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
- if (chan > ARRAYSIZE(_channel))
- return;
-
- switch (cmd) {
- case 0x80:// Note Off
- if (_channel[chan])
- _channel[chan]->noteOff(param1);
- break;
- case 0x90: // Note On
- if (_channel[chan])
- _channel[chan]->noteOn(param1, param2);
- break;
- case 0xA0: // Aftertouch
- break; // Not supported.
- case 0xB0: // Control Change
- if (param1 == 0x79) {
- fading(0);
- for (int i = 0; i < 15; i++) {
- if (_channel[i]) {
- _channel[i]->controlChange(param1, param2);
- _channel[i]->programChange(0);
- }
- }
- } else if (param1 == 0x7B) {
- for (int i = 0; i < 15; i++) {
- if (_channel[i])
- _channel[i]->controlChange(param1, param2);
- }
- } else {
- if (_channel[chan])
- _channel[chan]->controlChange(param1, param2);
- }
- break;
- case 0xC0: // Program Change
- for (int i = 0; i < 6; i++) {
- if (_channel[chan] == _fChannel[i]) {
- _channel[chan]->sysEx_customInstrument(0, _fmInstruments + param1 * 0x30);
- break;
- }
- }
- for (int i = 0; i < 8; i++) {
- if (_channel[chan] == _wChannel[i]) {
- _channel[chan]->sysEx_customInstrument(0, _waveInstruments + param1 * 0x80);
- _channel[chan]->sysEx_customInstrument(0x80, (const byte *)_waveSounds);
- break;
- }
- }
- break;
- case 0xD0: // Channel Pressure
- break; // Not supported.
- case 0xE0: // Pitch Bend
- if (_channel[chan])
- _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
- break;
- default:
- warning("Towns_EuphonyDriver: Unknown send() command 0x%02X", cmd);
- }
-}
-
-void Towns_EuphonyDriver::loadFmInstruments(const byte *instr) {
- delete[] _fmInstruments;
- _fmInstruments = new uint8[0x1800];
- memcpy(_fmInstruments, instr, 0x1800);
-}
-
-void Towns_EuphonyDriver::loadWaveInstruments(const byte *instr) {
- delete[] _waveInstruments;
- _waveInstruments = new uint8[0x1000];
- memcpy(_waveInstruments, instr, 0x1000);
-
- const uint8 *pos = (const uint8 *)(instr + 0x1000);
-
- for (uint8 i = 0; i < 10; i++) {
- delete[] _waveSounds[i];
- uint32 numsamples = READ_LE_UINT32(pos + 0x0C);
- _waveSounds[i] = new int8[numsamples + 0x20];
- memcpy(_waveSounds[i], pos, 0x20);
- pos += 0x20;
- for (uint32 ii = 0; ii < numsamples; ii++) {
- uint8 s = *(pos + ii);
- s = (s < 0x80) ? 0x80 - s : s;
- _waveSounds[i][ii + 0x20] = s ^ 0x80;
- }
- pos += numsamples;
- }
-}
-
-
-void Towns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) {
- _channel[midiChannelNumber] = _fChannel[fmChannelNumber];
-}
-
-void Towns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) {
- _channel[midiChannelNumber] = _wChannel[waveChannelNumber];
-}
-
-void Towns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) {
- _channel[midiChannelNumber] = 0;
-}
-
-void Towns_EuphonyDriver::generateSamples(int16 *data, int len) {
- memset(data, 0, 2 * sizeof(int16) * len);
- nextTick(data, len);
-}
-
-void Towns_EuphonyDriver::nextTick(int16 *buf1, int buflen) {
- int32 *buf0 = (int32 *)buf1;
-
- for (int i = 0; i < ARRAYSIZE(_channel); i++) {
- if (_channel[i])
- _channel[i]->nextTick(buf0, buflen);
- }
-
- for (int i = 0; i < buflen; ++i) {
- int s = int( float(buf0[i] * _volume) * float((float)_fadestate / EUPHONY_FADEOUT_TICKS) );
- buf1[i*2] = buf1[i*2+1] = (s >> 9) & 0xffff;
- }
-
- if (_fading) {
- if (_fadestate) {
- _fadestate--;
- } else {
- _fading = false;
- _queue->setPlayBackStatus(false);
- }
- }
-}
-
-void Towns_EuphonyDriver::rate(uint16 r) {
- for (uint8 i = 0; i < 16; i++) {
- if (_channel[i])
- _channel[i]->rate(r);
- }
-}
-
-void Towns_EuphonyDriver::fading(bool status) {
- _fading = status;
- if (!_fading)
- _fadestate = EUPHONY_FADEOUT_TICKS;
-}
-
-Towns_EuphonyParser::Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue) : MidiParser(),
- _firstBaseTickStep(0x33), _nextBaseTickStep(0x33) {
- _initialTempo = calculateTempo(0x5a);
- _queue = queue;
-}
-
-void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {
- byte *pos = _position._play_pos;
-
- if (_queue->_next) {
- if (info.ext.type == 0x2F) {
- unloadMusic();
- memset(&info, 0, sizeof(EventInfo));
- pos = _position._play_pos = _tracks[0] = _queue->trackData() + 0x806;
- } else if (_active_track == 255) {
- _queue = _queue->_next;
- setup();
- setTrack(0);
- _queue->setPlayBackStatus(true);
- return;
- } else if (!_queue->isPlaying()) {
- unloadMusic();
- _queue = _queue->_next;
- setup();
- setTrack(0);
- _queue->setPlayBackStatus(true);
- return;
- }
- }
-
- bool loop = true;
- while (loop) {
- byte cmd = *pos;
- byte evt = (cmd & 0xF0);
-
- if (evt == 0x90) {
- byte chan = pos[1];
-
- if (_enable[chan]) {
- uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick;
- info.start = pos + 6;
- uint32 last = _position._last_event_tick;
- info.delta = (tick < last) ? 0 : (tick - last);
-
- info.event = 0x90 | _channel[chan];
- info.length = pos[7] | (pos[8] << 4) | (pos[9] << 8) | (pos[10] << 12);
-
- int8 note = (int8) pos[4];
- if (_adjNote[chan]) {
- note = (note & 0x7f) & _adjNote[chan];
- if (note > 0x7c)
- note -= 0x0c;
- else if (note < 0)
- note += 0x0c;
- }
- info.basic.param1 = (byte) note;
-
- uint8 onVelo = (pos[5] & 0x7f) + _adjVelo[chan];
- if (onVelo > 0x7f)
- onVelo = 0x7f;
- if (onVelo < 1)
- onVelo = 1;
- info.basic.param2 = onVelo;
-
- pos += 12;
- loop = false;
- } else {
- pos += 6;
- }
- } else if (evt == 0xB0 || evt == 0xC0 || evt == 0xe0) {
- byte chan = pos[1];
-
- if (_enable[chan]) {
- info.start = pos;
- uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick;
- uint32 last = _position._last_event_tick;
- info.delta = (tick < last) ? 0 : (tick - last);
- info.event = evt | _channel[chan];
- info.length = 0;
- info.basic.param1 = pos[4];
- info.basic.param2 = pos[5];
- pos += 6;
- loop = false;
- } else {
- pos += 6;
- }
- } else if (cmd == 0xF2) {
- static const uint16 tickTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 };
- _baseTick += tickTable[_nextBaseTickStep >> 4] * ((_nextBaseTickStep & 0x0f) + 1);
- _nextBaseTickStep = pos[1];
- pos += 6;
- } else if (cmd == 0xF8) {
- int32 tempo = calculateTempo(pos[4] | (pos[5] << 7));
- info.event = 0xff;
- info.length = 3;
- info.ext.type = 0x51;
- _tempo[0] = (tempo >> 16) & 0xff;
- _tempo[1] = (tempo >> 8) & 0xff;
- _tempo[2] = tempo & 0xff;
- info.ext.data = (byte *)_tempo;
- pos += 6;
- loop = false;
- } else if (cmd == 0xFD || cmd == 0xFE) {
- // End of track.
- if (_autoLoop) {
- unloadMusic();
- _queue->setPlayBackStatus(true);
- pos = info.start = _tracks[0];
- } else {
- info.start = pos;
- }
-
- uint32 last = _position._last_event_tick;
- uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick;
- info.delta = (tick < last) ? 0 : (tick - last);
- info.event = 0xFF;
- info.ext.type = 0x2F;
- info.ext.data = pos;
- loop = false;
- } else {
- warning("Unknown Euphony music event 0x%02X", (int)cmd);
- memset(&info, 0, sizeof(info));
- pos = 0;
- loop = false;
- }
- }
- _position._play_pos = pos;
-}
-
-bool Towns_EuphonyParser::loadMusic(byte *data, uint32 size) {
- bool loop = _autoLoop;
-
- if (_queue->isPlaying() && !_queue->_loop) {
- _queue->loadDataToEndOfQueue(data, size, loop);
- } else {
- unloadMusic();
- _queue = _queue->release();
- _queue->loadDataToCurrentPosition(data, size, loop);
- setup();
- setTrack(0);
- _queue->setPlayBackStatus(true);
- }
- return true;
-}
-
-int32 Towns_EuphonyParser::calculateTempo(int16 val) {
- int32 tempo = val;
-
- if (tempo < 0)
- tempo = 0;
- if (tempo > 0x1F4)
- tempo = 0x1F4;
-
- tempo = 0x4C4B4 / (tempo + 0x1E);
- while (tempo < 0x451)
- tempo <<= 1;
- tempo <<= 8;
-
- return tempo;
-}
-
-void Towns_EuphonyParser::resetTracking() {
- MidiParser::resetTracking();
-
- _nextBaseTickStep = _firstBaseTickStep;
- _baseTick = 0;
- setTempo(_initialTempo);
- _queue->setPlayBackStatus(false);
-}
-
-void Towns_EuphonyParser::setup() {
- uint8 *data = _queue->trackData();
- if (!data)
- return;
- _queue->initDriver();
-
- _enable = data + 0x354;
- _mode = data + 0x374;
- _channel = data + 0x394;
- _adjVelo = data + 0x3B4;
- _adjNote = (int8 *)data + 0x3D4;
-
- _nextBaseTickStep = _firstBaseTickStep = data[0x804];
- _initialTempo = calculateTempo((data[0x805] > 0xfc) ? 0x5a : data[0x805]);
-
- property(MidiParser::mpAutoLoop, _queue->_loop);
-
- _num_tracks = 1;
- _ppqn = 120;
- _tracks[0] = data + 0x806;
-}
-
-Towns_EuphonyTrackQueue::Towns_EuphonyTrackQueue(Towns_EuphonyDriver * driver, Towns_EuphonyTrackQueue * last) {
- _trackData = 0;
- _next = 0;
- _driver = driver;
- _last = last;
- _used = _fchan = _wchan = 0;
- _playing = _loop = false;
-}
-
-void Towns_EuphonyTrackQueue::setPlayBackStatus(bool playing) {
- Towns_EuphonyTrackQueue *i = this;
- do {
- i->_playing = playing;
- i = i->_next;
- } while (i);
-}
-
-void Towns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) {
- delete[] _trackData;
- _trackData = new uint8[0xC58A];
- memset(_trackData, 0, 0xC58A);
- Screen::decodeFrame4(trackdata, _trackData, size);
-
- _used = _trackData + 0x374;
- _fchan = _trackData + 0x6d4;
- _wchan = _trackData + 0x6dA;
- _loop = loop;
- _playing = false;
-}
-
-void Towns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) {
- if (!_trackData) {
- loadDataToCurrentPosition(trackdata, size, loop);
- return;
- }
-
- Towns_EuphonyTrackQueue *i = this;
- while (i->_next)
- i = i->_next;
-
- i = i->_next = new Towns_EuphonyTrackQueue(_driver, i);
- i->_trackData = new uint8[0xC58A];
- memset(i->_trackData, 0, 0xC58A);
- Screen::decodeFrame4(trackdata, i->_trackData, size);
-
- i->_used = i->_trackData + 0x374;
- i->_fchan = i->_trackData + 0x6d4;
- i->_wchan = i->_trackData + 0x6dA;
- i->_loop = loop;
- i->_playing = _playing;
-}
-
-Towns_EuphonyTrackQueue *Towns_EuphonyTrackQueue::release() {
- Towns_EuphonyTrackQueue *i = this;
- while (i->_next)
- i = i->_next;
-
- Towns_EuphonyTrackQueue *res = i;
-
- while (i) {
- i->_playing = false;
- i->_used = i->_fchan = i->_wchan = 0;
- delete[] i->_trackData;
- i->_trackData = 0;
- i = i->_last;
- if (i) {
- res = i;
- delete i->_next;
- i->_next = 0;
- }
- }
-
- delete[] res->_trackData;
- res->_trackData = 0;
-
- return res;
-}
-
-void Towns_EuphonyTrackQueue::initDriver() {
- for (uint8 i = 0; i < 6; i++) {
- if (_used[_fchan[i]])
- _driver->assignFmChannel(_fchan[i], i);
- }
-
- for (uint8 i = 0; i < 8; i++) {
- if (_used[_wchan[i]])
- _driver->assignWaveChannel(_wchan[i], i);
- }
-
- for (uint8 i = 0; i < 16; i++) {
- if (!_used[i])
- _driver->removeChannel(i);
- }
- _driver->send(0x79B0);
-}
-
-class TownsPC98_OpnOperator {
-public:
- TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable,
- const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
- const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable);
- ~TownsPC98_OpnOperator() {}
-
- void keyOn();
- void keyOff();
- void frequency(int freq);
- void updatePhaseIncrement();
- void recalculateRates();
- void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out);
-
- void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; }
- void detune(int value) { _detn = &_detnTbl[value << 5]; }
- void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; }
- void attackRate(uint32 value) { _specifiedAttackRate = value; }
- bool scaleRate(uint8 value);
- void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); }
- void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); }
- void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; }
- void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); }
- void totalLevel(uint32 value) { _totalLevel = value << 3; }
- void reset();
-
-protected:
- EnvelopeState _state;
- bool _playing;
- uint32 _feedbackLevel;
- uint32 _multiple;
- uint32 _totalLevel;
- uint8 _keyScale1;
- uint8 _keyScale2;
- uint32 _specifiedAttackRate;
- uint32 _specifiedDecayRate;
- uint32 _specifiedSustainRate;
- uint32 _specifiedReleaseRate;
- uint32 _tickCount;
- uint32 _sustainLevel;
-
- uint32 _frequency;
- uint8 _kcode;
- uint32 _phase;
- uint32 _phaseIncrement;
- const int32 *_detn;
-
- const uint8 *_rateTbl;
- const uint8 *_rshiftTbl;
- const uint8 *_adTbl;
- const uint32 *_fTbl;
- const uint32 *_sinTbl;
- const int32 *_tLvlTbl;
- const int32 *_detnTbl;
-
- const uint32 _tickLength;
- uint32 _timer;
- int32 _currentLevel;
-
- struct EvpState {
- uint8 rate;
- uint8 shift;
- } fs_a, fs_d, fs_s, fs_r;
-};
-
-TownsPC98_OpnOperator::TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable,
- const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
- const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) :
- _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
- _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
- _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
- _phase(0), _state(s_ready), _playing(false), _timer(0), _keyScale1(0), _keyScale2(0), _currentLevel(1023),
- _tickCount(0) {
-
- fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0;
-
- reset();
-}
-
-void TownsPC98_OpnOperator::keyOn() {
- if (_playing)
- return;
-
- _playing = true;
- _state = s_attacking;
- _phase = 0;
-}
-
-void TownsPC98_OpnOperator::keyOff() {
- if (!_playing)
- return;
-
- _playing = false;
- if (_state != s_ready)
- _state = s_releasing;
-}
-
-void TownsPC98_OpnOperator::frequency(int freq) {
- uint8 block = (freq >> 11);
- uint16 pos = (freq & 0x7ff);
- uint8 c = pos >> 7;
-
- _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 ));
- _frequency = _fTbl[pos << 1] >> (7 - block);
-}
-
-void TownsPC98_OpnOperator::updatePhaseIncrement() {
- _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1;
- uint8 keyscale = _kcode >> _keyScale1;
- if (_keyScale2 != keyscale) {
- _keyScale2 = keyscale;
- recalculateRates();
- }
-}
-
-void TownsPC98_OpnOperator::recalculateRates() {
- int k = _keyScale2;
- int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
- fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
- fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
-
- r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0;
- fs_d.rate = _rateTbl[r + k];
- fs_d.shift = _rshiftTbl[r + k];
-
- r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0;
- fs_s.rate = _rateTbl[r + k];
- fs_s.shift = _rshiftTbl[r + k];
-
- r = (_specifiedReleaseRate << 2) + 0x22;
- fs_r.rate = _rateTbl[r + k];
- fs_r.shift = _rshiftTbl[r + k];
-}
-
-void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) {
- if (_state == s_ready)
- return;
-
- _timer += _tickLength;
- while (_timer > 0x5B8D80) {
- _timer -= 0x5B8D80;
- ++_tickCount;
-
- int32 levelIncrement = 0;
- uint32 targetTime = 0;
- int32 targetLevel = 0;
- EnvelopeState nextState = s_ready;
-
- switch (_state) {
- case s_ready:
- return;
- case s_attacking:
- targetLevel = 0;
- nextState = s_decaying;
- if ((_specifiedAttackRate << 1) + _keyScale2 < 64) {
- targetTime = (1 << fs_a.shift) - 1;
- levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
- break;
- } else {
- _currentLevel = targetLevel;
- _state = nextState;
- }
- // Fall through
- case s_decaying:
- targetTime = (1 << fs_d.shift) - 1;
- nextState = s_sustaining;
- targetLevel = _sustainLevel;
- levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
- break;
- case s_sustaining:
- targetTime = (1 << fs_s.shift) - 1;
- nextState = s_sustaining;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
- break;
- case s_releasing:
- targetTime = (1 << fs_r.shift) - 1;
- nextState = s_ready;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
- break;
- }
-
- if (!(_tickCount & targetTime)) {
- _currentLevel += levelIncrement;
- if ((_state == s_attacking && _currentLevel <= targetLevel) || (_state != s_attacking && _currentLevel >= targetLevel)) {
- if (_state != s_decaying)
- _currentLevel = targetLevel;
- _state = nextState;
- }
- }
- }
-
- uint32 lvlout = _totalLevel + (uint32) _currentLevel;
-
-
- int32 outp = 0;
- int32 *i = &outp, *o = &outp;
- int phaseShift = 0;
-
- if (feed) {
- o = &feed[0];
- i = &feed[1];
- phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0;
- *o = *i;
- } else {
- phaseShift = phasebuf << 15;
- }
-
- if (lvlout < 832) {
- uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000)
- + phaseShift)) >> 16) & 0x3ff];
- *i = ((index < 6656) ? _tLvlTbl[index] : 0);
- } else {
- *i = 0;
- }
-
- _phase += _phaseIncrement;
- out += *o;
-}
-
-void TownsPC98_OpnOperator::reset(){
- keyOff();
- _timer = 0;
- _keyScale2 = 0;
- _currentLevel = 1023;
-
- frequency(0);
- detune(0);
- scaleRate(0);
- multiple(0);
- updatePhaseIncrement();
- attackRate(0);
- decayRate(0);
- releaseRate(0);
- sustainRate(0);
- feedbackLevel(0);
- totalLevel(127);
-}
-
-bool TownsPC98_OpnOperator::scaleRate(uint8 value) {
- value = 3 - value;
- if (_keyScale1 != value) {
- _keyScale1 = value;
- return true;
- }
-
- int k = _keyScale2;
- int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
- fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
- fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
- return false;
-}
-
-class TownsPC98_OpnDriver;
-class TownsPC98_OpnChannel {
-public:
- TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
- uint8 key, uint8 prt, uint8 id);
- virtual ~TownsPC98_OpnChannel();
- virtual void init();
-
- typedef enum channelState {
- CHS_RECALCFREQ = 0x01,
- CHS_KEYOFF = 0x02,
- CHS_SSGOFF = 0x04,
- CHS_VBROFF = 0x08,
- CHS_ALLOFF = 0x0f,
- CHS_PROTECT = 0x40,
- CHS_EOT = 0x80
- } ChannelState;
-
- virtual void loadData(uint8 *data);
- virtual void processEvents();
- virtual void processFrequency();
- virtual bool processControlEvent(uint8 cmd);
-
- virtual void keyOn();
- void keyOff();
-
- void setOutputLevel();
- virtual void fadeStep();
- virtual void reset();
-
- const uint8 _idFlag;
-
-protected:
- void setupVibrato();
- bool processVibrato();
-
- bool control_dummy(uint8 para);
- bool control_f0_setPatch(uint8 para);
- bool control_f1_presetOutputLevel(uint8 para);
- bool control_f2_setKeyOffTime(uint8 para);
- bool control_f3_setFreqLSB(uint8 para);
- bool control_f4_setOutputLevel(uint8 para);
- bool control_f5_setTempo(uint8 para);
- bool control_f6_repeatSection(uint8 para);
- bool control_f7_setupVibrato(uint8 para);
- bool control_f8_toggleVibrato(uint8 para);
- bool control_fa_writeReg(uint8 para);
- virtual bool control_fb_incOutLevel(uint8 para);
- virtual bool control_fc_decOutLevel(uint8 para);
- bool control_fd_jump(uint8 para);
- virtual bool control_ff_endOfTrack(uint8 para);
-
- uint8 _ticksLeft;
- uint8 _algorithm;
- uint8 _instr;
- uint8 _totalLevel;
- uint8 _frqBlockMSB;
- int8 _frqLSB;
- uint8 _keyOffTime;
- bool _hold;
- uint8 *_dataPtr;
- uint8 _vbrInitDelayHi;
- uint8 _vbrInitDelayLo;
- int16 _vbrModInitVal;
- uint8 _vbrDuration;
- uint8 _vbrCurDelay;
- int16 _vbrModCurVal;
- uint8 _vbrDurLeft;
- uint16 _frequency;
- uint8 _block;
- uint8 _regOffset;
- uint8 _flags;
- uint8 _ssgTl;
- uint8 _ssgStep;
- uint8 _ssgTicksLeft;
- uint8 _ssgTargetLvl;
- uint8 _ssgStartLvl;
-
- const uint8 _chanNum;
- const uint8 _keyNum;
- const uint8 _part;
-
- TownsPC98_OpnDriver *_drv;
-
- typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
-};
-
-class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel {
-public:
- TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
- virtual ~TownsPC98_OpnChannelSSG() {}
- void init();
-
- virtual void loadData(uint8 *data);
- void processEvents();
- void processFrequency();
- bool processControlEvent(uint8 cmd);
-
- void keyOn();
- void nextShape();
-
- void protect();
- void restore();
- virtual void reset();
-
- void fadeStep();
-
-protected:
- void setOutputLevel(uint8 lvl);
-
- bool control_f0_setPatch(uint8 para);
- bool control_f1_setTotalLevel(uint8 para);
- bool control_f4_setAlgorithm(uint8 para);
- bool control_f9_loadCustomPatch(uint8 para);
- bool control_fb_incOutLevel(uint8 para);
- bool control_fc_decOutLevel(uint8 para);
- bool control_ff_endOfTrack(uint8 para);
-
- typedef bool (TownsPC98_OpnChannelSSG::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
-};
-
-class TownsPC98_OpnSfxChannel : public TownsPC98_OpnChannelSSG {
-public:
- TownsPC98_OpnSfxChannel(TownsPC98_OpnDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_OpnChannelSSG(driver, regOffs, flgs, num, key, prt, id) {}
- ~TownsPC98_OpnSfxChannel() {}
-
- void loadData(uint8 *data);
- void reset();
-};
-
-class TownsPC98_OpnChannelPCM : public TownsPC98_OpnChannel {
-public:
- TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
- ~TownsPC98_OpnChannelPCM() {}
- void init();
-
- void loadData(uint8 *data);
- void processEvents();
- bool processControlEvent(uint8 cmd);
-
-private:
- bool control_f1_prcStart(uint8 para);
- bool control_ff_endOfTrack(uint8 para);
-
- typedef bool (TownsPC98_OpnChannelPCM::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
-};
-
-class TownsPC98_OpnSquareSineSource {
-public:
- TownsPC98_OpnSquareSineSource(const uint32 timerbase);
- ~TownsPC98_OpnSquareSineSource();
-
- void init(const int *rsTable, const int *rseTable);
- void reset();
- void writeReg(uint8 address, uint8 value, bool force = false);
-
- void nextTick(int32 *buffer, uint32 bufferSize);
-
- void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; }
- void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; }
-
- uint8 chanEnable() const { return _chanEnable; }
-private:
- void updateRegs();
-
- uint8 _updateRequestBuf[64];
- int _updateRequest;
- int _rand;
-
- int8 _evpTimer;
- uint32 _pReslt;
- uint8 _attack;
-
- bool _evpUpdate, _cont;
-
- int _evpUpdateCnt;
- uint8 _outN;
- int _nTick;
-
- int32 *_tlTable;
- int32 *_tleTable;
-
- const uint32 _tickLength;
- uint32 _timer;
-
- struct Channel {
- int tick;
- uint8 smp;
- uint8 out;
-
- uint8 frqL;
- uint8 frqH;
- uint8 vol;
- } _channels[3];
-
- uint8 _noiseGenerator;
- uint8 _chanEnable;
-
- uint8 **_reg;
-
- uint16 _volumeA;
- uint16 _volumeB;
- int _volMaskA;
- int _volMaskB;
-
- bool _ready;
-};
-
-class TownsPC98_OpnPercussionSource {
-public:
- TownsPC98_OpnPercussionSource(const uint32 timerbase);
- ~TownsPC98_OpnPercussionSource() { delete[] _reg; }
-
- void init(const uint8 *instrData = 0);
- void reset();
- void writeReg(uint8 address, uint8 value);
-
- void nextTick(int32 *buffer, uint32 bufferSize);
-
- void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; }
- void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; }
-
-private:
- struct RhtChannel {
- const uint8 *data;
-
- const uint8 *start;
- const uint8 *end;
- const uint8 *pos;
- uint32 size;
- bool active;
- uint8 level;
-
- int8 decState;
- uint8 decStep;
-
- int16 samples[2];
- int out;
-
- uint8 startPosH;
- uint8 startPosL;
- uint8 endPosH;
- uint8 endPosL;
- };
-
- void recalcOuput(RhtChannel *ins);
- void advanceInput(RhtChannel *ins);
-
- RhtChannel _rhChan[6];
-
- uint8 _totalLevel;
-
- const uint32 _tickLength;
- uint32 _timer;
-
- uint8 **_reg;
-
- uint16 _volumeA;
- uint16 _volumeB;
- int _volMaskA;
- int _volMaskB;
-
- bool _ready;
-};
-
-class TownsPC98_OpnCore : public Audio::AudioStream {
-public:
- enum OpnType {
- OD_TOWNS,
- OD_TYPE26,
- OD_TYPE86
- };
-
- TownsPC98_OpnCore(Audio::Mixer *mixer, OpnType type);
- virtual ~TownsPC98_OpnCore();
-
- virtual bool init();
- virtual void reset();
-
- void writeReg(uint8 part, uint8 regAddress, uint8 value);
-
- // AudioStream interface
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const { return true; }
- bool endOfData() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
-protected:
- void toggleRegProtection(bool prot) { _regProtectionFlag = prot; }
- uint8 readSSGStatus() { return _ssg->chanEnable(); }
-
- virtual void timerCallbackA() = 0;
- virtual void timerCallbackB() = 0;
-
- // The audio driver can store and apply two different audio settings
- // (usually for music and sound effects). The channel mask will determine
- // which channels get effected by the setting. The first bits will be
- // the normal opn channels, the next bits the ssg channels and the final
- // bit the rhythm channel.
- void setVolumeIntern(int volA, int volB);
- void setVolumeChannelMasks(int channelMaskA, int channelMaskB);
-
- const int _numChan;
- const int _numSSG;
- const bool _hasPercussion;
-
- Common::Mutex _mutex;
-private:
- void generateTables();
- void nextTick(int32 *buffer, uint32 bufferSize);
- void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed);
-
- struct ChanInternal {
- ChanInternal() {
- memset(this, 0, sizeof(ChanInternal));
- }
-
- ~ChanInternal() {
- for (uint i = 0; i < ARRAYSIZE(opr); ++i)
- delete opr[i];
- }
-
- uint16 frqTemp;
- bool enableLeft;
- bool enableRight;
- bool updateEnvelopeParameters;
- int32 feedbuf[3];
- uint8 algorithm;
- TownsPC98_OpnOperator *opr[4];
- };
-
- TownsPC98_OpnSquareSineSource *_ssg;
- TownsPC98_OpnPercussionSource *_prc;
- ChanInternal *_chanInternal;
-
- uint8 *_oprRates;
- uint8 *_oprRateshift;
- uint8 *_oprAttackDecay;
- uint32 *_oprFrq;
- uint32 *_oprSinTbl;
- int32 *_oprLevelOut;
- int32 *_oprDetune;
-
- bool _regProtectionFlag;
-
- typedef void (TownsPC98_OpnCore::*OpnTimerProc)();
-
- struct OpnTimer {
- bool enabled;
- uint16 value;
-
- int32 smpTillCb;
- uint32 smpTillCbRem;
- int32 smpPerCb;
- uint32 smpPerCbRem;
-
- OpnTimerProc cb;
- };
-
- OpnTimer _timers[2];
-
- int _volMaskA, _volMaskB;
- uint16 _volumeA, _volumeB;
-
- const float _baserate;
- uint32 _timerbase;
-
- Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
-
- static const uint8 _percussionData[];
- static const uint32 _adtStat[];
- static const uint8 _detSrc[];
- static const int _ssgTables[];
-
- bool _ready;
-};
-
-class TownsPC98_OpnDriver : public TownsPC98_OpnCore {
-friend class TownsPC98_OpnChannel;
-friend class TownsPC98_OpnChannelSSG;
-friend class TownsPC98_OpnSfxChannel;
-friend class TownsPC98_OpnChannelPCM;
-public:
- TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type);
- ~TownsPC98_OpnDriver();
-
- void loadMusicData(uint8 *data, bool loadPaused = false);
- void loadSoundEffectData(uint8 *data, uint8 trackNum);
- bool init();
- void reset();
-
- void fadeStep();
-
- void pause() { _musicPlaying = false; }
- void cont() { _musicPlaying = true; }
-
- void timerCallbackB();
- void timerCallbackA();
-
- bool looping() { return _looping == _updateChannelsFlag ? true : false; }
- bool musicPlaying() { return _musicPlaying; }
-
- void setMusicVolume(int volume) { _musicVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); }
- void setSoundEffectVolume(int volume) { _sfxVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); }
-
-protected:
- void startSoundEffect();
-
- void setMusicTempo(uint8 tempo);
- void setSfxTempo(uint16 tempo);
-
- TownsPC98_OpnChannel **_channels;
- TownsPC98_OpnChannelSSG **_ssgChannels;
- TownsPC98_OpnSfxChannel **_sfxChannels;
- TownsPC98_OpnChannelPCM *_rhythmChannel;
-
- const uint8 *_opnCarrier;
- const uint8 *_opnFreqTable;
- const uint8 *_opnFreqTableSSG;
- const uint8 *_opnFxCmdLen;
- const uint8 *_opnLvlPresets;
-
- uint8 *_musicBuffer;
- uint8 *_sfxBuffer;
- uint8 *_trackPtr;
- uint8 *_patches;
- uint8 *_ssgPatches;
-
- uint8 _updateChannelsFlag;
- uint8 _updateSSGFlag;
- uint8 _updateRhythmFlag;
- uint8 _updateSfxFlag;
- uint8 _finishedChannelsFlag;
- uint8 _finishedSSGFlag;
- uint8 _finishedRhythmFlag;
- uint8 _finishedSfxFlag;
-
- bool _musicPlaying;
- bool _sfxPlaying;
- uint8 _fading;
- uint8 _looping;
- uint32 _musicTickCounter;
-
- int _sfxOffs;
- uint8 *_sfxData;
- uint16 _sfxOffsets[2];
-
- uint16 _musicVolume;
- uint16 _sfxVolume;
-
- static const uint8 _drvTables[];
-
- bool _ready;
-};
-
-TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
- uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),
- _part(prt), _idFlag(id), controlEvents(0) {
-
- _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0;
- _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0;
- _vbrInitDelayHi = _vbrInitDelayLo = _vbrDuration = _vbrCurDelay = _vbrDurLeft = 0;
- _frqLSB = 0;
- _hold = false;
- _dataPtr = 0;
- _vbrModInitVal = _vbrModCurVal = 0;
- _frequency = 0;
-}
-
-TownsPC98_OpnChannel::~TownsPC98_OpnChannel() {
-}
-
-void TownsPC98_OpnChannel::init() {
- #define Control(x) &TownsPC98_OpnChannel::control_##x
- static const ControlEventFunc ctrlEvents[] = {
- Control(f0_setPatch),
- Control(f1_presetOutputLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setOutputLevel),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupVibrato),
- Control(f8_toggleVibrato),
- Control(dummy),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(dummy),
- Control(ff_endOfTrack)
- };
- #undef Control
-
- controlEvents = ctrlEvents;
-}
-
-void TownsPC98_OpnChannel::keyOff() {
- // all operators off
- uint8 value = _keyNum & 0x0f;
- if (_part)
- value |= 4;
- uint8 regAddress = 0x28;
- _drv->writeReg(0, regAddress, value);
- _flags |= CHS_KEYOFF;
-}
-
-void TownsPC98_OpnChannel::keyOn() {
- // all operators on
- uint8 value = _keyNum | 0xf0;
- if (_part)
- value |= 4;
- uint8 regAddress = 0x28;
- _drv->writeReg(0, regAddress, value);
-}
-
-void TownsPC98_OpnChannel::loadData(uint8 *data) {
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
- _ticksLeft = 1;
- _dataPtr = data;
- _totalLevel = 0x7F;
-
- uint8 *tmp = _dataPtr;
- for (bool loop = true; loop; ) {
- uint8 cmd = *tmp++;
- if (cmd < 0xf0) {
- tmp++;
- } else if (cmd == 0xff) {
- if (READ_LE_UINT16(tmp)) {
- _drv->_looping |= _idFlag;
- tmp += _drv->_opnFxCmdLen[cmd - 240];
- } else
- loop = false;
- } else if (cmd == 0xf6) {
- // reset repeat section countdown
- tmp[0] = tmp[1];
- tmp += 4;
- } else {
- tmp += _drv->_opnFxCmdLen[cmd - 240];
- }
- }
-}
-
-void TownsPC98_OpnChannel::processEvents() {
- if (_flags & CHS_EOT)
- return;
-
- if (!_hold && _ticksLeft == _keyOffTime)
- keyOff();
-
- if (--_ticksLeft)
- return;
-
- if (!_hold)
- keyOff();
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *_dataPtr++;
- if (cmd < 0xf0)
- loop = false;
- else if (!processControlEvent(cmd))
- return;
- }
-
- uint8 para = *_dataPtr++;
-
- if (cmd == 0x80) {
- keyOff();
- _hold = false;
- } else {
- keyOn();
-
- if (_hold == false || cmd != _frqBlockMSB)
- _flags |= CHS_RECALCFREQ;
-
- _hold = (para & 0x80) ? true : false;
- _frqBlockMSB = cmd;
- }
-
- _ticksLeft = para & 0x7f;
-}
-
-void TownsPC98_OpnChannel::processFrequency() {
- if (_flags & CHS_RECALCFREQ) {
-
- _frequency = (((const uint16 *)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f] + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8);
-
- _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
- _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
-
- setupVibrato();
- }
-
- if (!(_flags & CHS_VBROFF)) {
- if (!processVibrato())
- return;
-
- _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
- _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
- }
-}
-
-void TownsPC98_OpnChannel::setupVibrato() {
- _vbrCurDelay = _vbrInitDelayHi;
- if (_flags & CHS_KEYOFF) {
- _vbrModCurVal = _vbrModInitVal;
- _vbrCurDelay += _vbrInitDelayLo;
- }
- _vbrDurLeft = (_vbrDuration >> 1);
- _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
-}
-
-bool TownsPC98_OpnChannel::processVibrato() {
- if (--_vbrCurDelay)
- return false;
-
- _vbrCurDelay = _vbrInitDelayHi;
- _frequency += _vbrModCurVal;
-
- if (!--_vbrDurLeft) {
- _vbrDurLeft = _vbrDuration;
- _vbrModCurVal = -_vbrModCurVal;
- }
-
- return true;
-}
-
-bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-void TownsPC98_OpnChannel::setOutputLevel() {
- uint8 outopr = _drv->_opnCarrier[_algorithm];
- uint8 reg = 0x40 + _regOffset;
-
- for (int i = 0; i < 4; i++) {
- if (outopr & 1)
- _drv->writeReg(_part, reg, _totalLevel);
- outopr >>= 1;
- reg += 4;
- }
-}
-
-void TownsPC98_OpnChannel::fadeStep() {
- _totalLevel += 3;
- if (_totalLevel > 0x7f)
- _totalLevel = 0x7f;
- setOutputLevel();
-}
-
-void TownsPC98_OpnChannel::reset() {
- _hold = false;
- _keyOffTime = 0;
- _ticksLeft = 1;
-
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
-
- _totalLevel = 0;
- _algorithm = 0;
- _flags = CHS_EOT;
- _algorithm = 0;
-
- _block = 0;
- _frequency = 0;
- _frqBlockMSB = 0;
- _frqLSB = 0;
-
- _ssgTl = 0;
- _ssgStartLvl = 0;
- _ssgTargetLvl = 0;
- _ssgStep = 0;
- _ssgTicksLeft = 0;
-
- _vbrInitDelayHi = 0;
- _vbrInitDelayLo = 0;
- _vbrModInitVal = 0;
- _vbrDuration = 0;
- _vbrCurDelay = 0;
- _vbrModCurVal = 0;
- _vbrDurLeft = 0;
-}
-
-bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) {
- _instr = para;
- uint8 reg = _regOffset + 0x80;
-
- for (int i = 0; i < 4; i++) {
- // set release rate for each operator
- _drv->writeReg(_part, reg, 0x0f);
- reg += 4;
- }
-
- const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5);
- reg = _regOffset + 0x30;
-
- // write registers 0x30 to 0x8f
- for (int i = 0; i < 6; i++) {
- _drv->writeReg(_part, reg, tptr[0]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[2]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[1]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[3]);
- reg += 4;
- tptr += 4;
- }
-
- reg = _regOffset + 0xB0;
- _algorithm = tptr[0] & 7;
- // set feedback and algorithm
- _drv->writeReg(_part, reg, tptr[0]);
-
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) {
- if (_drv->_fading)
- return true;
-
- _totalLevel = _drv->_opnLvlPresets[para];
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f2_setKeyOffTime(uint8 para) {
- _keyOffTime = para;
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) {
- _frqLSB = (int8) para;
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) {
- if (_drv->_fading)
- return true;
-
- _totalLevel = para;
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) {
- _drv->setMusicTempo(para);
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) {
- _dataPtr--;
- _dataPtr[0]--;
-
- if (*_dataPtr) {
- // repeat section until counter has reached zero
- _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2);
- } else {
- // reset counter, advance to next section
- _dataPtr[0] = _dataPtr[1];
- _dataPtr += 4;
- }
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f7_setupVibrato(uint8 para) {
- _vbrInitDelayHi = _dataPtr[0];
- _vbrInitDelayLo = para;
- _vbrModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1);
- _vbrDuration = _dataPtr[3];
- _dataPtr += 4;
- _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF | CHS_RECALCFREQ;
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_f8_toggleVibrato(uint8 para) {
- if (para == 0x10) {
- if (*_dataPtr++) {
- _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF;
- } else {
- _flags |= CHS_VBROFF;
- }
- } else {
- /* NOT IMPLEMENTED
- uint8 skipChannels = para / 36;
- uint8 entry = para % 36;
- TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels];
-
- t->unnamedEntries[entry] = *_dataPtr++;*/
- }
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) {
- _drv->writeReg(_part, para, *_dataPtr++);
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- uint8 val = (_totalLevel + 3);
- if (val > 0x7f)
- val = 0x7f;
-
- _totalLevel = val;
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- int8 val = (int8) (_totalLevel - 3);
- if (val < 0)
- val = 0;
-
- _totalLevel = (uint8) val;
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) {
- uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1);
- _dataPtr = (tmp[1] == 1) ? tmp : (_dataPtr + 1);
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_dummy(uint8 para) {
- _dataPtr--;
- return true;
-}
-
-bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) {
- uint16 val = READ_LE_UINT16(--_dataPtr);
- if (val) {
- // loop
- _dataPtr = _drv->_trackPtr + val;
- return true;
- } else {
- // quit parsing for active channel
- --_dataPtr;
- _flags |= CHS_EOT;
- _drv->_finishedChannelsFlag |= _idFlag;
- keyOff();
- return false;
- }
-}
-
-TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
-}
-
-void TownsPC98_OpnChannelSSG::init() {
- _algorithm = 0x80;
-
- #define Control(x) &TownsPC98_OpnChannelSSG::control_##x
- static const ControlEventFunc ctrlEventsSSG[] = {
- Control(f0_setPatch),
- Control(f1_setTotalLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setAlgorithm),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupVibrato),
- Control(f8_toggleVibrato),
- Control(f9_loadCustomPatch),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(dummy),
- Control(ff_endOfTrack)
- };
- #undef Control
-
- controlEvents = ctrlEventsSSG;
-}
-
-void TownsPC98_OpnChannelSSG::processEvents() {
- if (_flags & CHS_EOT)
- return;
-
- _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false);
-
- if (!_hold && _ticksLeft == _keyOffTime)
- nextShape();
-
- if (!--_ticksLeft) {
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *_dataPtr++;
- if (cmd < 0xf0)
- loop = false;
- else if (!processControlEvent(cmd))
- return;
- }
-
- uint8 para = *_dataPtr++;
-
- if (cmd == 0x80) {
- nextShape();
- _hold = false;
- } else {
- if (!_hold) {
- _instr &= 0xf0;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
- _ssgStartLvl = _drv->_ssgPatches[_instr + 3];
- _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF;
- }
-
- keyOn();
-
- if (_hold == false || cmd != _frqBlockMSB)
- _flags |= CHS_RECALCFREQ;
-
- _hold = (para & 0x80) ? true : false;
- _frqBlockMSB = cmd;
- }
-
- _ticksLeft = para & 0x7f;
- }
-
- if (!(_flags & CHS_SSGOFF)) {
- if (--_ssgTicksLeft) {
- if (!_drv->_fading)
- setOutputLevel(_ssgStartLvl);
- return;
- }
-
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
-
- if (_drv->_ssgPatches[_instr + 1] & 0x80) {
- uint8 t = _ssgStartLvl - _ssgStep;
-
- if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) {
- if (!_drv->_fading)
- setOutputLevel(t);
- return;
- }
- } else {
- int t = _ssgStartLvl + _ssgStep;
- uint8 p = (uint8) (t & 0xff);
-
- if (t < 256 && _ssgTargetLvl > p) {
- if (!_drv->_fading)
- setOutputLevel(p);
- return;
- }
- }
-
- setOutputLevel(_ssgTargetLvl);
- if (_ssgStartLvl && !(_instr & 8)){
- _instr += 4;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
- } else {
- _flags |= CHS_SSGOFF;
- setOutputLevel(0);
- }
- }
-}
-
-void TownsPC98_OpnChannelSSG::processFrequency() {
- if (_algorithm & 0x40)
- return;
-
- if (_flags & CHS_RECALCFREQ) {
- _block = _frqBlockMSB >> 4;
- _frequency = ((const uint16 *)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB;
-
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
-
- setupVibrato();
- }
-
- if (!(_flags & (CHS_EOT | CHS_VBROFF | CHS_SSGOFF))) {
- if (!processVibrato())
- return;
-
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
- }
-}
-
-bool TownsPC98_OpnChannelSSG::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-void TownsPC98_OpnChannelSSG::nextShape() {
- _instr = (_instr & 0xf0) + 0x0c;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
-}
-
-void TownsPC98_OpnChannelSSG::keyOn() {
- uint8 c = 0x7b;
- uint8 t = (_algorithm & 0xC0) << 1;
- if (_algorithm & 0x80)
- t |= 4;
-
- c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset));
- t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset));
-
- if (!(_algorithm & 0x80))
- _drv->writeReg(_part, 6, _algorithm & 0x7f);
-
- uint8 e = (_drv->readSSGStatus() & c) | t;
- _drv->writeReg(_part, 7, e);
-}
-
-void TownsPC98_OpnChannelSSG::protect() {
- _flags |= CHS_PROTECT;
-}
-
-void TownsPC98_OpnChannelSSG::restore() {
- _flags &= ~CHS_PROTECT;
- keyOn();
- _drv->writeReg(_part, 8 + _regOffset, _ssgTl);
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
-}
-
-void TownsPC98_OpnChannelSSG::loadData(uint8 *data) {
- _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false);
- TownsPC98_OpnChannel::loadData(data);
- setOutputLevel(0);
- _algorithm = 0x80;
-}
-
-void TownsPC98_OpnChannelSSG::setOutputLevel(uint8 lvl) {
- _ssgStartLvl = lvl;
- uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8;
- if (newTl == _ssgTl)
- return;
- _ssgTl = newTl;
- _drv->writeReg(_part, 8 + _regOffset, _ssgTl);
-}
-
-void TownsPC98_OpnChannelSSG::reset() {
- TownsPC98_OpnChannel::reset();
-
- // Unlike the original we restore the default patch data. This fixes a bug
- // where certain sound effects would bring each other out of tune (e.g. the
- // dragon's fire in Darm's house in Kyra 1 would sound different each time
- // you triggered another sfx by dropping an item etc.)
- uint8 i = (10 + _regOffset) << 4;
- const uint8 *src = &_drv->_drvTables[156];
- _drv->_ssgPatches[i] = src[i];
- _drv->_ssgPatches[i + 3] = src[i + 3];
- _drv->_ssgPatches[i + 4] = src[i + 4];
- _drv->_ssgPatches[i + 6] = src[i + 6];
- _drv->_ssgPatches[i + 8] = src[i + 8];
- _drv->_ssgPatches[i + 12] = src[i + 12];
-}
-
-void TownsPC98_OpnChannelSSG::fadeStep() {
- _totalLevel--;
- if ((int8)_totalLevel < 0)
- _totalLevel = 0;
- setOutputLevel(_ssgStartLvl);
-}
-
-bool TownsPC98_OpnChannelSSG::control_f0_setPatch(uint8 para) {
- _instr = para << 4;
- para = (para >> 3) & 0x1e;
- if (para)
- return control_f4_setAlgorithm(para | 0x40);
- return true;
-}
-
-bool TownsPC98_OpnChannelSSG::control_f1_setTotalLevel(uint8 para) {
- if (!_drv->_fading)
- _totalLevel = para;
- return true;
-}
-
-bool TownsPC98_OpnChannelSSG::control_f4_setAlgorithm(uint8 para) {
- _algorithm = para;
- return true;
-}
-
-bool TownsPC98_OpnChannelSSG::control_f9_loadCustomPatch(uint8 para) {
- _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4;
- _drv->_ssgPatches[_instr] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 3] = para;
- _drv->_ssgPatches[_instr + 4] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 6] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 8] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 12] = *_dataPtr++;
- return true;
-}
-
-bool TownsPC98_OpnChannelSSG::control_fb_incOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- _totalLevel--;
- if ((int8)_totalLevel < 0)
- _totalLevel = 0;
-
- return true;
-}
-
-bool TownsPC98_OpnChannelSSG::control_fc_decOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- if (_totalLevel + 1 < 0x10)
- _totalLevel++;
-
- return true;
-}
-
-bool TownsPC98_OpnChannelSSG::control_ff_endOfTrack(uint8 para) {
- if (!_drv->_sfxOffs) {
- uint16 val = READ_LE_UINT16(--_dataPtr);
- if (val) {
- // loop
- _dataPtr = _drv->_trackPtr + val;
- return true;
- } else {
- // stop parsing
- if (!_drv->_fading)
- setOutputLevel(0);
- --_dataPtr;
- _flags |= CHS_EOT;
- _drv->_finishedSSGFlag |= _idFlag;
- }
- } else {
- // end of sfx track - restore ssg music channel
- _flags |= CHS_EOT;
- _drv->_finishedSfxFlag |= _idFlag;
- _drv->_ssgChannels[_chanNum]->restore();
- }
-
- return false;
-}
-
-void TownsPC98_OpnSfxChannel::loadData(uint8 *data) {
- _flags = CHS_ALLOFF;
- _ticksLeft = 1;
- _dataPtr = data;
- _ssgTl = 0xff;
- _algorithm = 0x80;
-
- uint8 *tmp = _dataPtr;
- for (bool loop = true; loop; ) {
- uint8 cmd = *tmp++;
- if (cmd < 0xf0) {
- tmp++;
- } else if (cmd == 0xff) {
- loop = false;
- } else if (cmd == 0xf6) {
- // reset repeat section countdown
- tmp[0] = tmp[1];
- tmp += 4;
- } else {
- tmp += _drv->_opnFxCmdLen[cmd - 240];
- }
- }
-}
-
-void TownsPC98_OpnSfxChannel::reset() {
- TownsPC98_OpnChannel::reset();
-
- // Unlike the original we restore the default patch data. This fixes a bug
- // where certain sound effects would bring each other out of tune (e.g. the
- // dragon's fire in Darm's house in Kyra 1 would sound different each time
- // you triggered another sfx by dropping an item etc.)
- uint8 i = (13 + _regOffset) << 4;
- const uint8 *src = &_drv->_drvTables[156];
- _drv->_ssgPatches[i] = src[i];
- _drv->_ssgPatches[i + 3] = src[i + 3];
- _drv->_ssgPatches[i + 4] = src[i + 4];
- _drv->_ssgPatches[i + 6] = src[i + 6];
- _drv->_ssgPatches[i + 8] = src[i + 8];
- _drv->_ssgPatches[i + 12] = src[i + 12];
-}
-
-TownsPC98_OpnChannelPCM::TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
-}
-
-void TownsPC98_OpnChannelPCM::init() {
- _algorithm = 0x80;
-
- #define Control(x) &TownsPC98_OpnChannelPCM::control_##x
- static const ControlEventFunc ctrlEventsPCM[] = {
- Control(dummy),
- Control(f1_prcStart),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(f6_repeatSection),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(fa_writeReg),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(ff_endOfTrack)
- };
- #undef Control
-
- controlEvents = ctrlEventsPCM;
-}
-
-void TownsPC98_OpnChannelPCM::loadData(uint8 *data) {
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
- _ticksLeft = 1;
- _dataPtr = data;
- _totalLevel = 0x7F;
-}
-
-void TownsPC98_OpnChannelPCM::processEvents() {
- if (_flags & CHS_EOT)
- return;
-
- if (--_ticksLeft)
- return;
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *_dataPtr++;
- if (cmd == 0x80) {
- loop = false;
- } else if (cmd < 0xf0) {
- _drv->writeReg(_part, 0x10, cmd);
- } else if (!processControlEvent(cmd)) {
- return;
- }
- }
-
- _ticksLeft = *_dataPtr++;
-}
-
-bool TownsPC98_OpnChannelPCM::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-bool TownsPC98_OpnChannelPCM::control_f1_prcStart(uint8 para) {
- _totalLevel = para;
- _drv->writeReg(_part, 0x11, para);
- return true;
-}
-
-bool TownsPC98_OpnChannelPCM::control_ff_endOfTrack(uint8 para) {
- uint16 val = READ_LE_UINT16(--_dataPtr);
- if (val) {
- // loop
- _dataPtr = _drv->_trackPtr + val;
- return true;
- } else {
- // quit parsing for active channel
- --_dataPtr;
- _flags |= CHS_EOT;
- _drv->_finishedRhythmFlag |= _idFlag;
- return false;
- }
-}
-
-TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const uint32 timerbase) : _tlTable(0),
- _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0), _reg(0), _rand(1), _outN(1),
- _nTick(0), _evpUpdateCnt(0), _evpTimer(0x1f), _pReslt(0x1f), _attack(0), _cont(false), _evpUpdate(true),
- _timer(0), _noiseGenerator(0), _chanEnable(0),
- _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) {
-
- memset(_channels, 0, sizeof(_channels));
- memset(_updateRequestBuf, 0, sizeof(_updateRequestBuf));
- _reg = new uint8 *[11];
-
- _reg[0] = &_channels[0].frqL;
- _reg[1] = &_channels[0].frqH;
- _reg[2] = &_channels[1].frqL;
- _reg[3] = &_channels[1].frqH;
- _reg[4] = &_channels[2].frqL;
- _reg[5] = &_channels[2].frqH;
- _reg[6] = &_noiseGenerator;
- _reg[7] = &_chanEnable;
- _reg[8] = &_channels[0].vol;
- _reg[9] = &_channels[1].vol;
- _reg[10] = &_channels[2].vol;
-
- reset();
-}
-
-TownsPC98_OpnSquareSineSource::~TownsPC98_OpnSquareSineSource() {
- delete[] _tlTable;
- delete[] _tleTable;
- delete[] _reg;
-}
-
-void TownsPC98_OpnSquareSineSource::init(const int *rsTable, const int *rseTable) {
- if (_ready) {
- reset();
- return;
- }
-
- delete[] _tlTable;
- delete[] _tleTable;
- _tlTable = new int32[16];
- _tleTable = new int32[32];
- float a, b, d;
- d = 801.0f;
-
- for (int i = 0; i < 16; i++) {
- b = 1.0f / rsTable[i];
- a = 1.0f / d + b + 1.0f / 1000.0f;
- float v = (b / a) * 32767.0f;
- _tlTable[i] = (int32) v;
-
- b = 1.0f / rseTable[i];
- a = 1.0f / d + b + 1.0f / 1000.0f;
- v = (b / a) * 32767.0f;
- _tleTable[i] = (int32) v;
- }
-
- for (int i = 16; i < 32; i++) {
- b = 1.0f / rseTable[i];
- a = 1.0f / d + b + 1.0f / 1000.0f;
- float v = (b / a) * 32767.0f;
- _tleTable[i] = (int32) v;
- }
-
- _ready = true;
-}
-
-void TownsPC98_OpnSquareSineSource::reset() {
- _rand = 1;
- _outN = 1;
- _updateRequest = -1;
- _nTick = _evpUpdateCnt = 0;
- _evpTimer = 0x1f;
- _pReslt = 0x1f;
- _attack = 0;
- _cont = false;
- _evpUpdate = true;
- _timer = 0;
-
- for (int i = 0; i < 3; i++) {
- _channels[i].tick = 0;
- _channels[i].smp = _channels[i].out = 0;
- }
-
- for (int i = 0; i < 14; i++)
- writeReg(i, 0, true);
-
- writeReg(7, 0xbf, true);
-}
-
-void TownsPC98_OpnSquareSineSource::writeReg(uint8 address, uint8 value, bool force) {
- if (!_ready)
- return;
-
- if (address > 10 || *_reg[address] == value) {
- if ((address == 11 || address == 12 || address == 13) && value)
- warning("TownsPC98_OpnSquareSineSource: unsupported reg address: %d", address);
- return;
- }
-
- if (!force) {
- if (_updateRequest >= 63) {
- warning("TownsPC98_OpnSquareSineSource: event buffer overflow");
- _updateRequest = -1;
- }
- _updateRequestBuf[++_updateRequest] = value;
- _updateRequestBuf[++_updateRequest] = address;
- return;
- }
-
- *_reg[address] = value;
-}
-
-void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (uint32 i = 0; i < bufferSize; i++) {
- _timer += _tickLength;
- while (_timer > 0x5B8D80) {
- _timer -= 0x5B8D80;
-
- if (++_nTick >= (_noiseGenerator & 0x1f)) {
- if ((_rand + 1) & 2)
- _outN ^= 1;
-
- _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1);
- _nTick = 0;
- }
-
- for (int ii = 0; ii < 3; ii++) {
- if (++_channels[ii].tick >= (((_channels[ii].frqH & 0x0f) << 8) | _channels[ii].frqL)) {
- _channels[ii].tick = 0;
- _channels[ii].smp ^= 1;
- }
- _channels[ii].out = (_channels[ii].smp | ((_chanEnable >> ii) & 1)) & (_outN | ((_chanEnable >> (ii + 3)) & 1));
- }
-
- if (_evpUpdate) {
- if (++_evpUpdateCnt >= 0) {
- _evpUpdateCnt = 0;
-
- if (--_evpTimer < 0) {
- if (_cont) {
- _evpTimer &= 0x1f;
- } else {
- _evpUpdate = false;
- _evpTimer = 0;
- }
- }
- }
- }
- _pReslt = _evpTimer ^ _attack;
- updateRegs();
- }
-
- int32 finOut = 0;
- for (int ii = 0; ii < 3; ii++) {
- int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0];
-
- if ((1 << ii) & _volMaskA)
- finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume;
-
- if ((1 << ii) & _volMaskB)
- finOutTemp = (finOutTemp * _volumeB) / Audio::Mixer::kMaxMixerVolume;
-
- finOut += finOutTemp;
- }
-
- finOut /= 3;
-
- buffer[i << 1] += finOut;
- buffer[(i << 1) + 1] += finOut;
- }
-}
-
-void TownsPC98_OpnSquareSineSource::updateRegs() {
- for (int i = 0; i < _updateRequest;) {
- uint8 b = _updateRequestBuf[i++];
- uint8 a = _updateRequestBuf[i++];
- writeReg(a, b, true);
- }
- _updateRequest = -1;
-}
-
-TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const uint32 timerbase) :
- _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) {
-
- memset(_rhChan, 0, sizeof(RhtChannel) * 6);
- _reg = new uint8 *[40];
-
- _reg[0] = _reg[1] = _reg[2] = _reg[3] = _reg[4] = _reg[5] = _reg[6] = _reg[7] = _reg[8] = _reg[9] = _reg[10] = _reg[11] = _reg[12] = _reg[13] = _reg[14] = _reg[15] = 0;
- _reg[16] = &_rhChan[0].startPosL;
- _reg[17] = &_rhChan[1].startPosL;
- _reg[18] = &_rhChan[2].startPosL;
- _reg[19] = &_rhChan[3].startPosL;
- _reg[20] = &_rhChan[4].startPosL;
- _reg[21] = &_rhChan[5].startPosL;
- _reg[22] = &_rhChan[0].startPosH;
- _reg[23] = &_rhChan[1].startPosH;
- _reg[24] = &_rhChan[2].startPosH;
- _reg[25] = &_rhChan[3].startPosH;
- _reg[26] = &_rhChan[4].startPosH;
- _reg[27] = &_rhChan[5].startPosH;
- _reg[28] = &_rhChan[0].endPosL;
- _reg[29] = &_rhChan[1].endPosL;
- _reg[30] = &_rhChan[2].endPosL;
- _reg[31] = &_rhChan[3].endPosL;
- _reg[32] = &_rhChan[4].endPosL;
- _reg[33] = &_rhChan[5].endPosL;
- _reg[34] = &_rhChan[0].endPosH;
- _reg[35] = &_rhChan[1].endPosH;
- _reg[36] = &_rhChan[2].endPosH;
- _reg[37] = &_rhChan[3].endPosH;
- _reg[38] = &_rhChan[4].endPosH;
- _reg[39] = &_rhChan[5].endPosH;
-}
-
-void TownsPC98_OpnPercussionSource::init(const uint8 *instrData) {
- if (_ready) {
- reset();
- return;
- }
-
- const uint8 *start = instrData;
- const uint8 *pos = start;
-
- if (instrData) {
- for (int i = 0; i < 6; i++) {
- _rhChan[i].data = start + READ_BE_UINT16(pos);
- pos += 2;
- _rhChan[i].size = READ_BE_UINT16(pos);
- pos += 2;
- }
- reset();
- _ready = true;
- } else {
- memset(_rhChan, 0, sizeof(RhtChannel) * 6);
- _ready = false;
- }
-}
-
-void TownsPC98_OpnPercussionSource::reset() {
- _timer = 0;
- _totalLevel = 63;
-
- for (int i = 0; i < 6; i++) {
- RhtChannel *s = &_rhChan[i];
- s->pos = s->start = s->data;
- s->end = s->data + s->size;
- s->active = false;
- s->level = 0;
- s->out = 0;
- s->decStep = 1;
- s->decState = 0;
- s->samples[0] = s->samples[1] = 0;
- s->startPosH = s->startPosL = s->endPosH = s->endPosL = 0;
- }
-}
-
-void TownsPC98_OpnPercussionSource::writeReg(uint8 address, uint8 value) {
- if (!_ready)
- return;
-
- uint8 h = address >> 4;
- uint8 l = address & 15;
-
- if (address > 15)
- *_reg[address] = value;
-
- if (address == 0) {
- if (value & 0x80) {
- //key off
- for (int i = 0; i < 6; i++) {
- if ((value >> i) & 1)
- _rhChan[i].active = false;
- }
- } else {
- //key on
- for (int i = 0; i < 6; i++) {
- if ((value >> i) & 1) {
- RhtChannel *s = &_rhChan[i];
- s->pos = s->start;
- s->active = true;
- s->out = 0;
- s->samples[0] = s->samples[1] = 0;
- s->decStep = 1;
- s->decState = 0;
- }
- }
- }
- } else if (address == 1) {
- // total level
- _totalLevel = (value & 63) ^ 63;
- for (int i = 0; i < 6; i++)
- recalcOuput(&_rhChan[i]);
- } else if (!h && l & 8) {
- // instrument level
- l &= 7;
- _rhChan[l].level = (value & 0x1f) ^ 0x1f;
- recalcOuput(&_rhChan[l]);
- } else if (h & 3) {
- l &= 7;
- if (h == 1) {
- // set start offset
- _rhChan[l].start = _rhChan[l].data + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8);
- } else if (h == 2) {
- // set end offset
- _rhChan[l].end = _rhChan[l].data + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255;
- }
- }
-}
-
-void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (uint32 i = 0; i < bufferSize; i++) {
- _timer += _tickLength;
- while (_timer > 0x5B8D80) {
- _timer -= 0x5B8D80;
-
- for (int ii = 0; ii < 6; ii++) {
- RhtChannel *s = &_rhChan[ii];
- if (s->active) {
- recalcOuput(s);
- if (s->decStep) {
- advanceInput(s);
- if (s->pos == s->end)
- s->active = false;
- }
- s->decStep ^= 1;
- }
- }
- }
-
- int32 finOut = 0;
-
- for (int ii = 0; ii < 6; ii++) {
- if (_rhChan[ii].active)
- finOut += _rhChan[ii].out;
- }
-
- finOut <<= 1;
-
- if (1 & _volMaskA)
- finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume;
-
- if (1 & _volMaskB)
- finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume;
-
- buffer[i << 1] += finOut;
- buffer[(i << 1) + 1] += finOut;
- }
-}
-
-void TownsPC98_OpnPercussionSource::recalcOuput(RhtChannel *ins) {
- uint32 s = _totalLevel + ins->level;
- uint32 x = s > 62 ? 0 : (1 + (s >> 3));
- int32 y = s > 62 ? 0 : (15 - (s & 7));
- ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3;
-}
-
-void TownsPC98_OpnPercussionSource::advanceInput(RhtChannel *ins) {
- static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 };
-
- static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
- 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337,
- 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
- };
-
- uint8 cur = (int8) *ins->pos++;
-
- for (int i = 0; i < 2; i++) {
- int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8;
- ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047);
- ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48);
- cur >>= 4;
- }
-}
-
-TownsPC98_OpnCore::TownsPC98_OpnCore(Audio::Mixer *mixer, OpnType type) :
- _mixer(mixer),
- _chanInternal(0), _ssg(0), _prc(0),
- _numChan(type == OD_TYPE26 ? 3 : 6), _numSSG(type == OD_TOWNS ? 0 : 3), _hasPercussion(type == OD_TYPE86 ? true : false),
- _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0),
- _baserate(55125.0f / (float)mixer->getOutputRate()),
- _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255),
- _regProtectionFlag(false), _ready(false) {
-
- memset(&_timers[0], 0, sizeof(OpnTimer));
- memset(&_timers[1], 0, sizeof(OpnTimer));
- _timers[0].cb = &TownsPC98_OpnCore::timerCallbackA;
- _timers[1].cb = &TownsPC98_OpnCore::timerCallbackB;
- _timerbase = (uint32)(_baserate * 1000000.0f);
-}
-
-TownsPC98_OpnCore::~TownsPC98_OpnCore() {
- Common::StackLock lock(_mutex);
- _mixer->stopHandle(_soundHandle);
- delete _ssg;
- delete _prc;
- delete[] _chanInternal;
-
- delete[] _oprRates;
- delete[] _oprRateshift;
- delete[] _oprFrq;
- delete[] _oprAttackDecay;
- delete[] _oprSinTbl;
- delete[] _oprLevelOut;
- delete[] _oprDetune;
-}
-
-bool TownsPC98_OpnCore::init() {
- if (_ready) {
- reset();
- return true;
- }
-
- generateTables();
-
- _chanInternal = new ChanInternal[_numChan];
- for (int i = 0; i < _numChan; i++) {
- memset(&_chanInternal[i], 0, sizeof(ChanInternal));
- for (int j = 0; j < 4; ++j)
- _chanInternal[i].opr[j] = new TownsPC98_OpnOperator(_timerbase, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune);
- }
-
- if (_numSSG) {
- _ssg = new TownsPC98_OpnSquareSineSource(_timerbase);
- _ssg->init(&_ssgTables[0], &_ssgTables[16]);
- }
-
- if (_hasPercussion) {
- _prc = new TownsPC98_OpnPercussionSource(_timerbase);
- _prc->init(_percussionData);
- }
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType,
- &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- _ready = true;
-
- return true;
-}
-
-void TownsPC98_OpnCore::reset() {
- for (int i = 0; i < _numChan; i++) {
- for (int ii = 0; ii < 4; ii++)
- _chanInternal[i].opr[ii]->reset();
- memset(_chanInternal[i].feedbuf, 0, 3);
- _chanInternal[i].algorithm = 0;
- _chanInternal[i].frqTemp = 0;
- _chanInternal[i].enableLeft = _chanInternal[i].enableRight = true;
- _chanInternal[i].updateEnvelopeParameters = false;
- }
-
- writeReg(0, 0x27, 0x33);
-
- if (_ssg)
- _ssg->reset();
-
- if (_prc)
- _prc->reset();
-}
-
-void TownsPC98_OpnCore::writeReg(uint8 part, uint8 regAddress, uint8 value) {
- if (_regProtectionFlag || !_ready)
- return;
-
- static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
-
- uint8 h = regAddress & 0xf0;
- uint8 l = (regAddress & 0x0f);
-
- ChanInternal *c = 0;
- TownsPC98_OpnOperator **co = 0;
- TownsPC98_OpnOperator *o = 0;
-
- if (regAddress > 0x2F) {
- c = &_chanInternal[(l & 3) + 3 * part];
- co = c->opr;
- o = c->opr[oprOrdr[(l - (l & 3)) >> 2]];
- } else if (regAddress == 0x28) {
- c = &_chanInternal[(value & 3) + ((value & 4) ? 3 : 0)];
- co = c->opr;
- }
-
- switch (h) {
- case 0x00:
- // ssg
- if (_ssg)
- _ssg->writeReg(l, value);
- break;
- case 0x10:
- // pcm rhythm channel
- if (_prc)
- _prc->writeReg(l, value);
- break;
- case 0x20:
- if (l == 8) {
- // Key on/off
- for (int i = 0; i < 4; i++) {
- if ((value >> (4 + i)) & 1)
- co[oprOrdr[i]]->keyOn();
- else
- co[oprOrdr[i]]->keyOff();
- }
- } else if (l == 4) {
- // Timer A
- _timers[0].value = (_timers[0].value & 0xff00) | value;
- } else if (l == 5) {
- // Timer A
- _timers[0].value = (_timers[0].value & 0xff) | (value << 8);
- } else if (l == 6) {
- // Timer B
- _timers[1].value = value & 0xff;
- } else if (l == 7) {
- _timers[0].enabled = (value & 1) ? 1 : 0;
- _timers[1].enabled = (value & 2) ? 1 : 0;
-
- float spc = (float)(0x400 - _timers[0].value) / _baserate;
- _timers[0].smpPerCb = (int32) spc;
- _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f);
-
- spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate;
- _timers[1].smpPerCb = (int32) spc;
- _timers[1].smpPerCbRem = (uint32) ((spc - (float)_timers[1].smpPerCb) * 1000000.0f);
-
- if (value & 10) {
- _timers[0].smpTillCb = _timers[0].smpPerCb;
- _timers[0].smpTillCbRem = _timers[0].smpTillCbRem;
- }
-
- if (value & 20) {
- _timers[1].smpTillCb = _timers[1].smpPerCb;
- _timers[1].smpTillCbRem = _timers[1].smpTillCbRem;
- }
- } else if (l == 2) {
- // LFO
- warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)");
- } else if (l == 10 || l == 11) {
- // DAC
- warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)");
- }
- break;
-
- case 0x30:
- // detune, multiple
- o->detune((value >> 4) & 7);
- o->multiple(value & 0x0f);
- c->updateEnvelopeParameters = true;
- break;
-
- case 0x40:
- // total level
- o->totalLevel(value & 0x7f);
- break;
-
- case 0x50:
- // rate scaling, attack rate
- o->attackRate(value & 0x1f);
- if (o->scaleRate(value >> 6))
- c->updateEnvelopeParameters = true;
- break;
-
- case 0x60:
- // first decay rate, amplitude modulation
- o->decayRate(value & 0x1f);
- if (value & 0x80)
- warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)");
- break;
-
- case 0x70:
- // secondary decay rate
- o->sustainRate(value & 0x1f);
- break;
-
- case 0x80:
- // secondary amplitude, release rate;
- o->sustainLevel(value >> 4);
- o->releaseRate(value & 0x0f);
- break;
-
- case 0x90:
- warning("TownsPC98_OpnDriver: TRYING TO SSG ENVELOPE SHAPES (NOT SUPPORTED)");
- break;
-
- case 0xa0:
- // frequency
- l &= ~3;
- if (l == 0) {
- c->frqTemp = (c->frqTemp & 0xff00) | value;
- c->updateEnvelopeParameters = true;
- for (int i = 0; i < 4; i++)
- co[i]->frequency(c->frqTemp);
- } else if (l == 4) {
- c->frqTemp = (c->frqTemp & 0xff) | (value << 8);
- } else if (l == 8) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- } else if (l == 12) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- }
- break;
-
- case 0xb0:
- l &= ~3;
- if (l == 0) {
- // feedback, _algorithm
- co[0]->feedbackLevel((value >> 3) & 7);
- c->algorithm = value & 7;
- } else if (l == 4) {
- // stereo, LFO sensitivity
- c->enableLeft = value & 0x80 ? true : false;
- c->enableRight = value & 0x40 ? true : false;
- uint8 ams = (value & 0x3F) >> 3;
- if (ams)
- warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)");
- uint8 fms = value & 3;
- if (fms)
- warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)");
- }
- break;
-
- default:
- warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress);
- }
-}
-
-int TownsPC98_OpnCore::readBuffer(int16 *buffer, const int numSamples) {
- Common::StackLock lock(_mutex);
-
- memset(buffer, 0, sizeof(int16) * numSamples);
- int32 *tmp = new int32[numSamples];
- int32 *tmpStart = tmp;
- memset(tmp, 0, sizeof(int32) * numSamples);
- int32 samplesLeft = numSamples >> 1;
-
- while (samplesLeft) {
- int32 render = samplesLeft;
-
- for (int i = 0; i < 2; i++) {
- if (_timers[i].enabled && _timers[i].cb) {
- if (!_timers[i].smpTillCb) {
- (this->*_timers[i].cb)();
- _timers[i].smpTillCb = _timers[i].smpPerCb;
-
- _timers[i].smpTillCbRem += _timers[i].smpPerCbRem;
- if (_timers[i].smpTillCbRem >= _timerbase) {
- _timers[i].smpTillCb++;
- _timers[i].smpTillCbRem -= _timerbase;
- }
- }
- render = MIN(render, _timers[i].smpTillCb);
- }
- }
-
- samplesLeft -= render;
-
- for (int i = 0; i < 2; i++) {
- if (_timers[i].enabled && _timers[i].cb) {
- _timers[i].smpTillCb -= render;
- }
- }
-
- nextTick(tmp, render);
-
- if (_ssg)
- _ssg->nextTick(tmp, render);
- if (_prc)
- _prc->nextTick(tmp, render);
-
- for (int i = 0; i < render; ++i) {
- int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767);
- buffer[i << 1] = (int16) l;
- int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767);
- buffer[(i << 1) + 1] = (int16) r;
- }
-
- buffer += (render << 1);
- tmp += (render << 1);
- }
-
- delete[] tmpStart;
- return numSamples;
-}
-
-void TownsPC98_OpnCore::setVolumeIntern(int volA, int volB) {
- Common::StackLock lock(_mutex);
- _volumeA = volA;
- _volumeB = volB;
- if (_ssg)
- _ssg->setVolumeIntern(volA, volB);
- if (_prc)
- _prc->setVolumeIntern(volA, volB);
-}
-
-void TownsPC98_OpnCore::setVolumeChannelMasks(int channelMaskA, int channelMaskB) {
- Common::StackLock lock(_mutex);
- _volMaskA = channelMaskA;
- _volMaskB = channelMaskB;
- if (_ssg)
- _ssg->setVolumeChannelMasks(_volMaskA >> _numChan, _volMaskB >> _numChan);
- if (_prc)
- _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG));
-}
-
-void TownsPC98_OpnCore::generateTables() {
- delete[] _oprRates;
- _oprRates = new uint8[128];
-
- WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018);
- WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018);
- memset(_oprRates, 0x90, 32);
- memset(_oprRates + 96, 0x80, 32);
- uint8 *dst = (uint8 *)_oprRates + 40;
- for (int i = 0; i < 40; i += 4)
- WRITE_BE_UINT32(dst + i, 0x00081018);
- for (int i = 0; i < 48; i += 4)
- WRITE_BE_UINT32(dst + i, 0x00081018);
- dst += 40;
- for (uint8 i = 0; i < 16; i ++) {
- uint8 v = (i < 12) ? i : 12;
- *dst++ = ((4 + v) << 3);
- }
-
- delete[] _oprRateshift;
- _oprRateshift = new uint8[128];
- memset(_oprRateshift, 0, 128);
- dst = (uint8 *)_oprRateshift + 32;
- for (int i = 11; i; i--) {
- memset(dst, i, 4);
- dst += 4;
- }
-
- delete[] _oprFrq;
- _oprFrq = new uint32[0x1000];
- for (uint32 i = 0; i < 0x1000; i++)
- _oprFrq[i] = (uint32)(_baserate * (float)(i << 11));
-
- delete[] _oprAttackDecay;
- _oprAttackDecay = new uint8[152];
- memset(_oprAttackDecay, 0, 152);
- for (int i = 0; i < 36; i++)
- WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]);
-
- delete[] _oprSinTbl;
- _oprSinTbl = new uint32[1024];
- for (int i = 0; i < 1024; i++) {
- double val = sin((double) (((i << 1) + 1) * PI / 1024.0));
- double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0;
- int32 i_dcb = (int32)(2.0 * d_dcb);
- i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1);
- _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1);
- }
-
- delete[] _oprLevelOut;
- _oprLevelOut = new int32[0x1a00];
- for (int i = 0; i < 256; i++) {
- double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i)));
- int32 val_int = ((int32) val) >> 4;
- _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2;
- _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1];
- for (int ii = 1; ii < 13; ii++) {
- _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii;
- _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)];
- }
- }
-
- uint8 *dtt = new uint8[128];
- memset(dtt, 0, 36);
- memset(dtt + 36, 1, 8);
- memcpy(dtt + 44, _detSrc, 84);
-
- delete[] _oprDetune;
- _oprDetune = new int32[256];
- for (int i = 0; i < 128; i++) {
- _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0);
- _oprDetune[i + 128] = -_oprDetune[i];
- }
-
- delete[] dtt;
-}
-
-void TownsPC98_OpnCore::nextTick(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (int i = 0; i < _numChan; i++) {
- TownsPC98_OpnOperator **o = _chanInternal[i].opr;
-
- if (_chanInternal[i].updateEnvelopeParameters) {
- _chanInternal[i].updateEnvelopeParameters = false;
- for (int ii = 0; ii < 4 ; ii++)
- o[ii]->updatePhaseIncrement();
- }
-
- for (uint32 ii = 0; ii < bufferSize ; ii++) {
- int32 phbuf1, phbuf2, output;
- phbuf1 = phbuf2 = output = 0;
-
- int32 *leftSample = &buffer[ii * 2];
- int32 *rightSample = &buffer[ii * 2 + 1];
- int32 *del = &_chanInternal[i].feedbuf[2];
- int32 *feed = _chanInternal[i].feedbuf;
-
- switch (_chanInternal[i].algorithm) {
- case 0:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(*del, 0, phbuf2);
- *del = 0;
- o[1]->generateOutput(phbuf1, 0, *del);
- o[3]->generateOutput(phbuf2, 0, output);
- break;
- case 1:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(*del, 0, phbuf2);
- o[1]->generateOutput(0, 0, phbuf1);
- o[3]->generateOutput(phbuf2, 0, output);
- *del = phbuf1;
- break;
- case 2:
- o[0]->generateOutput(0, feed, phbuf2);
- o[2]->generateOutput(*del, 0, phbuf2);
- o[1]->generateOutput(0, 0, phbuf1);
- o[3]->generateOutput(phbuf2, 0, output);
- *del = phbuf1;
- break;
- case 3:
- o[0]->generateOutput(0, feed, phbuf2);
- o[2]->generateOutput(0, 0, *del);
- o[1]->generateOutput(phbuf2, 0, phbuf1);
- o[3]->generateOutput(*del, 0, output);
- *del = phbuf1;
- break;
- case 4:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(0, 0, phbuf2);
- o[1]->generateOutput(phbuf1, 0, output);
- o[3]->generateOutput(phbuf2, 0, output);
- *del = 0;
- break;
- case 5:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(*del, 0, output);
- o[1]->generateOutput(phbuf1, 0, output);
- o[3]->generateOutput(phbuf1, 0, output);
- *del = phbuf1;
- break;
- case 6:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(0, 0, output);
- o[1]->generateOutput(phbuf1, 0, output);
- o[3]->generateOutput(0, 0, output);
- *del = 0;
- break;
- case 7:
- o[0]->generateOutput(0, feed, output);
- o[2]->generateOutput(0, 0, output);
- o[1]->generateOutput(0, 0, output);
- o[3]->generateOutput(0, 0, output);
- *del = 0;
- break;
- };
-
- int32 finOut = (output << 2) / ((_numChan + _numSSG - 3) / 3);
-
- if ((1 << i) & _volMaskA)
- finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume;
-
- if ((1 << i) & _volMaskB)
- finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume;
-
- if (_chanInternal[i].enableLeft)
- *leftSample += finOut;
-
- if (_chanInternal[i].enableRight)
- *rightSample += finOut;
- }
- }
-}
-
-TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : TownsPC98_OpnCore(mixer, type),
- _channels(0), _ssgChannels(0), _sfxChannels(0), _rhythmChannel(0),
- _trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0),
- _patches(0), _sfxBuffer(0), _musicBuffer(0),
-
- _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 108), _opnFreqTableSSG(_drvTables + 132),
- _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 84)),
-
- _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), _finishedChannelsFlag(0),
- _updateSSGFlag(type == OD_TOWNS ? 0x00 : 0x07), _finishedSSGFlag(0),
- _updateRhythmFlag(type == OD_TYPE86 ? 0x01 : 0x00), _finishedRhythmFlag(0),
- _updateSfxFlag(0), _finishedSfxFlag(0),
-
- _musicTickCounter(0),
-
- _musicVolume(255), _sfxVolume(255),
-
- _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) {
-
- _sfxOffsets[0] = _sfxOffsets[1] = 0;
-}
-
-TownsPC98_OpnDriver::~TownsPC98_OpnDriver() {
- reset();
-
- if (_channels) {
- for (int i = 0; i < _numChan; i++)
- delete _channels[i];
- delete[] _channels;
- }
-
- if (_ssgChannels) {
- for (int i = 0; i < _numSSG; i++)
- delete _ssgChannels[i];
- delete[] _ssgChannels;
- }
-
- if (_sfxChannels) {
- for (int i = 0; i < 2; i++)
- delete _sfxChannels[i];
- delete[] _sfxChannels;
- }
-
- delete _rhythmChannel;
-
- delete[] _ssgPatches;
-}
-
-bool TownsPC98_OpnDriver::init() {
- if (_ready) {
- reset();
- return true;
- }
-
- TownsPC98_OpnCore::init();
-
- setVolumeChannelMasks(-1, 0);
-
- _channels = new TownsPC98_OpnChannel *[_numChan];
- for (int i = 0; i < _numChan; i++) {
- int ii = i * 6;
- _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _channels[i]->init();
- }
-
- if (_numSSG) {
- _ssgPatches = new uint8[256];
- memcpy(_ssgPatches, _drvTables + 156, 256);
-
- _ssgChannels = new TownsPC98_OpnChannelSSG *[_numSSG];
- for (int i = 0; i < _numSSG; i++) {
- int ii = i * 6;
- _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _ssgChannels[i]->init();
- }
-
- _sfxChannels = new TownsPC98_OpnSfxChannel *[2];
- for (int i = 0; i < 2; i++) {
- int ii = (i + 1) * 6;
- _sfxChannels[i] = new TownsPC98_OpnSfxChannel(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _sfxChannels[i]->init();
- }
- }
-
- if (_hasPercussion) {
- _rhythmChannel = new TownsPC98_OpnChannelPCM(this, 0, 0, 0, 0, 0, 1);
- _rhythmChannel->init();
- }
-
- setMusicTempo(84);
- setSfxTempo(654);
-
- _ready = true;
-
- return true;
-}
-
-void TownsPC98_OpnDriver::loadMusicData(uint8 *data, bool loadPaused) {
- if (!_ready) {
- warning("TownsPC98_OpnDriver: Driver must be initialized before loading data");
- return;
- }
-
- if (!data) {
- warning("TownsPC98_OpnDriver: Invalid music file data");
- return;
- }
-
- reset();
-
- Common::StackLock lock(_mutex);
- uint8 *src_a = _trackPtr = _musicBuffer = data;
-
- for (uint8 i = 0; i < 3; i++) {
- _channels[i]->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- for (int i = 0; i < _numSSG; i++) {
- _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- for (uint8 i = 3; i < _numChan; i++) {
- _channels[i]->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- if (_hasPercussion) {
- _rhythmChannel->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- toggleRegProtection(false);
-
- _patches = src_a + 4;
- _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0;
-
- _musicPlaying = (loadPaused ? false : true);
-}
-
-void TownsPC98_OpnDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) {
- if (!_ready) {
- warning("TownsPC98_OpnDriver: Driver must be initialized before loading data");
- return;
- }
-
- if (!_sfxChannels) {
- warning("TownsPC98_OpnDriver: Sound effects not supported by this configuration");
- return;
- }
-
- if (!data) {
- warning("TownsPC98_OpnDriver: Invalid sound effects file data");
- return;
- }
-
- Common::StackLock lock(_mutex);
- _sfxData = _sfxBuffer = data;
- _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]);
- _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]);
- _sfxPlaying = true;
- _finishedSfxFlag = 0;
-}
-
-void TownsPC98_OpnDriver::reset() {
- Common::StackLock lock(_mutex);
-
- _musicPlaying = false;
- _sfxPlaying = false;
- _fading = false;
- _looping = 0;
- _musicTickCounter = 0;
- _sfxData = 0;
-
- TownsPC98_OpnCore::reset();
-
- for (int i = 0; i < _numChan; i++)
- _channels[i]->reset();
- for (int i = 0; i < _numSSG; i++)
- _ssgChannels[i]->reset();
-
- if (_numSSG) {
- for (int i = 0; i < 2; i++)
- _sfxChannels[i]->reset();
-
- memcpy(_ssgPatches, _drvTables + 156, 256);
- }
-
- if (_rhythmChannel)
- _rhythmChannel->reset();
-}
-
-void TownsPC98_OpnDriver::fadeStep() {
- if (!_musicPlaying)
- return;
-
- Common::StackLock lock(_mutex);
- for (int j = 0; j < _numChan; j++) {
- if (_updateChannelsFlag & _channels[j]->_idFlag)
- _channels[j]->fadeStep();
- }
-
- for (int j = 0; j < _numSSG; j++) {
- if (_updateSSGFlag & _ssgChannels[j]->_idFlag)
- _ssgChannels[j]->fadeStep();
- }
-
- if (!_fading) {
- _fading = 19;
- if (_hasPercussion) {
- if (_updateRhythmFlag & _rhythmChannel->_idFlag)
- _rhythmChannel->reset();
- }
- } else {
- if (!--_fading)
- reset();
- }
-}
-
-void TownsPC98_OpnDriver::timerCallbackB() {
- _sfxOffs = 0;
-
- if (_musicPlaying) {
- _musicTickCounter++;
-
- for (int i = 0; i < _numChan; i++) {
- if (_updateChannelsFlag & _channels[i]->_idFlag) {
- _channels[i]->processEvents();
- _channels[i]->processFrequency();
- }
- }
-
- for (int i = 0; i < _numSSG; i++) {
- if (_updateSSGFlag & _ssgChannels[i]->_idFlag) {
- _ssgChannels[i]->processEvents();
- _ssgChannels[i]->processFrequency();
- }
- }
-
- if (_hasPercussion)
- if (_updateRhythmFlag & _rhythmChannel->_idFlag)
- _rhythmChannel->processEvents();
- }
-
- toggleRegProtection(false);
-
- if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag)
- _musicPlaying = false;
-}
-
-void TownsPC98_OpnDriver::timerCallbackA() {
- if (_sfxChannels && _sfxPlaying) {
- if (_sfxData)
- startSoundEffect();
-
- _sfxOffs = 3;
- _trackPtr = _sfxBuffer;
-
- for (int i = 0; i < 2; i++) {
- if (_updateSfxFlag & _sfxChannels[i]->_idFlag) {
- _sfxChannels[i]->processEvents();
- _sfxChannels[i]->processFrequency();
- }
- }
-
- _trackPtr = _musicBuffer;
- }
-
- if (_updateSfxFlag && _finishedSfxFlag == _updateSfxFlag) {
- _sfxPlaying = false;
- _updateSfxFlag = 0;
- setVolumeChannelMasks(-1, 0);
- }
-}
-
-void TownsPC98_OpnDriver::setMusicTempo(uint8 tempo) {
- writeReg(0, 0x26, tempo);
- writeReg(0, 0x27, 0x33);
-}
-
-void TownsPC98_OpnDriver::setSfxTempo(uint16 tempo) {
- writeReg(0, 0x24, tempo & 0xff);
- writeReg(0, 0x25, tempo >> 8);
- writeReg(0, 0x27, 0x33);
-}
-
-void TownsPC98_OpnDriver::startSoundEffect() {
- int volFlags = 0;
-
- for (int i = 0; i < 2; i++) {
- if (_sfxOffsets[i]) {
- _ssgChannels[i + 1]->protect();
- _sfxChannels[i]->reset();
- _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]);
- _updateSfxFlag |= _sfxChannels[i]->_idFlag;
- volFlags |= (_sfxChannels[i]->_idFlag << _numChan);
- } else {
- _ssgChannels[i + 1]->restore();
- _updateSfxFlag &= ~_sfxChannels[i]->_idFlag;
- }
- }
-
- setVolumeChannelMasks(~volFlags, volFlags);
- _sfxData = 0;
-}
-
-const uint8 TownsPC98_OpnDriver::_drvTables[] = {
- // channel presets
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x01,
- 0x01, 0x80, 0x01, 0x01, 0x00, 0x02,
- 0x02, 0x80, 0x02, 0x02, 0x00, 0x04,
- 0x00, 0x80, 0x03, 0x04, 0x01, 0x08,
- 0x01, 0x80, 0x04, 0x05, 0x01, 0x10,
- 0x02, 0x80, 0x05, 0x06, 0x01, 0x20,
-
- // control event size
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05,
- 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02,
-
- // fmt level presets
- 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38,
- 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18,
- 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90,
-
- // carriers
- 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F,
-
- // pc98 level presets
- 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25,
- 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10,
- 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90,
-
- // frequencies
- 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02,
- 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03,
- 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04,
-
- // ssg frequencies
- 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C,
- 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09,
- 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07,
-
- // ssg patch data
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00,
- 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
-
- 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00,
- 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00
-};
-
SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)
- : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0),
- _sfxFileIndex((uint)-1), _sfxWDTable(0), _sfxBTTable(0), _parser(0) {
+ : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0),
+ _sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46) {
- _driver = new Towns_EuphonyDriver(_mixer);
- int ret = open();
- if (ret != MERR_ALREADY_OPEN && ret != 0)
- error("couldn't open midi driver");
+ _driver = new TownsEuphonyDriver(_mixer);
}
SoundTowns::~SoundTowns() {
g_system->getAudioCDManager()->stop();
haltTrack();
+ delete[] _musicTrackData;
delete[] _sfxFileData;
-
- Common::StackLock lock(_mutex);
- _driver->setTimerCallback(0, 0);
- close();
-
- _driver = 0;
}
bool SoundTowns::init() {
_vm->checkCD();
int unused = 0;
+ _musicFadeTable = _vm->staticres()->loadRawData(k1TownsMusicFadeTable, unused);
_sfxWDTable = _vm->staticres()->loadRawData(k1TownsSFXwdTable, unused);
_sfxBTTable = _vm->staticres()->loadRawData(k1TownsSFXbtTable, unused);
+ _musicTrackData = new uint8[50570];
+
+ if (!_driver->init())
+ return false;
+
+ if (!loadInstruments())
+ return false;
+
+ _driver->cdaSetVolume(1, 118, 118);
- return loadInstruments();
+ return true;
}
void SoundTowns::process() {
@@ -3941,10 +91,13 @@ void SoundTowns::playTrack(uint8 track) {
beginFadeOut();
if (_musicEnabled == 2 && trackNum != -1) {
- g_system->getAudioCDManager()->play(trackNum+1, loop ? -1 : 1, 0, 0);
+ _driver->cdaSetVolume(1, 118, 118);
+ g_system->getAudioCDManager()->play(trackNum + 1, loop ? -1 : 1, 0, 0);
g_system->getAudioCDManager()->updateCD();
+ _cdaPlaying = true;
} else if (_musicEnabled) {
playEuphonyTrack(READ_LE_UINT32(&tTable[tTableIndex]), loop);
+ _cdaPlaying = false;
}
_lastTrack = track;
@@ -3954,15 +107,15 @@ void SoundTowns::haltTrack() {
_lastTrack = -1;
g_system->getAudioCDManager()->stop();
g_system->getAudioCDManager()->updateCD();
- if (_parser) {
- Common::StackLock lock(_mutex);
- _parser->setTrack(0);
- _parser->jumpToTick(0);
- _parser->unloadMusic();
- delete _parser;
- _parser = 0;
- }
- _driver->queue()->release();
+ _cdaPlaying = false;
+
+ for (int i = 0; i < 6; i++)
+ _driver->chanVolume(i, 0);
+ for (int i = 0x40; i < 0x46; i++)
+ _driver->chanVolume(i, 0);
+ for (int i = 0; i < 32; i++)
+ _driver->chanEnable(i, 0);
+ _driver->stopParser();
}
void SoundTowns::loadSoundFile(uint file) {
@@ -3976,27 +129,26 @@ void SoundTowns::loadSoundFile(uint file) {
void SoundTowns::playSoundEffect(uint8 track) {
if (!_sfxEnabled || !_sfxFileData)
return;
-
+
if (track == 0 || track == 10) {
- _mixer->stopHandle(_sfxHandle);
+ stopAllSoundEffects();
return;
} else if (track == 1) {
- // sfx fadeout
- _mixer->stopHandle(_sfxHandle);
+ fadeOutSoundEffects();
return;
}
- uint8 note = 0x3c;
+ uint8 note = 60;
if (_sfxFileIndex == 5) {
- if (track == 0x10) {
- note = 0x3e;
- track = 0x0f;
- } else if (track == 0x11) {
- note = 0x40;
- track = 0x0f;
- } else if (track == 0x12) {
- note = 0x41;
- track = 0x0f;
+ if (track == 16) {
+ note = 62;
+ track = 15;
+ } else if (track == 17) {
+ note = 64;
+ track = 15;
+ } else if (track == 18) {
+ note = 65;
+ track = 15;
}
}
@@ -4005,32 +157,37 @@ void SoundTowns::playSoundEffect(uint8 track) {
if (offset == -1)
return;
- uint32 *sfxHeader = (uint32 *)(fileBody + offset);
+ if (!_driver->soundEffectIsPlaying(_sfxChannel ^ 1)) {
+ _sfxChannel ^= 1;
+ } else if (_driver->soundEffectIsPlaying(_sfxChannel)) {
+ _sfxChannel ^= 1;
+ _driver->stopSoundEffect(_sfxChannel);
+ }
+ uint32 *sfxHeader = (uint32 *)(fileBody + offset);
uint32 sfxHeaderID = READ_LE_UINT32(sfxHeader);
- uint32 sfxHeaderInBufferSize = READ_LE_UINT32(&sfxHeader[1]);
- uint32 sfxHeaderOutBufferSize = READ_LE_UINT32(&sfxHeader[3]);
- uint32 sfxRootNoteOffs = READ_LE_UINT32(&sfxHeader[7]);
- uint32 sfxRate = READ_LE_UINT32(&sfxHeader[6]);
+ uint32 playbackBufferSize = sfxHeaderID == 1 ? 30704 : READ_LE_UINT32(&sfxHeader[3]);
- uint32 playbackBufferSize = (sfxHeaderID == 1) ? sfxHeaderInBufferSize : sfxHeaderOutBufferSize;
+ uint8 *sfxPlaybackBuffer = new uint8[playbackBufferSize + 32];
+ memcpy(sfxPlaybackBuffer, fileBody + offset, 32);
- uint8 *sfxPlaybackBuffer = (uint8 *)malloc(playbackBufferSize);
- memset(sfxPlaybackBuffer, 0x80, playbackBufferSize);
+ uint8 *dst = sfxPlaybackBuffer + 32;
+ memset(dst, 0x80, playbackBufferSize);
uint8 *sfxBody = ((uint8 *)sfxHeader) + 0x20;
if (!sfxHeaderID) {
- memcpy(sfxPlaybackBuffer, sfxBody, playbackBufferSize);
+ memcpy(dst, sfxBody, playbackBufferSize);
} else if (sfxHeaderID == 1) {
- Screen::decodeFrame4(sfxBody, sfxPlaybackBuffer, playbackBufferSize);
+ Screen::decodeFrame4(sfxBody, dst, playbackBufferSize);
} else if (_sfxWDTable) {
- uint8 *tgt = sfxPlaybackBuffer;
+ uint8 *tgt = dst;
uint32 sfx_BtTable_Offset = 0;
uint32 sfx_WdTable_Offset = 0;
uint32 sfx_WdTable_Number = 5;
+ uint32 inSize = READ_LE_UINT32(&sfxHeader[1]);
- for (uint32 i = 0; i < sfxHeaderInBufferSize; i++) {
+ for (uint32 i = 0; i < inSize; i++) {
sfx_WdTable_Offset = (sfx_WdTable_Number * 3 << 9) + sfxBody[i] * 6;
sfx_WdTable_Number = READ_LE_UINT16(_sfxWDTable + sfx_WdTable_Offset);
@@ -4042,124 +199,174 @@ void SoundTowns::playSoundEffect(uint8 track) {
}
}
- for (uint32 i = 0; i < playbackBufferSize; i++) {
- if (sfxPlaybackBuffer[i] < 0x80)
- sfxPlaybackBuffer[i] = 0x80 - sfxPlaybackBuffer[i];
- }
+ _driver->chanVolume(_sfxChannel, 127);
+ _driver->chanPanPos(_sfxChannel, 0x40);
+ _driver->chanPitch(_sfxChannel, 0);
+ _driver->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer);
+}
- playbackBufferSize -= 0x20;
+void SoundTowns::updateVolumeSettings() {
+ if (!_driver)
+ return;
- uint32 outputRate = uint32(11025 * calculatePhaseStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000));
+ bool mute = false;
+ _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume"));
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
- _currentSFX = Audio::makeRawStream(sfxPlaybackBuffer, playbackBufferSize,
- outputRate, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX);
+ _driver->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume")));
+ _driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume")));
+}
+
+void SoundTowns::stopAllSoundEffects() {
+ _driver->chanVolume(0x46, 0);
+ _driver->chanVolume(0x47, 0);
+ _driver->stopSoundEffect(0x46);
+ _driver->stopSoundEffect(0x47);
+ _sfxChannel = 0x46;
}
void SoundTowns::beginFadeOut() {
- _lastTrack = -1;
- _driver->fading();
+ if (_cdaPlaying) {
+ for (int i = 118; i > 103; i--) {
+ _driver->cdaSetVolume(1, i, i);
+ _vm->delay(2 * _vm->tickLength());
+ }
- // TODO: this should fade out too
- g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->updateCD();
-}
+ for (int i = 103; i > 83; i -= 2) {
+ _driver->cdaSetVolume(1, i, i);
+ _vm->delay(2 * _vm->tickLength());
+ }
-int SoundTowns::open() {
- if (!_driver)
- return 255;
+ for (int i = 83; i > 58; i -= 2) {
+ _driver->cdaSetVolume(1, i, i);
+ _vm->delay(_vm->tickLength());
+ }
- int ret = _driver->open();
- if (ret)
- return ret;
+ for (int i = 58; i > 0; i--)
+ _driver->cdaSetVolume(1, i, i);
- _driver->setTimerCallback(this, &onTimer);
- return 0;
-}
+ _driver->cdaSetVolume(1, 0, 0);
-void SoundTowns::close() {
- if (_driver)
- _driver->close();
-}
+ } else {
+ if (_lastTrack == -1)
+ return;
-void SoundTowns::send(uint32 b) {
- _driver->send(b);
-}
+ uint32 ticks = 2;
+ int tickAdv = 0;
+
+ uint16 fadeVolCur[12];
+ uint16 fadeVolStep[12];
+
+ for (int i = 0; i < 6; i++) {
+ fadeVolCur[i] = READ_LE_UINT16(&_musicFadeTable[(_lastTrack * 12 + i) * 2]);
+ fadeVolStep[i] = fadeVolCur[i] / 50;
+ fadeVolCur[i + 6] = READ_LE_UINT16(&_musicFadeTable[(_lastTrack * 12 + 6 + i) * 2]);
+ fadeVolStep[i + 6] = fadeVolCur[i + 6] / 30;
+ }
+
+ for (int i = 0; i < 12; i++) {
+ for (int ii = 0; ii < 6; ii++)
+ _driver->chanVolume(ii, fadeVolCur[ii]);
+ for (int ii = 0x40; ii < 0x46; ii++)
+ _driver->chanVolume(ii, fadeVolCur[ii - 0x3a]);
+
+ for (int ii = 0; ii < 6; ii++) {
+ fadeVolCur[ii] -= fadeVolStep[ii];
+ if (fadeVolCur[ii] < 10)
+ fadeVolCur[ii] = 0;
+ fadeVolCur[ii + 6] -= fadeVolStep[ii + 6];
+ if (fadeVolCur[ii + 6] < 10)
+ fadeVolCur[ii + 6] = 0;
+ }
+
+ if (++tickAdv == 3) {
+ tickAdv = 0;
+ ticks += 2;
+ }
+ _vm->delay(ticks * _vm->tickLength());
+ }
+ }
-uint32 SoundTowns::getBaseTempo() {
- return _driver ? _driver->getBaseTempo() : 0;
+ haltTrack();
}
bool SoundTowns::loadInstruments() {
uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
if (!twm)
return false;
- _driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0);
- _driver->loadFmInstruments(_driver->queue()->trackData() + 8);
- _driver->queue()->loadDataToCurrentPosition(twm + 0x0CA0, 0xC58A);
- _driver->loadWaveInstruments(_driver->queue()->trackData() + 8);
+ Common::StackLock lock(_mutex);
+
+ Screen::decodeFrame4(twm, _musicTrackData, 50570);
+ for (int i = 0; i < 128; i++)
+ _driver->loadInstrument(0, i, &_musicTrackData[i * 48 + 8]);
+
+ Screen::decodeFrame4(twm + 3232, _musicTrackData, 50570);
+ for (int i = 0; i < 32; i++)
+ _driver->loadInstrument(0x40, i, &_musicTrackData[i * 128 + 8]);
+
+ _driver->unloadWaveTable(-1);
+ uint8 *src = &_musicTrackData[32 * 128 + 8];
+ for (int i = 0; i < 10; i++) {
+ _driver->loadWaveTable(src);
+ src = src + READ_LE_UINT16(&src[12]) + 32;
+ }
+
+ _driver->reserveSoundEffectChannels(2);
+
delete[] twm;
- _driver->queue()->release();
return true;
}
void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
- uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
Common::StackLock lock(_mutex);
- if (!_parser) {
- _parser = new Towns_EuphonyParser(_driver->queue());
- _parser->setMidiDriver(this);
- _parser->setTimerRate(getBaseTempo());
- }
+ uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
+ Screen::decodeFrame4(twm + 19312 + offset, _musicTrackData, 50570);
+ delete[] twm;
- _parser->property(MidiParser::mpAutoLoop, loop);
- _parser->loadMusic(twm + 0x4b70 + offset, 0xC58A);
+ const uint8 *src = _musicTrackData + 852;
+ for (int i = 0; i < 32; i++)
+ _driver->chanEnable(i, *src++);
+ for (int i = 0; i < 32; i++)
+ _driver->chanMode(i, *src++);
+ for (int i = 0; i < 32; i++)
+ _driver->chanOrdr(i, *src++);
+ for (int i = 0; i < 32; i++)
+ _driver->chanLevel(i, *src++);
+ for (int i = 0; i < 32; i++)
+ _driver->chanTranspose(i, *src++);
+
+ src = _musicTrackData + 1748;
+ for (int i = 0; i < 6; i++)
+ _driver->assignChannel(i, *src++);
+ for (int i = 0x40; i < 0x46; i++)
+ _driver->assignChannel(i, *src++);
- delete[] twm;
-}
+ uint32 trackSize = READ_LE_UINT32(_musicTrackData + 2048);
+ uint8 startTick = _musicTrackData[2052];
+
+ _driver->setMusicTempo(_musicTrackData[2053]);
+
+ src = _musicTrackData + 2054;
+ uint32 l = READ_LE_UINT32(src + trackSize);
+ trackSize += (l + 4);
+ l = READ_LE_UINT32(src + trackSize);
+ trackSize += (l + 4);
-void SoundTowns::onTimer(void *data) {
- SoundTowns *music = (SoundTowns *)data;
- Common::StackLock lock(music->_mutex);
- if (music->_parser)
- music->_parser->onTimer();
+ _driver->setMusicLoop(loop);
+ _driver->startMusicTrack(src, trackSize, startTick);
}
-float SoundTowns::calculatePhaseStep(int8 semiTone, int8 semiToneRootkey,
- uint32 sampleRate, uint32 outputRate, int32 pitchWheel) {
- if (semiTone < 0)
- semiTone = 0;
- if (semiTone > 119)
- semiTone = 119;
- if (semiTone < 0)
- semiTone = 0;
- if (semiTone > 119)
- semiTone = 119;
-
- static const float noteFrq[] = {
- 0004.13f, 0004.40f, 0004.64f, 0004.95f, 0005.16f, 0005.50f, 0005.80f, 0006.19f, 0006.60f, 0006.86f,
- 0007.43f, 0007.73f, 0008.25f, 0008.80f, 0009.28f, 0009.90f, 0010.31f, 0011.00f, 0011.60f, 0012.38f,
- 0013.20f, 0013.75f, 0014.85f, 0015.47f, 0016.50f, 0017.60f, 0018.56f, 0019.80f, 0020.63f, 0022.00f,
- 0023.21f, 0024.75f, 0026.40f, 0027.50f, 0029.70f, 0030.94f, 0033.00f, 0035.20f, 0037.16f, 0039.60f,
- 0041.25f, 0044.00f, 0046.41f, 0049.50f, 0052.80f, 0055.00f, 0059.40f, 0061.88f, 0066.00f, 0070.40f,
- 0074.25f, 0079.20f, 0082.50f, 0088.00f, 0092.83f, 0099.00f, 0105.60f, 0110.00f, 0118.80f, 0123.75f,
- 0132.00f, 0140.80f, 0148.50f, 0158.40f, 0165.00f, 0176.00f, 0185.65f, 0198.00f, 0211.20f, 0220.00f,
- 0237.60f, 0247.50f, 0264.00f, 0281.60f, 0297.00f, 0316.80f, 0330.00f, 0352.00f, 0371.30f, 0396.00f,
- 0422.40f, 0440.00f, 0475.20f, 0495.00f, 0528.00f, 0563.20f, 0594.00f, 0633.60f, 0660.00f, 0704.00f,
- 0742.60f, 0792.00f, 0844.80f, 0880.00f, 0950.40f, 0990.00f, 1056.00f, 1126.40f, 1188.00f, 1267.20f,
- 1320.00f, 1408.00f, 1485.20f, 1584.00f, 1689.60f, 1760.00f, 1900.80f, 1980.00f, 2112.00f, 2252.80f,
- 2376.00f, 2534.40f, 2640.00f, 2816.00f, 2970.40f, 3168.00f, 3379.20f, 3520.00f, 3801.60f, 3960.00f
- };
-
- float pwModifier = (pitchWheel - 0x2000) / 0x2000;
- int8 d = pwModifier ? (pwModifier < 0 ? -1 : 1) : 0;
- float rateshift = (noteFrq[semiTone] - ((noteFrq[semiTone] -
- noteFrq[semiTone + d]) * pwModifier * d)) / noteFrq[semiToneRootkey];
-
- return (float)sampleRate * 10.0f * rateshift / outputRate;
+void SoundTowns::fadeOutSoundEffects() {
+ for (int i = 127; i > 0; i-= 12) {
+ _driver->chanVolume(0x46, i);
+ _driver->chanVolume(0x47, i);
+ _vm->delay(_vm->tickLength());
+ }
+ stopAllSoundEffects();
}
SoundPC98::SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
@@ -4173,7 +380,7 @@ SoundPC98::~SoundPC98() {
}
bool SoundPC98::init() {
- _driver = new TownsPC98_OpnDriver(_mixer, TownsPC98_OpnDriver::OD_TYPE26);
+ _driver = new TownsPC98_AudioDriver(_mixer, TownsPC98_AudioDriver::kType26);
bool reslt = _driver->init();
updateVolumeSettings();
return reslt;
@@ -4254,6 +461,7 @@ void SoundPC98::updateVolumeSettings() {
return;
bool mute = false;
+ _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume"));
if (ConfMan.hasKey("mute"))
mute = ConfMan.getBool("mute");
@@ -4274,8 +482,8 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() {
}
bool SoundTownsPC98_v2::init() {
- _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ?
- TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS);
+ _driver = new TownsPC98_AudioDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ?
+ TownsPC98_AudioDriver::kType86 : TownsPC98_AudioDriver::kTypeTowns);
if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
_vm->checkCD();
@@ -4375,7 +583,7 @@ void SoundTownsPC98_v2::beginFadeOut() {
}
int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle, uint8, bool) {
- static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
+ //static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
static const char patternHOF[] = "%s.PCM";
static const char patternLOL[] = "%s.VOC";
@@ -4396,7 +604,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle,
if (!src)
return 0;
- uint16 sfxRate = rates[READ_LE_UINT16(src)];
+ //uint16 sfxRate = rates[READ_LE_UINT16(src)];
src += 2;
bool compressed = (READ_LE_UINT16(src) & 1) ? true : false;
src += 2;
@@ -4436,9 +644,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle,
sfx[i] = cmd;
}
- uint32 outputRate = uint32(11025 * SoundTowns::calculatePhaseStep(0x3c, 0x3c, sfxRate, 11025, 0x2000));
-
- _currentSFX = Audio::makeRawStream(sfx, outsize, outputRate,
+ _currentSFX = Audio::makeRawStream(sfx, outsize, 11025,
Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h], _currentSFX);
if (handle)
@@ -4460,6 +666,7 @@ void SoundTownsPC98_v2::updateVolumeSettings() {
return;
bool mute = false;
+ _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume"));
if (ConfMan.hasKey("mute"))
mute = ConfMan.getBool("mute");
@@ -4467,158 +674,6 @@ void SoundTownsPC98_v2::updateVolumeSettings() {
_driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume")));
}
-// static resources
-
-const uint32 TownsPC98_OpnCore::_adtStat[] = {
- 0x00010001, 0x00010001, 0x00010001, 0x01010001,
- 0x00010101, 0x00010101, 0x00010101, 0x01010101,
- 0x01010101, 0x01010101, 0x01010102, 0x01010102,
- 0x01020102, 0x01020102, 0x01020202, 0x01020202,
- 0x02020202, 0x02020202, 0x02020204, 0x02020204,
- 0x02040204, 0x02040204, 0x02040404, 0x02040404,
- 0x04040404, 0x04040404, 0x04040408, 0x04040408,
- 0x04080408, 0x04080408, 0x04080808, 0x04080808,
- 0x08080808, 0x08080808, 0x10101010, 0x10101010
-};
-
-const uint8 TownsPC98_OpnCore::_detSrc[] = {
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
- 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07,
- 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
- 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07,
- 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05,
- 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14,
- 0x16, 0x16, 0x16, 0x16
-};
-
-const int TownsPC98_OpnCore::_ssgTables[] = {
- 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C,
- 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB,
- 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB,
- 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C,
- 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9,
- 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB
-};
-
-const uint8 TownsPC98_OpnCore::_percussionData[] = {
- 0,24,1,192,1,216,2,128,4,88,23,64,27,152,1,128,29,24,2,128,31,152,0,128,136,128,128,128,0,136,97,103,153,139,34,163,72,195,27,69,1,154,137,35,8,51,169,122,164,75,133,203,81,146,168,121,185,68,202,8,33,237,49,177,12,133,140,17,160,42,161,10,0,137,176, 57,
- 233,41,160,136,235,65,177,137,128,26,164,28,3,157,51,137,1,152,113,161,40,146,115,192,56,5,169,66,161,56,1,50,145,59,39,168,97,1,160,57,7,153,50,153,32,2,25,129,32,20,186,66,129,24,153,164,142,130,169,153,26,242,138,217,9,128,204,58,209,172,40, 176, 141,
- 128,155,144,203,139,0,235,9,177,172,0,185,168,138,25,240,59,211,139,19,176,90,160,17,26,132,41,1,5,25,3,50,144,115,147,42,39,152,41,3,56,193,105,130,155,66,200,26,19,218,154,49,201,171,138,176,251,139,185,172,136,189,139,145,207,41,160,171,152, 186, 139,
- 186,141,128,218,171,51,217,170,56,163,12,4,155,81,147,42,37,152,32,54,136,49,50,48,37,32,69,0,17,50,50,83,2,16,68,20,8,66,4,154,84,145,24,33,24,32,17,18,145,32,22,168,49,163,1,33,50,184,115,129,25,66,1,24,67,2,80,35,40,53,2,65,51,19,67,37,0,52,35,49, 37,
- 34,49,37,17,52,17,35,35,35,34,32,49,33,152,34,145,24,24,128,138,128,184,9,177,171,168,185,155,152,172,155,186,172,185,172,155,186,173,153,202,187,185,202,170,171,202,186,169,170,170,171,139,154,171,153,154,169,10,168,154,128,168,154,0,153, 152, 136, 137,
- 128,153,0,152,8,128,137,0,136,136,8,9,8,9,8,24,153,128,136,153,144,0,161,138,1,169,136,128,160,168,152,153,138,137,154,153,153,154,153,170,168,170,185,168,169,154,169,171,153,169,170,153,152,154,153,137,169,137,136,144,152,144,128,128,144,129,129, 0, 33,
- 0,17,17,17,33,33,18,18,34,34,34,34,34,34,35,19,35,19,35,35,18,19,18,35,18,33,0,8,8,8,8,8,8,8,160,205,65,176,171,203,16,240,95,242,120,145,156,66,177,26,19,153,9,35,35,239,56,132,138,154,50,145,203,25,32,20,237,24,130,138,160,27,39,173,50,203,64,145, 139,
- 18,168,48,146,171,65,18,176,12,52,128,25,5,57,240,104,161,25,129,18,188,114,160,26,36,200,154,18,1,128,186,73,162,173,32,184,25,144,137,234,8,154,32,160,158,18,187,81,2,235,41,36,144,154,17,67,128,33,160,114,146,26,37,33,232,41,130,41,178,29,50, 251, 24,
- 1,153,138,160,76,179,155,11,0,38,252,41,146,41,178,27,193,43,39,170,136,17,129,8,49,233,48,129,11,6,26,130,136,128,64,1,248,105,145,9,16,144,140,5,25,168,16,186,48,5,171,217,57,134,171,8,34,188,20,203,41,6,155,161,89,164,140,2,136,51,202,41,131, 56, 144,
- 8,97,144,146,13,69,200,42,130,25,152,57,6,220,88,177,26,148,9,168,8,67,192,156,65,145,137,10,4,154,18,157,67,160,154,1,50,188,82,170,82,185,49,220,97,144,10,8,16,145,9,136,18,202,51,184,141,114,179,139,24,19,8,250,121,160,40,160,10,18,152,168,42,35, 216,
- 187,120,145,18,156,203,84,144,9,144,26,66,161,13,1,128,17,154,18,142,6,154,65,192,29,35,186,64,192,24,9,146,56,185,16,248,121,176,40,129,136,171,96,147,140,50,203,64,144,41,128,161,187,71,200,24,129,24,217,56,20,220,24,4,169,9,1,33,201,26,134,141,51,201,
- 25,16,33,235,32,144,33,153,169,99,160,11,3,136,58,210,33,203,48,163,17,219,128,140,38,8,184,141,50,131,159,33,128,153,25,18,153,88,242,43,3,9,136,157,53,202,40,145,25,2,204,105,146,156,66,152,8,153,33,128,129,136,153,50,186,55,188,51,249,64,178, 27, 128,
- 48,177,156,18,35,175,51,189,32,51,234,155,69,184,26,2,152,9,17,136,144,137,50,235,115,216,24,2,170,67,187,49,129,155,4,27,129,56,232,43,39,203,40,3,154,169,66,184,114,224,25,2,9,128,11,35,155,18,11,202,84,169,26,5,154,8,160,98,185,17,187,50, 23, 188, 33,
- 1,139,4,154,90,147,12,3,43,2,170,171,103,193,28,132,137,8,129,24,170,50,201,42,35,202,169,52,201,33,218,40,39,203,0,40,147,29,163,139,83,185,1,4,159,34,160,12,21,155,40,129,137,58,151,13,2,136,144,16,153,40,17,131,207,51,144,140,4,154,17,146,170,73, 163,
- 44,164,12,152,37,203,17,128,144,139,23,154,128,138,38,216,41,1,0,233,73,131,171,49,136,9,164,46,3,171,32,0,145,157,38,187,64,176,58,134,155,18,136,217,64,1,200,140,38,153,170,66,161,8,169,65,185,98,200,41,3,155,144,58,23,187,1,145,40,147,189,32, 68, 249,
- 1,112,255,199,195,19,108,76,187,247,247,183,40,168,212,245,199,227,68,45,59,10,145,177,198,24,130,76,26,193,180,129,0,162,42,160,199,162,0,16,152,137,132,168,195,130,162,181,227,163,161,179,211,180,179,164,128,162,161,194,164,179,40,153,195,213,146, 178,
- 147,176,50,186,161,196,151,58,16,28,162,160,131,122,155,33,241,146,128,40,26,128,154,36,170,89,59,9,24,144,77,161,8,177,112,139,33,232,148,24,41,61,9,26,162,32,30,58,153,32,59,73,59,11,79,137,57,9,49,30,24,153,131,25,106,61,153,73,28,56,27, 41, 137, 148,
- 76,43,74,58,13,161,3,171,149,32,77,10,74,42,168,16,0,123,138,129,162,178,225,50,140,161,0,147,10,129,41,244,210,165,1,152,24,162,184,166,32,144,59,216,132,177,8,145,67,143,146,160,183,162,130,24,192,32,225,146,144,33,44,73,30,129,137,32,76, 152, 25, 161,
- 2,154,32,177,132,232,2,136,210,128,149,177,32,58,27,168,225,133,8,44,107,136,25,136,17,26,58,46,16,11,145,17,144,79,136,144,136,145,152,33,31,162,130,200,82,153,74,137,147,26,0,13,133,170,149,16,192,0,178,0,128,152,182,150,9,16,9,137,33,59,63,10,152, 32,
- 179,192,5,154,228,182,145,130,144,42,128,242,2,136,41,168,17,76,57,31,129,136,17,47,8,41,138,32,138,123,59,58,10,136,161,4,46,25,145,136,129,25,56,28,91,41,154,108,9,16,44,24,137,48,15,0,194,162,41,194,56,241,163,146,0,139,7,186,150,129,152,1,208,33,176,
- 136,164,163,185,7,138,130,242,162,163,177,88,136,184,166,146,0,25,25,177,199,146,16,136,9,145,178,178,0,147,138,229,18,152,25,144,163,246,162,129,129,184,5,152,178,145,148,136,146,95,152,128,144,33,170,81,11,40,202,131,0,243,24,1,11,148,42, 24, 163, 140,
- 120,9,76,58,153,145,56,30,72,46,42,9,8,57,91,76,59,26,160,129,41,76,10,57,192,163,129,16,225,2,27,40,200,48,91,226,40,145,43,177,177,182,196,145,33,184,165,17,192,163,194,129,211,128,162,197,129,0,136,211,146,8,162,144,0,167,160,1,176,150,137,1, 24, 243,
- 0,129,145,25,123,169,130,168,132,41,63,42,136,137,120,26,136,8,24,89,29,58,177,193,147,1,26,162,176,167,180,8,49,28,29,178,162,88,43,42,57,43,61,8,29,129,128,128,123,137,24,243,16,136,16,46,0,169,149,128,1,60,153,72,154,90,25,25,25,8,91,73,12,16,137,144,
- 72,11,8,167,128,129,9,138,166,193,147,162,123,137,145,1,162,26,1,219,147,129,210,147,243,1,243,16,144,145,160,131,200,4,59,75,57,218,2,178,77,24,60,11,147,10,50,141,64,27,185,122,161,41,128,90,136,24,46,16,139,16,24,28,124,9,41,8,26,121,10,42,40,139,129,
- 0,201,135,137,56,176,176,35,215,145,1,26,145,144,160,135,138,1,177,146,146,161,65,242,136,164,177,1,1,186,151,208,148,129,10,32,241,145,163,178,17,168,136,151,168,2,148,185,133,176,130,129,154,163,215,0,146,136,40,211,161,131,171,81,144,170, 21, 184, 56,
- 195,168,133,177,91,16,187,5,145,153,66,172,18,177,42,120,138,27,134,26,106,42,138,146,184,66,75,46,41,168,0,145,57,91,75,27,24,27,48,169,40,122,9,109,10,8,177,146,16,74,30,129,160,162,146,41,124,138,24,145,152,3,1,14,3,139,1,192,161,151,177,122,8, 10, 0,
- 176,130,129,27,88,225,0,2,154,129,129,193,49,203,81,153,226,33,0,30,0,176,179,18,9,96,156,162,148,160,129,2,29,195,128,0,56,156,20,232,129,128,32,10,144,74,183,9,145,162,1,162,138,23,171,1,164,224,34,43,43,177,200,135,161,91,57,154,177,148, 145, 146, 58,
- 108,136,170,35,208,177,34,128,44,129,155,151,243,16,1,154,72,193,144,18,11,122,160,153,5,192,24,130,184,132,226,0,128,153,131,181,136,65,154,128,17,170,39,28,59,144,168,80,25,47,24,26,144,32,47,41,153,161,148,8,92,9,9,129,144,33,26,47,24,137,108, 25, 10,
- 17,10,73,75,47,24,184,48,8,45,57,138,136,150,10,48,139,136,35,203,121,8,27,179,161,106,0,29,16,176,179,3,185,19,227,41,145,168,61,197,177,20,10,57,42,250,147,196,16,41,138,24,195,208,135,137,0,145,160,2,210,146,195,177,132,136,153,167,210,146,162, 40, 8,
- 138,148,227,145,17,137,40,169,179,130,242,2,196,9,146,145,169,167,146,130,137,136,51,220,17,163,28,74,10,76,40,140,5,137,43,18,12,107,137,40,8,201,50,0,143,3,138,161,134,138,104,169,16,162,160,121,25,28,129,152,32,56,14,16,184,146,3,46,25, 176, 129, 179,
- 193,17,130,202,135,8,57,25,154,148,184,120,9,153,211,165,24,128,26,17,242,161,18,185,81,42,11,17,12,25,181,137,66,42,47,41,184,166,129,24,91,27,136,196,0,0,74,28,178,161,149,160,32,8,225,32,128,59,8,169,50,139,47,72,186,16,132,9,122,9,160,146,144,89,153,
- 10,149,178,0,121,11,146,152,162,48,13,123,177,24,0,106,27,9,144,132,12,17,0,168,0,181,56,169,129,242,195,129,17,154,64,161,244,16,137,24,144,144,164,129,75,42,176,149,9,179,148,203,4,166,136,163,128,227,163,8,57,11,30,165,0,74,59,62,9,208,131,144,40, 76,
- 26,27,196,129,1,25,43,49,174,67,153,136,106,152,41,25,28,2,43,44,104,45,59,8,43,128,144,120,25,12,17,152,9,130,155,151,145,74,40,13,48,192,58,90,43,43,177,146,49,31,75,24,217,131,0,76,26,152,149,161,24,74,154,193,166,145,32,27,161,164,176,135,152,24,193,
- 162,146,164,58,227,193,148,161,128,18,234,130,180,145,2,200,1,163,186,98,184,129,149,153,49,42,186,151,242,129,1,43,8,177,212,165,8,40,137,24,8,144,90,9,25,48,44,46,24,138,40,144,108,58,27,128,181,128,80,29,42,152,162,130,25,106,136,11,148,8,144,128,136,
- 112,139,80,153,24,136,129,46,0,60,129,208,1,3,13,57,168,144,1,242,17,9,26,2,185,27,55,140,73,137,179,16,192,3,145,143,33,9,171,135,160,17,137,10,151,168,3,178,44,17,208,144,167,0,40,155,16,167,152,18,144,26,160,199,1,136,91,136,160,178,150,161,1,10, 181,
- 145,161,1,145,161,198,2,9,90,137,177,160,150,40,29,129,144,145,162,57,77,169,16,148,42,42,40,141,34,170,121,154,210,131,162,107,8,9,160,195,40,73,139,18,224,162,34,139,0,244,178,163,24,26,146,194,166,49,29,42,137,130,192,16,93,128,154,19,59, 11, 122, 11,
- 146,177,120,42,26,43,164,152,17,60,63,137,128,48,10,58,92,9,59,91,75,139,32,25,25,61,74,28,177,40,130,74,29,73,168,130,128,48,14,8,77,9,25,26,179,211,32,78,26,41,152,161,180,89,59,9,153,166,160,3,26,57,106,154,88,184,40,1,27,58,73,143,131,169,3,161, 184,
- 122,152,16,181,145,129,17,15,129,193,147,145,192,33,193,162,183,163,136,178,129,178,197,2,41,216,131,168,163,181,226,163,178,1,33,187,166,212,129,1,27,24,162,184,151,8,16,160,144,181,210,72,168,128,32,42,25,40,142,5,185,88,58,11,58,177,32,129,63,42, 136,
- 186,53,29,75,58,144,144,129,77,128,11,144,133,29,40,152,24,161,129,80,155,60,3,12,89,8,60,152,152,49,136,47,57,224,129,16,41,90,139,162,147,170,51,169,27,17,95,26,26,160,5,139,48,76,10,228,146,1,136,44,161,147,209,130,137,73,224,1,162,195,32,210,177,180,
- 179,148,145,154,132,242,146,1,152,32,192,1,144,155,7,177,168,5,138,178,148,152,150,136,89,152,9,41,196,145,40,28,16,8,10,178,167,24,1,44,123,137,136,145,194,48,27,74,26,192,179,135,136,88,27,10,177,163,164,128,73,24,31,8,0,192,149,144,129,9,106, 41, 200,
- 161,151,41,138,0,24,226,162,49,42,11,90,136,136,152,17,145,10,63,40,11,56,245,162,16,26,73,11,144,135,137,58,106,10,25,8,57,137,28,33,129,156,113,10,10,161,18,8,153,77,3,217,0,1,242,128,193,18,128,75,60,178,154,37,45,58,29,144,1,184,66,41,29, 8, 145, 10,
- 194,33,148,170,107,89,139,128,163,178,16,63,59,176,144,151,129,42,74,10,129,192,2,128,154,97,192,0,177,128,178,183,16,16,155,149,145,184,84,138,8,192,161,20,225,0,130,138,165,0,28,148,153,18,209,128,88,153,89,152,9,17,9,29,130,43,122,153,24, 32, 202, 49,
- 24,43,106,154,130,193,27,51,29,28,133,138,65,11,123,25,10,40,152,44,130,26,43,148,45,73,140,33,8,153,88,128,61,144,42,59,225,128,18,155,50,75,186,20,202,120,144,42,92,176,162,165,25,2,169,152,135,185,19,152,8,146,160,123,195,137,132,209,0,16, 11, 2, 242,
- 146,164,152,73,193,136,130,178,1,136,169,23,169,128,164,242,129,178,129,32,138,180,167,153,132,8,138,2,209,4,138,1,128,138,92,136,44,129,136,162,33,63,40,141,2,160,144,106,137,64,155,17,129,60,30,146,26,17,28,48,46,169,51,154,91,137,41,26,32,143,18, 138,
- 1,32,28,123,177,9,181,195,56,57,14,145,161,17,17,31,41,152,145,194,194,20,153,41,9,243,129,180,0,128,45,16,43,170,135,144,16,25,42,137,242,163,194,16,0,57,14,130,194,178,16,33,30,8,59,211,163,160,5,137,44,10,17,170,3,120,9,44,146,136,131,140, 91, 9, 171,
- 7,161,32,73,13,8,161,40,106,11,25,129,59,0,49,31,42,28,40,11,0,81,176,61,32,138,25,178,241,148,136,106,8,136,128,177,90,8,155,96,176,9,18,217,132,129,10,81,156,40,178,161,36,169,76,147,203,150,0,10,146,200,147,149,128,144,148,154,182,24,0,137,11,134,211,
- 24,136,129,145,209,33,8,43,163,243,88,41,13,0,160,145,33,31,32,185,145,4,155,17,32,47,161,128,73,160,44,56,176,75,74,12,35,141,104,137,9,89,152,58,56,44,41,30,41,40,157,48,128,154,88,41,42,8,14,3,184,59,120,152,9,56,10,128,41,57,227,186,52,152,62, 8, 56,
- 242,0,58,8,156,34,243,128,24,176,51,169,58,183,192,146,164,177,18,170,7,177,208,132,161,24,136,27,147,243,128,133,10,24,161,161,178,214,17,160,25,16,161,137,165,192,48,27,72,58,218,133,162,26,72,27,10,197,178,49,138,89,56,142,1,24,11,0,44,105, 10, 25, 0,
- 194,9,3,47,8,138,147,18,28,48,202,147,199,146,25,161,0,145,194,163,57,11,146,248,130,32,57,63,154,16,48,14,128,144,209,133,26,56,154,182,162,195,18,152,44,194,180,168,5,24,137,138,35,192,232,66,176,161,24,41,26,244,129,163,160,75,129,226,147,40, 145, 61,
- 13,130,177,17,137,112,170,130,0,136,75,152,177,241,34,0,59,156,51,186,178,91,132,137,137,122,1,45,28,50,172,57,108,8,26,136,32,152,46,144,131,171,4,152,18,141,148,1,216,32,9,60,169,66,152,128,72,90,201,1,17,201,136,3,195,26,73,133,200,176, 150, 146, 169,
- 24,33,178,184,151,73,11,28,72,44,153,82,153,17,42,57,78,153,8,160,0,1,123,11,19,171,195,18,59,31,129,10,162,2,58,96,142,130,26,75,128,176,17,180,123,9,90,137,211,145,32,26,76,43,145,130,12,90,41,27,58,160,160,128,178,7,76,59,0,203,180,147,33,62,10,0,243,
- 129,146,73,29,145,144,0,26,56,153,185,83,8,76,27,166,161,193,146,131,224,145,165,161,40,168,149,162,226,2,136,138,163,131,211,0,59,146,218,148,1,192,16,16,58,248,88,144,177,136,1,58,45,9,195,197,147,48,29,10,0,162,176,64,122,9,10,17,9,153,56, 75, 27, 31,
- 72,136,9,129,129,61,45,59,10,161,18,122,43,59,41,169,34,155,130,131,219,120,162,27,49,208,160,131,156,66,12,145,50,240,16,136,12,162,40,129,130,15,129,162,146,180,83,139,58,217,129,177,4,0,169,197,163,144,242,131,168,179,179,17,197,145,178,164, 128, 160,
- 211,2,244,163,145,162,129,212,177,163,17,208,163,195,180,57,24,170,182,164,129,0,60,60,169,149,162,177,122,26,24,136,136,133,43,27,178,56,77,24,128,240,0,2,44,46,8,128,193,146,64,27,42,16,193,25,0,192,148,11,52,47,153,147,243,0,24,73,28,144, 161, 150, 9,
- 8,73,170,2,162,25,27,147,167,131,29,1,168,200,165,16,91,137,8,162,176,35,41,31,24,169,50,168,58,123,144,48,128,13,73,169,144,16,57,123,44,200,163,56,153,80,10,176,146,57,94,8,152,131,9,168,125,26,145,177,132,137,41,60,26,144,243,32,192,34,60, 43, 26, 16,
- 249,164,16,58,61,11,130,243,146,2,42,44,27,128,165,137,49,45,28,16,43,8,211,48,28,152,105,9,9,163,161,169,35,107,42,232,164,130,168,72,42,168,210,148,144,136,129,3,217,194,50,27,192,41,210,147,40,76,226,1,161,1,155,132,145,147,171,67,173,210,132,161,106,
- 137,56,169,209,131,64,13,129,9,194,17,57,61,169,17,128,40,31,16,10,162,57,61,75,139,40,242,17,58,59,138,179,144,50,105,140,179,243,57,40,26,9,243,130,24,29,57,128,210,129,25,59,91,137,162,178,72,27,181,168,19,129,8,184,231,147,178,32,28,184,198,148, 144,
- 1,26,128,16,192,2,26,144,244,129,0,16,10,197,177,181,1,41,9,178,165,211,129,25,145,137,210,147,152,210,163,132,194,17,91,169,145,181,130,9,89,137,152,178,4,128,9,63,160,128,106,8,25,43,10,32,47,26,123,152,24,40,25,27,18,186,35,158,64,42,216,33,25,58, 58,
- 45,184,147,29,72,46,9,0,178,146,58,77,26,25,209,165,128,145,17,153,128,129,148,240,129,1,40,31,0,152,242,163,16,59,44,24,243,146,128,1,26,26,179,213,145,130,176,131,40,25,145,219,179,167,8,33,59,14,176,166,16,136,74,128,176,128,149,8,8,209,148,152,0, 72,
- 153,161,178,35,62,75,154,163,153,19,62,170,133,179,136,89,12,129,164,144,3,47,58,193,177,148,0,61,43,10,129,17,41,61,43,25,8,126,26,25,137,145,34,44,45,129,216,179,1,90,25,137,32,227,8,16,9,170,49,31,32,29,128,145,148,75,25,75,153,162,192,35,12, 80, 136,
- 176,8,194,24,1,176,21,154,145,80,251,130,2,30,9,8,130,145,128,98,27,26,129,136,162,15,33,168,59,65,177,77,141,1,128,168,113,10,137,178,163,146,132,74,153,224,164,33,184,19,184,228,161,17,91,152,25,146,152,44,121,9,160,145,17,25,28,93,128,152,2,25,27,161,
- 210,129,146,45,179,227,163,162,9,40,193,148,179,57,107,140,196,32,25,57,47,136,210,130,24,40,28,152,210,182,145,40,8,129,184,147,147,140,163,166,160,34,45,144,194,161,134,41,46,152,162,162,3,44,58,75,209,162,144,57,129,47,152,130,59,16,248,129,17,26, 57,
- 9,29,167,2,60,42,138,136,209,130,90,42,42,176,146,178,120,28,8,160,145,16,33,31,1,8,160,129,128,242,164,32,152,177,146,213,196,128,40,26,160,163,180,146,108,60,144,144,136,147,137,40,90,161,3,17,219,243,33,184,130,60,136,243,178,179,132,26,8,168,212,147,
- 16,57,42,31,145,145,160,32,43,184,66,45,180,33,140,226,1,91,152,16,144,193,162,48,77,25,137,153,17,178,78,0,0,16,14,90,152,153,19,129,13,123,137,129,160,1,73,44,9,129,0,153,120,10,9,162,195,32,139,28,151,161,2,128,26,45,193,146,48,29,146,153, 194, 5, 59,
- 29,128,144,195,1,64,43,208,178,149,8,9,16,240,163,129,16,42,185,181,211,24,48,45,137,149,9,24,41,75,184,177,4,43,91,128,180,16,144,29,25,184,167,1,59,60,153,148,161,146,91,42,186,4,24,145,123,11,2,178,77,136,26,25,195,40,115,61,27,168,177,3,59,79,26, 25,
- 144,1,48,13,56,154,248,1,16,9,129,8,2,178,31,130,153,162,20,15,33,170,56,40,29,28,128,152,149,144,56,120,11,162,212,129,144,145,59,180,243,147,145,144,16,152,48,241,0,161,176,1,134,10,129,200,166,144,128,121,26,24,177,178,196,48,75,138,41,180,195,26, 24,
- 89,138,24,33,187,41,84,155,57,79,136,160,210,130,0,58,58,168,243,132,27,41,75,138,3,8,61,8,29,145,179,76,24,28,146,208,2,49,140,75,196,144,0,40,44,179,208,3,176,33,15,177,2,160,106,8,160,164,164,8,73,27,226,179,161,1,57,1,196,211,128,40,156,145,166, 178,
- 131,29,128,145,162,165,40,27,216,146,135,144,40,160,194,177,145,20,139,200,151,178,17,136,40,25,205,130,17,11,17,129,156,38,26,25,137,179,163,11,79,16,12,146,147,143,89,25,136,136,25,48,26,46,129,40,29,42,29,8,145,2,56,27,62,8,25,212,161,48,43, 144, 129,
- 29,145,144,41,106,10,107,43,184,131,1,36,61,13,138,2,194,1,16,27,75,186,181,151,8,1,161,138,211,129,2,59,248,129,16,0,144,63,152,150,136,24,25,128,30,161,128,17,24,225,146,10,16,0,9,227,183,129,40,60,26,162,194,181,24,90,9,24,0,176,161,193,194,35,12, 63,
- 8,210,162,1,32,78,28,152,164,144,16,48,45,137,162,147,168,152,98,27,43,33,12,160,165,129,137,63,41,153,153,151,16,91,26,8,8,9,56,10,46,24,146,57,168,160,166,241,129,32,140,16,145,179,164,137,113,138,208,131,26,25,1,42,178,196,106,24,171,18,196,8, 18, 29,
- 41,194,128,3,249,57,162,152,48,184,120,160,208,33,137,74,57,187,149,129,26,35,158,72,128,168,32,26,25,180,75,2,136,15,163,161,136,120,27,41,160,128,182,56,60,25,12,178,151,128,168,72,10,152,4,177,26,147,137,113,44,42,33,220,2,152,41,82,11, 210, 163, 184,
- 133,162,10,196,128,3,234,40,149,152,161,1,44,129,194,4,225,16,58,168,24,194,146,146,154,49,21,218,33,152,248,129,194,147,0,28,1,195,162,20,140,42,25,160,198,1,33,136,142,3,25,24,141,16,177,208,112,0,138,41,160,130,45,60,32,170,73,24,75,59,161,176,49,159,
- 97,26,168,149,145,32,28,25,184,211,129,179,74,73,8,153,136,193,151,160,32,48,143,9,147,181,145,32,60,9,187,133,166,144,32,152,25,136,161,150,168,145,81,10,42,0,169,182,148,136,58,41,187,182,211,131,16,137,25,243,144,129,2,9,8,202,7,25,185,21,144,136,153,
- 65,184,137,56,151,10,153,49,16,145,14,56,176,11,192,19,89,91,44,168,147,2,8,147,63,27,1,136,229,129,73,26,136,26,137,81,170,147,77,72,12,42,42,192,24,104,91,26,27,65,177,27,32,41,60,14,136,17,170,150,129,24,58,11,16,251,162,19,57,31,0,152,129,145,17, 61,
- 14,1,129,27,129,66,169,178,74,12,11,19,198,145,75,33,138,174,133,1,184,57,40,136,169,20,1,60,174,20,154,201,67,26,162,151,42,16,138,59,130,204,20,169,59,180,59,114,184,56,178,242,128,130,43,8,194,3,229,144,33,185,144,34,181,145,168,17,149,153,74,35, 220,
- 129,128,1,88,59,75,225,136,130,168,17,144,12,151,8,25,179,8,1,240,16,8,25,145,211,41,130,138,115,169,160,163,168,84,154,74,0,170,144,211,149,2,30,128,137,9,149,1,144,58,60,57,153,178,150,17,29,27,74,25,195,152,56,15,1,25,26,152,149,80,153,57,73,140, 128,
- 160,144,113,27,56,28,25,4,42,44,137,60,171,130,50,240,8,5,139,145,1,105,137,200,80,137,145,146,178,179,160,46,16,240,195,131,128,144,24,164,198,128,0,136,137,131,194,165,177,2,161,147,11,144,188,181,148,144,23,0,28,224,128,131,192,32,1,224,1,168,132,145,
- 9,41,208,58,137,179,151,145,16,1,30,8,145,178,1,47,32,186,72,169,146,75,8,41,48,136,89,13,48,9,10,124,26,11,42,32,129,91,77,16,12,128,42,57,138,10,60,2,63,9,0,93,128,152,90,8,10,24,40,44,144,29,49,188,48,72,25,30,177,33,128,186,120,129,186,133, 152, 130,
- 24,156,51,154,8,226,2,56,155,2,179,233,167,128,24,129,176,136,151,8,184,0,33,224,152,21,177,24,10,163,16,250,17,130,171,83,137,136,37,12,56,242,154,17,160,145,82,13,3,201,128,18,137,24,162,63,162,8,107,178,128,57,158,32,24,200,18,0,106,154,73,16, 248, 8,
- 73,137,57,75,0,128,12,65,137,59,75,28,144,129,122,0,58,140,160,195,145,105,56,28,153,145,164,88,8,28,25,153,9,162,113,89,153,136,33,234,147,128,41,72,11,138,151,144,145,16,43,58,248,130,178,42,4,40,10,196,154,147,216,24,7,136,10,161,148,210,161, 98, 138,
- 137,128,146,176,33,105,27,43,163,49,185,6,10,136,43,67,174,161,162,151,137,1,64,200,193,24,64,200,56,145,242,24,57,137,1,128,3,162,175,80,128,162,152,25,58,175,17,17,0,200,64,168,162,91,1,154,44,211,177,35,64,160,161,144,4,241,41,209,162,25,1,3,242, 176,
- 134,153,42,41,136,135,154,2,130,46,41,161,153,180,145,34,26,46,18,242,137,146,129,25,128,11,151,161,40,179,27,122,168,59,137,181,50,172,36,56,15,9,129,137,128,75,2,58,12,52,141,8,24,58,153,157,122,145,9,1,80,27,184,32,74,219,50,57,168,153,180,48,28, 143,
- 131,144,178,65,13,48,168,162,147,155,121,9,170,5,16,153,21,29,144,161,91,0,184,57,128,137,17,159,88,178,128,105,152,9,162,33,164,141,88,178,224,1,0,16,27,185,150,161,9,4,139,16,128,160,194,144,65,180,46,40,136,27,135,160,16,44,57,145,236,2,195,40,75,177,
- 2,200,179,146,186,104,50,141,24,169,165,148,11,97,10,11,130,177,49,57,78,42,154,128,165,59,33,28,30,1,136,16,192,41,128,152,123,136,24,1,169,113,10,11,49,153,14,147,19,45,43,8,176,210,148,8,16,11,96,144,192,163,150,10,128,43,26,150,178,165,24,41,171, 18,
- 27,215,1,8,128,136,40,35,208,11,161,193,18,73,154,133,155,165,164,10,49,154,8,199,0,2,168,64,192,0,40,162,43,202,180,150,10,106,24,185,145,131,184,113,43,24,162,187,73,146,42,81,171,121,58,155,151,16,43,32,31,9,160,146,17,136,94,10,24,145,25, 9, 130, 59,
- 65,13,91,25,169,146,176,112,42,59,16,217,130,20,13,25,9,40,161,138,68,169,154,18,62,154,180,145,135,152,56,58,155,165,211,8,40,42,10,198,1,2,184,57,184,224,51,154,27,134,168,19,202,73,75,184,35,176,75,24,25,209,51,157,19,30,184,179,3,33,148,45, 232, 146,
- 129,168,41,32,170,149,193,35,136,16,50,191,56,146,173,149,16,24,41,30,129,168,209,3,57,31,0,16,176,147,41,152,10,17,181,14,40,144,49,170,75,97,141,25,162,146,72,177,92,137,137,19,137,153,113,154,2,41,60,129,217,2,211,152,73,42,193,197,146,147, 10, 59, 0,
- 192,196,132,41,160,25,88,169,16,40,241,1,153,81,28,10,147,161,209,88,75,9,161,162,180,16,43,57,235,33,56,156,129,144,2,135,31,128,145,136,163,56,59,154,57,167,160,105,137,0,138,163,3,41,47,185,211,131,41,41,60,139,182,146,16,16,43,242,144,145,129,16,179,
- 183,1,26,9,147,240,131,160,91,74,152,184,166,178,33,140,9,4,162,233,34,136,129,144,163,60,142,144,149,128,33,73,13,161,194,131,0,26,56,142,128,163,128,1,233,56,209,41,145,194,147,179,149,64,30,8,128,216,18,24,43,43,32,153,25,74,109,137,153,48,8,137, 122,
- 25,144,26,43,59,30,33,41,27,24,96,153,160,50,76,27,47,152,145,163,73,40,14,152,131,176,74,90,8,8,200,67,155,154,50,49,155,28,124,177,152,1,2,17,62,138,180,176,4,25,9,177,245,162,129,40,25,176,164,130,172,4,8,181,194,49,11,168,154,165,133,152,40,136, 226,
- 179,19,26,185,16,167,194,16,25,57,243,136,147,1,31,25,184,132,160,33,62,138,129,130,41,121,137,153,145,26,17,107,136,179,1,61,60,26,162,168,148,64,31,25,32,168,152,64,31,137,8,129,33,62,24,137,8,16,59,47,153,33,162,91,59,41,170,145,5,43,60,41,13,178,134,
- 57,153,12,194,227,8,2,128,57,208,162,19,216,32,178,25,128,160,48,194,195,37,155,10,33,251,163,146,16,136,12,166,195,160,148,129,176,147,178,150,160,72,162,162,193,162,60,200,145,5,144,25,122,216,129,161,130,0,10,73,1,241,2,9,168,33,13,161,165,24,64, 203,
- 50,1,14,9,9,129,161,106,33,27,13,164,128,40,41,107,169,160,33,136,60,92,168,152,2,91,57,176,129,0,144,47,136,162,164,128,80,43,154,179,213,130,74,27,0,145,145,167,58,59,160,9,26,76,8,171,5,49,28,44,169,162,183,130,72,28,144,179,228,2,25,26,129, 186, 151,
- 1,75,128,169,17,178,15,57,170,16,166,16,57,8,139,162,181,1,8,152,164,181,41,81,43,10,242,145,57,139,89,8,193,18,154,32,176,10,165,129,137,147,177,134,0,25,25,201,147,227,129,72,59,185,167,128,129,160,91,25,176,130,147,145,9,160,5,202,17,16, 186, 136, 37,
- 177,56,76,42,169,186,48,9,145,57,24,128,41,169,134,137,145,147,28,41,168,131,228,32,27,9,60,129,178,64,60,45,25,9,24,152,49,31,136,57,42,0,25,12,181,18,153,57,96,169,177,132,153,123,9,152,129,177,17,74,43,24,169,128,121,137,25,1,139,96,42,10,146,178, 18,
- 44,29,1,161,164,146,31,137,146,177,19,1,10,26,209,165,146,43,40,138,240,130,18,144,25,40,212,1,58,11,152,196,147,10,74,26,152,225,130,146,58,60,210,145,16,148,16,185,192,18,44,42,57,199,162,1,9,87,47,186,215,231,197,179,180,195,212,164,32,59,92, 126, 62,
- 41,59,76,59,60,168,179,213,197,163,72,44,25,74,126,127,127,79,26,177,148,90,27,225,247,165,0,152,147,123,138,211,164,72,126,127,46,210,196,163,228,215,64,11,210,180,1,8,58,153,1,224,149,57,76,27,24,76,42,43,136,128,243,179,130,106,60,42,42,92,28,243,231,
- 147,24,57,44,58,94,45,8,57,139,214,148,40,77,26,9,16,10,144,64,62,43,25,123,59,138,162,48,63,26,41,92,60,43,176,3,59,232,214,164,16,75,75,76,60,153,179,33,62,26,136,40,75,169,197,163,129,57,60,59,75,138,145,64,63,138,179,1,42,136,90,43,176,214,180,1, 25,
- 152,195,129,129,106,76,60,137,145,178,2,25,10,228,130,57,59,44,41,154,165,105,76,44,144,16,76,26,41,76,26,152,1,58,26,9,193,165,16,92,26,41,77,59,76,76,60,26,136,161,130,152,195,163,211,146,0,57,11,211,130,8,25,40,62,153,162,17,109,60,153,146,40, 76, 60,
- 26,160,179,211,163,32,60,42,153,179,194,199,130,24,58,43,58,27,128,161,195,129,226,196,147,90,59,75,44,136,128,145,160,148,123,59,42,26,41,26,57,27,192,215,147,57,59,27,161,145,213,130,106,76,43,9,144,162,129,177,181,130,136,194,146,40,10,129,25,210,146,
- 178,197,196,179,196,130,8,41,9,144,178,130,209,182,17,92,43,176,147,144,212,130,136,0,177,130,73,62,10,161,130,91,75,59,43,57,46,25,41,77,10,177,164,16,26,136,210,197,179,130,128,57,77,43,25,75,10,227,179,180,179,146,128,57,185,183,163,145,0,8,8,10, 119,
- 114,120,16,210,244,60,28,41,25,152,149,56,161,35,44,89,27,24,136,24,164,211,17,233,176,136,192,129,179,17,17,25,0,10,46,160,132,49,66,24,132,177,147,193,56,72,26,29,232,168,176,12,137,41,139,147,9,1,41,15,91,136,35,148,21,18,48,40,1,168,167,144,0,42,172,
- 177,204,193,155,232,152,152,26,152,41,146,17,6,4,65,34,35,135,4,16,32,9,24,186,176,0,250,153,204,186,173,154,153,177,3,65,41,34,145,134,35,65,98,49,50,50,2,33,169,138,155,175,170,172,204,192,138,234,136,155,136,10,32,18,5,52,48,24,162,17,67,54,66,51, 34,
- 131,184,174,234,153,10,9,40,0,152,251,168,142,154,9,16,33,49,33,128,154,170,156,34,54,54,33,68,0,1,136,201,137,26,88,48,35,99,8,152,189,189,187,155,171,16,24,130,145,188,175,203,144,49,115,67,67,50,19,2,1,0,0,130,131,1,136,206,216,188,203, 204, 187, 187,
- 156,153,0,0,51,17,34,24,112,20,69,67,67,34,19,0,136,169,185,137,186,232,185,219,201,203,187,173,170,154,153,129,131,6,2,19,49,49,21,65,19,53,51,83,34,16,168,201,154,172,156,138,0,1,24,201,233,186,204,186,171,137,3,37,48,24,128,201,202,202,129,17, 48, 21,
- 22,20,19,19,32,16,2,66,52,68,4,3,1,203,235,188,189,186,171,153,137,153,170,219,170,140,9,17,53,115,50,52,67,51,51,51,17,130,0,145,154,169,188,236,187,190,203,187,172,171,138,136,17,33,18,2,34,98,98,50,50,52,66,34,35,2,19,24,169,203,203,188,219, 169, 154,
- 9,137,171,204,188,203,184,136,34,83,50,33,153,184,170,170,152,40,57,19,36,50,50,18,35,17,2,49,49,66,66,66,34,17,168,233,202,202,170,171,170,186,219,203,188,188,154,138,25,33,68,52,68,67,67,36,51,36,18,17,17,136,8,170,176,202,188,206,202,171,172,186, 169,
- 153,8,25,144,128,1,34,68,52,68,51,52,34,49,18,34,2,144,136,155,140,187,186,186,154,154,185,185,153,9,9,0,24,0,128,144,168,169,170,154,154,153,9,8,16,8,0,144,19,35,68,51,52,67,51,66,34,50,33,1,144,185,186,172,204,187,188,173,172,186,172,186, 154, 138, 41,
- 33,52,53,83,50,51,52,52,37,34,34,18,16,144,152,154,187,219,203,188,173,186,186,186,170,154,153,138,144,16,17,67,82,50,51,21,34,19,33,2,18,33,1,8,153,169,153,153,136,128,0,136,154,153,153,8,8,1,16,0,169,170,187,171,171,154,153,153,152,153,153,0,16,51, 83,
- 66,50,67,50,51,67,51,52,35,18,136,186,219,187,189,186,171,187,173,187,188,187,203,138,9,16,33,50,52,53,67,67,147,8,128,128,128,128,128,128,128,128,0,240,255,55,232,23,220,0,148,1,9,18,148,10,189,32,163,62,160,5,137,12,149,42,153,144,34,42,8, 1, 138, 181,
- 45,136,18,144,105,138,1,160,14,128,132,145,186,37,138,41,192,48,145,46,160,33,44,24,225,16,13,132,136,137,16,148,25,170,194,82,152,136,91,24,42,169,33,233,131,179,24,185,149,16,57,172,164,18,10,211,160,147,211,33,138,243,129,16,41,193,0,43, 132, 155, 73,
- 58,145,244,145,43,35,9,171,16,110,25,8,28,74,162,128,26,27,82,45,136,153,18,8,136,8
-};
-
} // End of namespace Kyra
#undef EUPHONY_FADEOUT_TICKS
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 9ad2f50619..274acae22c 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -42,7 +42,7 @@
namespace Kyra {
-#define RESFILE_VERSION 70
+#define RESFILE_VERSION 71
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
diff --git a/engines/kyra/text_hof.cpp b/engines/kyra/text_hof.cpp
index 48eda97f80..9d20cdd51a 100644
--- a/engines/kyra/text_hof.cpp
+++ b/engines/kyra/text_hof.cpp
@@ -255,7 +255,8 @@ void KyraEngine_HoF::objectChatInit(const char *str, int object, int vocHigh, in
_screen->hideMouse();
- if (textEnabled()) {
+ _chatTextEnabled = textEnabled();
+ if (_chatTextEnabled) {
objectChatPrintText(str, object);
_chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
} else {
diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp
index 79b16bc1be..40f2217a2b 100644
--- a/engines/kyra/text_lok.cpp
+++ b/engines/kyra/text_lok.cpp
@@ -32,10 +32,9 @@
namespace Kyra {
-void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const char *chatStr, uint8 charNum) {
+void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const char *chatStr, uint8 charNum, const bool printText) {
bool hasUpdatedNPCs = false;
bool runLoop = true;
- bool drawText = textEnabled();
uint8 currPage;
uint32 timeToEnd = strlen(chatStr) * 8 * _tickLength + _system->getMillis();
@@ -92,7 +91,7 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const
_animator->preserveAnyChangedBackgrounds();
_animator->prepDrawAllObjects();
- if (drawText) {
+ if (printText) {
currPage = _screen->_curPage;
_screen->_curPage = 2;
_text->printCharacterText(chatStr, charNum, _characterList[charNum].x1);
@@ -102,7 +101,7 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const
_animator->copyChangedObjectsForward(0);
updateTextFade();
- if (((chatDuration < (int16)(_system->getMillis() - timeAtStart)) && chatDuration != -1 && drawText) || (!drawText && !snd_voiceIsPlaying()))
+ if (((chatDuration < (int16)(_system->getMillis() - timeAtStart)) && chatDuration != -1 && printText) || (!printText && !snd_voiceIsPlaying()))
break;
uint32 nextTime = loopStart + _tickLength;
@@ -293,7 +292,9 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu
_text->_talkMessageY = yPos;
_text->_talkMessageH = lineNum * 10;
- if (textEnabled()) {
+ const bool printText = textEnabled();
+
+ if (printText) {
_animator->restoreAllObjectBackgrounds();
_screen->copyRegion(12, _text->_talkMessageY, 12, 136, 296, _text->_talkMessageH, 2, 2);
@@ -310,9 +311,9 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu
if (!speechEnabled())
vocFile = -1;
- waitForChatToFinish(vocFile, chatTicks, chatStr, charNum);
+ waitForChatToFinish(vocFile, chatTicks, chatStr, charNum, printText);
- if (textEnabled()) {
+ if (printText) {
_animator->restoreAllObjectBackgrounds();
_screen->copyRegion(12, 136, 12, _text->_talkMessageY, 296, _text->_talkMessageH, 2, 2);
diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp
index ea2dc48031..726d9e339f 100644
--- a/engines/kyra/text_mr.cpp
+++ b/engines/kyra/text_mr.cpp
@@ -265,7 +265,8 @@ void KyraEngine_MR::objectChatInit(const char *str, int object, int vocHigh, int
_screen->hideMouse();
- if (textEnabled()) {
+ _chatTextEnabled = textEnabled();
+ if (_chatTextEnabled) {
objectChatPrintText(str, object);
_chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
} else {
diff --git a/engines/kyra/timer_hof.cpp b/engines/kyra/timer_hof.cpp
index 117b84f48a..d8f86e30a2 100644
--- a/engines/kyra/timer_hof.cpp
+++ b/engines/kyra/timer_hof.cpp
@@ -97,6 +97,9 @@ void KyraEngine_HoF::setTimer1DelaySecs(int secs) {
}
void KyraEngine_HoF::setWalkspeed(uint8 newSpeed) {
+ if (!_timer)
+ return;
+
if (newSpeed < 5)
newSpeed = 3;
else
diff --git a/engines/kyra/timer_lok.cpp b/engines/kyra/timer_lok.cpp
index 40426a3dfe..6f4948c279 100644
--- a/engines/kyra/timer_lok.cpp
+++ b/engines/kyra/timer_lok.cpp
@@ -188,6 +188,9 @@ void KyraEngine_LoK::timerRedrawAmulet(int timerNum) {
}
void KyraEngine_LoK::setWalkspeed(uint8 newSpeed) {
+ if (!_timer)
+ return;
+
static const uint8 speeds[] = { 11, 9, 6, 5, 3 };
assert(newSpeed < ARRAYSIZE(speeds));
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index a45a4294c8..17456b8ec3 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -342,7 +342,7 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool
entry.loop = loop;
entry.enabled = true;
entry->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
- entry->load(*_vm->getRawData(ID_TMOV, id));
+ entry->load(_vm->getRawData(ID_TMOV, id));
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
@@ -378,7 +378,7 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u
return NULL_VID_HANDLE;
}
- entry->load(*file);
+ entry->load(file);
// Search for any deleted videos so we can take a formerly used slot
for (uint32 i = 0; i < _videoStreams.size(); i++)
diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp
index 5cda4e3208..74bb52f574 100644
--- a/engines/queen/queen.cpp
+++ b/engines/queen/queen.cpp
@@ -422,7 +422,7 @@ void QueenEngine::makeGameStateName(int slot, char *buf) const {
int QueenEngine::getGameStateSlot(const char *filename) const {
int i = -1;
const char *slot = strrchr(filename, '.');
- if (slot && slot[1] == 's') {
+ if (slot && (slot[1] == 's' || slot[1] == 'S')) {
i = atoi(slot + 2);
}
return i;
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 20acbed450..2432d84faa 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -67,7 +67,7 @@ bool g_debug_track_mouse_clicks = false;
static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeValue);
Console::Console(SciEngine *engine) : GUI::Debugger(),
- _engine(engine), _debugState(engine->_debugState) {
+ _engine(engine), _debugState(engine->_debugState), _enterTime(0) {
// Variables
DVar_Register("sleeptime_factor", &g_debug_sleeptime_factor, DVAR_INT, 0);
@@ -176,10 +176,12 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
DCmd_Register("bp_del", WRAP_METHOD(Console, cmdBreakpointDelete));
DCmd_Register("bpdel", WRAP_METHOD(Console, cmdBreakpointDelete)); // alias
DCmd_Register("bc", WRAP_METHOD(Console, cmdBreakpointDelete)); // alias
- DCmd_Register("bp_exec_method", WRAP_METHOD(Console, cmdBreakpointExecMethod));
- DCmd_Register("bpx", WRAP_METHOD(Console, cmdBreakpointExecMethod)); // alias
- DCmd_Register("bp_exec_function", WRAP_METHOD(Console, cmdBreakpointExecFunction));
- DCmd_Register("bpe", WRAP_METHOD(Console, cmdBreakpointExecFunction)); // alias
+ DCmd_Register("bp_method", WRAP_METHOD(Console, cmdBreakpointMethod));
+ DCmd_Register("bpx", WRAP_METHOD(Console, cmdBreakpointMethod)); // alias
+ DCmd_Register("bp_kernel", WRAP_METHOD(Console, cmdBreakpointKernel));
+ DCmd_Register("bpk", WRAP_METHOD(Console, cmdBreakpointKernel)); // alias
+ DCmd_Register("bp_function", WRAP_METHOD(Console, cmdBreakpointFunction));
+ DCmd_Register("bpe", WRAP_METHOD(Console, cmdBreakpointFunction)); // alias
// VM
DCmd_Register("script_steps", WRAP_METHOD(Console, cmdScriptSteps));
DCmd_Register("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist));
@@ -214,6 +216,7 @@ Console::~Console() {
void Console::preEnter() {
if (g_sci && g_sci->_soundCmd)
g_sci->_soundCmd->pauseAll(true);
+ _enterTime = g_system->getMillis();
}
void Console::postEnter() {
@@ -272,6 +275,9 @@ void Console::postEnter() {
_videoFile.clear();
_videoFrameDelay = 0;
}
+
+ // Subtract the time we were running the debugger from the game running time
+ _engine->_gamestate->gameStartTime += g_system->getMillis() - _enterTime;
}
bool Console::cmdHelp(int argc, const char **argv) {
@@ -380,8 +386,9 @@ bool Console::cmdHelp(int argc, const char **argv) {
DebugPrintf("Breakpoints:\n");
DebugPrintf(" bp_list / bplist / bl - Lists the current breakpoints\n");
DebugPrintf(" bp_del / bpdel / bc - Deletes a breakpoint with the specified index\n");
- DebugPrintf(" bp_exec_method / bpx - Sets a breakpoint on the execution of the specified method\n");
- DebugPrintf(" bp_exec_function / bpe - Sets a breakpoint on the execution of the specified exported function\n");
+ DebugPrintf(" bp_method / bpx - Sets a breakpoint on the execution or access of a specified method/selector\n");
+ DebugPrintf(" bp_kernel / bpk - Sets a breakpoint on execution of a kernel function\n");
+ DebugPrintf(" bp_function / bpe - Sets a breakpoint on the execution of the specified exported function\n");
DebugPrintf("\n");
DebugPrintf("VM:\n");
DebugPrintf(" script_steps - Shows the number of executed SCI operations\n");
@@ -840,6 +847,7 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) {
}
DebugPrintf("SCI1.1-SCI2.1 script check finished\n");
+ delete resources;
return true;
}
@@ -1002,6 +1010,7 @@ bool Console::cmdShowInstruments(int argc, const char **argv) {
DebugPrintf("\n\n");
}
+ delete resources;
return true;
}
@@ -1047,7 +1056,6 @@ bool Console::cmdList(int argc, const char **argv) {
++itr;
}
DebugPrintf("\n");
-
delete resources;
}
@@ -2711,7 +2719,7 @@ bool Console::cmdLogKernel(int argc, const char **argv) {
return true;
}
- if (g_sci->getKernel()->debugSetFunctionLogging(argv[1], logging))
+ if (g_sci->getKernel()->debugSetFunction(argv[1], logging, -1))
DebugPrintf("Logging %s for k%s\n", logging ? "enabled" : "disabled", argv[1]);
else
DebugPrintf("Unknown kernel function %s\n", argv[1]);
@@ -2789,10 +2797,10 @@ bool Console::cmdBreakpointDelete(int argc, const char **argv) {
return true;
}
-bool Console::cmdBreakpointExecMethod(int argc, const char **argv) {
+bool Console::cmdBreakpointMethod(int argc, const char **argv) {
if (argc != 2) {
- DebugPrintf("Sets a breakpoint on the execution of the specified method.\n");
- DebugPrintf("Usage: %s <method name>\n", argv[0]);
+ DebugPrintf("Sets a breakpoint on execution/access of a specified method/selector.\n");
+ DebugPrintf("Usage: %s <name>\n", argv[0]);
DebugPrintf("Example: %s ego::doit\n", argv[0]);
DebugPrintf("May also be used to set a breakpoint that applies whenever an object\n");
DebugPrintf("of a specific type is touched: %s foo::\n", argv[0]);
@@ -2812,7 +2820,23 @@ bool Console::cmdBreakpointExecMethod(int argc, const char **argv) {
return true;
}
-bool Console::cmdBreakpointExecFunction(int argc, const char **argv) {
+bool Console::cmdBreakpointKernel(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Sets a breakpoint on execution of a kernel function.\n");
+ DebugPrintf("Usage: %s <name>\n", argv[0]);
+ DebugPrintf("Example: %s DrawPic\n", argv[0]);
+ return true;
+ }
+
+ if (g_sci->getKernel()->debugSetFunction(argv[1], -1, true))
+ DebugPrintf("Breakpoint enabled for k%s\n", argv[1]);
+ else
+ DebugPrintf("Unknown kernel function %s\n", argv[1]);
+
+ return true;
+}
+
+bool Console::cmdBreakpointFunction(int argc, const char **argv) {
// TODO/FIXME: Why does this accept 2 parameters (the high and the low part of the address)?"
if (argc != 3) {
DebugPrintf("Sets a breakpoint on the execution of the specified exported function.\n");
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 234272bbab..60599ea783 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -134,8 +134,9 @@ private:
// Breakpoints
bool cmdBreakpointList(int argc, const char **argv);
bool cmdBreakpointDelete(int argc, const char **argv);
- bool cmdBreakpointExecMethod(int argc, const char **argv);
- bool cmdBreakpointExecFunction(int argc, const char **argv);
+ bool cmdBreakpointMethod(int argc, const char **argv);
+ bool cmdBreakpointKernel(int argc, const char **argv);
+ bool cmdBreakpointFunction(int argc, const char **argv);
// VM
bool cmdScriptSteps(int argc, const char **argv);
bool cmdVMVarlist(int argc, const char **argv);
@@ -163,6 +164,7 @@ private:
bool _mouseVisible;
Common::String _videoFile;
int _videoFrameDelay;
+ uint32 _enterTime;
};
} // End of namespace Sci
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 3698964de5..e330bd5f30 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -299,7 +299,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R
if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
demoThreshold = 150;
- Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
+ Common::ScopedPtr<Common::List<ResourceId> > resources(resMan->listResources(kResourceTypeScript, -1));
if (resources->size() < demoThreshold) {
*gameFlags |= ADGF_DEMO;
@@ -496,8 +496,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
filename.contains("patch.005") || filename.contains("bank.001"))
s_fallbackDesc.platform = Common::kPlatformAmiga;
- // The existence of 7.pat indicates a Mac game
- if (filename.contains("7.pat"))
+ // The existence of 7.pat or patch.200 indicates a Mac game
+ if (filename.contains("7.pat") || filename.contains("patch.200"))
s_fallbackDesc.platform = Common::kPlatformMacintosh;
// The data files for Atari ST versions are the same as their DOS counterparts
@@ -627,7 +627,7 @@ bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
bool SciEngine::hasFeature(EngineFeature f) const {
return
- //(f == kSupportsRTL) ||
+ (f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime); // ||
//(f == kSupportsSavingDuringRuntime);
// We can't allow saving through ScummVM menu, because
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index da3763b236..0614eff6e6 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -32,7 +32,7 @@ namespace Sci {
{"sci-fanmade", name, { \
{"resource.map", 0, resMapMd5, resMapSize}, \
{"resource.001", 0, resMd5, resSize}, \
- {NULL, 0, NULL, 0}}, lang, Common::kPlatformPC, 0, GUIO_NOSPEECH \
+ AD_LISTEND}, lang, Common::kPlatformPC, 0, GUIO_NOSPEECH \
}
#define FANMADE(name, resMapMd5, resMapSize, resMd5, resSize) FANMADE_L(name, resMapMd5, resMapSize, resMd5, resSize, Common::EN_ANY)
@@ -47,7 +47,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"astrochicken", "", {
{"resource.map", 0, "f3d1be7752d30ba60614533d531e2e98", 474},
{"resource.001", 0, "6fd05926c2199af0af6f72f90d0d7260", 126895},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Castle of Dr. Brain - English Amiga (from www.back2roots.org)
@@ -59,10 +59,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "3fb02ce493f6eacdcc3713851024f80e", 559540},
{"resource.002", 0, "d226d7d3b4f77c4a566913fc310487fc", 792380},
{"resource.003", 0, "d226d7d3b4f77c4a566913fc310487fc", 464348},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
- // Castle of Dr. Brain - German Amiga (from www.back2roots.org)
+ // Castle of Dr. Brain - German Amiga (from www.back2roots.org, also includes english language)
// Executable scanning reports "1.005.001"
// SCI interpreter version 1.000.510
{"castlebrain", "", {
@@ -71,8 +71,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "4e0836fadc324316c1a418125709ba45", 569057},
{"resource.002", 0, "85e51acb5f9c539d66e3c8fe40e17da5", 826309},
{"resource.003", 0, "85e51acb5f9c539d66e3c8fe40e17da5", 493638},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Castle of Dr. Brain - English DOS Non-Interactive Demo
// SCI interpreter version 1.000.005
@@ -80,7 +80,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "467bb5e3224bb54640c3280032aebff5", 633},
{"resource.000", 0, "9780f040d58182994e22d2e34fab85b0", 67367},
{"resource.001", 0, "2af49dbd8f2e1db4ab09f9310dc91259", 570553},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Castle of Dr. Brain - English DOS Floppy EGA (from omer_mor, bug report #3035349)
@@ -93,7 +93,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "5e7b90949422de005f80285979972e43", 292423},
{"resource.005", 0, "8a5ed3ba96e2eaf18e36fedfaab89419", 297838},
{"resource.006", 0, "dceed92e709cad1bd9582809a235b0a0", 266682},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Castle of Dr. Brain - English DOS Floppy (from jvprat)
@@ -104,7 +104,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "27ec5fa09cd12a7fd16e86d96a2ed245", 346731},
{"resource.001", 0, "d2f5a1be74ed963fa849a76892be5290", 794832},
{"resource.002", 0, "c0c29c51af66d65cb53f49e785a2d978", 1280907},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Castle of Dr. Brain - English DOS Floppy 1.1
@@ -113,24 +113,39 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "27ec5fa09cd12a7fd16e86d96a2ed245", 347071},
{"resource.001", 0, "13e81e1839cd7b216d2bb5615c1ca160", 796776},
{"resource.002", 0, "930e416bec196b9703a331d81b3d66f2", 1283812},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Castle of Dr. Brain - Spanish DOS
+ // Castle of Dr. Brain - English DOS Floppy 1.000
+ // Reported by graxer in bug report #3037942
+ {"castlebrain", "", {
+ {"resource.map", 0, "453daa935535cef68d19704c2b1b78a2", 2649},
+ {"resource.000", 0, "6e125f4ce3f4f5c35f2617c7b66c6e21", 25929},
+ {"resource.001", 0, "4891faa2f6594c622e482f0ddce24fb4", 99404},
+ {"resource.002", 0, "aebb56d5d005557ca0d122a03aa85386", 322459},
+ {"resource.003", 0, "278ec1e6132c7be844d433dd23beb318", 335156},
+ {"resource.004", 0, "fca1c3f2be660185206f004bda09f4fb", 333549},
+ {"resource.005", 0, "9294e55da1e83708ad3104b2a3963e18", 327537},
+ {"resource.006", 0, "1d778a0c65cac9ddbab65495e50a94ee", 335281},
+ {"resource.007", 0, "063bb8ce4157c778cf30d1c912c006f1", 335631},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // Castle of Dr. Brain - Spanish DOS (also includes english language)
// SCI interpreter version 1.000.510
{"castlebrain", "", {
{"resource.map", 0, "5738c163e014bbe046474de009020b82", 2727},
{"resource.000", 0, "27ec5fa09cd12a7fd16e86d96a2ed245", 1197694},
{"resource.001", 0, "735be4e58957180cfc807d5e18fdffcd", 1433302},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Christmas Card 1988 - English DOS
// SCI interpreter version 0.000.294
{"christmas1988", "", {
{"resource.map", 0, "39485580d34a72997f3d5b3aba4d24f1", 426},
{"resource.001", 0, "11391434f41c834090d7a1e9488ce936", 129739},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Christmas Card 1990: The Seasoned Professional - English DOS (16 Colors)
@@ -138,7 +153,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"christmas1990", "16 Colors", {
{"resource.map", 0, "8f656714a05b94423ac6eb10ee8797d0", 600},
{"resource.001", 0, "acde93e58fca4f7a2a5a220558a94aa8", 272629},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Christmas Card 1990: The Seasoned Professional - English DOS (256 Colors)
@@ -146,7 +161,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"christmas1990", "256 Colors", {
{"resource.map", 0, "44b8f45b841b9b5e17e939a35e443988", 600},
{"resource.001", 0, "acde93e58fca4f7a2a5a220558a94aa8", 335362},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Christmas Card 1992 - English DOS
@@ -154,7 +169,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"christmas1992", "", {
{"resource.map", 0, "f1f8c8a8443f523422af70b4ec85b71c", 318},
{"resource.000", 0, "62fb9256f8e7e6e65a6875efdb7939ac", 203396},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Codename: Iceman - English Amiga (from www.back2roots.org)
@@ -168,7 +183,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "d97a96f1ab91b41cf46a02cc89b0a04e", 619219},
{"resource.004", 0, "8613c45fc771d658e5a505b9a4a54f31", 713382},
{"resource.005", 0, "605b67a9ef199a9bb015745e7c004cf4", 478384},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Codename: Iceman - English DOS Non-Interactive Demo
@@ -176,7 +191,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"iceman", "Demo", {
{"resource.map", 0, "782974f29d8a824782d2d4aea39964e3", 1056},
{"resource.001", 0, "d4b75e280d1c3a97cfef1b0bebff387c", 573647},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Codename: Iceman - English DOS (from jvprat)
@@ -189,7 +204,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "36670a917550757d57df84c96cf9e6d9", 566549},
{"resource.003", 0, "d97a96f1ab91b41cf46a02cc89b0a04e", 624303},
{"resource.004", 0, "8613c45fc771d658e5a505b9a4a54f31", 670883},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Codename: Iceman - English DOS (from FRG)
@@ -201,7 +216,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "250b859381ebf2bf8922bd99683b0cc1", 566464},
{"resource.003", 0, "dc7c5280e7acfaffe6ef2a6c963c5f94", 622118},
{"resource.004", 0, "64f342463f6f35ba71b3509ef696ae3f", 669188},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Codename: Iceman - English DOS 1.023 (from abevi, bug report #2612718)
@@ -215,7 +230,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "dc7c5280e7acfaffe6ef2a6c963c5f94", 330653},
{"resource.006", 0, "08050329aa113a9f14ed99cbfe3536ec", 232942},
{"resource.007", 0, "64f342463f6f35ba71b3509ef696ae3f", 267702},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of Camelot - English Amiga (from www.back2roots.org)
@@ -230,7 +245,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "6821dc97cf643ba521a4e840dda3c58b", 647410},
{"resource.005", 0, "c6e551bdc24f0acc193159038d4ca767", 605882},
{"resource.006", 0, "8f880a536908ab496bbc552f7f5c3738", 585255},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Conquests of Camelot - English DOS Non-Interactive Demo
@@ -238,7 +253,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"camelot", "Demo", {
{"resource.map", 0, "f4cd75c15be75e04cdca3acda2c0b0ea", 468},
{"resource.001", 0, "4930708722f34bfbaa4945fb08f55f61", 232523},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Conquests of Camelot - English DOS (from jvprat)
@@ -250,7 +265,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "8e1a3a8c588007404b532b8dfacc1460", 722250},
{"resource.003", 0, "8e1a3a8c588007404b532b8dfacc1460", 723712},
{"resource.004", 0, "8e1a3a8c588007404b532b8dfacc1460", 729143},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of Camelot - English DOS
@@ -264,7 +279,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "8e1a3a8c588007404b532b8dfacc1460", 345734},
{"resource.006", 0, "8e1a3a8c588007404b532b8dfacc1460", 332446},
{"resource.007", 0, "8e1a3a8c588007404b532b8dfacc1460", 358182},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of the Longbow - English Amiga (from www.back2roots.org)
@@ -279,7 +294,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "d1038c75d85a6650d48e07d174a6a913", 838175},
{"resource.005", 0, "1c3804e56b114028c5873a35c2f06d13", 653002},
{"resource.006", 0, "f9487732289a4f4966b4e34eea413325", 842817},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Conquests of the Longbow - English DOS
@@ -293,7 +308,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "9cfce07e204a329e94fda8b5657621da", 1064637},
{"resource.005", 0, "d036df0872f2db19bca34601276be2d7", 1154950},
{"resource.006", 0, "b367a6a59f29ee30dde1d88a5a41152d", 1042966},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of the Longbow - English DOS Floppy (from jvprat)
@@ -307,7 +322,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "1867136d01ece57b531032d466910522", 823686},
{"resource.004", 0, "9cfce07e204a329e94fda8b5657621da", 1261462},
{"resource.005", 0, "21ebe6b39b57a73fc449f67f013765aa", 1284720},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of the Longbow - English DOS
@@ -320,7 +335,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "1867136d01ece57b531032d466910522", 823610},
{"resource.004", 0, "9cfce07e204a329e94fda8b5657621da", 1260237},
{"resource.005", 0, "21ebe6b39b57a73fc449f67f013765aa", 1284609},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of the Longbow EGA - English DOS
@@ -334,18 +349,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "b7bb35c027bb424ecefcd122768e5e60", 705631},
{"resource.005", 0, "58942b1aa6d6ffeb66e9f8897fd4435f", 469243},
{"resource.006", 0, "8c767b3939add63d11274065e46aad04", 713158},
- {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Conquests of the Longbow - English DOS Non-Interactive Demo
// SCI interpreter version 1.000.510
{"longbow", "Demo", {
{"resource.map", 0, "cbc5cb73341de1bff1b1e20a640af220", 588},
{"resource.001", 0, "f05a20cc07eee85da8e999d0ac0f596b", 869916},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Conquests of the Longbow - German DOS (suplied by markcoolio in bug report #2727681)
+ // Conquests of the Longbow - German DOS (suplied by markcoolio in bug report #2727681, also includes english language)
// SCI interpreter version 1.000.510
{"longbow", "", {
{"resource.map", 0, "7376b7a07f8bd3a8ab8d67595d3f5b51", 6285},
@@ -356,8 +370,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "9cfce07e204a329e94fda8b5657621da", 1101869},
{"resource.005", 0, "d036df0872f2db19bca34601276be2d7", 1176914},
{"resource.006", 0, "b367a6a59f29ee30dde1d88a5a41152d", 1123585},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Eco Quest - English DOS Non-Interactive Demo (from FRG)
// Executable scanning reports "x.yyy.zzz"
@@ -365,16 +379,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ecoquest", "Demo", {
{"resource.map", 0, "c819e171359b7c95f4c13b846d5c034e", 873},
{"resource.001", 0, "baf9393a9bfa73098adb501e5bc5487b", 657518},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Eco Quest - English DOS CD 1.1
// SCI interpreter version 1.001.064
{"ecoquest", "CD", {
{"resource.map", 0, "a4b73d5d2b55bdb6e44345e99c8fbdd0", 4804},
{"resource.000", 0, "d908dbef56816ac6c60dd145fdeafb2b", 3536046},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Eco Quest - English DOS Floppy
@@ -385,7 +398,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "96d4435d24c01f1c1675e46457604c5f", 1413719},
{"resource.002", 0, "28fe9b4f0567e71feb198bc9f3a2c605", 1241816},
{"resource.003", 0, "f3146df0ad4297f5ce35aa8c4753bf6c", 586832},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Eco Quest - English DOS Floppy
@@ -396,10 +409,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "2fed7451bca81b0c891eed1a956f2263", 1212161},
{"resource.002", 0, "323b3b12f43d53f27d259beb225f0aa7", 1129316},
{"resource.003", 0, "83ac03e4bddb2c1ac2d36d2a587d0536", 1145616},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Eco Quest - German DOS Floppy (supplied by markcoolio in bug report #2723744)
+ // Eco Quest - German DOS Floppy (supplied by markcoolio in bug report #2723744, also includes english language)
// SCI interpreter version 1.000.510
{"ecoquest", "Floppy", {
{"resource.map", 0, "7a9b43bf27dc000ac8559ecbe824b659", 4395},
@@ -407,10 +420,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "2fed7451bca81b0c891eed1a956f2263", 1212060},
{"resource.002", 0, "02d7d0411f7903aacb3bc8b0f8ca8a9a", 1202581},
{"resource.003", 0, "84dd11b6825255671c703aee5ceff620", 1175835},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Eco Quest - Spanish DOS Floppy (from jvprat)
+ // Eco Quest - Spanish DOS Floppy (from jvprat, also includes english language)
// Executable scanning reports "1.ECO.013", VERSION file reports "1.000, 11.12.92"
// SCI interpreter version 1.000.510
{"ecoquest", "Floppy", {
@@ -419,10 +432,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "2fed7451bca81b0c891eed1a956f2263", 1212060},
{"resource.002", 0, "2d21a1d2dcbffa551552e3e0725d2284", 1186033},
{"resource.003", 0, "84dd11b6825255671c703aee5ceff620", 1174993},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Eco Quest - French DOS Floppy (from Strangerke)
+ // Eco Quest - French DOS Floppy (from Strangerke, also includes english language)
// SCI interpreter version 1.ECO.013
{"ecoquest", "Floppy", {
{"resource.map", 0, "67742945cd59b896d9f22a549f605217", 4407},
@@ -430,15 +443,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "fc7fba54b6bb88fd7e9c229636599aa9", 1205841},
{"resource.002", 0, "b836c6ee9de67d814ac5d1b05f5b9858", 1173872},
{"resource.003", 0, "f8f767f9d6351432621c6e54c1b2ba8c", 1141520},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Eco Quest 2 - English DOS Non-Interactive Demo
// SCI interpreter version 1.001.055
{"ecoquest2", "Demo", {
{"resource.map", 0, "607cfa0d8a03b7d348c06ee727e3d939", 1321},
{"resource.000", 0, "dd6f614c43c029f063e93cd243af90a4", 525992},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Eco Quest 2 - English DOS Floppy (supplied by markcoolio in bug report #2723761)
@@ -446,7 +459,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ecoquest2", "Floppy", {
{"resource.map", 0, "28fb7b6abb9fc1cb8882d7c2e701b63f", 5658},
{"resource.000", 0, "cc1d17e5637528dbe4a812699e1cbfc6", 4208192},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Eco Quest 2 - French DOS Floppy (from Strangerke)
@@ -454,7 +467,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ecoquest2", "Floppy", {
{"resource.map", 0, "c22ab8b33c339c138b6b1697b77b9e79", 5588},
{"resource.000", 0, "1c4093f7248240329121fdf8c0d59152", 4231946},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Freddy Pharkas - English DOS demo (from FRG)
@@ -462,7 +475,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"freddypharkas", "Demo", {
{"resource.map", 0, "97aa9fcfe84c9993a64debd28c32393a", 1909},
{"resource.000", 0, "5ea8e7a3ea10cce6efd5c106dc62fd8c", 867724},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Freddy Pharkas - English CD (from FRG)
@@ -470,7 +483,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"freddypharkas", "CD", {
{"resource.map", 0, "d46b282f228a67ba13bd4b4009e95f8f", 6058},
{"resource.000", 0, "ee3c64ffff0ba9fb08bea2624631c598", 5490246},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Freddy Pharkas - English DOS Floppy (updated information from markcoolio in bug reports #2723773 and #2724720)
@@ -480,7 +493,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a32674e7fbf7b213b4a066c8037f16b6", 5816},
{"resource.000", 0, "96b07e9b914dba1c8dc6c78a176326df", 5233230},
{"resource.msg", 0, "554f65315d851184f6e38211489fdd8f", -1},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Freddy Pharkas - Windows (supplied by abevi in bug report #2612718)
@@ -489,7 +502,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"freddypharkas", "Floppy", {
{"resource.map", 0, "a32674e7fbf7b213b4a066c8037f16b6", 5816},
{"resource.000", 0, "fed4808fdb72486908ac7ad0044b14d8", 5233230},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// Freddy Pharkas - German DOS Floppy (from Tobis87, updated information from markcoolio in bug reports #2723772 and #2724720)
@@ -499,7 +512,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a32674e7fbf7b213b4a066c8037f16b6", 5816},
{"resource.000", 0, "96b07e9b914dba1c8dc6c78a176326df", 5233230},
{"resource.msg", 0, "304b5a5781800affd2235152a5794fa8", -1},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Freddy Pharkas - Spanish DOS (from jvprat)
@@ -512,7 +525,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "419dbd5366f702b4123dedbbb0cffaae", 1456640},
{"resource.003", 0, "05acdc256c742e79c50b9fe7ec2cc898", 863310},
{"resource.msg", 0, "45b5bf74933ac3727e4cc844446dc052", 796156},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE },
// Freddy Pharkas - Spanish DOS (from jvprat)
@@ -522,7 +535,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a32674e7fbf7b213b4a066c8037f16b6", 5816},
{"resource.000", 0, "96b07e9b914dba1c8dc6c78a176326df", 5233230},
{"resource.msg", 0, "45b5bf74933ac3727e4cc844446dc052", 796156},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Freddy Pharkas - English DOS CD Demo
@@ -530,7 +543,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"freddypharkas", "CD Demo", {
{"resource.map", 0, "a62a7eae85dd1e6b07f39662b278437e", 1918},
{"resource.000", 0, "4962a3c4dd44e36e78ea4a7a374c2220", 957382},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE },
// Fun Seeker's Guide - English DOS
@@ -538,7 +551,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"funseeker", "", {
{"resource.map", 0, "7ee6859ef74314f6d91938c3595348a9", 282},
{"resource.001", 0, "f1e680095424e31f7fae1255d36bacba", 40692},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Gabriel Knight - English DOS CD Demo
@@ -546,7 +559,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD Demo", {
{"resource.map", 0, "39645952ae0ed8072c7e838f31b75464", 2490},
{"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE },
#ifdef ENABLE_SCI32
@@ -555,16 +568,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "", {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Gabriel Knight - English DOS Floppy (supplied my markcoolio in bug report #2723777)
// SCI interpreter version 2.000.000
{"gk1", "", {
{"resource.map", 0, "65e8c14092e4c9b3b3538b7602c8c5ec", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Gabriel Knight - German DOS Floppy (supplied my markcoolio in bug report #2723775)
@@ -572,7 +584,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "", {
{"resource.map", 0, "ad6508b0296b25c07b1f58828dc33696", 10789},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13077029},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Gabriel Knight - English DOS CD (from jvprat)
@@ -580,7 +592,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Gabriel Knight - German DOS CD (from Tobis87)
@@ -588,7 +600,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NONE },
// Gabriel Knight - Spanish DOS CD (from jvprat)
@@ -596,7 +608,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE },
// Gabriel Knight - French DOS CD (from Hkz)
@@ -604,7 +616,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "55f909ba93a2515042a08d8a2da8414e", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13325145},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NONE },
// Gabriel Knight - English Windows CD (from jvprat)
@@ -612,7 +624,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE },
// Gabriel Knight - German Windows CD (from Tobis87)
@@ -620,7 +632,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformWindows, 0, GUIO_NONE },
// Gabriel Knight - Spanish Windows CD (from jvprat)
@@ -628,7 +640,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk1", "CD", {
{"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformWindows, 0, GUIO_NONE },
// Gabriel Knight 2 - English Windows Non-Interactive Demo
@@ -636,7 +648,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"gk2", "Demo", {
{"resource.map", 0, "e0effce11c4908f4b91838741716c83d", 1351},
{"resource.000", 0, "d04cfc7f04b6f74d13025378be49ec2b", 4640330},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Gabriel Knight 2 - English DOS (from jvprat)
@@ -654,7 +666,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.005", 0, "14b62d4a3bddee57a03cb1495a798a0f", 38075705},
{"resmap.006", 0, "ce9359037277b7d7976da185c2fa0aad", 2977},
{"ressci.006", 0, "8e44e03890205a7be12f45aaba9644b4", 60659424},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Gabriel Knight 2 - French DOS (6-CDs Sierra Originals reedition)
@@ -672,7 +684,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.005", 0, "1eb5a72744799f5a5518543f5b4c3c79", 37882126},
{"resmap.006", 0, "11b2e722170b8c93fdaa5428e2c7676f", 3001},
{"ressci.006", 0, "4037d941aec39d2e654e20960429aefc", 60568486},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::FR_FRA, Common::kPlatformPC, 0,
GUIO_NOSPEECH },
@@ -685,7 +697,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 162783},
{"resource.002", 0, "e0dd44069a62a463fd124974b915f10d", 342309},
{"resource.003", 0, "e0dd44069a62a463fd124974b915f10d", 328912},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Hoyle 1 - English DOS (supplied by merkur in bug report #2719227)
@@ -693,7 +705,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"hoyle1", "", {
{"resource.map", 0, "1034a218943d12f1f36e753fa10c95b8", 4386},
{"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 518308},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
#if 0 // TODO: unknown if these files are corrupt
@@ -703,7 +715,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "2a72b1aba65fa6e339370eb86d8601d1", 5166},
{"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 218755},
{"resource.002", 0, "e0dd44069a62a463fd124974b915f10d", 439502},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
#endif
@@ -713,7 +725,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "4f894d203f64aa23d9ff64d30ae36926", 2100},
{"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 98138},
{"resource.002", 0, "8f2dd70abe01112eca464cda818b5eb6", 196631},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Hoyle 2 - English Amiga (from www.back2roots.org)
@@ -722,9 +734,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"hoyle2", "", {
{"resource.map", 0, "62ed48d20c580e5a98f102f7cd93706a", 1356},
{"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 222704},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
+
+ // Hoyle 2 - English Macintosh
+ // Executable scanning reports "x.yyy.zzz"
+ {"hoyle2", "", {
+ {"resource.map", 0, "1af1d3aa3cf564f93477c9f87e53f495", 1728},
+ {"resource.001", 0, "b73b8131669d69d41a326415e4519138", 482882},
{NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH },
#if 0 // TODO: unknown if these files are corrupt
// Hoyle 3 - English Amiga (from www.back2roots.org)
@@ -734,7 +753,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "f1f158e428398cb87fc41fb4aa8c2119", 2088},
{"resource.000", 0, "595b6039ea1356e7f96a52c58eedcf22", 355791},
{"resource.001", 0, "143df8aef214a2db34c2d48190742012", 632273},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
#endif
@@ -744,7 +763,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"hoyle3", "Demo", {
{"resource.map", 0, "0d06cacc87dc21a08cd017e73036f905", 735},
{"resource.001", 0, "24db2bccda0a3c43ac4a7b5edb116c7e", 797678},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Hoyle 3 - English DOS Floppy (from jvprat)
@@ -754,7 +773,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7216a2972f9c595c45ab314941628e43", 2247},
{"resource.000", 0, "6ef28cac094dcd97fdb461662ead6f92", 541845},
{"resource.001", 0, "0a98a268ee99b92c233a0d7187c1f0fa", 845795},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Hoyle 3 - English DOS Floppy 1.0 (supplied by abevi in bug report #2612718)
@@ -762,14 +781,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "1728af1f6a85938c3522e64449e76ca1", 2205},
{"resource.000", 0, "6ef28cac094dcd97fdb461662ead6f92", 319905},
{"resource.001", 0, "0a98a268ee99b92c233a0d7187c1f0fa", 526438},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Hoyle 4 - English DOS Demo
{"hoyle4", "Demo", {
{"resource.map", 0, "60f764020a6b788bbbe415dbc2ccb9f3", 931},
{"resource.000", 0, "5fe3670e3ddcd4f85c10013b5453141a", 615522},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Hoyle 4 - English DOS Demo
@@ -778,16 +797,32 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"hoyle4", "Demo", {
{"resource.map", 0, "662087cb383e52e3cc4ae7ecb10e20aa", 938},
{"resource.000", 0, "24c10844792c54d476d272213cbac300", 675252},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
+ // Hoyle 4 (Hoyle Classic Card Games) - English DOS/Win
+ // SCI1.1
+ // Supplied by abevi in bug report #3039291
+ {"hoyle4", "Demo", {
+ {"resource.map", 0, "2b577c975cc8d8d43f61b6a756129fe3", 4352},
+ {"resource.000", 0, "43e2c15ce436aab611a462ad0603e12d", 2000132},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
// Jones in the Fast Lane EGA - English DOS
// SCI interpreter version 1.000.172 (not 100% sure FIXME)
- {"jones", "", {
+ {"jones", "EGA", {
{"resource.map", 0, "be4cf9e8c1e253623ef35ae3b8a1d998", 1800},
{"resource.001", 0, "bac3ec6cb3e3920984ab0f32becf5163", 202105},
{"resource.002", 0, "b86daa3ba2784d1502da881eedb80d9b", 341771},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // Jones in the Fast Lane EGA - English DOS (supplied by EddyDrama in bug report #3038761)
+ {"jones", "EGA", {
+ {"resource.map", 0, "8e92cf319180cc8b5b87b2ce93a4fe22", 1602},
+ {"resource.001", 0, "bac3ec6cb3e3920984ab0f32becf5163", 511528},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Jones in the Fast Lane VGA - English DOS
@@ -796,14 +831,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "65cbe19b36fffc71c8e7b2686bd49ad7", 1800},
{"resource.001", 0, "bac3ec6cb3e3920984ab0f32becf5163", 313476},
{"resource.002", 0, "b86daa3ba2784d1502da881eedb80d9b", 719747},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // Jones in the Fast Lane VGA - English DOS (supplied by omer_mor in bug report #3037054)
+ // VERSION file reports "1.000.060"
+ {"jones", "", {
+ {"resource.map", 0, "db175ab494ab0666f19ab8f2597a8e49", 1602},
+ {"resource.001", 0, "bac3ec6cb3e3920984ab0f32becf5163", 994487},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Jones in the Fast Lane - English DOS CD
{"jones", "CD", {
{"resource.map", 0, "459f5b04467bc2107aec02f5c4b71b37", 4878},
{"resource.001", 0, "3876da2ce16fb7dea2f5d943d946fa84", 1652150},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO_NONE },
// King's Quest 1 SCI Remake - English Amiga (from www.back2roots.org)
@@ -815,7 +858,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "9ae2a13708d691cd42f9129173c4b39d", 795123},
{"resource.003", 0, "9ae2a13708d691cd42f9129173c4b39d", 763224},
{"resource.004", 0, "9ae2a13708d691cd42f9129173c4b39d", 820443},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// King's Quest 1 SCI Remake - English DOS Non-Interactive Demo
@@ -823,7 +866,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq1sci", "SCI Remake Demo", {
{"resource.map", 0, "59b13619078bd47011421468959ee5d4", 954},
{"resource.001", 0, "4cfb9040db152868f7cb6a1e8151c910", 296555},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// King's Quest 1 SCI Remake - English DOS (from the King's Quest Collection)
@@ -834,7 +877,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "fed9e0072ffd511d248674e60dee2099", 555439},
{"resource.002", 0, "fed9e0072ffd511d248674e60dee2099", 714062},
{"resource.003", 0, "fed9e0072ffd511d248674e60dee2099", 717478},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 4 - English Amiga (from www.back2roots.org)
@@ -847,7 +890,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "fb351106ec865fad9af5d78bd6b8e3cb", 663629},
{"resource.003", 0, "fd16c9c223f7dc5b65f06447615224ff", 683016},
{"resource.004", 0, "3fac034c7d130e055d05bc43a1f8d5f8", 549993},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// King's Quest 4 - English DOS Non-Interactive Demo
@@ -855,7 +898,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq4sci", "Demo", {
{"resource.map", 0, "992ac7cc31d3717fe53818a9bb6d1dae", 594},
{"resource.001", 0, "143e1c14f15ad0fbfc714f648a65f661", 205330},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// King's Quest 4 - English DOS (from the King's Quest Collection)
@@ -867,7 +910,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "77615c595388acf3d1df8e107bfb6b52", 536573},
{"resource.003", 0, "77615c595388acf3d1df8e107bfb6b52", 707591},
{"resource.004", 0, "77615c595388acf3d1df8e107bfb6b52", 479562},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 4 - English DOS
@@ -881,7 +924,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "851a62d00972dc4002f472cc0d84e71d", 321593},
{"resource.006", 0, "851a62d00972dc4002f472cc0d84e71d", 333777},
{"resource.007", 0, "851a62d00972dc4002f472cc0d84e71d", 341038},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 4 - English DOS
@@ -895,7 +938,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "0c8566848a76eea19a6d6220914030a7", 325102},
{"resource.006", 0, "0c8566848a76eea19a6d6220914030a7", 337288},
{"resource.007", 0, "0c8566848a76eea19a6d6220914030a7", 343882},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 5 - English Amiga (from www.back2roots.org)
@@ -911,10 +954,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "31a5487f4d942e6354d5be49d59707c9", 834146},
{"resource.006", 0, "26c0c25399b6715fec03fc3e12544fe3", 823048},
{"resource.007", 0, "b914b5901e786327213e779725d30dd1", 778772},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
- // King's Quest 5 - German Amiga
+ // King's Quest 5 - German Amiga (also includes english language)
// Executable scanning reports "1.004.024"
// SCI interpreter version 1.000.060
{"kq5", "", {
@@ -927,10 +970,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "5aa3d59968b569cd509dde00d4eb8751", 754201},
{"resource.006", 0, "56546b20db11a4836f900efa6d3a3e74", 672099},
{"resource.007", 0, "56546b20db11a4836f900efa6d3a3e74", 794194},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // King's Quest 5 - Italian Amiga
+ // King's Quest 5 - Italian Amiga (also includes english language)
// Executable scanning reports "1.004.024"
// SCI interpreter version 1.000.060
{"kq5", "", {
@@ -943,8 +986,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "de3c5c09e350fded36ca354998c2194d", 754784},
{"resource.006", 0, "11cb750f5f816445ad0f4b9f50a4f59a", 672527},
{"resource.007", 0, "11cb750f5f816445ad0f4b9f50a4f59a", 794259},
- {NULL, 0, NULL, 0}},
- Common::IT_ITA, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::IT_ITA, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// King's Quest 5 - English DOS CD (from the King's Quest Collection)
// Executable scanning reports "x.yyy.zzz", VERSION file reports "1.000.052"
@@ -953,7 +996,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "f68ba690e5920725dcf9328001b90e33", 13122},
{"resource.000", 0, "449471bfd77be52f18a3773c7f7d843d", 571368},
{"resource.001", 0, "b45a581ff8751e052c7e364f58d3617f", 16800210},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// King's Quest 5 - English DOS Floppy
@@ -968,7 +1011,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "b6c43441cb78a9b484efc8e614aac092", 1287999},
{"resource.006", 0, "672ede1136e9e401658538e51bd5dc22", 1172619},
{"resource.007", 0, "2f48faf27666b58c276dda20f91f4a93", 1240456},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // King's Quest 5 - English DOS Floppy (supplied by omer_mor in bug report #3036996)
+ // VERSION file reports "0.000.051"
+ {"kq5", "", {
+ {"resource.map", 0, "8b2158083302568b73b16fa3655360fe", 8184},
+ {"resource.000", 0, "a591bd4b879fc832b8095c0b3befe9e2", 276398},
+ {"resource.001", 0, "c0f48d4a7ebeaa6aa074fc98d77423e9", 1099506},
+ {"resource.002", 0, "e0c40d0e85340357d2404f9b5ae1921c", 1061243},
+ {"resource.003", 0, "89c00d788d022c13a9b250fa96290ab0", 1110169},
+ {"resource.004", 0, "d68f0d8a52ac990aa5641b7087476253", 1153751},
+ {"resource.005", 0, "ef4f1166bc37b6cfab70234ea60ddc3d", 1032675},
+ {"resource.006", 0, "06cb3f689836086ebe08b1efc0126592", 921113},
+ {"resource.007", 0, "252249753c6e850eacceb8af634986d3", 1133608},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 5 EGA (supplied by markcoolio in bug report #2829470)
@@ -984,7 +1042,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "3cca5b2dae8afe94532edfdc98d7edbe", 669919},
{"resource.006", 0, "698c698570cde9015e4d51eb8d2e9db1", 666527},
{"resource.007", 0, "703d8df30e89541af337d7706540d5c4", 541743},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 5 EGA (supplied by omer_mor in bug report #3035421)
@@ -999,10 +1057,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "3cca5b2dae8afe94532edfdc98d7edbe", 669961},
{"resource.006", 0, "698c698570cde9015e4d51eb8d2e9db1", 666541},
{"resource.007", 0, "703d8df30e89541af337d7706540d5c4", 541762},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // King's Quest 5 - German DOS Floppy (supplied by markcoolio in bug report #2727101)
+ // King's Quest 5 - German DOS Floppy (supplied by markcoolio in bug report #2727101, also includes english language)
// SCI interpreter version 1.000.060
{"kq5", "", {
{"resource.map", 0, "bff44f0c326a71b1757c793a02b502d6", 8283},
@@ -1014,10 +1072,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "9c429782d102739f6bbb81e8b953b0cb", 1267525},
{"resource.006", 0, "d1a75fdc01840664d00366cff6919366", 1208972},
{"resource.007", 0, "c07494f0cce7c05210893938786a955b", 1337361},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // King's Quest 5 - French DOS Floppy (from the King's Quest Collector's Edition 1994)
+ // King's Quest 5 - French DOS Floppy (from the King's Quest Collector's Edition 1994, also includes english language)
// Supplied by aroenai in bug report #2812611
// VERSION file reports "1.000", SCI interpreter version 1.000.784
{"kq5", "", {
@@ -1030,10 +1088,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "f4b31cafc5defac75125c5f7b7f9a31a", 1268334},
{"resource.006", 0, "f7dc85307632ef657ceb1651204f6f51", 1210081},
{"resource.007", 0, "7db4d0a1d8d547c0019cb7d2a6acbdd4", 1338473},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // King's Quest 5 - Italian DOS Floppy (from glorifindel)
+ // King's Quest 5 - Italian DOS Floppy (from glorifindel, includes english language)
// SCI interpreter version 1.000.060
{"kq5", "", {
{"resource.map", 0, "d55c9e83894a0885e37cd79bacf86384", 8283},
@@ -1045,10 +1103,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "f4e441f284560eaa8022102315656a7d", 1267757},
{"resource.006", 0, "8eeabd92af71e766e323db2100879102", 1209325},
{"resource.007", 0, "dc10c107e0923b902326a040b9c166b9", 1337859},
- {NULL, 0, NULL, 0}},
- Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::IT_ITA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // King's Quest 5 - Polish DOS Floppy (supplied by jacek909 in bug report #2725722)
+ // King's Quest 5 - Polish DOS Floppy (supplied by jacek909 in bug report #2725722, includes english language?!)
// SCI interpreter version 1.000.060
{"kq5", "", {
{"resource.map", 0, "70010c20138541f89013bb5e1b30f16a", 7998},
@@ -1060,8 +1118,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "6556ff8e7c4d1acf6a78aea154daa76c", 1287869},
{"resource.006", 0, "da82e4beb744731d0a151f1d4922fafa", 1170456},
{"resource.007", 0, "431def14ca29cdb5e6a5e84d3f38f679", 1240176},
- {NULL, 0, NULL, 0}},
- Common::PL_POL, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::PL_POL, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// King's Quest 5 - English Macintosh
// VERSION file reports "1.000.055"
@@ -1075,9 +1133,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "432e2a58e4d496d730697db072437337", 1366732},
{"resource.006", 0, "3d22904a374c192f51e5665b74364133", 1264079},
{"resource.007", 0, "ffe17e23d5833a79f3695addfc149a56", 1361965},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH },
+ // King's Quest 5 - FM-Towns (supplied by abevi in bug report #3038720)
+ {"kq5", "", {
+ {"resource.map", 0, "20c7cd248ff1a349ed354568eebd972b", 12733},
+ {"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094},
+ {"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO_NONE },
+
// King's Quest 6 - English DOS Non-Interactive Demo
// Executable scanning reports "1.001.055", VERSION file reports "1.000.000"
// SCI interpreter version 1.001.055
@@ -1085,7 +1151,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "f75727c00a6d884234fa2a43c951943a", 706},
{"resource.000", 0, "535b1b920441ec73f42eaa4ccfd47b89", 264116},
{"resource.msg", 0, "54d1fdc936f98c81f9e4c19e04fb1510", 8260},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// King's Quest 6 - English DOS Floppy
@@ -1094,7 +1160,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a362063318eebe7d6423b1d9dc6213e1", 8703},
{"resource.000", 0, "f2b7f753992c56a0c7a08d6a5077c895", 7863324},
{"resource.msg", 0, "3cf5de44de36191f109d425b8450efc8", 258590},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 6 - German DOS Floppy (supplied by markcoolio in bug report #2727156)
@@ -1103,7 +1169,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a362063318eebe7d6423b1d9dc6213e1", 8703},
{"resource.000", 0, "f2b7f753992c56a0c7a08d6a5077c895", 7863324},
{"resource.msg", 0, "756297b2155db9e43f621c6f6fb763c3", 282822},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 6 - English DOS CD (from the King's Quest Collection)
@@ -1112,7 +1178,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq6", "CD", {
{"resource.map", 0, "7a550ebfeae2575ca00d47703a6a774c", 9215},
{"resource.000", 0, "233394a5f33b475ae5975e7e9a420865", 8376352},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// King's Quest 6 - English Windows CD (from the King's Quest Collection)
@@ -1121,7 +1187,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq6", "CD", {
{"resource.map", 0, "7a550ebfeae2575ca00d47703a6a774c", 9215},
{"resource.000", 0, "233394a5f33b475ae5975e7e9a420865", 8376352},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE },
// King's Quest 6 - Spanish DOS CD (from jvprat)
@@ -1131,7 +1197,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a73a5ab04b8f60c4b75b946a4dccea5a", 8953},
{"resource.000", 0, "4da3ad5868a775549a7cc4f72770a58e", 8537260},
{"resource.msg", 0, "41eed2d3893e1ca6c3695deba4e9d2e8", 267102},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE },
// King's Quest 6 - English Macintosh Floppy
@@ -1139,7 +1205,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq6", "", {
{"Data1", 0, "f3c38a33c94293b8ff0337c1090a4973", 3916479},
{"Data2", 0, "b255edf327d7b366dce816b7debf3b94", 15046256},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
@@ -1150,7 +1216,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "", {
{"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195},
{"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// King's Quest 7 - English Windows (from the King's Quest Collection)
@@ -1158,7 +1224,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "", {
{"resource.map", 0, "2be9ab94429c721af8e05c507e048a15", 18697},
{"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 203882535},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// King's Quest 7 - English DOS (from FRG)
@@ -1166,7 +1232,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "", {
{"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 7 - English Windows (from FRG)
@@ -1174,7 +1240,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "", {
{"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// King's Quest 7 - German Windows (supplied by markcoolio in bug report #2727402)
@@ -1182,7 +1248,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "", {
{"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
{"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 7 - Spanish DOS (from jvprat)
@@ -1190,7 +1256,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "", {
{"resource.map", 0, "0b62693cbe87e3aaca3e8655a437f27f", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// King's Quest 7 - English DOS Non-Interactive Demo
@@ -1198,7 +1264,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"kq7", "Demo", {
{"resource.map", 0, "b44f774108d63faa1d021101221c5a54", 1690},
{"resource.000", 0, "d9659d2cf0c269c6a9dc776707f5bea0", 2433827},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#endif // ENABLE_SCI32
@@ -1214,7 +1280,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "2ab23f64306b18c28302c8ec2964c5d6", 605134},
{"resource.004", 0, "aa553977f7e5804081de293800d3bcce", 695067},
{"resource.005", 0, "bfd870d51dc97729f0914095f58e6957", 676881},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Laura Bow - English Atari ST (from jvprat)
@@ -1226,7 +1292,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 721149},
{"resource.003", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 667365},
{"resource.004", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 683737},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO_NOSPEECH },
// Laura Bow - English DOS Non-Interactive Demo
@@ -1234,7 +1300,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"laurabow", "Demo", {
{"resource.map", 0, "e625726268ff4e123ada11f31f0249f3", 768},
{"resource.001", 0, "0c8912290af0890f8d95faeb4ddb2d68", 333031},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Laura Bow - English DOS 3.5" Floppy (from "The Roberta Williams Anthology"/1996)
@@ -1245,7 +1311,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 721381},
{"resource.003", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 667468},
{"resource.004", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 683807},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Laura Bow - English DOS (from FRG)
@@ -1259,10 +1325,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 327465},
{"resource.006", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 328390},
{"resource.007", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 317687},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Laura Bow - German DOS (from Tobis87)
+ // Laura Bow - German DOS (from Tobis87, also includes english language)
// SCI interpreter version 0.000.631 (or 0.000.685?)
{"laurabow", "", {
{"resource.map", 0, "b1905f6aa68ff65a057b080b1eae954c", 12030},
@@ -1273,8 +1339,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 327465},
{"resource.006", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 328390},
{"resource.007", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 317687},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Laura Bow 2 - English DOS Non-Interactive Demo (from FRG)
// Executable scanning reports "x.yyy.zzz"
@@ -1282,7 +1348,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"laurabow2", "Demo", {
{"resource.map", 0, "24dffc5db1d88c7999f13e8767ed7346", 855},
{"resource.000", 0, "2b2b1b4f7584f9b38fd13f6ab95634d1", 781912},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Laura Bow 2 - English DOS Floppy
@@ -1291,7 +1357,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"laurabow2", "", {
{"resource.map", 0, "610bfd9a852004222f0faaf5fc9e630a", 6489},
{"resource.000", 0, "57084910bc923bff5d6d9bc1b56e9604", 5035964},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Laura Bow 2 - English DOS CD (from "The Roberta Williams Antology"/1996)
@@ -1300,7 +1366,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"laurabow2", "CD", {
{"resource.map", 0, "a70945e61ba7ac7bfea6b7bd72c6aec5", 7274},
{"resource.000", 0, "82578b8d5a7e09c4c58891ca49fae35b", 5598672},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Laura Bow 2 v1.1 - French DOS Floppy (from Hkz)
@@ -1308,7 +1374,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "3b6dfbcda210bbc3f23fd1927113bf98", 6483},
{"resource.000", 0, "57084910bc923bff5d6d9bc1b56e9604", 5028766},
{"resource.msg", 0, "0fceedfbdd85a4bc7851fdd9dd2d2f19", 278253},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Laura Bow 2 v1.1 - German DOS Floppy (from Tobis87, updated info from markcoolio in bug report #2723787, updated info from #2797962))
@@ -1317,7 +1383,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "3b6dfbcda210bbc3f23fd1927113bf98", 6483},
{"resource.000", 0, "57084910bc923bff5d6d9bc1b56e9604", 5028766},
{"resource.msg", 0, "795c928cd00dfec9fbc62ebcd12e1f65", 303185},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Laura Bow 2 - Spanish DOS CD (from jvprat)
@@ -1326,7 +1392,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "3b6dfbcda210bbc3f23fd1927113bf98", 6483},
{"resource.000", 0, "57084910bc923bff5d6d9bc1b56e9604", 5028766},
{"resource.msg", 0, "71f1f0cd9f082da2e750c793a8ed9d84", 286141},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 1 EGA Remake - English DOS (from spookypeanut)
@@ -1337,7 +1403,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "38936d3c68b6f79d3ffb13955713fed7", 591352},
{"resource.002", 0, "24c958bc922b07f91e25e8c93aa01fcf", 491230},
{"resource.003", 0, "685cd6c1e05a695ab1e0db826337ee2a", 553279},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 1 VGA Remake - English Amiga (from www.back2roots.org)
@@ -1349,7 +1415,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "24ed6dc01b1e7fbc66c3d63a5994549a", 750465},
{"resource.002", 0, "5790ac0505f7ca98d4567132b875eb1e", 681041},
{"resource.003", 0, "4a34c3367c2fe7eb380d741374da1989", 572251},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Larry 1 VGA Remake - English DOS (from spookypeanut)
@@ -1359,7 +1425,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "d3bceaebef3f7be941c2038b3565161e", 922406},
{"resource.001", 0, "ec20246209d7b19f38989261e5c8f5b8", 1111226},
{"resource.002", 0, "85d6935ef77e6b0e16bc307640a0d913", 1088312},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 1 VGA Remake - English DOS (from FRG)
@@ -1369,7 +1435,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "d3bceaebef3f7be941c2038b3565161e", 918242},
{"resource.001", 0, "d34cadb11e1aefbb497cf91bc1d3baa7", 1114688},
{"resource.002", 0, "85b030bb66d5342b0a068f1208c431a8", 1078443},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 1 VGA Remake - English DOS Non-Interactive Demo
@@ -1377,10 +1443,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl1sci", "VGA Remake, Demo", {
{"resource.map", 0, "434e1f6c39d71647b34f0ee57b2bbd68", 444},
{"resource.001", 0, "0c0768215c562d9dace4a5ca53696cf3", 359913},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Larry 1 VGA Remake - Spanish DOS (from the Leisure Suit Larry Collection)
+ // Larry 1 VGA Remake - Spanish DOS (from the Leisure Suit Larry Collection, also includes english language)
// Executable scanning reports "1.SQ4.057", VERSION file reports "1.000"
// This version is known to be corrupted
// SCI interpreter version 1.000.510
@@ -1390,10 +1456,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "112648995dbc194037f1e4ed2e195910", 1063341},
{"resource.002", 0, "3fe2a3aec0ed53c7d6db1845a67e3aa2", 1095908},
{"resource.003", 0, "ac175df0ea9a2cba57f0248651856d27", 376556},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Larry 1 VGA Remake - Russian DOS
+ // Larry 1 VGA Remake - Russian DOS (also includes english language?!)
// Executable scanning reports "1.000.510", VERSION file reports "2.0"
// SCI interpreter version 1.000.510
{"lsl1sci", "VGA Remake", {
@@ -1401,8 +1467,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "0d7b2afa666bd36d9535a15d3a837a66", 928566},
{"resource.001", 0, "bc8ca10c807515d959cbd91f9ba47735", 1123759},
{"resource.002", 0, "b7409ab32bc3bee2d6cce887cd33f2b6", 1092160},
- {NULL, 0, NULL, 0}},
- Common::RU_RUS, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::RU_RUS, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
+
+ // Larry 1 VGA Remake - Polish DOS (from Polish Leisure Suit Larry Collection, official release)
+ // SCI interpreter version 1.000.577, VERSION file reports "2.1" (this release does NOT include english text)
+ {"lsl1sci", "VGA Remake", {
+ {"resource.map", 0, "58330a85767e42a2487129913283ab5b", 3228},
+ {"resource.000", 0, "b6097ff35cdc8469f02150fe2f824198", 4781210},
+ AD_LISTEND},
+ Common::PL_POL, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 2 - English Amiga (from www.back2roots.org)
// Executable scanning reports "x.yyy.zzz"
@@ -1413,7 +1487,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "a0d4a625311d307257da7fc43d00459d", 630106},
{"resource.003", 0, "a0d4a625311d307257da7fc43d00459d", 570356},
{"resource.004", 0, "a0d4a625311d307257da7fc43d00459d", 717844},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Larry 2 - English DOS Non-Interactive Demo
@@ -1422,7 +1496,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl2", "Demo", {
{"resource.map", 0, "03dba704bb77da55a91ad27b5a3cac09", 528},
{"resource.001", 0, "9f5520f0297206928df0b0b36493cd33", 127532},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Larry 2 - English DOS
@@ -1435,7 +1509,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "4a24443a25e2b1492462a52809605dc2", 204861},
{"resource.005", 0, "4a24443a25e2b1492462a52809605dc2", 277732},
{"resource.006", 0, "4a24443a25e2b1492462a52809605dc2", 345683},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 2 - English DOS
@@ -1450,7 +1524,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
// TODO/FIXME: is the version with size 208739 corrupted?
//{"resource.006", 0, "96033f57accfca903750413fd09193c8", 345818},
{"resource.006", 0, "96033f57accfca903750413fd09193c8", -1}, // 345818 or 208739
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 3 - English Amiga (from www.back2roots.org)
@@ -1464,7 +1538,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "5c10e462c8cf589610773e4fe8bfd996", 527238},
{"resource.004", 0, "f408e59cbee1457f042e5773b8c53951", 651634},
{"resource.005", 0, "433911eb764089d493aed1f958a5615a", 524259},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Larry 3 - English DOS
@@ -1475,7 +1549,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "f18441027154292836b973c655fa3175", 578024},
{"resource.003", 0, "f18441027154292836b973c655fa3175", 506807},
{"resource.004", 0, "f18441027154292836b973c655fa3175", 513651},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 3 - English DOS
@@ -1489,7 +1563,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "f18441027154292836b973c655fa3175", 302946},
{"resource.006", 0, "f18441027154292836b973c655fa3175", 282465},
{"resource.007", 0, "f18441027154292836b973c655fa3175", 257174},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 3 - English DOS Non-Interactive Demo
@@ -1498,10 +1572,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "33a2384f395470af3d2180e37ad0322a", 1140},
{"resource.001", 0, "f773d79b93dfd4052ec8c1cc64c1e6ab", 76525},
{"resource.002", 0, "f773d79b93dfd4052ec8c1cc64c1e6ab", 268299},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Larry 3 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723832)
+ // Larry 3 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723832, also includes english language)
// Executable scanning reports "S.old.123"
// SCI interpreter version 0.000.572 (just a guess)
{"lsl3", "", {
@@ -1510,10 +1584,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "3827a9b17b926e12dcc336860f50612a", 672403},
{"resource.003", 0, "3827a9b17b926e12dcc336860f50612a", 587036},
{"resource.004", 0, "3827a9b17b926e12dcc336860f50612a", 691932},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Larry 3 - French DOS (provided by richiefs in bug report #2670691)
+ // Larry 3 - French DOS (provided by richiefs in bug report #2670691, also includes english language)
// Executable scanning reports "S.old.123"
// SCI interpreter version 0.000.572 (just a guess)
{"lsl3", "", {
@@ -1522,8 +1596,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "65f1bdaa20f6d0470e9d969f22473873", 671614},
{"resource.003", 0, "65f1bdaa20f6d0470e9d969f22473873", 586921},
{"resource.004", 0, "65f1bdaa20f6d0470e9d969f22473873", 690826},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Larry 5 - English Amiga
// Executable scanning reports "1.004.023"
@@ -1537,10 +1611,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "3ce5901f1bc171ac0274d99a4eeb9e57", 623022},
{"resource.005", 0, "f8b2d1137bb767e5d232056b99dd69eb", 623621},
{"resource.006", 0, "bafc64e3144f115dc58c6aee02de98fb", 715598},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
- // Larry 5 - German Amiga
+ // Larry 5 - German Amiga (also includes english language)
// Executable scanning reports "1.004.024"
// SCI interpreter version 1.000.784
{"lsl5", "", {
@@ -1553,15 +1627,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "59eba83ad465b08d763b44f86afa86f6", 664717},
{"resource.006", 0, "bafc64e3144f115dc58c6aee02de98fb", 754966},
{"resource.007", 0, "59eba83ad465b08d763b44f86afa86f6", 683135},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Larry 5 - English DOS Non-Interactive Demo (from FRG)
// SCI interpreter version 1.000.181
{"lsl5", "Demo", {
{"resource.map", 0, "efe8d3f45ce4f6bd9a6643e0ac8d2a97", 504},
{"resource.001", 0, "8bd8d9c0b5f455ee1269d63ce86c50dd", 531380},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Larry 5 - English DOS (from spookypeanut)
@@ -1576,7 +1650,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "0cc8d35a744031c772ca7cd21ae95273", 1011944},
{"resource.006", 0, "dda27ce00682aa76198dac124bbbe334", 1024810},
{"resource.007", 0, "ac443fae1285fb359bf2b2bc6a7301ae", 1030656},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 5 - German DOS (from Tobis87)
@@ -1591,8 +1665,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "0cc8d35a744031c772ca7cd21ae95273", 959342},
{"resource.006", 0, "dda27ce00682aa76198dac124bbbe334", 1021774},
{"resource.007", 0, "ac443fae1285fb359bf2b2bc6a7301ae", 993408},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Larry 5 - French DOS (provided by richiefs in bug report #2670691)
// Executable scanning reports "1.lsl5.019"
@@ -1607,8 +1681,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "0cc8d35a744031c772ca7cd21ae95273", 920524},
{"resource.006", 0, "dda27ce00682aa76198dac124bbbe334", 946540},
{"resource.007", 0, "ac443fae1285fb359bf2b2bc6a7301ae", 958842},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Larry 5 - Spanish DOS (from the Leisure Suit Larry Collection)
// Executable scanning reports "1.ls5.006", VERSION file reports "1.000, 4/21/92"
@@ -1623,15 +1697,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "0cc8d35a744031c772ca7cd21ae95273", 958079},
{"resource.006", 0, "dda27ce00682aa76198dac124bbbe334", 1015136},
{"resource.007", 0, "ac443fae1285fb359bf2b2bc6a7301ae", 987222},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Larry 5 - Italian DOS Floppy (from glorifindel)
// SCI interpreter version 1.000.510 (just a guess)
{"lsl5", "", {
{"resource.map", 0, "a99776df795127f387cb35dae872d4e4", 5919},
{"resource.000", 0, "a8989a5a89e7d4f702b26b378c7a357a", 7001981},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 6 - English DOS (from spookypeanut)
@@ -1639,7 +1713,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6", "", {
{"resource.map", 0, "bb8a39d9e2a77ba449a1e591109ad9a8", 6973},
{"resource.000", 0, "4462fe48c7452d98fddcec327a3e738d", 5789138},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 6 - English/German/French DOS CD - LORES
@@ -1647,7 +1721,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6", "", {
{"resource.map", 0, "0b91234b7112782962cb480b7791b6e2", 7263},
{"resource.000", 0, "57d5fe8bb9e044158514476ea7678eb0", 5754790},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 6 - German DOS CD - LORES (provided by richiefs in bug report #2670691)
@@ -1655,7 +1729,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6", "", {
{"resource.map", 0, "bafe85f32738854135991d4324ad147e", 7268},
{"resource.000", 0, "f6cbc6da7b90ea135883e0759848ca2c", 5773160},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 6 - French DOS CD - LORES (provided by richiefs in bug report #2670691)
@@ -1663,7 +1737,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6", "", {
{"resource.map", 0, "97797ea775baaf18a1907d357d3c0ea6", 7268},
{"resource.000", 0, "f6cbc6da7b90ea135883e0759848ca2c", 5776092},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 6 - Spanish DOS - LORES (from the Leisure Suit Larry Collection)
@@ -1671,7 +1745,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6", "", {
{"resource.map", 0, "633bf8f42170b6271019917c8009989b", 6943},
{"resource.000", 0, "7884a8db9253e29e6b37a2651fd90ba3", 5733116},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Crazy Nick's Software Picks: Leisure Suit Larry's Casino - English DOS (from the Leisure Suit Larry Collection)
@@ -1679,35 +1753,35 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"cnick-lsl", "", {
{"resource.map", 0, "194f1578f2624db813c9072359ad1639", 783},
{"resource.001", 0, "3733433b517ec3d14a3331d9ab3842ae", 344830},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Crazy Nick's Software Picks: King Graham's Board Game Challenge
{"cnick-kq", "", {
{"resource.map", 0, "44bc538a5cd24b39ffccc967c0ebf84d", 1137},
{"resource.001", 0, "470e7a4a3504635e70b623c44461e1ac", 451272},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Crazy Nick's Software Picks: Parlor Games with Laura Bow
{"cnick-laurabow", "", {
{"resource.map", 0, "3b826bfe64f8ff1ccf30eef93cd2f727", 999},
{"resource.001", 0, "985ac8db6f636f2b4334c04b0fbb44fb", 336698},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Crazy Nick's Software Picks: Robin Hood's Game of Skill and Chance
{"cnick-longbow", "", {
{"resource.map", 0, "4a5c81f485a2416bde12978506f2fb5f", 897},
{"resource.001", 0, "ef16dc9e867eb8eeb5b13e110b90bd4b", 571466},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Crazy Nick's Software Picks: Roger Wilco's Spaced Out Game Pack
{"cnick-sq", "", {
{"resource.map", 0, "b4d95b02d84e297441bd999d34eaa6b1", 879},
{"resource.001", 0, "82ff2b64a60117886fbcd6a3a8c977c6", 364921},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
@@ -1716,7 +1790,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6hires", "", {
{"resource.map", 0, "0c0804434ea62278dd15032b1947426c", 8872},
{"resource.000", 0, "9a9f4870504444cda863dd14d077a680", 18520872},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 6 - German DOS CD - HIRES (provided by richiefs in bug report #2670691)
@@ -1724,7 +1798,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6hires", "", {
{"resource.map", 0, "badfdf446ffed569a310d2c63a249421", 8896},
{"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18534274},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 6 - French DOS CD - HIRES (provided by richiefs in bug report #2670691)
@@ -1732,7 +1806,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl6hires", "", {
{"resource.map", 0, "d184e9aa4f2d4b5670ddb3669db82cda", 8896},
{"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18538987},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 7 - English DOS Demo (provided by richiefs in bug report #2670691)
@@ -1740,7 +1814,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl7", "Demo", {
{"ressci.000", 0, "5cc6159688b2dc03790a67c90ccc67f9", 10195878},
{"resmap.000", 0, "6a2b2811eef82e87cde91cf1de845af8", 2695},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#ifdef ENABLE_SCI3_GAMES
@@ -1749,7 +1823,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl7", "", {
{"resmap.000", 0, "eae93e1b1d1ccc58b4691c371281c95d", 8188},
{"ressci.000", 0, "89353723488219e25589165d73ed663e", 66965678},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 7 - German DOS (from Tobis87)
@@ -1757,7 +1831,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl7", "", {
{"resmap.000", 0, "c11e6bfcfc2f2d05da47e5a7df3e9b1a", 8188},
{"ressci.000", 0, "a8c6817bb94f332ff498a71c8b47f893", 66971724},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 7 - French DOS (provided by richiefs in bug report #2670691)
@@ -1765,7 +1839,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl7", "", {
{"resmap.000", 0, "4407849fd52fe3efb0c30fba60cd5cd4", 8206},
{"ressci.000", 0, "dc37c3055fffbefb494ff22b145d377b", 66964472},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Larry 7 - Italian DOS CD (from glorifindel)
@@ -1773,7 +1847,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl7", "", {
{"resmap.000", 0, "9852a97141f789413f29bf956052acdb", 8212},
{"ressci.000", 0, "440b9fed89590abb4e4386ed6f948ee2", 67140181},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NONE },
// Larry 7 - Spanish DOS (from the Leisure Suit Larry Collection)
@@ -1781,23 +1855,25 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"lsl7", "", {
{"resmap.000", 0, "8f3d603e1acc834a5d598b30cdfc93f3", 8188},
{"ressci.000", 0, "32792f9bc1bf3633a88b382bb3f6e40d", 67071418},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+#endif
// Lighthouse - English Windows Demo (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.00"
{"lighthouse", "Demo", {
{"resource.map", 0, "543124606352bfa5e07696ddf2a669be", 64},
{"resource.000", 0, "5d7714416b612463d750fb9c5690c859", 28952},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
+#ifdef ENABLE_SCI3_GAMES
// Lighthouse - English Windows Demo
// Executable scanning reports "3.000.000", VERSION file reports "1.00"
{"lighthouse", "Demo", {
{"resmap.000", 0, "3bdee7a16926975a4729f75cf6b80a92", 1525},
{"ressci.000", 0, "3c585827fa4a82f4c04a56a0bc52ccee", 11494351},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Lighthouse - English DOS (from jvprat)
@@ -1807,7 +1883,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.001", 0, "14e922c47b92156377cb49e241691792", 99591924},
{"resmap.002", 0, "c68db5333f152fea6ca2dfc75cad8b34", 7573},
{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94628315},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Lighthouse - Spanish DOS (from jvprat)
@@ -1817,7 +1893,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.001", 0, "18553177dbf83fb2cb6c8edcbb174183", 99543093},
{"resmap.002", 0, "e7dc85884a2417e2eff9de0c63dd65fa", 7630},
{"ressci.002", 0, "3c8d627c555b0e3e4f1d9955bc0f0df4", 94631127},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
#endif // ENABLE_SCI3_GAMES
@@ -1828,7 +1904,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "c2cf672c3f4251e7472d4542af3bf764", 933},
{"resource.000", 0, "8be56a3a88c065ee00c02c0e29199f3a", 14643},
{"resource.001", 0, "9e33566515b18bee7915db448063bba2", 871853},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Mixed-Up Fairy Tales - English DOS Floppy EGA (from omer_mor, bug report #3035350)
@@ -1839,7 +1915,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "4db83250f821607b634c99d663cae74a", 663713},
{"resource.003", 0, "509b2467ba779100d5933ed51a9ae32f", 560255},
{"resource.004", 0, "93afc85d5ffa60ea555d6cc336d22c03", 651109},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Mixed-Up Fairy Tales v1.000 - English DOS (supplied by markcoolio in bug report #2723791)
@@ -1851,7 +1927,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "6767f8c8585f617aaa91d442f41ae714", 1032989},
{"resource.003", 0, "b1288e0821ee358d1ffe877e5900c8ec", 1047565},
{"resource.004", 0, "f79daa70390d73746742ffcfc3dc4471", 937580},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Mixed-Up Fairy Tales - English DOS Floppy (from jvprat)
@@ -1862,7 +1938,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "49c8f7dcd9989e4491a93554bec325b0", 238019},
{"resource.002", 0, "564f516d991032e781492592a4eaa275", 1414142},
{"resource.003", 0, "dd6cef0c592eadb7e6be9a25307c57a2", 1344719},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Mixed-Up Mother Goose - English Amiga (from www.back2roots.org)
@@ -1872,7 +1948,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "4aa28ac93fae03cf854594da13d9229c", 2700},
{"resource.001", 0, "fb552ae550ca1dac19ed8f6a3767612d", 262885},
{"resource.002", 0, "fb552ae550ca1dac19ed8f6a3767612d", 817191},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Mixed-Up Mother Goose - English DOS Floppy EGA (from omer_mor, bug report #3035354)
@@ -1880,7 +1956,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "3490f85dab47e504c41b7eb3312e285e", 2598},
{"resource.001", 0, "d893892d62b3f061357291d66775e360", 239906},
{"resource.002", 0, "d893892d62b3f061357291d66775e360", 719398},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Mixed-Up Mother Goose v2.000 - English DOS Floppy (supplied by markcoolio in bug report #2723795)
@@ -1888,7 +1964,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"mothergoose", "", {
{"resource.map", 0, "52aae15e493cafd1da7e1c9b657a5bb9", 7026},
{"resource.000", 0, "b7ecd8ae9e254e80310b5a668b276e6e", 2948975},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Mixed-Up Mother Goose - English DOS CD (from jvprat)
@@ -1897,7 +1973,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"mothergoose", "CD", {
{"resource.map", 0, "1c7f311b0a2c927b2fbe81ae341fb2f6", 5790},
{"resource.001", 0, "5a0ed1d745855148364de1b3be099bac", 4369438},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Mixed-Up Mother Goose - English Windows Interactive Demo
@@ -1905,9 +1981,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"mothergoose", "Demo", {
{"resource.map", 0, "87f9dc1cafc4d4fa835fb2f00cf3a6ef", 4560},
{"resource.001", 0, "5a0ed1d745855148364de1b3be099bac", 2070072},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH },
+
+ // Mixed-Up Mother Goose - FM-Towns (supplied by abevi in bug report #3038720)
+ {"mothergoose", "", {
+ {"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772},
+ {"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO_NONE },
#ifdef ENABLE_SCI32
// Mixed-Up Mother Goose Deluxe - English Windows/DOS CD (supplied by markcoolio in bug report #2723810)
@@ -1915,7 +1997,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"mothergoosehires", "", {
{"resource.map", 0, "5159a1578c4306bfe070a3e4d8c2e1d3", 4741},
{"resource.000", 0, "1926925c95d82f0999590e93b02887c5", 15150768},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Mixed-Up Mother Goose Deluxe - Multilingual Windows CD (English/French/German/Spanish)
@@ -1923,7 +2005,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"mothergoosehires", "", {
{"resmap.000", 0, "ef611af561898dcfea87846919ebf3eb", 4969},
{"ressci.000", 0, "227685bc59d90821978d330713e44a7a", 17205800},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
#endif // ENABLE_SCI32
@@ -1932,7 +2014,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"msastrochicken", "", {
{"resource.map", 0, "5b457cbe5042f557e5b610148171f6c0", 1158},
{"resource.001", 0, "453ea81ef66a50cbe33ce06302afe47f", 229737},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
@@ -1953,7 +2035,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 77901360},
{"resmap.007", 0, "afbd16ea77869a720afa1c5371de107d", 7972},
//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Phantasmagoria - English DOS Demo
@@ -1961,7 +2043,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"phantasmagoria", "Demo", {
{"resmap.001", 0, "416138651ea828219ca454cae18341a3", 11518},
{"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#ifdef ENABLE_SCI3_GAMES
@@ -1978,7 +2060,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.004", 0, "53f457cddb0dffc056593905c4cbb989", 42447131},
{"resmap.005", 0, "8bd5ceeedcbe16dfe55d1b90dcd4be84", 1942},
{"ressci.005", 0, "05f9fe2bee749659acb3cd2c90252fc5", 67905112},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
#endif // ENABLE_SCI3_GAMES
@@ -1989,7 +2071,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pepper", "", {
{"resource.map", 0, "72726dc81c1b4c1110c486be77369bc8", 5179},
{"resource.000", 0, "670d0c53622429f4b11275caf7f8d292", 5459574},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Pepper - English DOS Non-Interactive Demo
@@ -1997,7 +2079,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pepper", "Demo", {
{"resource.map", 0, "379bb4fb896630b14f2d91ed21e36ba1", 984},
{"resource.000", 0, "118f6c31a93ec7fd9a231c61125229e3", 645494},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Pepper - English DOS/Windows Interactive Demo
@@ -2005,7 +2087,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pepper", "Demo", {
{"resource.map", 0, "975e8df76106a5c13d12ab674f906a02", 2514},
{"resource.000", 0, "e6a918a2dd7a4bcecd8fb389f43287c2", 1698164},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Pepper - English DOS Interactive Demo
@@ -2013,7 +2095,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pepper", "Demo", {
{"resource.map", 0, "9c9b7b900651a370dd3fb38d478b1798", 2524},
{"resource.000", 0, "e6a918a2dd7a4bcecd8fb389f43287c2", 1713544},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Police Quest 1 VGA Remake - English DOS (from the Police Quest Collection)
@@ -2021,7 +2103,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pq1sci", "VGA Remake", {
{"resource.map", 0, "35efa814fb994b1cbdac9611e401da67", 5013},
{"resource.000", 0, "e0d5ddf34eda903a38f0837e2aa7145b", 6401433},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 2 - English Amiga (from www.back2roots.org)
@@ -2032,7 +2114,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "523db0c07f1da2a822c2c39ee0482544", 179334},
{"resource.002", 0, "499737c21a28ac026e11ab817100d610", 511099},
{"resource.003", 0, "e008f5d6e2a7c4d4a0da0173e4fa8f8b", 553970},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Police Quest 2 - English DOS Non-Interactive Demo
@@ -2040,7 +2122,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pq2", "Demo", {
{"resource.map", 0, "8b77d0d4650c2052b356cece28294b58", 576},
{"resource.001", 0, "376ef6d6eaaeed66e1424bd219c4b9ab", 215398},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Police Quest 2 - English DOS (provided by richiefs in bug report #2670691)
@@ -2053,7 +2135,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "77f02def3094af804fd2371db25b7100", 342149},
{"resource.005", 0, "77f02def3094af804fd2371db25b7100", 349899},
{"resource.006", 0, "77f02def3094af804fd2371db25b7100", 354991},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 2 - English DOS (from the Police Quest Collection)
@@ -2063,7 +2145,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "77f02def3094af804fd2371db25b7100", 509525},
{"resource.002", 0, "77f02def3094af804fd2371db25b7100", 546000},
{"resource.003", 0, "77f02def3094af804fd2371db25b7100", 591851},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 2 - English DOS (from FRG)
@@ -2073,19 +2155,27 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "77f02def3094af804fd2371db25b7100", 509760},
{"resource.002", 0, "77f02def3094af804fd2371db25b7100", 542897},
{"resource.003", 0, "77f02def3094af804fd2371db25b7100", 586857},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // Police Quest 2 English DOS 1.001.006 (supplied by merkur-kun in bug report #3028479)
+ {"pq2", "", {
+ {"resource.map", 0, "8e1161c684b342742d30f938a4839a4b", 4518},
+ {"resource.001", 0, "77f02def3094af804fd2371db25b7100", 506563},
+ {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 541261},
+ {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 587511},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Police Quest 2 - Japanese PC-98
+ // Police Quest 2 - Japanese PC-98 (also includes english language)
// SCI interpreter version unknown
{"pq2", "", {
{"resource.map", 0, "883804c616dca1d82373bf9fda3a71d2", 4656},
{"resource.001", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 669319},
{"resource.002", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 637662},
{"resource.003", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 684395},
- {NULL, 0, NULL, 0}},
- Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH
- }, // also includes english language
+ AD_LISTEND},
+ Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Police Quest 3 - English Amiga
// Executable scanning reports "1.004.024"
@@ -2097,10 +2187,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "f7044bb08a1fcbe5077791ed8d4996f0", 691207},
{"resource.003", 0, "630bfa65beb05f743552704ac2899dae", 759891},
{"resource.004", 0, "7b229fbdf30d670d0728cede3e984a7e", 838663},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
- // Police Quest 3 - German Amiga
+ // Police Quest 3 - German Amiga (also includes english language)
// Executable scanning reports "1.004.024"
// SCI interpreter version 1.000.784
{"pq3", "", {
@@ -2111,9 +2201,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "87361c17fd863b58f98828de68770279", 682288},
{"resource.004", 0, "6258d5dd85898d8e218eb8113ebc9059", 722738},
{"resource.005", 0, "6258d5dd85898d8e218eb8113ebc9059", 704485},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Police Quest 3 - English DOS (from the Police Quest Collection)
// Executable scanning reports "T.A00.178", VERSION file reports "1.00"
@@ -2125,9 +2214,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "c18e0d408e4f4f40365d42aa15931f67", 1153561},
{"resource.003", 0, "8791b9eef53edf77c2dac950142221d3", 1159791},
{"resource.004", 0, "1b91e891a3c60a941dac0eecdf83375b", 1143606},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 3 - English DOS Non-Interactive Demo
// Executable scanning reports "T.A00.052"
@@ -2136,11 +2224,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "ec8e58e7663ae5173853abf6c76b52bb", 867},
{"resource.000", 0, "277f97771f7a6d89677141f02da313d6", 65150},
{"resource.001", 0, "5c5a551b6c86cce2ee75becb90e0b586", 624411},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Police Quest 3 - German DOS (supplied by markcoolio in bug report #2723837)
+ // Police Quest 3 - German DOS (supplied by markcoolio in bug report #2723837, also includes english language)
// Executable scanning reports "T.A00.178"
// SCI interpreter version 1.000.510
{"pq3", "", {
@@ -2150,18 +2237,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "cce99b96a578b62ff6cebdae8d122feb", 1179358},
{"resource.003", 0, "4836f460f4cfc8de61e2df4c45775504", 1180956},
{"resource.004", 0, "0c3eb84b9755852d9e795e0d5c9373c7", 1171760},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Police Quest 4 - English DOS Non-Interactive Demo (from FRG)
// SCI interpreter version 1.001.096
{"pq4", "Demo", {
{"resource.map", 0, "be56f87a1c4a13062a30a362df860c2f", 1472},
{"resource.000", 0, "527d5684016e6816157cd15d9071b11b", 1121310},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
// Police Quest 4 - English DOS (from the Police Quest Collection)
@@ -2169,45 +2254,40 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"pq4", "", {
{"resource.map", 0, "379dfe80ed6bd16c47e4b950c4722eac", 11374},
{"resource.000", 0, "fd316a09b628b7032248139003369022", 18841068},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 4 - English DOS
// SCI interpreter version 2.000.000 (a guess?)
{"pq4", "", {
{"resource.map", 0, "aed9643158ccf01b71f359db33137f82", 9895},
{"resource.000", 0, "da383857b3be1e4514daeba2524359e0", 15141432},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 4 - French DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 2.000.000
{"pq4", "", {
{"resource.map", 0, "008030846edcc7c5c7a812c7f4ae4ceb", 9256},
{"resource.000", 0, "6ba98bd2e436739d87ecd2a9b99cabb4", 14730153},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest 4 - German DOS (supplied by markcoolio in bug report #2723840)
// SCI interpreter version 2.000.000 (a guess?)
{"pq4", "", {
{"resource.map", 0, "2393ee728ab930b2762cb5889f9b5aff", 9256},
{"resource.000", 0, "6ba98bd2e436739d87ecd2a9b99cabb4", 14730155},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Police Quest: SWAT - English DOS/Windows Demo (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "0.001.200"
{"pqswat", "Demo", {
{"resource.map", 0, "8c96733ef94c21526792f7ca4e3f2120", 1648},
{"resource.000", 0, "d8892f1b8c56c8f7704325460f49b300", 3676175},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Police Quest: SWAT - English Windows (from the Police Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
@@ -2221,9 +2301,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.003", 0, "00a755e917c442ca8cf1a1bea689e6fb", 45073980},
{"resmap.004", 0, "4228038906f041623e65789500b22285", 6835},
{"ressci.004", 0, "b7e619e6ecf62fe65d5116a3a422e5f0", 46223872},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
#endif // ENABLE_SCI32
// Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by merkur in bug report #2718784)
@@ -2235,9 +2314,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "439ba9b6dde216e6eb97ef3a9830fbe4", 646869},
{"resource.003", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 642203},
{"resource.004", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 641688},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by markcoolio in bug report #2723843)
// Executable scanning reports "0.000.566"
@@ -2251,31 +2329,36 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "7288ed6d5da89b7a80b4af3897a7963a", 271185},
{"resource.006", 0, "69366c2a2f99917199fe1b60a4fee19d", 267852},
{"resource.007", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 272747},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
+ // Quest for Glory 1 / Hero's Quest - English DOS Demo
+ // Executable scanning reports "0.000.685"
+ {"qfg1", "Demo", {
+ {"resource.map", 0, "df34c758cbb9026da175793ff686b0e6", 882},
+ {"resource.001", 0, "73fbaafdd313b39aeedb80fbf85ecef1", 389884},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Quest for Glory 1 - Japanese PC-98 5.25" Floppy
+ // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes english language)
// Executable scanning reports "S.old.201"
{"qfg1", "8 Colors", {
{"resource.map", 0, "5cbeb95dd2a4b7cb242b415cc6ec1c47", 6444},
{"resource.001", 0, "a21451ef6fa8179bd4b22c4950004c44", 859959},
{"resource.002", 0, "a21451ef6fa8179bd4b22c4950004c44", 1136968},
{"resource.003", 0, "a21451ef6fa8179bd4b22c4950004c44", 769897},
- {NULL, 0, NULL, 0}},
- Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Quest for Glory 1 - Japanese PC-98 5.25" Floppy
+ // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes english language)
// Executable scanning reports "S.old.201"
{"qfg1", "16 Colors", {
{"resource.map", 0, "3ecaba33bf77cb434067a0b8aee15097", 6444},
{"resource.001", 0, "a21451ef6fa8179bd4b22c4950004c44", 864754},
{"resource.002", 0, "a21451ef6fa8179bd4b22c4950004c44", 1147121},
{"resource.003", 0, "a21451ef6fa8179bd4b22c4950004c44", 777575},
- {NULL, 0, NULL, 0}},
- Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Quest for Glory 1 - English Amiga
// Executable scanning reports "1.002.020"
@@ -2288,9 +2371,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "16cd4414c37ae3bb6d6da33dce8e25e8", 654096},
{"resource.004", 0, "16cd4414c37ae3bb6d6da33dce8e25e8", 689124},
{"resource.005", 0, "5f3386ef2f2b1254e4a066f5d9027324", 609529},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Quest for Glory 1 (from abevi, bug report #2612718)
{"qfg1", "", {
@@ -2300,9 +2382,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635561},
{"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640502},
{"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644575},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Quest for Glory 1 - English DOS
// SCI interpreter version 0.000.629
@@ -2313,36 +2394,32 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "05ddce5f437a516b89ede2438fac09d8", 635734},
{"resource.003", 0, "951299a82a8134ed12c5c18118d45c2f", 640483},
{"resource.004", 0, "951299a82a8134ed12c5c18118d45c2f", 644443},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 1 VGA Remake - English DOS
// Executable scanning reports "2.000.411"
{"qfg1vga", "VGA Remake", {
{"resource.map", 0, "a731fb6c9c0b282443f7027bc8694d4c", 8469},
{"resource.000", 0, "ecace1a2771846b1a8aa1afdd44111a0", 6570147},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 1 VGA Remake - English DOS Non-Interactive Demo (from FRG)
// SCI interpreter version 1.001.029
{"qfg1vga", "VGA Remake, Demo", {
{"resource.map", 0, "ac0257051c95a59c0cdc0be24d9b11fa", 729},
{"resource.000", 0, "ec6f5cf369054dd3e5392995e9975b9e", 768218},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Quest for Glory 1 VGA Remake - English Macintosh Floppy
// VERSION file reports "2.0"
{"qfg1vga", "VGA Remake", {
{"Data1", 0, "14f26bc75f24bb1ecc94532df17b5371", 1768155},
{"Data2", 0, "a7aee8bd46fc9cef7fd3bea93ef173e0", 6586422},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NOSPEECH },
// Quest for Glory 2 - English Amiga
// Executable scanning reports "1.003.004"
@@ -2357,9 +2434,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "a77d2576c842b2b06da57d4ac8fc51c0", 579975},
{"resource.006", 0, "ccf5dba33e5cab6d5872838c0f8db44c", 500039},
{"resource.007", 0, "4c9fc1587545879295cb9627f56a2cb8", 575056},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Quest for Glory 2 - English (from FRG)
// Executable scanning reports "1.000.072"
@@ -2370,9 +2446,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "df137dc7869cab07e1149ba2333c815c", 790750},
{"resource.003", 0, "b192607c42f6960ecdf2ad2e4f90e9bc", 972804},
{"resource.004", 0, "cd2de58e27665d5853530de93fae7cd6", 983617},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 2 - English DOS
// Executable scanning reports "1.000.072"
@@ -2386,54 +2461,48 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "df137dc7869cab07e1149ba2333c815c", 478688},
{"resource.006", 0, "b1944bd664ddbd2859cdaa0c4a0d6281", 507489},
{"resource.007", 0, "cd2de58e27665d5853530de93fae7cd6", 490794},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 2 - English DOS Non-Interactive Demo
// Executable scanning reports "1.000.046"
{"qfg2", "Demo", {
{"resource.map", 0, "e75eb86bdd517b3ef709058249986a87", 906},
{"resource.001", 0, "9b098f9e1008abe30e56c93b896494e6", 362123},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Quest for Glory 3 - English DOS Non-Interactive Demo (from FRG)
// Executable scanning reports "1.001.021", VERSION file reports "1.000, 0.001.059, 6.12.92"
{"qfg3", "Demo", {
{"resource.map", 0, "fd71de9b588a45f085317caacf050e91", 687},
{"resource.000", 0, "b6c69bf6c18bf177492249fe81fc6a6d", 648702},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Quest for Glory 3 - English DOS
// SCI interpreter version 1.001.050
{"qfg3", "", {
{"resource.map", 0, "19e2bf9b693932b5e2bb59b9f9ab86c9", 5958},
{"resource.000", 0, "6178ad2e83e58e4671ca03315f7a6498", 5868000},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 3 - English DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 1.001.050
{"qfg3", "", {
{"resource.map", 0, "62c185d190363d7df06330fa0cc45b36", 5958},
{"resource.000", 0, "6178ad2e83e58e4671ca03315f7a6498", 5867442},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 3 - German DOS (supplied by markcoolio in bug report #2723846)
// Executable scanning reports "L.rry.083"
{"qfg3", "", {
{"resource.map", 0, "19e2bf9b693932b5e2bb59b9f9ab86c9", 5958},
{"resource.000", 0, "6178ad2e83e58e4671ca03315f7a6498", 5868042},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 3 - Spanish DOS CD (from jvprat)
// Executable scanning reports "L.rry.083", VERSION file reports "1.000.000, June 30, 1994"
@@ -2441,18 +2510,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "10809197c33a5e62819311d8a2f73f85", 5978},
{"resource.000", 0, "ba7ac86155e4c531e46cd73c86daa80a", 5884098},
{"resource.msg", 0, "a63974730d294dec0bea10057c36e506", 256014},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE },
// Quest for Glory 4 - English DOS Non-Interactive Demo (from FRG)
// SCI interpreter version 1.001.069 (just a guess)
{"qfg4", "Demo", {
{"resource.map", 0, "1ba7c7ae1efb315326d45cb931569b1b", 922},
{"resource.000", 0, "41ba03f0b188b029132daa3ece0d3e14", 623154},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
// Quest for Glory 4 1.1 Floppy - English DOS (supplied by markcool in bug report #2723852)
@@ -2460,36 +2527,32 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"qfg4", "", {
{"resource.map", 0, "685bdb1ed47bbbb0e5e25db392da83ce", 9301},
{"resource.000", 0, "f64fd6aa3977939a86ff30783dd677e1", 11004993},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 4 1.1 Floppy - English DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 2.000.000
{"qfg4", "", {
{"resource.map", 0, "d10a4cc177d2091d744e2ad8c049b0ae", 9295},
{"resource.000", 0, "f64fd6aa3977939a86ff30783dd677e1", 11003589},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 4 1.1 Floppy - German DOS (supplied by markcool in bug report #2723850)
// Executable scanning reports "2.000.000", VERSION file reports "1.1"
{"qfg4", "", {
{"resource.map", 0, "9e0abba8746f40565bc7eb5720522ecd", 9301},
{"resource.000", 0, "57f22cdc54eeb35fce1f26b31b5c3ee1", 11076197},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Quest for Glory 4 - English DOS/Windows (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
{"qfg4", "", {
{"resource.map", 0, "aba367f2102e81782d961b14fbe3d630", 10246},
{"resource.000", 0, "263dce4aa34c49d3ad29bec889007b1c", 11571394},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
#endif
@@ -2498,9 +2561,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "1846b57fe84774be72f7c50ab3c90df0", 2256126},
{"resource.map", 0, "21f85414124dc23e54544a5536dc35cd", 4044},
{"resource.msg", 0, "c44f51fb955eae266fecf360ebcd5ad2", 1132},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
// RAMA - English DOS/Windows Demo
@@ -2508,9 +2570,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"rama", "Demo", {
{"resmap.001", 0, "775304e9b2a545156be4d94209550094", 1393},
{"ressci.001", 0, "259437fd75fdf51e8207fda8c01fa4fd", 2334384},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NONE },
#ifdef ENABLE_SCI3_GAMES
// RAMA - English Windows (from jvprat)
@@ -2522,9 +2583,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.002", 0, "2a68edd064e5e4937b5e9c74b38f2082", 128562138},
{"resmap.003", 0, "31ef4c0621711585d031f0ae81707251", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6860492},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE },
// RAMA - English Windows (from Quietust, in bug report #2850645)
{"rama", "", {
@@ -2534,18 +2594,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.002", 0, "2a68edd064e5e4937b5e9c74b38f2082", 128572432},
{"resmap.003", 0, "48841e4b84ef1b98b48d43566fda9e13", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6870356},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE },
// RAMA - Italian Windows CD (from glorifindel)
// SCI interpreter version 3.000.000 (a guess?)
{"rama", "", {
{"ressci.001", 0, "2a68edd064e5e4937b5e9c74b38f2082", 70611091},
{"resmap.001", 0, "70ba2ff04a2b7fb2c52420ba7fbd47c2", 8338},
- {NULL, 0, NULL, 0}},
- Common::IT_ITA, Common::kPlatformWindows, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::IT_ITA, Common::kPlatformWindows, 0, GUIO_NONE },
#endif // ENABLE_SCI3_GAMES
// Shivers - English Windows (from jvprat)
@@ -2553,26 +2611,23 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"shivers", "", {
{"resmap.000", 0, "f2ead37749ed8f6535a2445a7d05a0cc", 46525},
{"ressci.000", 0, "4294c6d7510935f2e0a52e302073c951", 262654836},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE },
// Shivers - German Windows (from Tobis87)
{"shivers", "", {
{"resmap.000", 0, "f483d0a1f78334c18052e92785c3086e", 46537},
{"ressci.000", 0, "6751b144671e2deed919eb9d284b07eb", 262390692},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformWindows, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformWindows, 0, GUIO_NONE },
// Shivers - English Windows Demo
// Executable scanning reports "2.100.002"
{"shivers", "Demo", {
{"resmap.000", 0, "d9e0bc5eddefcbe47f528760085d8927", 1186},
{"ressci.000", 0, "3a93c6340b54e07e65d0e5583354d186", 10505469},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NONE },
#ifdef ENABLE_SCI3_GAMES
@@ -2581,16 +2636,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"shivers2", "Demo", {
{"resmap.000", 0, "d8659188b84beaef076bd869837cd530", 634},
{"ressci.000", 0, "7fbac0807a044c9543e8ac376d200e59", 4925003},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NONE },
// Shivers 2 - English Windows (from abevi)
// VERSION.TXT Version 1.0 (3/25/97)
{"shivers2", "", {
{"ressci.001", 0, "a79d03d6eb75be0a79324f14e3d2ace4", 95346793},
{"resmap.001", 0, "a4804d436d90c4ec2e46b537f5e954db", 6268},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
#endif //ENABLE_SCI3_GAMES
@@ -2603,9 +2657,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "61b4f74039399e5aa1e737b16d0fc023", 1409},
{"resource.msg", 0, "1aeafe2b495de288d002109650b66614", 1364},
{"resource.000", 0, "8e10d4f05c1fd9f883384fa38a898489", 377394},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Space Quest 1 VGA Remake - English Amiga (from www.back2roots.org)
// SCI interpreter version 1.000.510 (just a guess)
@@ -2617,9 +2670,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "2588c1c2ca8b9bed0e3411948c0856a9", 839302},
{"resource.004", 0, "b25a1539c71701f7715f738c5037e9a6", 775515},
{"resource.005", 0, "640ffe1a9acde392cc33cc1b1a528328", 806324},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
// Space Quest 1 VGA Remake - English DOS (from the Space Quest Collection)
// Executable scanning reports "T.A00.081", VERSION file reports "2.000"
@@ -2631,9 +2683,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "a9e847c687529481f3a22b9bf01f45f7", 1169831},
{"resource.003", 0, "c47600e50c6fc591957ae0c5020ee7b8", 1213262},
{"resource.004", 0, "e19ea4ad131472f9238590f2e1d40289", 1203051},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 1 VGA Remake - English Mac (from Fingolfin)
{"sq1sci", "VGA Remake", {
@@ -2643,18 +2694,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "96860704f7a07ecc10bef223b4b2f153", 1273992},
{"resource.003", 0, "ae46e195e66df5a131917f0aa80b5669", 1242794},
{"resource.004", 0, "91d58a9eb2187c38424990afe4c12bc6", 1250949},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH },
// Space Quest 1 VGA Remake - English Non-Interactive Demo (from FRG)
// SCI interpreter version 1.000.181
{"sq1sci", "VGA Remake, Demo", {
{"resource.map", 0, "5af709ac5e0e923e0b8174f49978c30e", 636},
{"resource.001", 0, "fd99ea43f57576ded7c86036996346cf", 507642},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Space Quest 1 VGA Remake - Spanish DOS Floppy (from jvprat)
// Executable scanning reports "T.A00.081", VERSION file reports "2.000"
@@ -2667,9 +2716,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "8c22700a02991b763f512f837636b3ca", 1211307},
{"resource.004", 0, "9b78228ad4f9f335fedf74f1812dcfca", 513325},
{"resource.005", 0, "7d4ebcb745c0bf8fc42e4013f52ecd49", 1101812},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 3 - English Amiga (from www.back2roots.org)
// SCI interpreter version 0.000.453 (just a guess)
@@ -2679,10 +2727,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.002", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 754432},
{"resource.003", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 746496},
{"resource.004", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 761984},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
- // Space Quest 3 - German Amiga
+ // Space Quest 3 - German Amiga (also includes english language)
// Executable scanning reports "1.004.006"
// SCI interpreter version 0.000.453 (just a guess)
{"sq3", "", {
@@ -2692,15 +2740,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "6d8f34090503ce937e7dbef6cb6cdb6a", 712374},
{"resource.004", 0, "6d8f34090503ce937e7dbef6cb6cdb6a", 545053},
{"resource.005", 0, "6d8f34090503ce937e7dbef6cb6cdb6a", 687507},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Space Quest 3 - English DOS Non-Interactive Demo
// SCI interpreter version 0.000.453
{"sq3", "Demo", {
{"resource.map", 0, "ec66ac2b1ce58b2575ba00b65058de1a", 612},
{"resource.001", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 180245},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
// Space Quest 3 - English DOS (provided by richiefs in bug report #2670691)
@@ -2710,7 +2758,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 485158},
{"resource.002", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 720244},
{"resource.003", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 688367},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 3 - English DOS (from the Space Quest Collection)
@@ -2720,7 +2768,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 490247},
{"resource.002", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 715777},
{"resource.003", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 703370},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 3 - English DOS (from abevi, bug report #2612718)
@@ -2732,7 +2780,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 321222},
{"resource.005", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 328278},
{"resource.006", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 356702},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 3 - English Mac (from Fingolfin)
@@ -2741,10 +2789,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "0d8dfe42683b46f3131823233a91ce6a", 771917},
{"resource.002", 0, "0d8dfe42683b46f3131823233a91ce6a", 794072},
{"resource.003", 0, "0d8dfe42683b46f3131823233a91ce6a", 776536},
- {NULL, 0, NULL, 0}},
+ AD_LISTEND},
Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH },
- // Space Quest 3 - German DOS (from Tobis87)
+ // Space Quest 3 - German DOS (from Tobis87, also includes english language)
// SCI interpreter version 0.000.453 (?)
{"sq3", "", {
{"resource.map", 0, "4965c78b5eff50d5e4148ce114594ba8", 7584},
@@ -2755,18 +2803,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.005", 0, "9107c2aa5398e28b5c5406df13491f85", 322107},
{"resource.006", 0, "9107c2aa5398e28b5c5406df13491f85", 320643},
{"resource.007", 0, "9107c2aa5398e28b5c5406df13491f85", 344287},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Space Quest 3 v1.052 - German DOS (supplied by markcoolio in bug report #2723860)
+ // Space Quest 3 v1.052 - German DOS (supplied by markcoolio in bug report #2723860, also includes english language)
// Executable scanning reports "S.old.114"
{"sq3", "", {
{"resource.map", 0, "f0dd735098c254f584878649c6f08dbc", 5154},
{"resource.001", 0, "9107c2aa5398e28b5c5406df13491f85", 567245},
{"resource.002", 0, "9107c2aa5398e28b5c5406df13491f85", 596768},
{"resource.003", 0, "9107c2aa5398e28b5c5406df13491f85", 693573},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Space Quest 4 - English Amiga
// Executable scanning reports "1.004.024"
@@ -2780,11 +2828,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "1887ed88bb34ae7238650e8f77f26315", 798226},
{"resource.005", 0, "3540d1cc84d674cf4b2c898b88a3b563", 790296},
{"resource.006", 0, "ade814bc4d56244c156d9e9bcfebbc11", 664085},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH },
- // Space Quest 4 - German Amiga (from www.back2roots.org)
+ // Space Quest 4 - German Amiga (from www.back2roots.org, also includes english language)
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
{"resource.map", 0, "79641c0d43408e33c251a1d494d2575e", 6252},
@@ -2795,19 +2842,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "99c6a017da5e769a3b427ca52c8a564f", 824601},
{"resource.005", 0, "10ee1709e6559c724676d058199b75b5", 818745},
{"resource.006", 0, "67fb188b191d88efe8414af6ea297b93", 672675},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformAmiga, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Space Quest 4 - English DOS
+#if 0
+ // Space Quest 4 - English DOS - THIS VERSION IS PIRATED/CRACKED AND REPACKAGED =DO NOT RE-ADD=
// Executable scanning reports "1.000.753"
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
{"resource.map", 0, "a18088c8aceb06025dbc945f29e02935", 5124},
{"resource.000", 0, "e1f46832cd2458796028e054a0466031", 5502009},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+#endif
// Space Quest 4 - English DOS
// Executable scanning reports "1.000.753"
@@ -2815,9 +2862,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"sq4", "", {
{"resource.map", 0, "71ccf4f82ac4efb588731acfb7bf2603", 5646},
{"resource.000", 0, "e1f46832cd2458796028e054a0466031", 933928},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 4 1.052 - English DOS Floppy (supplied by markcoolio in bug report #2723865)
// Executable scanning reports "1.000.753"
@@ -2830,9 +2876,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "96fa33d89d838bc3f671c5b953e7a896", 1240130},
{"resource.004", 0, "ff9c87da3bc53473fdee8b9d3edbc93c", 1200631},
{"resource.005", 0, "e33019ac19f755ae33fbf49b4fc9066c", 1053294},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 4 1.000 - English DOS Floppy (from abevi, bug report #2612718)
{"sq4", "", {
@@ -2843,11 +2888,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "47ee647b5b12232d27e63cc627c25899", 1321146},
{"resource.004", 0, "c06350184a490c10eb4585fff0aa3192", 1254368},
{"resource.005", 0, "b8d6efbd3235329bfe844c794097b2c9", 1098717},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Space Quest 4 - German DOS (from Tobis87)
+ // Space Quest 4 - German DOS (from Tobis87, also includes english language)
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
{"resource.map", 0, "71715e775e3791178d606cfe6c7e1fb9", 6339},
@@ -2858,11 +2902,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "b8d6efbd3235329bfe844c794097b2c9", 1064761},
{"resource.005", 0, "47ee647b5b12232d27e63cc627c25899", 1156765},
{"resource.006", 0, "dfb023e4e2a1e7a00fa18f9ede72a91b", 924059},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Space Quest 4 - Italian DOS Floppy (from glorifindel)
+ // Space Quest 4 - Italian DOS Floppy (from glorifindel, also includes english language)
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
{"resource.map", 0, "e753dfa96d68dd95f84f6cd80479a35e", 6135},
@@ -2872,42 +2915,38 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "5289000399d503b59da9e23129256f1a", 1325546},
{"resource.004", 0, "4277c61bed40a50dadc4b5a344520af2", 1251000},
{"resource.005", 0, "5f885abd335978e2fd4e5f886d7676c8", 1102880},
- {NULL, 0, NULL, 0}},
- Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::IT_ITA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Space Quest 4 - Japanese PC-98 5.25" Floppy
+ // Space Quest 4 - Japanese PC-98 5.25" Floppy (also includes english language)
// SCI interpreter version 1.000.1068
{"sq4", "", {
{"resource.map", 0, "ca7bba01019222b6f3e54e9051067a99", 5283},
{"resource.000", 0, "161d719f38ed98d33f058a8cf3dc09c3", 952909},
{"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088},
{"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249},
- {NULL, 0, NULL, 0}},
- Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Space Quest 4 - Japanese PC-98 5.25" Floppy
+ // Space Quest 4 - Japanese PC-98 5.25" Floppy (also includes english language)
// SCI interpreter version 1.000.1068
{"sq4", "", {
{"resource.map", 0, "ca7bba01019222b6f3e54e9051067a99", 5283},
{"resource.000", 0, "161d719f38ed98d33f058a8cf3dc09c3", 952909},
{"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088},
{"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC98, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Space Quest 4 - English DOS CD (from the Space Quest Collection)
// Executable scanning reports "1.001.064", VERSION file reports "1.0"
{"sq4", "CD", {
{"resource.map", 0, "ed90a8e3ccc53af6633ff6ab58392bae", 7054},
{"resource.000", 0, "63247e3901ab8963d4eece73747832e0", 5157378},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
- // Space Quest 4 - Spanish DOS CD (from jvprat)
+ // Space Quest 4 - Spanish DOS CD (from jvprat, is still text only, not talkie, also includes english language)
// Executable scanning reports "1.SQ4.057", VERSION file reports "1.000"
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
@@ -2918,11 +2957,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "42a307941edeb1a3be31daeb2e4be90b", 1319306},
{"resource.004", 0, "776fba81c110d1908776232cbe190e20", 1253752},
{"resource.005", 0, "55fae26c2a92f16ef72c1e216e827c0f", 1098328},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NONE },
- // Space Quest 4 - Spanish DOS Floppy (from jvprat)
+ // Space Quest 4 - Spanish DOS Floppy (from jvprat, also includes english language)
// Executable scanning reports "1.SQ4.056", VERSION file reports "1.000"
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
@@ -2931,11 +2969,10 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.001", 0, "567608beb69d9dffdb42a8f39cb11a5e", 994323},
{"resource.002", 0, "74c62fa2146ff3b3b2ea2b3fb95b9af9", 1140801},
{"resource.003", 0, "42a307941edeb1a3be31daeb2e4be90b", 1088408},
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Space Quest 4 1.000 - German DOS Floppy (supplied by markcoolio in bug report #2723862)
+ // Space Quest 4 1.000 - German DOS Floppy (supplied by markcoolio in bug report #2723862, also includes english language)
// Executable scanning reports "1.SQ4.030"
// SCI interpreter version 1.000.200 (just a guess)
{"sq4", "", {
@@ -2946,9 +2983,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "47ee647b5b12232d27e63cc627c25899", 1321146},
{"resource.004", 0, "c06350184a490c10eb4585fff0aa3192", 1254368},
{"resource.005", 0, "b8d6efbd3235329bfe844c794097b2c9", 1098717},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO_NOSPEECH },
// Space Quest 4 - English Macintosh
// Executable scanning reports "x.yyy.zzz"
@@ -2962,9 +2998,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.004", 0, "20fc54556ebfc737506288a1a32f7705", 364217},
{"resource.005", 0, "869d16cab6641c80b06f4dcee18f86bc", 1426228},
{"resource.006", 0, "91d23407bc0447a3722fbeb952d7edee", 1402451},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO_NOSPEECH },
// Space Quest 5 - English DOS (from the Space Quest Collection)
// Executable scanning reports "1.001.068", VERSION file reports "1.04"
@@ -2972,18 +3007,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "66317c12ac6e818d1f7c17e83c1d9819", 6143},
{"resource.000", 0, "4147edc5045e6d62998018b5614c58ec", 5496486},
{"resource.msg", 0, "bb8ad78793c26bdb3f77498b1d6515a9", 125988},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 5 - English DOS
// SCI interpreter version 1.001.067
{"sq5", "", {
{"resource.map", 0, "8bde0a9adb9a3e9aaa861826874c9834", 6473},
{"resource.000", 0, "f4a48705764544d7cc64a7bb22a610df", 6025184},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 5 v1.04 - German DOS (from Tobis87, updated information by markcool from bug reports #2723935 and #2724762)
// SCI interpreter version 1.001.068
@@ -2991,27 +3024,24 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "66317c12ac6e818d1f7c17e83c1d9819", 6143},
{"resource.000", 0, "4147edc5045e6d62998018b5614c58ec", 5496486},
{"resource.msg", 0, "7c71cfc36153cfe07b450423a51f7e68", 146282},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 5 v1.04 - French DOS (from Hkz, Included in Space Quest Collector's Edition, with chapters I-V)
{"sq5", "", {
{"resource.map", 0, "66317c12ac6e818d1f7c17e83c1d9819", 6143},
{"resource.000", 0, "4147edc5045e6d62998018b5614c58ec", 5496486},
{"resource.msg", 0, "877c42380320eb1db7dad83ccd261214", 140374},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// Space Quest 5 - Italian DOS Floppy (from glorifindel)
// SCI interpreter version 1.001.068 (just a guess)
{"sq5", "", {
{"resource.000", 0, "5040026519f37199f3616fb1d4704dff", 6047170},
{"resource.map", 0, "5b09168baa2f6e2e22787429b2d72f54", 6492},
- {NULL, 0, NULL, 0}},
- Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::IT_ITA, Common::kPlatformPC, 0, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
// Space Quest 6 - English DOS/Win3.11 CD (from the Space Quest Collection)
@@ -3019,45 +3049,40 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"sq6", "", {
{"resource.map", 0, "6dddfa3a8f3a3a513ec9dfdfae955005", 10528},
{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Space Quest 6 - English DOS/Win3.11 CD ver 1.11 (from FRG)
// SCI interpreter version 2.100.002 (just a guess)
{"sq6", "", {
{"resource.map", 0, "e0615d6e4e10e37ae42e6a2a95aaf145", 10528},
{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// Space Quest 6 - French DOS/Win3.11 CD (from French magazine Joystick - September 1997)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
{"sq6", "", {
{"resource.map", 0, "3c831625931d5079b73ae8c275f52c95", 10534},
{"resource.000", 0, "4195ca940f759424f62b90e262cc1737", 40932397},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NONE },
// Space Quest 6 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723884)
// SCI interpreter version 2.100.002 (just a guess)
{"sq6", "", {
{"resource.map", 0, "664d797415484f85c90b1b45aedc7686", 10534},
{"resource.000", 0, "ba87ba91e5bdabb4169dd0df75777722", 40933685},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NONE },
// Space Quest 6 - English DOS/Win3.11 Interactive Demo (from FRG)
// SCI interpreter version 2.100.002 (just a guess)
{"sq6", "Demo", {
{"resource.map", 0, "368f07b07433db3f819fa3fa0e5efee5", 2572},
{"resource.000", 0, "ab12724e078dea34b624e0d2a38dcd7c", 2272050},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#endif // ENABLE_SCI32
// The Island of Dr. Brain - English DOS CD (from jvprat)
@@ -3065,27 +3090,24 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"islandbrain", "", {
{"resource.map", 0, "2388efef8430b041b0f3b00b9050e4a2", 3281},
{"resource.000", 0, "b3acd9b9dd7fe53c4ee133ac9a1acfab", 2103560},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
// The Island of Dr. Brain - English DOS (from Quietust)
// Executable scanning reports "1.001.053", VERSION file reports "1.1 2.3.93"
{"islandbrain", "", {
{"resource.map", 0, "3c07da06bdd1689f9d07af78fb94d0ec", 3101},
{"resource.000", 0, "ecc686e0034fb4d41de077ac7167b3cf", 1947866},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
// The Island of Dr. Brain - English DOS Non-Interactive Demo
// SCI interpreter version 1.001.053 (just a guess)
{"islandbrain", "Demo", {
{"resource.map", 0, "a8e5ca8ed1996974afa59f4c45e06195", 986},
{"resource.000", 0, "b3acd9b9dd7fe53c4ee133ac9a1acfab", 586560},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
#ifdef ENABLE_SCI32
// Torin's Passage - English Windows Interactive Demo
@@ -3093,18 +3115,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"torin", "Demo", {
{"resmap.000", 0, "9a3e172cde9963d0a969f26469318cec", 3403},
{"ressci.000", 0, "db3e290481c35c3224e9602e71e4a1f1", 5073868},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH },
// Torin's Passage - English Windows
// SCI interpreter version 2.100.002 (just a guess)
{"torin", "", {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
- {NULL, 0, NULL, 0}},
- Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// Torin's Passage - Spanish Windows (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -3112,36 +3132,32 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
// TODO: depend on one of the patches?
- {NULL, 0, NULL, 0}},
- Common::ES_ESP, Common::kPlatformWindows, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::ES_ESP, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// Torin's Passage - French Windows
// SCI interpreter version 2.100.002 (just a guess)
{"torin", "", {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
- {NULL, 0, NULL, 0}},
- Common::FR_FRA, Common::kPlatformWindows, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// Torin's Passage - German Windows
// SCI interpreter version 2.100.002 (just a guess)
{"torin", "", {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
- {NULL, 0, NULL, 0}},
- Common::DE_DEU, Common::kPlatformWindows, 0, GUIO_NOSPEECH
- },
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
// Torin's Passage - Italian Windows CD (from glorifindel)
// SCI interpreter version 2.100.002 (just a guess)
{"torin", "", {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
- {NULL, 0, NULL, 0}},
- Common::IT_ITA, Common::kPlatformWindows, 0, GUIO_NONE
- },
+ AD_LISTEND},
+ Common::IT_ITA, Common::kPlatformWindows, 0, GUIO_NONE },
#endif // ENABLE_SCI32
// SCI Fanmade Games
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 315c86c56c..f99d412c64 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -216,9 +216,9 @@ SciVersion GameFeatures::detectSetCursorType() {
return _setCursorType;
}
-bool GameFeatures::autoDetectLofsType(int methodNum) {
+bool GameFeatures::autoDetectLofsType(Common::String gameSuperClassName, int methodNum) {
// Look up the script address
- reg_t addr = getDetectionAddr("Game", -1, methodNum);
+ reg_t addr = getDetectionAddr(gameSuperClassName.c_str(), -1, methodNum);
if (!addr.segment)
return false;
@@ -275,20 +275,35 @@ SciVersion GameFeatures::detectLofsType() {
return _lofsType;
}
+ // Find the "Game" object, super class of the actual game-object
+ const reg_t game = g_sci->getGameObject();
+ const Object *gameObject = _segMan->getObject(game);
+ reg_t gameSuperClass = NULL_REG;
+ if (gameObject) {
+ gameSuperClass = gameObject->getSuperClassSelector();
+ }
+
// Find a function of the game object which invokes lofsa/lofss
- reg_t gameClass = _segMan->findObjectByName("Game");
- const Object *obj = _segMan->getObject(gameClass);
bool found = false;
+ if (!gameSuperClass.isNull()) {
+ Common::String gameSuperClassName = _segMan->getObjectName(gameSuperClass);
+ const Object *gameSuperObject = _segMan->getObject(gameSuperClass);
- for (uint m = 0; m < obj->getMethodCount(); m++) {
- found = autoDetectLofsType(m);
-
- if (found)
- break;
+ if (gameSuperObject) {
+ for (uint m = 0; m < gameSuperObject->getMethodCount(); m++) {
+ found = autoDetectLofsType(gameSuperClassName, m);
+ if (found)
+ break;
+ }
+ } else {
+ warning("detectLofsType(): Could not get superclass object");
+ }
+ } else {
+ warning("detectLofsType(): Could not find superclass of game object");
}
if (!found) {
- warning("Lofs detection failed, taking an educated guess");
+ warning("detectLofsType(): failed, taking an educated guess");
if (getSciVersion() >= SCI_VERSION_1_MIDDLE)
_lofsType = SCI_VERSION_1_MIDDLE;
@@ -423,6 +438,8 @@ SciVersion GameFeatures::detectMessageFunctionType() {
Common::List<ResourceId> *resources = g_sci->getResMan()->listResources(kResourceTypeMessage, -1);
if (resources->empty()) {
+ delete resources;
+
// No messages found, so this doesn't really matter anyway...
_messageFunctionType = SCI_VERSION_1_1;
return _messageFunctionType;
@@ -430,6 +447,7 @@ SciVersion GameFeatures::detectMessageFunctionType() {
Resource *res = g_sci->getResMan()->findResource(*resources->begin(), false);
assert(res);
+ delete resources;
// Only v2 Message resources use the kGetMessage kernel function.
// v3-v5 use the kMessage kernel function.
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index 167c207437..755054fb25 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -103,7 +103,7 @@ public:
private:
reg_t getDetectionAddr(const Common::String &objName, Selector slc, int methodNum = -1);
- bool autoDetectLofsType(int methodNum);
+ bool autoDetectLofsType(Common::String gameSuperClassName, int methodNum);
bool autoDetectGfxFunctionsType(int methodNum = -1);
bool autoDetectSoundType();
bool autoDetectMoveCountType();
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index d76199c794..157884fac3 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -43,8 +43,17 @@ Kernel::Kernel(ResourceManager *resMan, SegManager *segMan)
}
Kernel::~Kernel() {
- for (KernelFunctionArray::iterator i = _kernelFuncs.begin(); i != _kernelFuncs.end(); ++i)
- delete[] i->signature;
+ for (KernelFunctionArray::iterator it = _kernelFuncs.begin(); it != _kernelFuncs.end(); ++it) {
+ if (it->subFunctionCount) {
+ uint16 subFunctionNr = 0;
+ while (subFunctionNr < it->subFunctionCount) {
+ delete[] it->subFunctions[subFunctionNr].signature;
+ subFunctionNr++;
+ }
+ delete[] it->subFunctions;
+ }
+ delete[] it->signature;
+ }
}
uint Kernel::getSelectorNamesSize() const {
@@ -56,12 +65,14 @@ const Common::String &Kernel::getSelectorName(uint selector) {
// This should only occur in games w/o a selector-table
// We need this for proper workaround tables
// TODO: maybe check, if there is a fixed selector-table and error() out in that case
- for (uint loopSelector = _selectorNames.size(); loopSelector <= selector; loopSelector++) {
- Common::String newSelectorName;
- newSelectorName = newSelectorName.printf("<noname %d>", loopSelector);
- _selectorNames.push_back(newSelectorName);
- }
+ for (uint loopSelector = _selectorNames.size(); loopSelector <= selector; ++loopSelector)
+ _selectorNames.push_back(Common::String::printf("<noname%d>", loopSelector));
}
+
+ // Ensure that the selector has a name
+ if (_selectorNames[selector].empty())
+ _selectorNames[selector] = Common::String::printf("<noname%d>", selector);
+
return _selectorNames[selector];
}
@@ -650,7 +661,7 @@ void Kernel::mapFunctions() {
return;
}
-bool Kernel::debugSetFunctionLogging(const char *kernelName, bool logging) {
+bool Kernel::debugSetFunction(const char *kernelName, int logging, int breakpoint) {
if (strcmp(kernelName, "*")) {
for (uint id = 0; id < _kernelFuncs.size(); id++) {
if (_kernelFuncs[id].name) {
@@ -660,14 +671,21 @@ bool Kernel::debugSetFunctionLogging(const char *kernelName, bool logging) {
KernelSubFunction *kernelSubCall = _kernelFuncs[id].subFunctions;
uint kernelSubCallCount = _kernelFuncs[id].subFunctionCount;
for (uint subId = 0; subId < kernelSubCallCount; subId++) {
- if (kernelSubCall->function)
- kernelSubCall->debugLogging = logging;
+ if (kernelSubCall->function) {
+ if (logging != -1)
+ kernelSubCall->debugLogging = logging == 1 ? true : false;
+ if (breakpoint != -1)
+ kernelSubCall->debugBreakpoint = breakpoint == 1 ? true : false;
+ }
kernelSubCall++;
}
return true;
}
// function name matched, set for this one and exit
- _kernelFuncs[id].debugLogging = logging;
+ if (logging != -1)
+ _kernelFuncs[id].debugLogging = logging == 1 ? true : false;
+ if (breakpoint != -1)
+ _kernelFuncs[id].debugBreakpoint = breakpoint == 1 ? true : false;
return true;
} else {
// main name was not matched
@@ -679,7 +697,10 @@ bool Kernel::debugSetFunctionLogging(const char *kernelName, bool logging) {
if (kernelSubCall->function) {
if (strcmp(kernelName, kernelSubCall->name) == 0) {
// sub-function name matched, set for this one and exit
- kernelSubCall->debugLogging = logging;
+ if (logging != -1)
+ kernelSubCall->debugLogging = logging == 1 ? true : false;
+ if (breakpoint != -1)
+ kernelSubCall->debugBreakpoint = breakpoint == 1 ? true : false;
return true;
}
}
@@ -696,14 +717,21 @@ bool Kernel::debugSetFunctionLogging(const char *kernelName, bool logging) {
if (_kernelFuncs[id].name) {
if (!_kernelFuncs[id].subFunctions) {
// No sub-functions, enable actual kernel function
- _kernelFuncs[id].debugLogging = logging;
+ if (logging != -1)
+ _kernelFuncs[id].debugLogging = logging == 1 ? true : false;
+ if (breakpoint != -1)
+ _kernelFuncs[id].debugBreakpoint = breakpoint == 1 ? true : false;
} else {
// Sub-Functions available, enable those too
KernelSubFunction *kernelSubCall = _kernelFuncs[id].subFunctions;
uint kernelSubCallCount = _kernelFuncs[id].subFunctionCount;
for (uint subId = 0; subId < kernelSubCallCount; subId++) {
- if (kernelSubCall->function)
- kernelSubCall->debugLogging = logging;
+ if (kernelSubCall->function) {
+ if (logging != -1)
+ kernelSubCall->debugLogging = logging == 1 ? true : false;
+ if (breakpoint != -1)
+ kernelSubCall->debugBreakpoint = breakpoint == 1 ? true : false;
+ }
kernelSubCall++;
}
}
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 285e746349..b6247b46f1 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -127,6 +127,7 @@ struct KernelSubFunction {
uint16 *signature;
const SciWorkaroundEntry *workarounds;
bool debugLogging;
+ bool debugBreakpoint;
};
struct KernelFunction {
@@ -137,6 +138,7 @@ struct KernelFunction {
KernelSubFunction *subFunctions;
uint16 subFunctionCount;
bool debugLogging;
+ bool debugBreakpoint;
};
class Kernel {
@@ -218,9 +220,9 @@ public:
void loadKernelNames(GameFeatures *features);
/**
- * Sets debugCalls flag for a kernel function
+ * Sets debug flags for a kernel function
*/
- bool debugSetFunctionLogging(const char *kernelName, bool debugCalls);
+ bool debugSetFunction(const char *kernelName, int logging, int breakpoint);
private:
/**
@@ -467,7 +469,7 @@ reg_t kMoveToEnd(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundPlay(EngineState *s, int argc, reg_t *argv);
-reg_t kDoSoundDummy(EngineState *s, int argc, reg_t *argv);
+reg_t kDoSoundRestore(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundDispose(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundMute(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundStop(EngineState *s, int argc, reg_t *argv);
@@ -482,6 +484,7 @@ reg_t kDoSoundUpdateCues(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSendMidi(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundReverb(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSetHold(EngineState *s, int argc, reg_t *argv);
+reg_t kDoSoundDummy(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundGetAudioCapability(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSuspend(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSetVolume(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 886e918fd8..b2b8eb593e 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -86,7 +86,7 @@ struct SciKernelMapSubEntry {
static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 0, MAP_CALL(DoSoundInit), "o", NULL },
{ SIG_SOUNDSCI0, 1, MAP_CALL(DoSoundPlay), "o", NULL },
- { SIG_SOUNDSCI0, 2, MAP_CALL(DoSoundDummy), "(o)", NULL },
+ { SIG_SOUNDSCI0, 2, MAP_CALL(DoSoundRestore), "(o)", NULL },
{ SIG_SOUNDSCI0, 3, MAP_CALL(DoSoundDispose), "o", NULL },
{ SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL },
{ SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL },
@@ -99,7 +99,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 12, MAP_CALL(DoSoundStopAll), "", NULL },
{ SIG_SOUNDSCI1EARLY, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 2, MAP_CALL(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL },
@@ -111,7 +111,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
// it actually does internally
{ SIG_SOUNDSCI1EARLY, 8, MAP_CALL(DoSoundStop), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 9, MAP_CALL(DoSoundPause), "[o0]i", NULL },
- { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", NULL },
+ { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
{ SIG_SOUNDSCI1EARLY, 11, MAP_CALL(DoSoundUpdateCues), "o", NULL },
{ SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL },
{ SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundReverb), "i", NULL },
@@ -120,7 +120,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
// ^^ Longbow demo
{ SIG_SOUNDSCI1LATE, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 2, MAP_CALL(DoSoundDummy), "", NULL },
+ { SIG_SOUNDSCI1LATE, 2, MAP_CALL(DoSoundRestore), "", NULL },
{ SIG_SOUNDSCI1LATE, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
{ SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
@@ -142,7 +142,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
#ifdef ENABLE_SCI32
{ SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI21, 2, MAP_CALL(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI21, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
{ SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), NULL, NULL },
{ SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), NULL, NULL },
@@ -184,8 +184,8 @@ static const SciKernelMapSubEntry kGraph_subops[] = {
{ SIG_SCIALL, 9, MAP_CALL(GraphFillBoxBackground), "iiii", NULL },
{ SIG_SCIALL, 10, MAP_CALL(GraphFillBoxForeground), "iiii", kGraphFillBoxForeground_workarounds },
{ SIG_SCIALL, 11, MAP_CALL(GraphFillBoxAny), "iiiiii(i)(i)", kGraphFillBoxAny_workarounds },
- { SIG_SCI11, 12, MAP_CALL(GraphUpdateBox), "iiii(i)(r0)", NULL }, // kq6 hires
- { SIG_SCIALL, 12, MAP_CALL(GraphUpdateBox), "iiii(i)", NULL },
+ { SIG_SCI11, 12, MAP_CALL(GraphUpdateBox), "iiii(i)(r0)", kGraphUpdateBox_workarounds }, // kq6 hires
+ { SIG_SCIALL, 12, MAP_CALL(GraphUpdateBox), "iiii(i)", kGraphUpdateBox_workarounds },
{ SIG_SCIALL, 13, MAP_CALL(GraphRedrawBox), "iiii", kGraphRedrawBox_workarounds },
{ SIG_SCIALL, 14, MAP_CALL(GraphAdjustPriority), "ii", NULL },
{ SIG_SCI11, 15, MAP_CALL(GraphSaveUpscaledHiresBox), "iiii", NULL }, // kq6 hires
@@ -319,7 +319,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(CoordPri), SIG_EVERYWHERE, "i(i)", NULL, NULL },
{ MAP_CALL(CosDiv), SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(DeleteKey), SIG_EVERYWHERE, "l.", NULL, NULL },
- { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, NULL }, // subop
+ { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, kDeviceInfo_workarounds }, // subop
{ MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, NULL },
// ^ we allow invalid references here, because kDisplay gets called with those in e.g. pq3 during intro
// restoreBits() checks and skips invalid handles, so that's fine. Sierra SCI behaved the same
@@ -418,7 +418,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
{ MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
// TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why
- { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i*)", NULL, NULL },
+ { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL },
+ { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
{ MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL },
{ MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL },
{ MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
@@ -432,7 +433,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL },
{ MAP_CALL(Sqrt), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, NULL },
+ { MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, kStrAt_workarounds },
{ MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, NULL },
{ MAP_CALL(StrCmp), SIG_EVERYWHERE, "rr(i)", NULL, NULL },
{ MAP_CALL(StrCpy), SIG_EVERYWHERE, "r[r0](i)", NULL, NULL },
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index d4ba467b25..39c32ccc68 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -282,6 +282,14 @@ enum {
};
reg_t kDeviceInfo(EngineState *s, int argc, reg_t *argv) {
+ if (g_sci->getGameId() == GID_FANMADE && argc == 1) {
+ // WORKAROUND: The fan game script library calls kDeviceInfo with one parameter.
+ // According to the scripts, it wants to call CurDevice. However, it fails to
+ // provide the subop to the function.
+ s->_segMan->strcpy(argv[0], "/");
+ return s->r_acc;
+ }
+
int mode = argv[0].toUint16();
switch (mode) {
@@ -480,6 +488,10 @@ reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
Common::Array<SavegameDesc> saves;
listSavegames(saves);
+ // we allow 0 (happens in QfG2 when trying to restore from an empty saved game list) and return false in that case
+ if (virtualId == 0)
+ return NULL_REG;
+
// Find saved-game
if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
error("kCheckSaveGame: called with invalid savegameId!");
@@ -494,7 +506,7 @@ reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
// Otherwise we assume the savegame is OK
- return make_reg(0, 1);
+ return TRUE_REG;
}
reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 56518f10bf..e1e92b1cf9 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -29,6 +29,8 @@
#include "graphics/cursorman.h"
#include "graphics/surface.h"
+#include "gui/message.h"
+
#include "sci/sci.h"
#include "sci/debug.h" // for g_debug_sleeptime_factor
#include "sci/resource.h"
@@ -172,8 +174,8 @@ static reg_t kSetCursorSci11(EngineState *s, int argc, reg_t *argv) {
}
break;
}
+ case 9: // case for kq5cd, we are getting calling with 4 additional 900d parameters
case 5:
- case 9:
hotspot = new Common::Point(argv[3].toSint16(), argv[4].toSint16());
// Fallthrough
case 3:
@@ -182,6 +184,18 @@ static reg_t kSetCursorSci11(EngineState *s, int argc, reg_t *argv) {
else
g_sci->_gfxCursor->kernelSetView(argv[0].toUint16(), argv[1].toUint16(), argv[2].toUint16(), hotspot);
break;
+ case 10:
+ // Freddy pharkas, when using the whiskey glass to read the prescription (bug #3034973)
+ // magnifier support, disabled using argc == 1, argv == -1
+ warning("kSetCursor: unsupported magnifier");
+ // we just set the view cursor currently
+ g_sci->_gfxCursor->kernelSetView(argv[5].toUint16(), argv[6].toUint16(), argv[7].toUint16(), hotspot);
+ // argv[0] -> 1, 2, 4 -> maybe magnification multiplier
+ // argv[1-4] -> rect for magnification
+ // argv[5, 6, 7] -> view resource for cursor
+ // argv[8] -> picture resource for mag
+ // argv[9] -> color for magnifier replacement
+ break;
default :
error("kSetCursor: Unhandled case: %d arguments given", argc);
break;
@@ -739,8 +753,10 @@ reg_t kPortrait(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-// Original top-left must stay on kControl rects, we adjust accordingly because sierra sci actually wont draw rects that
-// are upside down (example: jones, when challenging jones - one button is a duplicate and also has lower-right which is 0, 0)
+// Original top-left must stay on kControl rects, we adjust accordingly because
+// sierra sci actually wont draw rects that are upside down (example: jones,
+// when challenging jones - one button is a duplicate and also has lower-right
+// which is 0, 0)
Common::Rect kControlCreateRect(int16 x, int16 y, int16 x1, int16 y1) {
if (x > x1) x1 = x;
if (y > y1) y1 = y;
@@ -882,7 +898,8 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
// Disable the "Change Directory" button, as we don't allow the game engine to
// change the directory where saved games are placed
- if (objName == "changeDirI") {
+ // "changeDirItem" is used in the import windows of QFG2&3
+ if ((objName == "changeDirI") || (objName == "changeDirItem")) {
int state = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
writeSelectorValue(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
}
@@ -898,6 +915,24 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
}
}
}
+ if (objName == "savedHeros") {
+ // Import of QfG character files dialog is shown
+ // display additional popup information before letting user use it
+ reg_t changeDirButton = s->_segMan->findObjectByName("changeDirItem");
+ if (!changeDirButton.isNull()) {
+ // check if checkDirButton is still enabled, in that case we are called the first time during that room
+ if (!(readSelectorValue(s->_segMan, changeDirButton, SELECTOR(state)) & SCI_CONTROLS_STYLE_DISABLED)) {
+ GUI::MessageDialog dialog("Characters saved inside ScummVM are shown "
+ "automatically. Character files saved in the original "
+ "interpreter need to be put inside ScummVM's saved games "
+ "directory and a prefix needs to be added depending on which "
+ "game it was saved in: 'qfg1-' for Quest for Glory 1, 'qfg2-' "
+ "for Quest for Glory 2. Example: 'qfg2-thief.sav'.",
+ "OK");
+ dialog.runModal();
+ }
+ }
+ }
_k_GenericDrawControl(s, controlObject, false);
return NULL_REG;
@@ -1070,7 +1105,7 @@ reg_t kShakeScreen(EngineState *s, int argc, reg_t *argv) {
int16 shakeCount = (argc > 0) ? argv[0].toUint16() : 1;
int16 directions = (argc > 1) ? argv[1].toUint16() : 1;
- g_sci->_gfxPaint->kernelShakeScreen(shakeCount, directions);
+ g_sci->_gfxScreen->kernelShakeScreen(shakeCount, directions);
return s->r_acc;
}
diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp
index bdc705cae3..f3769b653b 100644
--- a/engines/sci/engine/kmath.cpp
+++ b/engines/sci/engine/kmath.cpp
@@ -37,8 +37,18 @@ reg_t kRandom(EngineState *s, int argc, reg_t *argv) {
case 2: { // get random number
int fromNumber = argv[0].toUint16();
int toNumber = argv[1].toUint16();
- double randomNumber = fromNumber + ((toNumber + 1.0 - fromNumber) * (rand() / (RAND_MAX + 1.0)));
- return make_reg(0, (int)randomNumber);
+
+ // TODO/CHECKME: It is propbably not required to check whether
+ // toNumber is greater than fromNumber, at least not when one
+ // goes by their names, but let us be on the safe side and
+ // allow toNumber to be smaller than fromNumber too.
+ if (fromNumber > toNumber)
+ SWAP(fromNumber, toNumber);
+
+ const uint diff = (uint)(toNumber - fromNumber);
+
+ const int randomNumber = fromNumber + (int)g_sci->getRNG().getRandomNumber(diff);
+ return make_reg(0, randomNumber);
}
case 3: // get seed
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 305e202ae9..fbe20410de 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -46,25 +46,37 @@ reg_t kRestartGame(EngineState *s, int argc, reg_t *argv) {
** Returns the restarting_flag in acc
*/
reg_t kGameIsRestarting(EngineState *s, int argc, reg_t *argv) {
- s->r_acc = make_reg(0, s->gameWasRestarted);
+ s->r_acc = make_reg(0, s->gameIsRestarting);
if (argc) { // Only happens during replay
if (!argv[0].toUint16()) // Set restarting flag
- s->gameWasRestarted = false;
+ s->gameIsRestarting = GAMEISRESTARTING_NONE;
}
uint32 neededSleep = 30;
- // WORKAROUND: LSL3 calculates a machinespeed variable during game startup
- // (right after the filthy questions). This one would go through w/o
- // throttling resulting in having to do 1000 pushups or something. Another
- // way of handling this would be delaying incrementing of "machineSpeed"
- // selector.
- if (g_sci->getGameId() == GID_LSL3 && s->currentRoomNumber() == 290)
- s->_throttleTrigger = true;
- else if (g_sci->getGameId() == GID_ICEMAN && s->currentRoomNumber() == 27) {
- s->_throttleTrigger = true;
- neededSleep = 60;
+ // WORKAROUNDS:
+ switch (g_sci->getGameId()) {
+ case GID_LSL3:
+ // LSL3 calculates a machinespeed variable during game startup
+ // (right after the filthy questions). This one would go through w/o
+ // throttling resulting in having to do 1000 pushups or something. Another
+ // way of handling this would be delaying incrementing of "machineSpeed"
+ // selector.
+ if (s->currentRoomNumber() == 290)
+ s->_throttleTrigger = true;
+ break;
+ case GID_ICEMAN:
+ // In ICEMAN the submarine control room is not animating much, so it runs way too fast
+ // we calm it down even more otherwise especially fighting against other submarines
+ // is almost impossible
+ if (s->currentRoomNumber() == 27) {
+ s->_throttleTrigger = true;
+ neededSleep = 60;
+ }
+ break;
+ default:
+ break;
}
s->speedThrottler(neededSleep);
@@ -160,10 +172,10 @@ reg_t kSetDebug(EngineState *s, int argc, reg_t *argv) {
}
enum {
- K_NEW_GETTIME_TICKS = 0,
- K_NEW_GETTIME_TIME_12HOUR = 1,
- K_NEW_GETTIME_TIME_24HOUR = 2,
- K_NEW_GETTIME_DATE = 3
+ KGETTIME_TICKS = 0,
+ KGETTIME_TIME_12HOUR = 1,
+ KGETTIME_TIME_24HOUR = 2,
+ KGETTIME_DATE = 3
};
reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
@@ -180,19 +192,19 @@ reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
error("kGetTime called in SCI0 with mode %d (expected 0 or 1)", mode);
switch (mode) {
- case K_NEW_GETTIME_TICKS :
+ case KGETTIME_TICKS :
retval = elapsedTime * 60 / 1000;
debugC(2, kDebugLevelTime, "GetTime(elapsed) returns %d", retval);
break;
- case K_NEW_GETTIME_TIME_12HOUR :
+ case KGETTIME_TIME_12HOUR :
retval = ((loc_time.tm_hour % 12) << 12) | (loc_time.tm_min << 6) | (loc_time.tm_sec);
debugC(2, kDebugLevelTime, "GetTime(12h) returns %d", retval);
break;
- case K_NEW_GETTIME_TIME_24HOUR :
+ case KGETTIME_TIME_24HOUR :
retval = (loc_time.tm_hour << 11) | (loc_time.tm_min << 5) | (loc_time.tm_sec >> 1);
debugC(2, kDebugLevelTime, "GetTime(24h) returns %d", retval);
break;
- case K_NEW_GETTIME_DATE :
+ case KGETTIME_DATE :
retval = loc_time.tm_mday | ((loc_time.tm_mon + 1) << 5) | (((loc_time.tm_year + 1900) & 0x7f) << 9);
debugC(2, kDebugLevelTime, "GetTime(date) returns %d", retval);
break;
@@ -215,17 +227,32 @@ enum {
reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
- case K_MEMORY_ALLOCATE_CRITICAL :
- if (!s->_segMan->allocDynmem(argv[1].toUint16(), "kMemory() critical", &s->r_acc)) {
+ case K_MEMORY_ALLOCATE_CRITICAL: {
+ int byteCount = argv[1].toUint16();
+ // WORKAROUND: pq3 (multilingual) when plotting crimes - allocates the
+ // returned bytes from kStrLen on "W" and "E" and wants to put a
+ // string in there, which doesn't fit of course. That's why we allocate
+ // one byte more all the time inside that room
+ if (g_sci->getGameId() == GID_PQ3) {
+ if (s->currentRoomNumber() == 202)
+ byteCount++;
+ }
+ if (!s->_segMan->allocDynmem(byteCount, "kMemory() critical", &s->r_acc)) {
error("Critical heap allocation failed");
}
break;
- case K_MEMORY_ALLOCATE_NONCRITICAL :
+ }
+ case K_MEMORY_ALLOCATE_NONCRITICAL:
s->_segMan->allocDynmem(argv[1].toUint16(), "kMemory() non-critical", &s->r_acc);
break;
case K_MEMORY_FREE :
- if (s->_segMan->freeDynmem(argv[1])) {
- error("Attempt to kMemory::free() non-dynmem pointer %04x:%04x", PRINT_REG(argv[1]));
+ if (!s->_segMan->freeDynmem(argv[1])) {
+ if (g_sci->getGameId() == GID_QFG1VGA) {
+ // Ignore script bug in QFG1VGA, when closing any conversation dialog with esc
+ } else {
+ // Usually, the result of a script bug. Non-critical
+ warning("Attempt to kMemory::free() non-dynmem pointer %04x:%04x", PRINT_REG(argv[1]));
+ }
}
break;
case K_MEMORY_MEMCPY : {
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index 114b6eb755..dfd1aa699e 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -30,6 +30,7 @@
#include "sci/engine/selector.h"
#include "sci/engine/kernel.h"
#include "sci/graphics/animate.h"
+#include "sci/graphics/screen.h"
namespace Sci {
@@ -313,8 +314,15 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
|| ((y == desty) && (abs(dy) >= abs(dx))) /* Moving fast, reached? */
))) {
// Whew... in short: If we have reached or passed our target position
- x = destx;
- y = desty;
+
+ // Sanity check: make sure that destx, desty are inside the screen coordinates.
+ // They can go off screen in some cases, e.g. in SQ5 while scrubbing the floor (bug #3037351)
+ if (destx < g_sci->_gfxScreen->getWidth() && desty < g_sci->_gfxScreen->getHeight()) {
+ x = destx;
+ y = desty;
+ } else {
+ warning("kDoBresen: destination x, y would be off-screen(%d, %d)", destx, desty);
+ }
completed = 1;
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x", PRINT_REG(mover));
@@ -437,7 +445,7 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "Movement (%d,%d), angle %d is %sblocked", dx, dy, angle, (s->r_acc.offset) ? " " : "not ");
if (s->r_acc.offset) { // isBlocked() returned non-zero
- int rotation = (rand() & 1) ? 45 : (360 - 45); // Clockwise/counterclockwise
+ int rotation = (g_sci->getRNG().getRandomBit() == 1) ? 45 : (360 - 45); // Clockwise/counterclockwise
int oldx = readSelectorValue(segMan, client, SELECTOR(x));
int oldy = readSelectorValue(segMan, client, SELECTOR(y));
int xstep = readSelectorValue(segMan, client, SELECTOR(xStep));
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index e211867ef9..a5501c160f 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -95,6 +95,7 @@ reg_t kLock(EngineState *s, int argc, reg_t *argv) {
++itr;
}
+ delete resources;
} else {
which = g_sci->getResMan()->findResource(id, 0);
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index 4e5ddc5e96..2f00cd7da2 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -48,7 +48,7 @@ reg_t kDoSound(EngineState *s, int argc, reg_t *argv) {
CREATE_DOSOUND_FORWARD(DoSoundInit)
CREATE_DOSOUND_FORWARD(DoSoundPlay)
-CREATE_DOSOUND_FORWARD(DoSoundDummy)
+CREATE_DOSOUND_FORWARD(DoSoundRestore)
CREATE_DOSOUND_FORWARD(DoSoundDispose)
CREATE_DOSOUND_FORWARD(DoSoundMute)
CREATE_DOSOUND_FORWARD(DoSoundStop)
@@ -63,6 +63,7 @@ CREATE_DOSOUND_FORWARD(DoSoundUpdateCues)
CREATE_DOSOUND_FORWARD(DoSoundSendMidi)
CREATE_DOSOUND_FORWARD(DoSoundReverb)
CREATE_DOSOUND_FORWARD(DoSoundSetHold)
+CREATE_DOSOUND_FORWARD(DoSoundDummy)
CREATE_DOSOUND_FORWARD(DoSoundGetAudioCapability)
CREATE_DOSOUND_FORWARD(DoSoundSuspend)
CREATE_DOSOUND_FORWARD(DoSoundSetVolume)
@@ -222,16 +223,17 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
// 3 new subops in Pharkas. kDoAudio in Pharkas sits at seg026:038C
case 11:
+ // Not sure where this is used yet
warning("kDoAudio: Unhandled case 11, %d extra arguments passed", argc - 1);
break;
case 12:
- // Seems to be audio sync, used in Pharkas. Silenced the warning due to
- // the high level of spam it produces.
+ // Seems to be some sort of audio sync, used in Pharkas. Silenced the
+ // warning due to the high level of spam it produces. (takes no params)
//warning("kDoAudio: Unhandled case 12, %d extra arguments passed", argc - 1);
break;
case 13:
- // Used in Pharkas whenever a speech sample starts
- warning("kDoAudio: Unhandled case 13, %d extra arguments passed", argc - 1);
+ // Used in Pharkas whenever a speech sample starts (takes no params)
+ //warning("kDoAudio: Unhandled case 13, %d extra arguments passed", argc - 1);
break;
default:
warning("kDoAudio: Unhandled case %d, %d extra arguments passed", argv[0].toUint16(), argc - 1);
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index cd103dade7..3ad2d95f58 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -205,11 +205,15 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
videoDecoder = new VMDDecoder(g_system->getMixer());
+ if (!videoDecoder->loadFile(fileName)) {
+ warning("Could not open VMD %s", fileName.c_str());
+ break;
+ }
+
if (reshowCursor)
g_sci->_gfxCursor->kernelHide();
- if (videoDecoder && videoDecoder->loadFile(fileName))
- playVideo(videoDecoder);
+ playVideo(videoDecoder);
if (reshowCursor)
g_sci->_gfxCursor->kernelShow();
@@ -280,8 +284,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
// Looks to be setting the video size and position. Called with 4 extra integer
// parameters (e.g. 86, 41, 235, 106)
default:
- warningMsg = "PlayVMD - unsupported subop. Params: " +
- Common::String::printf("%d", argc) + " (";
+ warningMsg = Common::String::printf("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
for (int i = 0; i < argc; i++) {
warningMsg += Common::String::printf("%04x:%04x", PRINT_REG(argv[i]));
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index cdecc556e8..6e1b326c4f 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -166,6 +166,8 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
}
if (!reader->init()) {
+ delete reader;
+
warning("Message: failed to read resource header");
return false;
}
@@ -180,6 +182,7 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
continue;
}
+ delete reader;
return false;
}
@@ -193,6 +196,7 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
}
}
+ delete reader;
return true;
}
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 806c8893b4..a7716516e7 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -53,42 +53,8 @@ namespace Sci {
#define VER(x) Common::Serializer::Version(x)
-// OBSOLETE: This const is used for backward compatibility only.
-const uint32 INTMAPPER_MAGIC_KEY = 0xDEADBEEF;
-
-
#pragma mark -
-// TODO: Many of the following sync_*() methods should be turned into member funcs
-// of the classes they are syncing.
-
-#define DEFROBNICATE_HANDLE(handle) (make_reg((handle >> 16) & 0xffff, handle & 0xffff))
-
-void MusicEntry::saveLoadWithSerializer(Common::Serializer &s) {
- soundObj.saveLoadWithSerializer(s);
- s.syncAsSint16LE(resourceId);
- s.syncAsSint16LE(dataInc);
- s.syncAsSint16LE(ticker);
- s.syncAsSint16LE(signal, VER(17));
- s.syncAsByte(priority);
- s.syncAsSint16LE(loop, VER(17));
- s.syncAsByte(volume);
- s.syncAsByte(hold, VER(17));
- s.syncAsByte(fadeTo);
- s.syncAsSint16LE(fadeStep);
- s.syncAsSint32LE(fadeTicker);
- s.syncAsSint32LE(fadeTickerStep);
- s.syncAsByte(status);
-
- // pMidiParser and pStreamAud will be initialized when the
- // sound list is reconstructed in gamestate_restore()
- if (s.isLoading()) {
- soundRes = 0;
- pMidiParser = 0;
- pStreamAud = 0;
- }
-}
-
// Experimental hack: Use syncWithSerializer to sync. By default, this assume
// the object to be synced is a subclass of Serializable and thus tries to invoke
// the saveLoadWithSerializer() method. But it is possible to specialize this
@@ -148,7 +114,8 @@ void syncArray(Common::Serializer &s, Common::Array<T> &arr) {
template <>
void syncWithSerializer(Common::Serializer &s, reg_t &obj) {
- obj.saveLoadWithSerializer(s);
+ s.syncAsUint16LE(obj.segment);
+ s.syncAsUint16LE(obj.offset);
}
void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
@@ -206,7 +173,7 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
template <>
void syncWithSerializer(Common::Serializer &s, Class &obj) {
s.syncAsSint32LE(obj.script);
- obj.reg.saveLoadWithSerializer(s);
+ syncWithSerializer(s, obj.reg);
}
static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) {
@@ -266,7 +233,7 @@ void LocalVariables::saveLoadWithSerializer(Common::Serializer &s) {
void Object::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint32LE(_flags);
- _pos.saveLoadWithSerializer(s);
+ syncWithSerializer(s, _pos);
s.syncAsSint32LE(_methodCount); // that's actually a uint16
syncArray<reg_t>(s, _variables);
@@ -283,18 +250,18 @@ template <>
void syncWithSerializer(Common::Serializer &s, Table<List>::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
- obj.first.saveLoadWithSerializer(s);
- obj.last.saveLoadWithSerializer(s);
+ syncWithSerializer(s, obj.first);
+ syncWithSerializer(s, obj.last);
}
template <>
void syncWithSerializer(Common::Serializer &s, Table<Node>::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
- obj.pred.saveLoadWithSerializer(s);
- obj.succ.saveLoadWithSerializer(s);
- obj.key.saveLoadWithSerializer(s);
- obj.value.saveLoadWithSerializer(s);
+ syncWithSerializer(s, obj.pred);
+ syncWithSerializer(s, obj.succ);
+ syncWithSerializer(s, obj.key);
+ syncWithSerializer(s, obj.value);
}
#ifdef ENABLE_SCI32
@@ -328,7 +295,7 @@ void syncWithSerializer(Common::Serializer &s, Table<SciArray<reg_t> >::Entry &o
if (s.isSaving())
value = obj.getValue(i);
- value.saveLoadWithSerializer(s);
+ syncWithSerializer(s, value);
if (s.isLoading())
obj.setValue(i, value);
@@ -414,14 +381,14 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) {
_objects.clear();
Object tmp;
for (uint i = 0; i < numObjs; ++i) {
- syncWithSerializer<Object>(s, tmp);
+ syncWithSerializer(s, tmp);
_objects[tmp.getPos().offset] = tmp;
}
} else {
ObjMap::iterator it;
const ObjMap::iterator end = _objects.end();
for (it = _objects.begin(); it != end; ++it) {
- syncWithSerializer<Object>(s, it->_value);
+ syncWithSerializer(s, it->_value);
}
}
@@ -526,6 +493,31 @@ void SciMusic::saveLoadWithSerializer(Common::Serializer &s) {
}
}
+void MusicEntry::saveLoadWithSerializer(Common::Serializer &s) {
+ syncWithSerializer(s, soundObj);
+ s.syncAsSint16LE(resourceId);
+ s.syncAsSint16LE(dataInc);
+ s.syncAsSint16LE(ticker);
+ s.syncAsSint16LE(signal, VER(17));
+ s.syncAsByte(priority);
+ s.syncAsSint16LE(loop, VER(17));
+ s.syncAsByte(volume);
+ s.syncAsByte(hold, VER(17));
+ s.syncAsByte(fadeTo);
+ s.syncAsSint16LE(fadeStep);
+ s.syncAsSint32LE(fadeTicker);
+ s.syncAsSint32LE(fadeTickerStep);
+ s.syncAsByte(status);
+
+ // pMidiParser and pStreamAud will be initialized when the
+ // sound list is reconstructed in gamestate_restore()
+ if (s.isLoading()) {
+ soundRes = 0;
+ pMidiParser = 0;
+ pStreamAud = 0;
+ }
+}
+
void SoundCommandParser::syncPlayList(Common::Serializer &s) {
_music->saveLoadWithSerializer(s);
}
@@ -748,11 +740,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
}
// We don't need the thumbnail here, so just read it and discard it
- Graphics::Surface *thumbnail = new Graphics::Surface();
- assert(thumbnail);
- Graphics::loadThumbnail(*fh, *thumbnail);
- delete thumbnail;
- thumbnail = 0;
+ Graphics::skipThumbnail(*fh);
s->reset(true);
s->saveLoadWithSerializer(ser); // FIXME: Error handling?
@@ -770,12 +758,19 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
s->gameStartTime = g_system->getMillis();
s->_screenUpdateTime = g_system->getMillis();
+ if (g_sci->_gfxPorts)
+ g_sci->_gfxPorts->reset();
+
g_sci->_soundCmd->reconstructPlayList(meta.savegame_version);
// Message state:
+ delete s->_msgState;
s->_msgState = new MessageState(s->_segMan);
s->abortScriptProcessing = kAbortLoadGame;
+
+ // signal restored game to game scripts
+ s->gameIsRestarting = GAMEISRESTARTING_RESTORE;
}
bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) {
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 25cf1d069f..1fb37f458d 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -851,13 +851,13 @@ byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
return (byte *)(d._buf);
}
-int SegManager::freeDynmem(reg_t addr) {
+bool SegManager::freeDynmem(reg_t addr) {
if (addr.segment < 1 || addr.segment >= _heap.size() || !_heap[addr.segment] || _heap[addr.segment]->getType() != SEG_TYPE_DYNMEM)
- return 1; // error
+ return false; // error
deallocate(addr.segment, true);
- return 0; // OK
+ return true; // OK
}
#ifdef ENABLE_SCI32
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index e0808dbb1b..59ac6f39b6 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -274,7 +274,7 @@ public:
* Deallocates a piece of dynamic memory
* @param[in] addr Offset of the dynmem chunk to free
*/
- int freeDynmem(reg_t addr);
+ bool freeDynmem(reg_t addr);
// Generic Operations on Segments and Addresses
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 2465576302..c8cb4cd203 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -143,9 +143,6 @@ public:
}
};
-
-struct IntMapper;
-
enum {
SYS_STRINGS_MAX = 4,
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index f5eb9eb73a..f99a41e088 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -164,6 +164,7 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(vanishingX);
FIND_SELECTOR(vanishingY);
FIND_SELECTOR(iconIndex);
+ FIND_SELECTOR(port);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index 661290f58c..00e795c1b9 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -127,6 +127,8 @@ struct SelectorCache {
// SCI1.1 Mac icon bar selectors
Selector iconIndex; ///< Used to index icon bar objects
+ Selector port; // used by a hoyle 4 workaround
+
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()
Selector picture; // Used to hold the picture ID for SCI32 pictures
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 243a460645..4f1d686b17 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -87,6 +87,12 @@ enum {
SAVEGAMEID_OFFICIALRANGE_END = 1999
};
+enum {
+ GAMEISRESTARTING_NONE = 0,
+ GAMEISRESTARTING_RESTART = 1,
+ GAMEISRESTARTING_RESTORE = 2
+};
+
class FileHandle {
public:
Common::String _name;
@@ -159,7 +165,7 @@ public:
int variablesMax[4]; ///< Max. values for all variables
AbortGameState abortScriptProcessing;
- bool gameWasRestarted;
+ int16 gameIsRestarting; // is set when restarting (=1) or restoring the game (=2)
int scriptStepCounter; // Counts the number of steps executed
int scriptGCInterval; // Number of steps in between gcs
diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp
index 55e18613e0..aae6de01f1 100644
--- a/engines/sci/engine/static_selectors.cpp
+++ b/engines/sci/engine/static_selectors.cpp
@@ -38,66 +38,66 @@ struct SelectorRemap {
};
static const char * const sci0Selectors[] = {
- "y", "x", "view", "loop", "cel", // 0 - 4
- "underBits", "nsTop", "nsLeft", "nsBottom", "nsRight", // 5 - 9
- "lsTop", "lsLeft", "lsBottom", "lsRight", "signal", // 10 - 14
- "illegalBits", "brTop", "brLeft", "brBottom", "brRight", // 15 - 19
- "name", "key", "time", "text", "elements", // 20 - 25
- "color", "back", "mode", "style", "state", // 25 - 29
- "font", "type", "window", "cursor", "max", // 30 - 34
- "mark", "who", "message", "edit", "play", // 35 - 39
- "number", "handle", "client", "dx", "dy", // 40 - 44
- "b-moveCnt", "b-i1", "b-i2", "b-di", "b-xAxis", // 45 - 49
- "b-incr", "xStep", "yStep", "moveSpeed", "canBeHere", // 50 - 54
- "heading", "mover", "doit", "isBlocked", "looper", // 55 - 59
- "priority", "modifiers", "replay", "setPri", "at", // 60 - 64
- "next", "done", "width", "wordFail", "syntaxFail", // 65 - 69
- "semanticFail", "pragmaFail", "said", "claimed", "value", // 70 - 74
- "save", "restore", "title", "button", "icon", // 75 - 79
- "draw", "delete", "z" // 80 - 82
+ "y", "x", "view", "loop", "cel", // 0 - 4
+ "underBits", "nsTop", "nsLeft", "nsBottom", "nsRight", // 5 - 9
+ "lsTop", "lsLeft", "lsBottom", "lsRight", "signal", // 10 - 14
+ "illegalBits", "brTop", "brLeft", "brBottom", "brRight", // 15 - 19
+ "name", "key", "time", "text", "elements", // 20 - 25
+ "color", "back", "mode", "style", "state", // 25 - 29
+ "font", "type", "window", "cursor", "max", // 30 - 34
+ "mark", "who", "message", "edit", "play", // 35 - 39
+ "number", "handle", "client", "dx", "dy", // 40 - 44
+ "b-moveCnt", "b-i1", "b-i2", "b-di", "b-xAxis", // 45 - 49
+ "b-incr", "xStep", "yStep", "moveSpeed", "canBeHere", // 50 - 54
+ "heading", "mover", "doit", "isBlocked", "looper", // 55 - 59
+ "priority", "modifiers", "replay", "setPri", "at", // 60 - 64
+ "next", "done", "width", "wordFail", "syntaxFail", // 65 - 69
+ "semanticFail", "pragmaFail", "said", "claimed", "value", // 70 - 74
+ "save", "restore", "title", "button", "icon", // 75 - 79
+ "draw", "delete", "z" // 80 - 82
};
static const char * const sci1Selectors[] = {
- "parseLang", "printLang", "subtitleLang", "size", "points", // 83 - 87
- "palette", "dataInc", "handle", "min", "sec", // 88 - 92
- "frame", "vol", "pri", "perform", "moveDone" // 93 - 97
+ "parseLang", "printLang", "subtitleLang", "size", "points", // 83 - 87
+ "palette", "dataInc", "handle", "min", "sec", // 88 - 92
+ "frame", "vol", "pri", "perform", "moveDone" // 93 - 97
};
#ifdef ENABLE_SCI32
static const char * const sci2Selectors[] = {
- "plane", "x", "y", "z", "scaleX", // 0 - 4
- "scaleY", "maxScale", "priority", "fixPriority", "inLeft", // 5 - 9
- "inTop", "inRight", "inBottom", "useInsetRect", "view", // 10 - 14
- "loop", "cel", "bitmap", "nsLeft", "nsTop", // 15 - 19
- "nsRight", "nsBottom", "lsLeft", "lsTop", "lsRight", // 20 - 25
- "lsBottom", "signal", "illegalBits", "brLeft", "brTop", // 25 - 29
- "brRight", "brBottom", "name", "key", "time", // 30 - 34
- "text", "elements", "fore", "back", "mode", // 35 - 39
- "style", "state", "font", "type", "window", // 40 - 44
- "cursor", "max", "mark", "who", "message", // 45 - 49
- "edit", "play", "number", "nodePtr", "client", // 50 - 54
- "dx", "dy", "b-moveCnt", "b-i1", "b-i2", // 55 - 59
- "b-di", "b-xAxis", "b-incr", "xStep", "yStep", // 60 - 64
- "moveSpeed", "cantBeHere", "heading", "mover", "doit", // 65 - 69
- "isBlocked", "looper", "modifiers", "replay", "setPri", // 70 - 74
- "at", "next", "done", "width", "pragmaFail", // 75 - 79
- "claimed", "value", "save", "restore", "title", // 80 - 84
- "button", "icon", "draw", "delete", "printLang", // 85 - 89
- "size", "points", "palette", "dataInc", "handle", // 90 - 94
- "min", "sec", "frame", "vol", "perform", // 95 - 99
- "moveDone", "topString", "flags", "quitGame", "restart", // 100 - 104
- "hide", "scaleSignal", "vanishingX", "vanishingY", "picture", // 105 - 109
- "resX", "resY", "coordType", "data", "skip", // 110 - 104
- "center", "all", "show", "textLeft", "textTop", // 115 - 119
- "textRight", "textBottom", "borderColor", "titleFore", "titleBack", // 120 - 124
- "titleFont", "dimmed", "frameOut", "lastKey", "magnifier", // 125 - 129
- "magPower", "mirrored", "pitch", "roll", "yaw", // 130 - 134
- "left", "right", "top", "bottom", "numLines" // 135 - 139
+ "plane", "x", "y", "z", "scaleX", // 0 - 4
+ "scaleY", "maxScale", "priority", "fixPriority", "inLeft", // 5 - 9
+ "inTop", "inRight", "inBottom", "useInsetRect", "view", // 10 - 14
+ "loop", "cel", "bitmap", "nsLeft", "nsTop", // 15 - 19
+ "nsRight", "nsBottom", "lsLeft", "lsTop", "lsRight", // 20 - 25
+ "lsBottom", "signal", "illegalBits", "brLeft", "brTop", // 25 - 29
+ "brRight", "brBottom", "name", "key", "time", // 30 - 34
+ "text", "elements", "fore", "back", "mode", // 35 - 39
+ "style", "state", "font", "type", "window", // 40 - 44
+ "cursor", "max", "mark", "who", "message", // 45 - 49
+ "edit", "play", "number", "nodePtr", "client", // 50 - 54
+ "dx", "dy", "b-moveCnt", "b-i1", "b-i2", // 55 - 59
+ "b-di", "b-xAxis", "b-incr", "xStep", "yStep", // 60 - 64
+ "moveSpeed", "cantBeHere", "heading", "mover", "doit", // 65 - 69
+ "isBlocked", "looper", "modifiers", "replay", "setPri", // 70 - 74
+ "at", "next", "done", "width", "pragmaFail", // 75 - 79
+ "claimed", "value", "save", "restore", "title", // 80 - 84
+ "button", "icon", "draw", "delete", "printLang", // 85 - 89
+ "size", "points", "palette", "dataInc", "handle", // 90 - 94
+ "min", "sec", "frame", "vol", "perform", // 95 - 99
+ "moveDone", "topString", "flags", "quitGame", "restart", // 100 - 104
+ "hide", "scaleSignal", "vanishingX", "vanishingY", "picture", // 105 - 109
+ "resX", "resY", "coordType", "data", "skip", // 110 - 104
+ "center", "all", "show", "textLeft", "textTop", // 115 - 119
+ "textRight", "textBottom", "borderColor", "titleFore", "titleBack", // 120 - 124
+ "titleFont", "dimmed", "frameOut", "lastKey", "magnifier", // 125 - 129
+ "magPower", "mirrored", "pitch", "roll", "yaw", // 130 - 134
+ "left", "right", "top", "bottom", "numLines" // 135 - 139
};
#endif
static const SelectorRemap sciSelectorRemap[] = {
- { SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE, "moveDone", 170 },
+ { SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE, "moveDone", 170 },
{ SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE, "points", 316 },
{ SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE, "flags", 368 },
{ SCI_VERSION_1_EARLY, SCI_VERSION_1_LATE, "nodePtr", 44 },
@@ -176,11 +176,12 @@ Common::StringArray Kernel::checkStaticSelectorNames() {
names[110] = "init";
} else if (g_sci->getGameId() == GID_LAURABOW2) {
- // The floppy of version needs the open selector set to match up with the CD version's
- // workaround - bug #3035694
+ // The floppy of version needs the open and changeState selectors set to match up with the
+ // CD version's workarounds - bugs #3035694 and #3036291
if (names.size() < 190)
names.resize(190);
+ names[144] = "changeState";
names[189] = "open";
}
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index b7f6896a48..7bcc5b43a3 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -135,9 +135,13 @@ static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) {
static int validate_arithmetic(reg_t reg) {
if (reg.segment) {
// The results of this are likely unpredictable... It most likely means that a kernel function is returning something wrong.
- // If such an error occurs, we usually need to find the last kernel function called and check its return value. Check
- // callKernelFunc() below
- error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg));
+ // If such an error occurs, we usually need to find the last kernel function called and check its return value.
+ if (g_sci->getGameId() == GID_QFG2 && g_sci->getEngineState()->currentRoomNumber() == 200) {
+ // WORKAROUND: This happens in QFG2, room 200, when talking to the astrologer (bug #3039879) - script bug.
+ // Returning 0 in this case.
+ } else {
+ error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg));
+ }
return 0;
}
@@ -231,7 +235,7 @@ static reg_t validate_read_var(reg_t *r, reg_t *stack_base, int type, int max, i
case VAR_PARAM:
// Out-of-bounds read for a parameter that goes onto stack and hits an uninitialized temp
// We return 0 currently in that case
- warning("Read for a parameter goes out-of-bounds, onto the stack and gets uninitialized temp");
+ debugC(2, kDebugLevelVM, "[VM] Read for a parameter goes out-of-bounds, onto the stack and gets uninitialized temp");
return NULL_REG;
default:
break;
@@ -743,6 +747,11 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
if (kernelCall.debugLogging)
logKernelCall(&kernelCall, NULL, s, argc, argv, s->r_acc);
+ if (kernelCall.debugBreakpoint) {
+ printf("Break on k%s\n", kernelCall.name);
+ g_sci->_debugState.debugging = true;
+ g_sci->_debugState.breakpointWasHit = true;
+ }
} else {
// Sub-functions available, check signature and call that one directly
if (argc < 1)
@@ -793,6 +802,11 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
if (kernelSubCall.debugLogging)
logKernelCall(&kernelCall, &kernelSubCall, s, argc, argv, s->r_acc);
+ if (kernelSubCall.debugBreakpoint) {
+ printf("Break on k%s\n", kernelSubCall.name);
+ g_sci->_debugState.debugging = true;
+ g_sci->_debugState.breakpointWasHit = true;
+ }
}
// Remove callk stack frame again, if there's still an execution stack
@@ -923,11 +937,7 @@ void run_vm(EngineState *s) {
obj = s->_segMan->getObject(s->xs->objp);
local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
if (!local_script) {
- // FIXME: Why does this happen? Is the script not loaded yet at this point?
- warning("Could not find local script from segment %x", s->xs->local_segment);
- local_script = NULL;
- s->variablesBase[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL;
- s->variablesMax[VAR_LOCAL] = 0;
+ error("Could not find local script from segment %x", s->xs->local_segment);
} else {
s->variablesSegment[VAR_LOCAL] = local_script->_localsSegment;
if (local_script->_localsBlock)
@@ -1053,7 +1063,7 @@ void run_vm(EngineState *s) {
if (validate_signedInteger(s->r_acc, value1) && validate_signedInteger(r_temp, value2))
s->r_acc = make_reg(0, value1 * value2);
else
- s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp);
+ s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeMulWorkarounds, s->r_acc, r_temp);
break;
}
@@ -1069,11 +1079,30 @@ void run_vm(EngineState *s) {
case op_mod: { // 0x05 (05)
r_temp = POP32();
- int16 modulo, value;
- if (validate_signedInteger(s->r_acc, modulo) && validate_signedInteger(r_temp, value))
- s->r_acc = make_reg(0, (modulo != 0 ? value % modulo : 0));
- else
- s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp);
+
+ if (getSciVersion() <= SCI_VERSION_0_LATE) {
+ uint16 modulo, value;
+ if (validate_unsignedInteger(s->r_acc, modulo) && validate_unsignedInteger(r_temp, value))
+ s->r_acc = make_reg(0, (modulo != 0 ? value % modulo : 0));
+ else
+ s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp);
+ } else {
+ // In Iceman (and perhaps from SCI0 0.000.685 onwards in general),
+ // handling for negative numbers was added. Since Iceman doesn't
+ // seem to have issues with the older code, we exclude it for now
+ // for simplicity's sake and use the new code for SCI01 and newer
+ // games. Fixes the battlecruiser mini game in SQ5 (room 850),
+ // bug #3035755
+ int16 modulo, value, result;
+ if (validate_signedInteger(s->r_acc, modulo) && validate_signedInteger(r_temp, value)) {
+ modulo = ABS(modulo);
+ result = (modulo != 0 ? value % modulo : 0);
+ if (result < 0)
+ result += modulo;
+ s->r_acc = make_reg(0, result);
+ } else
+ s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp);
+ }
break;
}
@@ -1196,7 +1225,7 @@ void run_vm(EngineState *s) {
if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2))
s->r_acc = make_reg(0, compare1 >= compare2);
else
- s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc);
+ s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeGeWorkarounds, r_temp, s->r_acc);
}
break;
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index 828fba3d7d..edf35a122a 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -27,7 +27,6 @@
#define SCI_ENGINE_VM_TYPES_H
#include "common/scummsys.h"
-#include "common/serializer.h"
namespace Sci {
@@ -57,11 +56,6 @@ struct reg_t {
int16 toSint16() const {
return (int16) offset;
}
-
- void saveLoadWithSerializer(Common::Serializer &s) {
- s.syncAsUint16LE(segment);
- s.syncAsUint16LE(offset);
- }
};
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 0db73e34d5..bc6d457f7f 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -38,12 +38,6 @@ const SciWorkaroundEntry opcodeDivWorkarounds[] = {
SCI_WORKAROUNDENTRY_TERMINATOR
};
-// gameID, room,script,lvl, object-name, method-name, call,index, workaround
-const SciWorkaroundEntry opcodeOrWorkarounds[] = {
- { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xcc6, 0, { WORKAROUND_FAKE, 0 } }, // when giving the papers to the customs officer, gets called against a pointer instead of a number - bug #3034464
- SCI_WORKAROUNDENTRY_TERMINATOR
-};
-
// gameID, room,script,lvl, object-name, method-name, call, index, workaround
const SciWorkaroundEntry opcodeDptoaWorkarounds[] = {
{ GID_LSL6, 360, 938, 0, "ROsc", "cycleDone", -1, 0, { WORKAROUND_FAKE, 1 } }, // when looking through tile in the shower room initial cycles get set to an object instead of 2, we fix this by setting 1 after decrease
@@ -52,16 +46,37 @@ const SciWorkaroundEntry opcodeDptoaWorkarounds[] = {
SCI_WORKAROUNDENTRY_TERMINATOR
};
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry opcodeGeWorkarounds[] = {
+ { GID_PQ3, 31, 31, 0, "rm031", "init", -1, 0, { WORKAROUND_FAKE, 1 } }, // pq3 english: when exiting the car, while morales is making phonecalls - bug #3037565
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry opcodeMulWorkarounds[] = {
+ { GID_FANMADE, 516, 983, 0, "Wander", "setTarget", -1, 0, { WORKAROUND_FAKE, 0 } }, // The Legend of the Lost Jewel Demo (fan made): called with object as second parameter when attacked by insects - bug #3038913
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry opcodeOrWorkarounds[] = {
+ { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xcc6, 0, { WORKAROUND_FAKE, 0 } }, // when giving the papers to the customs officer, gets called against a pointer instead of a number - bug #3034464
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
- { GID_CNICK_KQ, 200, 0, 1, "Character", "<noname 446>", -1, 504, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3
- { GID_CNICK_KQ, 200, 0, 1, "Character", "<noname 446>", -1, 505, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3
- { GID_CNICK_KQ, -1, 700, 0, "gcWindow", "<noname 183>", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu, like in hoyle 3
- { GID_CNICK_LONGBOW, 0, 0, 0, "RH Budget", "<noname 110>", -1, 1, { WORKAROUND_FAKE, 0 } }, // when starting the game
+ { GID_CASTLEBRAIN, 280, 280, 0, "programmer", "dispatchEvent", -1, 0, { WORKAROUND_FAKE, 0xf } }, // pressing 'q' on the computer screen in the robot room, and closing the help dialog that pops up (bug #3039656). Moves the cursor to the view with the ID returned (in this case, the robot hand)
+ { GID_CNICK_KQ, 200, 0, 1, "Character", "<noname446>", -1, 504, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3
+ { GID_CNICK_KQ, 200, 0, 1, "Character", "<noname446>", -1, 505, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3
+ { GID_CNICK_KQ, -1, 700, 0, "gcWindow", "<noname183>", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu, like in hoyle 3
+ { GID_CNICK_LONGBOW, 0, 0, 0, "RH Budget", "<noname110>", -1, 1, { WORKAROUND_FAKE, 0 } }, // when starting the game
{ GID_ECOQUEST, -1, -1, 0, NULL, "doVerb", -1, 0, { WORKAROUND_FAKE, 0 } }, // almost clicking anywhere triggers this in almost all rooms
+ { GID_FANMADE, 516, 979, 0, "", "export 0", -1, 20, { WORKAROUND_FAKE, 0 } }, // Happens in Grotesteing after the logos
+ { GID_FANMADE, 528, 990, 0, "GDialog", "doit", -1, 4, { WORKAROUND_FAKE, 0 } }, // Happens in Cascade Quest when closing the glossary - bug #3038757
{ GID_FREDDYPHARKAS, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
{ GID_FREDDYPHARKAS, -1, 31, 0, "quitWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
- { GID_GK1, -1, 64950, 1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // sometimes when walk-clicking
+ { GID_GK1, -1, 64950, -1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // sometimes when walk-clicking
{ GID_GK2, -1, 11, 0, "", "export 10", -1, 3, { WORKAROUND_FAKE, 0 } }, // called when the game starts
{ GID_GK2, -1, 11, 0, "", "export 10", -1, 4, { WORKAROUND_FAKE, 0 } }, // called during the game
{ GID_HOYLE1, 4, 104, 0, "GinRummyCardList", "calcRuns", -1, 4, { WORKAROUND_FAKE, 0 } }, // Gin Rummy / right when the game starts
@@ -69,6 +84,8 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_HOYLE3, -1, 0, 1, "Character", "say", -1, 504, { WORKAROUND_FAKE, 0 } }, // when starting checkers or dominoes, first time a character says something
{ GID_HOYLE3, -1, 0, 1, "Character", "say", -1, 505, { WORKAROUND_FAKE, 0 } }, // when starting checkers or dominoes, first time a character says something
{ GID_HOYLE3, -1, 700, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu
+ { GID_HOYLE4, -1, 0, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when selecting "Control" from the menu (temp vars 0-3) - bug #3039294
+ { GID_HOYLE4, 910, 910, 0, "IconBarList", "setup", -1, 3, { WORKAROUND_FAKE, 0 } }, // when selecting "Tutorial" from the main menu - bug #3039294
{ GID_ISLANDBRAIN, 140, 140, 0, "piece", "init", -1, 3, { WORKAROUND_FAKE, 1 } }, // first puzzle right at the start, some initialization variable. bnt is done on it, and it should be non-0
{ GID_ISLANDBRAIN, 200, 268, 0, "anElement", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // elements puzzle, gets used before super TextIcon
{ GID_JONES, 1, 232, 0, "weekendText", "draw", 0x3d3, 0, { WORKAROUND_FAKE, 0 } }, // jones/cd only - gets called during the game
@@ -84,17 +101,19 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_KQ6, 520, 520, 0, "rm520", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // going to boiling water trap on beast isle
{ GID_KQ6, -1, 903, 0, "controlWin", "open", -1, 4, { WORKAROUND_FAKE, 0 } }, // when opening the controls window (save, load etc)
{ GID_KQ7, 30, 64996, 0, "User", "handleEvent", -1, 1, { WORKAROUND_FAKE, 0 } }, // called when pushing a keyboard key
- { GID_LAURABOW, 44, 967, 0, "myIcon", "cycle", -1, 1, { WORKAROUND_FAKE, 0 } }, // second dialog box after the intro, when talking with Lillian - bug #3034985
+ { GID_LAURABOW, 37, 0, 0, "CB1", "doit", -1, 1, { WORKAROUND_FAKE, 0 } }, // when going up the stairs (bug #3037694)
+ { GID_LAURABOW, -1, 967, 0, "myIcon", "cycle", -1, 1, { WORKAROUND_FAKE, 0 } }, // having any portrait conversation coming up (initial bug #3034985)
{ GID_LAURABOW2, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
- { GID_LAURABOW2, -1, 21, 0, "dropCluesCode", "doit", -1, 1, { WORKAROUND_FAKE, 0 } }, // when asking some questions (e.g. the reporter about the burglary, or the policeman about Ziggy) - bugs #3035068, #3036274
+ { GID_LAURABOW2, -1, 21, 0, "dropCluesCode", "doit", -1, 1, { WORKAROUND_FAKE, 0x7fff } }, // when asking some questions (e.g. the reporter about the burglary, or the policeman about Ziggy). Must be big, as the game scripts perform lt on it and start deleting journal entries - bugs #3035068, #3036274
{ GID_LAURABOW2, 240, 240, 0, "sSteveAnimates", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // Steve Dorian's idle animation at the docks - bug #3036291
- { GID_LONGBOW, -1, 213, 0, "clear", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // When giving an aswer using the druid hand sign code in any room
+ { GID_LONGBOW, -1, 213, 0, "clear", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // When giving an answer using the druid hand sign code in any room
{ GID_LONGBOW, -1, 213, 0, "letter", "handleEvent", 0xa8, 1, { WORKAROUND_FAKE, 0 } }, // When using the druid hand sign code in any room - bug #3036601
{ GID_LSL1, 250, 250, 0, "increase", "handleEvent", -1, 2, { WORKAROUND_FAKE, 0 } }, // casino, playing game, increasing bet
{ GID_LSL1, 720, 720, 0, "rm720", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // age check room
{ GID_LSL2, 38, 38, 0, "cloudScript", "changeState", -1, 1, { WORKAROUND_FAKE, 0 } }, // entering the room in the middle deck of the ship - bug #3036483
{ GID_LSL3, 340, 340, 0, "ComicScript", "changeState", -1, -1, { WORKAROUND_FAKE, 0 } }, // right after entering the 3 ethnic groups inside comedy club (temps 200, 201, 202, 203)
{ GID_LSL3, -1, 997, 0, "TheMenuBar", "handleEvent", -1, 1, { WORKAROUND_FAKE, 0xf } }, // when setting volume the first time, this temp is used to set volume on entry (normally it would have been initialized to 's')
+ { GID_LSL6, 820, 82, 0, "", "export 0", -1, -1, { WORKAROUND_FAKE, 0 } }, // when touching the electric fence - bug #3038326
{ GID_LSL6, -1, 85, 0, "washcloth", "doVerb", -1, 0, { WORKAROUND_FAKE, 0 } }, // washcloth in inventory
{ GID_LSL6, -1, 928, -1, "Narrator", "startText", -1, 0, { WORKAROUND_FAKE, 0 } }, // used by various objects that are even translated in foreign versions, that's why we use the base-class
{ GID_LSL6HIRES, 0, 85, 0, "LL6Inv", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // on startup
@@ -103,16 +122,22 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_MOTHERGOOSE, 18, 992, 0, "AIPath", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // DEMO: Called when walking north from mother goose's house two screens
{ GID_MOTHERGOOSEHIRES,-1,64950, 1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // right when clicking on a child at the start and probably also later
{ GID_MOTHERGOOSEHIRES,-1,64950, 1, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // see above
+ { GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbd0, 0, { WORKAROUND_FAKE, 0 } }, // hq1: going to the brigands hideout
+ { GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbe4, 0, { WORKAROUND_FAKE, 0 } }, // qfg1: going to the brigands hideout
{ GID_QFG2, -1, 71, 0, "theInvSheet", "doit", -1, 1, { WORKAROUND_FAKE, 0 } }, // accessing the inventory
- { GID_QFG2, -1, 701, 0, "Alley", "at", -1, 0, { WORKAROUND_FAKE, 0 } }, // when walking inside the alleys in the town - bug #3035835
- { GID_QFG3, 330, 330, 0, "rajahTeller", "doChild", -1, 0, { WORKAROUND_FAKE, 0 } }, // when talking to King Rajah about "Tarna"
- { GID_QFG3, 330, 330, 0, "rajahTeller", "doChild", -1, 1, { WORKAROUND_FAKE, 0 } }, // when talking to King Rajah about "Rajah" - bug #3036390
- { GID_SQ1, 103, 103, 0, "hand", "internalEvent", -1, 1, { WORKAROUND_FAKE, 0 } }, // spanish (and maybe early versions?) only: when moving cursor over input pad
- { GID_SQ1, 103, 103, 0, "hand", "internalEvent", -1, 2, { WORKAROUND_FAKE, 0 } }, // spanish (and maybe early versions?) only: when moving cursor over input pad
+ { GID_QFG2, -1, 701, -1, "Alley", "at", -1, 0, { WORKAROUND_FAKE, 0 } }, // when walking inside the alleys in the town - bug #3035835 & #3038367
+ { GID_QFG2, -1, 990, 0, "Restore", "doit", -1, 364, { WORKAROUND_FAKE, 0 } }, // when pressing enter in restore dialog w/o any saved games present
+ { GID_QFG2, 260, 260, 0, "abdulS", "changeState",0x2d22, -1, { WORKAROUND_FAKE, 0 } }, // During the thief's first mission (in the house), just before the second brother is about to enter the house (where you have to hide in the wardrobe), bug #3039891, temps 1 and 2
+ { GID_QFG3, 330, 330, -1, "Teller", "doChild", -1, -1, { WORKAROUND_FAKE, 0 } }, // when talking to King Rajah about "Rajah" (bug #3036390, temp 1) or "Tarna" (temp 0), or when clicking on yourself and saying "Greet" (bug #3039774, temp 1)
+ { GID_QFG4, -1, 15, -1, "charInitScreen", "dispatchEvent", -1, 5, { WORKAROUND_FAKE, 0 } }, // floppy version, when viewing the character screen
+ { GID_QFG4, -1, 64917, -1, "controlPlane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, when entering the game menu
+ { GID_QFG4, -1, 64917, -1, "Plane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, happen sometimes in fights
+ { GID_SQ1, 103, 103, 0, "hand", "internalEvent", -1, -1, { WORKAROUND_FAKE, 0 } }, // Spanish (and maybe early versions?) only: when moving cursor over input pad, temps 1 and 2
{ GID_SQ1, -1, 703, 0, "", "export 1", -1, 0, { WORKAROUND_FAKE, 0 } }, // sub that's called from several objects while on sarien battle cruiser
{ GID_SQ1, -1, 703, 0, "firePulsar", "changeState", 0x18a, 0, { WORKAROUND_FAKE, 0 } }, // export 1, but called locally (when shooting at aliens)
{ GID_SQ4, -1, 398, 0, "showBox", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // sq4cd: called when rummaging in Software Excess bargain bin
{ GID_SQ4, -1, 928, 0, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // sq4cd: method returns this to the caller
+ { GID_SQ5, 201, 201, 0, "buttonPanel", "doVerb", -1, 0, { WORKAROUND_FAKE, 1 } }, // when looking at the orange or red button - bug #3038563
{ GID_SQ6, 100, 0, 0, "SQ6", "init", -1, 2, { WORKAROUND_FAKE, 0 } }, // called when the game starts
{ GID_SQ6, 100, 64950, 0, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu
{ GID_SQ6, -1, 64964, 0, "DPath", "init", -1, 1, { WORKAROUND_FAKE, 0 } }, // during the game
@@ -129,19 +154,38 @@ const SciWorkaroundEntry kAbs_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kCelHigh_workarounds[] = {
- { GID_SQ1, 1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu
+ { GID_KQ5, -1, 255, 0, "deathIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #3037003
+ { GID_PQ2, -1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects
+ { GID_SQ1, 1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #3035720
SCI_WORKAROUNDENTRY_TERMINATOR
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kCelWide_workarounds[] = {
+ { GID_KQ5, -1, 255, 0, "deathIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #3037003
+ { GID_PQ2, -1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects
{ GID_SQ1, 1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #3035720
SCI_WORKAROUNDENTRY_TERMINATOR
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry kDeviceInfo_workarounds[] = {
+ { GID_FANMADE, -1, 994, 1, "Game", "save", 0xd1c, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (Cascade Quest)
+ { GID_FANMADE, -1, 994, 1, "Game", "save", 0xe55, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (Demo Quest)
+ { GID_FANMADE, -1, 994, 1, "Game", "save", 0xe57, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (I Want My C64 Back)
+ { GID_FANMADE, -1, 994, 1, "Game", "save", 0xe5c, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (Most of them)
+ { GID_FANMADE, -1, 994, 1, "Game", "restore", 0xd1c, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (Cascade Quest)
+ { GID_FANMADE, -1, 994, 1, "Game", "restore", 0xe55, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (Demo Quest)
+ { GID_FANMADE, -1, 994, 1, "Game", "restore", 0xe57, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (I Want My C64 Back)
+ { GID_FANMADE, -1, 994, 1, "Game", "restore", 0xe5c, 0, { WORKAROUND_STILLCALL, 0 } }, // In fanmade games, this is called with one parameter for CurDevice (Most of them)
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kDisplay_workarounds[] = {
{ GID_ISLANDBRAIN, 300, 300, 0, "geneDude", "show", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when looking at the gene explanation chart - a parameter is an object
+ { GID_PQ2, 23, 23, 0, "rm23Script", "elements", 0x4ae, 0, { WORKAROUND_IGNORE, 0 } }, // when looking at the 2nd page of pate's file - 0x75 as id
+ { GID_QFG1, 11, 11, 0, "battle", "<noname90>", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When entering battle, 0x75 as id
{ GID_SQ4, 391, 391, 0, "doCatalog", "mode", 0x84, 0, { WORKAROUND_IGNORE, 0 } }, // clicking on catalog in roboter sale - a parameter is an object
{ GID_SQ4, 391, 391, 0, "choosePlug", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // ordering connector in roboter sale - a parameter is an object
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -160,6 +204,8 @@ const SciWorkaroundEntry kDisposeScript_workarounds[] = {
const SciWorkaroundEntry kDoSoundFade_workarounds[] = {
{ GID_CAMELOT, -1, 989, 0, "rmMusic", "fade", -1, 0, { WORKAROUND_IGNORE, 0 } }, // gets called frequently with a NULL reference (i.e. 0:0) - bug #3035149
{ GID_KQ1, -1, 989, 0, "gameSound", "fade", -1, 0, { WORKAROUND_IGNORE, 0 } }, // gets called in several scenes (e.g. graham cracker) with 0:0
+ { GID_KQ4, -1, 989, 0, "mySound", "", -1, 0, { WORKAROUND_IGNORE, 0 } }, // gets called in the demo when trying to open the non-existent menu with 0:0 - bug #3036942
+ { GID_KQ5, 213, 989, 0, "globalSound3", "fade", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when bandits leave the secret temple, parameter 4 is an object - bug #3037594
{ GID_KQ6, 105, 989, 0, "globalSound", "fade", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // floppy: during intro, parameter 4 is an object
{ GID_KQ6, 460, 989, 0, "globalSound2", "fade", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // after pulling the black widow's web on the isle of wonder, parameter 4 is an object - bug #3034567
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -167,6 +213,7 @@ const SciWorkaroundEntry kDoSoundFade_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kGetAngle_workarounds[] = {
+ { GID_FANMADE, 516, 992, 0, "Motion", "init", -1, 0, { WORKAROUND_IGNORE, 0 } }, // The Legend of the Lost Jewel Demo (fan made): called with third/fourth parameters as objects
{ GID_KQ6, 740, 752, 0, "throwDazzle", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // after the Genie is exposed in the Palace (short and long ending), it starts shooting lightning bolts around. An extra 5th parameter is passed - bug #3034610
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -190,6 +237,7 @@ const SciWorkaroundEntry kGraphSaveBox_workarounds[] = {
{ GID_ISLANDBRAIN, 290, 291, 0, "upElevator", "changeState",0x201f, 0, { WORKAROUND_STILLCALL, 0 } }, // when testing in the elevator puzzle, gets called with 1 argument less - 15 is on stack - bug #3034485
{ GID_ISLANDBRAIN, 290, 291, 0, "downElevator", "changeState",0x201f, 0, { WORKAROUND_STILLCALL, 0 } }, // see above
{ GID_ISLANDBRAIN, 290, 291, 0, "correctElevator", "changeState",0x201f, 0, { WORKAROUND_STILLCALL, 0 } }, // see above (when testing the correct solution)
+ { GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -228,6 +276,13 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = {
+ { GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077
+ { GID_PQ3, 202, 202, 0, "MapEdit", "addPt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kIsObject_workarounds[] = {
{ GID_GK1, 50, 999, 0, "List", "eachElementDo", -1, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #3034519
{ GID_ISLANDBRAIN, -1, 999, 0, "List", "eachElementDo", -1, 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 #3035262
@@ -243,13 +298,19 @@ const SciWorkaroundEntry kMemory_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kNewWindow_workarounds[] = {
- { GID_ECOQUEST, -1, 981, 0, "SysWindow", "<noname 178>", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // EcoQuest 1 demo uses an in-between interpreter from SCI1 to SCI1.1. It's SCI1.1, but uses the SCI1 semantics for this call - bug #3035057
+ { GID_ECOQUEST, -1, 981, 0, "SysWindow", "<noname178>", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // EcoQuest 1 demo uses an in-between interpreter from SCI1 to SCI1.1. It's SCI1.1, but uses the SCI1 semantics for this call - bug #3035057
SCI_WORKAROUNDENTRY_TERMINATOR
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = {
- { GID_QFG4, 100, 100, 0, "doMovie", "<noname 144>", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #3034506
+ { GID_QFG4, 100, 100, 0, "doMovie", "<noname144>", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #3034506
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry kSetCursor_workarounds[] = {
+ { GID_KQ5, -1, 768, 0, "KQCursor", "init", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // CD: gets called with 4 additional "900d" parameters
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -260,6 +321,12 @@ const SciWorkaroundEntry kSetPort_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
+const SciWorkaroundEntry kStrAt_workarounds[] = {
+ { GID_ISLANDBRAIN, 300, 310, 0, "childBreed", "changeState",0x1c7c, 0, { WORKAROUND_FAKE, 0 } }, // when clicking Breed to get the second-generation cyborg hybrid (Standard difficulty), the two parameters are swapped - bug #3037835
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kUnLoad_workarounds[] = {
{ GID_CAMELOT, 921, 921, 1, "Script", "changeState", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: While showing Camelot (and other places), the reference is invalid - bug #3035000
{ GID_CAMELOT, 921, 921, 1, "Script", "init", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When being attacked by the boar (and other places), the reference is invalid - bug #3035000
@@ -274,6 +341,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = {
{ GID_LSL6, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident
{ GID_LSL6, 740, 740, 0, "showCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during ending, 4 additional parameters are passed by accident
{ GID_LSL6HIRES, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident
+ { GID_PQ3, 877, 998, 0, "View", "delete", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when getting run over on the freeway, the reference is invalid
{ GID_SQ1, 43, 303, 0, "slotGuy", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when leaving ulence flats bar, parameter 1 is not passed - script error
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index d509d300d7..8a3edb6246 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -69,12 +69,15 @@ struct SciWorkaroundEntry {
};
extern const SciWorkaroundEntry opcodeDivWorkarounds[];
-extern const SciWorkaroundEntry opcodeOrWorkarounds[];
extern const SciWorkaroundEntry opcodeDptoaWorkarounds[];
+extern const SciWorkaroundEntry opcodeGeWorkarounds[];
+extern const SciWorkaroundEntry opcodeMulWorkarounds[];
+extern const SciWorkaroundEntry opcodeOrWorkarounds[];
extern const SciWorkaroundEntry uninitializedReadWorkarounds[];
extern const SciWorkaroundEntry kAbs_workarounds[];
extern const SciWorkaroundEntry kCelHigh_workarounds[];
extern const SciWorkaroundEntry kCelWide_workarounds[];
+extern const SciWorkaroundEntry kDeviceInfo_workarounds[];
extern const SciWorkaroundEntry kDisplay_workarounds[];
extern const SciWorkaroundEntry kDisposeScript_workarounds[];
extern const SciWorkaroundEntry kDoSoundFade_workarounds[];
@@ -83,6 +86,7 @@ extern const SciWorkaroundEntry kGetAngle_workarounds[];
extern const SciWorkaroundEntry kGraphDrawLine_workarounds[];
extern const SciWorkaroundEntry kGraphSaveBox_workarounds[];
extern const SciWorkaroundEntry kGraphRestoreBox_workarounds[];
+extern const SciWorkaroundEntry kGraphUpdateBox_workarounds[];
extern const SciWorkaroundEntry kGraphFillBoxForeground_workarounds[];
extern const SciWorkaroundEntry kGraphFillBoxAny_workarounds[];
extern const SciWorkaroundEntry kGraphRedrawBox_workarounds[];
@@ -90,7 +94,9 @@ extern const SciWorkaroundEntry kIsObject_workarounds[];
extern const SciWorkaroundEntry kMemory_workarounds[];
extern const SciWorkaroundEntry kNewWindow_workarounds[];
extern const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[];
+extern const SciWorkaroundEntry kSetCursor_workarounds[];
extern const SciWorkaroundEntry kSetPort_workarounds[];
+extern const SciWorkaroundEntry kStrAt_workarounds[];
extern const SciWorkaroundEntry kUnLoad_workarounds[];
extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin);
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index c637ef8374..ab4362cda9 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -177,6 +177,15 @@ void GfxAnimate::makeSortedList(List *list) {
curNode = _s->_segMan->lookupNode(curAddress);
}
+ // Possible TODO: As noted in the comment in sortHelper we actually
+ // require a stable sorting algorithm here. Since Common::sort is not stable
+ // at the time of writing this comment, we work around that in our ordering
+ // comparator. If that changes in the future or we want to use some
+ // stable sorting algorithm here, we should change that.
+ // In that case we should test such changes intensively. A good place to test stable sort
+ // is iceman, cupboard within the submarine. If sort isn't stable, the cupboard will be
+ // half-open, half-closed. Of course that's just one of many special cases.
+
// Now sort the list according y and z (descending)
Common::sort(_list.begin(), _list.end(), sortHelper);
}
@@ -190,6 +199,7 @@ void GfxAnimate::fill(byte &old_picNotValid) {
for (it = _list.begin(); it != end; ++it) {
curObject = it->object;
+ signal = it->signal;
// Get the corresponding view
view = _cache->getView(it->viewId);
@@ -233,18 +243,30 @@ void GfxAnimate::fill(byte &old_picNotValid) {
}
}
+ if (!view->isScaleable()) {
+ // Laura Bow 2 (especially floppy) depends on this, some views are not supposed to be scaleable
+ // this "feature" was removed in later versions of SCI1.1
+ it->scaleSignal = 0;
+ it->scaleY = it->scaleX = 128;
+ }
+
+ bool setNsRect = true;
+
// Create rect according to coordinates and given cel
if (it->scaleSignal & kScaleSignalDoScaling) {
view->getCelScaledRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->scaleX, it->scaleY, it->celRect);
+ // when being scaled, only set nsRect, if object will get drawn
+ if ((signal & kSignalHidden) && !(signal & kSignalAlwaysUpdate))
+ setNsRect = false;
} else {
view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
}
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), it->celRect.right);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), it->celRect.bottom);
-
- signal = it->signal;
+ if (setNsRect) {
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), it->celRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), it->celRect.bottom);
+ }
// Calculate current priority according to y-coordinate
if (!(signal & kSignalFixedPriority)) {
@@ -521,13 +543,21 @@ void GfxAnimate::addToPicDrawCels() {
}
}
-void GfxAnimate::addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
+void GfxAnimate::addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y, int16 priority, int16 control) {
GfxView *view = _cache->getView(viewId);
Common::Rect celRect;
+ if (priority == -1)
+ priority = _ports->kernelCoordinateToPriority(y);
+
// Create rect according to coordinates and given cel
- view->getCelRect(loopNo, celNo, leftPos, topPos, priority, celRect);
+ view->getCelRect(loopNo, celNo, x, y, 0, celRect);
_paint16->drawCel(view, loopNo, celNo, celRect, priority, 0);
+
+ if (control != -1) {
+ celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(priority) - 1, celRect.top, celRect.bottom - 1);
+ _paint16->fillRect(celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, control);
+ }
}
@@ -595,14 +625,49 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
updateScreen(old_picNotValid);
restoreAndDelete(argc, argv);
- if (_lastCastData.size() > 1)
- _s->_throttleTrigger = true;
-
// We update the screen here as well, some scenes like EQ1 credits run w/o calling kGetEvent thus we wouldn't update
// screen at all
g_sci->getEventManager()->updateScreen();
_ports->setPort(oldPort);
+
+
+ // Now trigger speed throttler
+ switch (_lastCastData.size()) {
+ case 0:
+ // No entries drawn -> no speed throttler triggering
+ break;
+ case 1: {
+
+ // One entry drawn -> check if that entry was a speed benchmark view, if not enable speed throttler
+ AnimateEntry *onlyCast = &_lastCastData[0];
+ if ((onlyCast->viewId == 0) && (onlyCast->loopNo == 13) && (onlyCast->celNo == 0)) {
+ // this one is used by jones talkie
+ if ((onlyCast->celRect.height() == 8) && (onlyCast->celRect.width() == 8))
+ return;
+ }
+ // first loop and first cel used?
+ if ((onlyCast->loopNo == 0) && (onlyCast->celNo == 0)) {
+ // and that cel has a known speed benchmark resolution
+ int16 onlyHeight = onlyCast->celRect.height();
+ int16 onlyWidth = onlyCast->celRect.width();
+ if (((onlyWidth == 12) && (onlyHeight == 35)) || // regular benchmark view ("fred", "Speedy", "ego")
+ ((onlyWidth == 29) && (onlyHeight == 45)) || // King's Quest 5 french "fred"
+ ((onlyWidth == 1) && (onlyHeight == 1))) { // Laura Bow 2 Talkie
+ // check further that there is only one cel in that view
+ GfxView *onlyView = _cache->getView(onlyCast->viewId);
+ if ((onlyView->getLoopCount() == 1) && (onlyView->getCelCount(0)))
+ return;
+ }
+ }
+ _s->_throttleTrigger = true;
+ break;
+ }
+ default:
+ // More than 1 entry drawn -> time for speed throttling
+ _s->_throttleTrigger = true;
+ break;
+ }
}
void GfxAnimate::addToPicSetPicNotValid() {
@@ -627,9 +692,9 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv)
addToPicSetPicNotValid();
}
-void GfxAnimate::kernelAddToPicView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
+void GfxAnimate::kernelAddToPicView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y, int16 priority, int16 control) {
_ports->setPort((Port *)_ports->_picWind);
- addToPicDrawView(viewId, loopNo, celNo, leftPos, topPos, priority, control);
+ addToPicDrawView(viewId, loopNo, celNo, x, y, priority, control);
addToPicSetPicNotValid();
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 06dce6d111..a433b26ef2 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -68,6 +68,7 @@ void GfxFrameout::kernelAddPlane(reg_t object) {
newPlane.object = object;
newPlane.pictureId = 0xFFFF;
+ newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority));
newPlane.lastPriority = 0xFFFF; // hidden
_planes.push_back(newPlane);
@@ -108,10 +109,12 @@ void GfxFrameout::kernelDeletePlane(reg_t object) {
planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1;
planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1;
- planeRect.top = (planeRect.top * _screen->getHeight()) / scriptsRunningHeight;
- planeRect.left = (planeRect.left * _screen->getWidth()) / scriptsRunningWidth;
- planeRect.bottom = (planeRect.bottom * _screen->getHeight()) / scriptsRunningHeight;
- planeRect.right = (planeRect.right * _screen->getWidth()) / scriptsRunningWidth;
+ Common::Rect screenRect(_screen->getWidth(), _screen->getHeight());
+ planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight;
+ planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth;
+ planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight;
+ planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth;
+ planeRect.clip(screenRect); // we need to do this, at least in gk1 on cemetary we get bottom right -> 201, 321
// Blackout removed plane rect
_paint32->fillRect(planeRect, 0);
return;
@@ -125,6 +128,7 @@ void GfxFrameout::addPlanePicture(reg_t object, GuiResourceId pictureId, uint16
newPicture.pictureId = pictureId;
newPicture.picture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, pictureId, false);
newPicture.startX = startX;
+ newPicture.pictureCels = 0;
_planePictures.push_back(newPicture);
}
@@ -218,10 +222,11 @@ void GfxFrameout::kernelFrameout() {
// Update priority here, sq6 sets it w/o UpdatePlane
uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
- planeRect.top = (planeRect.top * _screen->getHeight()) / scriptsRunningHeight;
- planeRect.left = (planeRect.left * _screen->getWidth()) / scriptsRunningWidth;
- planeRect.bottom = (planeRect.bottom * _screen->getHeight()) / scriptsRunningHeight;
- planeRect.right = (planeRect.right * _screen->getWidth()) / scriptsRunningWidth;
+ Common::Rect screenRect(_screen->getWidth(), _screen->getHeight());
+ planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight;
+ planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth;
+ planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight;
+ planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth;
int16 planeOffsetX = 0;
@@ -364,7 +369,7 @@ void GfxFrameout::kernelFrameout() {
int16 pictureOffsetX = planeOffsetX;
int16 pictureX = itemEntry->x;
- if (planeOffsetX) {
+ if ((planeOffsetX) || (itemEntry->picStartX)) {
if (planeOffsetX <= itemEntry->picStartX) {
pictureX += itemEntry->picStartX - planeOffsetX;
pictureOffsetX = 0;
@@ -480,7 +485,15 @@ void GfxFrameout::kernelFrameout() {
// This draws text the "SCI0-SCI11" way. In SCI2, text is prerendered in kCreateTextBitmap
// TODO: rewrite this the "SCI2" way (i.e. implement the text buffer to draw inside kCreateTextBitmap)
if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) {
- Common::String text = _segMan->getString(readSelector(_segMan, itemEntry->object, SELECTOR(text)));
+ reg_t stringObject = readSelector(_segMan, itemEntry->object, SELECTOR(text));
+
+ // The object in the text selector of the item can be either a raw string
+ // or a Str object. In the latter case, we need to access the object's data
+ // selector to get the raw string.
+ if (_segMan->isHeapObject(stringObject))
+ stringObject = readSelector(_segMan, stringObject, SELECTOR(data));
+
+ Common::String text = _segMan->getString(stringObject);
GfxFont *font = _cache->getFont(readSelectorValue(_segMan, itemEntry->object, SELECTOR(font)));
bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed));
uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore));
diff --git a/engines/sci/graphics/paint.cpp b/engines/sci/graphics/paint.cpp
index 13dcebc27a..50b0534ba7 100644
--- a/engines/sci/graphics/paint.cpp
+++ b/engines/sci/graphics/paint.cpp
@@ -49,8 +49,4 @@ void GfxPaint::kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, ui
void GfxPaint::kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) {
}
-void GfxPaint::kernelShakeScreen(uint16 shakeCount, uint16 directions) {
- warning("Unimplemented kShakeScreen");
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/paint.h b/engines/sci/graphics/paint.h
index 75a17461d4..994bc4e5e9 100644
--- a/engines/sci/graphics/paint.h
+++ b/engines/sci/graphics/paint.h
@@ -38,10 +38,6 @@ public:
virtual void kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo);
virtual void kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle);
virtual void kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control);
-
- virtual void kernelShakeScreen(uint16 shakeCount, uint16 directions);
-
-private:
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index bb3975e9ef..4551e9dafc 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -459,8 +459,8 @@ void GfxPaint16::kernelGraphRedrawBox(Common::Rect rect) {
#define SCI_DISPLAY_WIDTH 106
#define SCI_DISPLAY_SAVEUNDER 107
#define SCI_DISPLAY_RESTOREUNDER 108
-#define SCI_DISPLAY_DUMMY1 114 // used in longbow-demo, not supported in sierra sci - no parameters
-#define SCI_DISPLAY_DUMMY2 115 // used in longbow-demo, not supported in sierra sci - has 1 parameter
+#define SCI_DISPLAY_DUMMY1 114 // used in longbow demo/qfg1 ega demo, not supported in sierra sci - no parameters
+#define SCI_DISPLAY_DUMMY2 115 // used in longbow demo, not supported in sierra sci - has 1 parameter
#define SCI_DISPLAY_DONTSHOWBITS 121
reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
@@ -531,15 +531,16 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
break;
// 2 Dummy functions, longbow-demo is using those several times but sierra sci doesn't support them at all
+ // The Quest for Glory 1 EGA demo also calls kDisplay(114)
case SCI_DISPLAY_DUMMY1:
case SCI_DISPLAY_DUMMY2:
- if (!((g_sci->getGameId() == GID_LONGBOW) && (g_sci->isDemo())))
- error("Unknown kDisplay argument %X", displayArg.offset);
+ if (!g_sci->isDemo() || (g_sci->getGameId() != GID_LONGBOW && g_sci->getGameId() != GID_QFG1))
+ error("Unknown kDisplay argument %d", displayArg.offset);
if (displayArg.offset == SCI_DISPLAY_DUMMY2) {
if (argc) {
argc--; argv++;
} else {
- error("No parameter left for kDisplay(0x73)");
+ error("No parameter left for kDisplay(115)");
}
}
break;
@@ -596,23 +597,6 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
return result;
}
-// TODO: If this matches the sci32 implementation, we may put it into GfxScreen
-void GfxPaint16::kernelShakeScreen(uint16 shakeCount, uint16 directions) {
- while (shakeCount--) {
- if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
- _screen->setVerticalShakePos(10);
- // TODO: horizontal shakes
- g_system->updateScreen();
- g_sci->getEngineState()->wait(3);
-
- if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
- _screen->setVerticalShakePos(0);
-
- g_system->updateScreen();
- g_sci->getEngineState()->wait(3);
- }
-}
-
reg_t GfxPaint16::kernelPortraitLoad(const Common::String &resourceName) {
//Portrait *myPortrait = new Portrait(g_sci->getResMan(), _screen, _palette, resourceName);
return NULL_REG;
diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h
index edffa8da6e..e944c71bdd 100644
--- a/engines/sci/graphics/paint16.h
+++ b/engines/sci/graphics/paint16.h
@@ -88,8 +88,6 @@ public:
reg_t kernelDisplay(const char *text, int argc, reg_t *argv);
- void kernelShakeScreen(uint16 shakeCount, uint16 directions);
-
reg_t kernelPortraitLoad(const Common::String &resourceName);
void kernelPortraitShow(const Common::String &resourceName, Common::Point position, uint16 resourceNum, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
void kernelPortraitUnload(uint16 portraitId);
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index 9268888b6c..2e9128cda6 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -27,7 +27,9 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
+#include "sci/engine/kernel.h"
#include "sci/engine/state.h"
+#include "sci/engine/selector.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint16.h"
#include "sci/graphics/animate.h"
@@ -50,7 +52,10 @@ GfxPorts::GfxPorts(SegManager *segMan, GfxScreen *screen)
}
GfxPorts::~GfxPorts() {
- // TODO: Clear _windowList and delete all stuff in it?
+ // reset frees all windows but _picWind
+ reset();
+ freeWindow(_picWind);
+ delete _wmgrPort;
delete _menuPort;
}
@@ -99,8 +104,15 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te
offTop = 0;
break;
case GID_MOTHERGOOSE:
- if (getSciVersion() == SCI_VERSION_1_EARLY)
+ // TODO: if mother goose EGA also uses offTop we can simply remove this check altogether
+ switch (getSciVersion()) {
+ case SCI_VERSION_1_EARLY:
+ case SCI_VERSION_1_1:
offTop = 0;
+ break;
+ default:
+ break;
+ }
break;
case GID_FAIRYTALES:
// Mixed-Up Fairy Tales (& its demo) uses -w 26 0 200 320. If we don't
@@ -128,7 +140,7 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te
_wmgrPort->curLeft = 0;
_windowList.push_front(_wmgrPort);
- _picWind = newWindow(Common::Rect(0, offTop, _screen->getWidth(), _screen->getHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true);
+ _picWind = addWindow(Common::Rect(0, offTop, _screen->getWidth(), _screen->getHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true);
// For SCI0 games till kq4 (.502 - not including) we set _picWind top to offTop instead
// Because of the menu/status bar
if (g_sci->_features->usesOldGfxFunctions())
@@ -137,6 +149,30 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te
kernelInitPriorityBands();
}
+// Removes any windows from windowList
+// is used when restoring/restarting the game
+// Sierra SCI actually saved the whole windowList, it seems we don't need to do this at all
+// but in some games there are still windows active when restoring. Leaving those windows open
+// would create all sorts of issues, that's why we remove them
+void GfxPorts::reset() {
+ PortList::iterator it = _windowList.begin();
+ const PortList::iterator end = _windowList.end();
+
+ setPort(_picWind);
+
+ while (it != end) {
+ Port *pPort = *it;
+ if (pPort->id > 2) {
+ // found a window beyond _picWind
+ freeWindow((Window *)pPort);
+ }
+ it++;
+ }
+ _windowList.clear();
+ _windowList.push_front(_wmgrPort);
+ _windowList.push_back(_picWind);
+}
+
void GfxPorts::kernelSetActive(uint16 portId) {
switch (portId) {
case 0:
@@ -145,8 +181,13 @@ void GfxPorts::kernelSetActive(uint16 portId) {
case 0xFFFF:
setPort(_menuPort);
break;
- default:
- setPort(getPortById(portId));
+ default: {
+ Port *newPort = getPortById(portId);
+ if (newPort)
+ setPort(newPort);
+ else
+ error("GfxPorts::kernelSetActive was requested to set invalid port id %d", portId);
+ }
};
}
@@ -172,9 +213,9 @@ reg_t GfxPorts::kernelNewWindow(Common::Rect dims, Common::Rect restoreRect, uin
Window *wnd = NULL;
if (restoreRect.bottom != 0 && restoreRect.right != 0)
- wnd = newWindow(dims, &restoreRect, title, style, priority, false);
+ wnd = addWindow(dims, &restoreRect, title, style, priority, false);
else
- wnd = newWindow(dims, NULL, title, style, priority, false);
+ wnd = addWindow(dims, NULL, title, style, priority, false);
wnd->penClr = colorPen;
wnd->backClr = colorBack;
drawWindow(wnd);
@@ -184,7 +225,36 @@ reg_t GfxPorts::kernelNewWindow(Common::Rect dims, Common::Rect restoreRect, uin
void GfxPorts::kernelDisposeWindow(uint16 windowId, bool reanimate) {
Window *wnd = (Window *)getPortById(windowId);
- disposeWindow(wnd, reanimate);
+ if (wnd)
+ removeWindow(wnd, reanimate);
+ else
+ error("GfxPorts::kernelDisposeWindow: Request to dispose invalid port id %d", windowId);
+
+ if ((g_sci->getGameId() == GID_HOYLE4) && (!g_sci->isDemo())) {
+ // WORKAROUND: hoyle 4 has a broken User::handleEvent implementation
+ // first of all iconbar is always set and always gets called with
+ // events checking if event got claimed got removed inside that code
+ // and it will call handleEvent on gameObj afterwards. Iconbar windows
+ // are handled inside iconbar as well including disposing
+ // e.g. iconOK::doit, script 14) and claimed isn't even set. gameObj
+ // handleEvent calling will result in coordinate adjust with a now
+ // invalid port.
+ // We fix this by adjusting the port variable to be global
+ // again when hoyle4 is disposing windows.
+ // This worked because sierra sci leaves old port data, so the pointer
+ // was still valid for a short period of time
+ // TODO: maybe this could get implemented as script patch somehow
+ // although this could get quite tricky to implement (script 996)
+ // IconBar::handleEvent (script 937)
+ // maybe inside export 8 of script 0, which is called by iconOK
+ // and iconReplay
+ // or inside GameControls::hide (script 978) which is called to
+ // actually remove the window
+ reg_t eventObject = _segMan->findObjectByName("uEvt");
+ if (!eventObject.isNull()) {
+ writeSelectorValue(_segMan, eventObject, SELECTOR(port), 0);
+ }
+ }
}
int16 GfxPorts::isFrontWindow(Window *pWnd) {
@@ -221,7 +291,7 @@ void GfxPorts::endUpdate(Window *wnd) {
setPort(oldPort);
}
-Window *GfxPorts::newWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw) {
+Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw) {
// Find an unused window/port id
uint id = 1;
while (id < _windowsById.size() && _windowsById[id]) {
@@ -371,7 +441,7 @@ void GfxPorts::drawWindow(Window *pWnd) {
setPort(oldport);
}
-void GfxPorts::disposeWindow(Window *pWnd, bool reanimate) {
+void GfxPorts::removeWindow(Window *pWnd, bool reanimate) {
setPort(_wmgrPort);
_paint16->bitsRestore(pWnd->hSaved1);
_paint16->bitsRestore(pWnd->hSaved2);
@@ -381,6 +451,15 @@ void GfxPorts::disposeWindow(Window *pWnd, bool reanimate) {
_paint16->kernelGraphRedrawBox(pWnd->restoreRect);
_windowList.remove(pWnd);
setPort(_windowList.back());
+ _windowsById[pWnd->id] = NULL;
+ delete pWnd;
+}
+
+void GfxPorts::freeWindow(Window *pWnd) {
+ if (!pWnd->hSaved1.isNull())
+ _segMan->freeHunkEntry(pWnd->hSaved1);
+ if (!pWnd->hSaved2.isNull())
+ _segMan->freeHunkEntry(pWnd->hSaved1);
_windowsById[pWnd->id] = 0;
delete pWnd;
}
@@ -401,13 +480,9 @@ void GfxPorts::updateWindow(Window *wnd) {
}
Port *GfxPorts::getPortById(uint16 id) {
- if (id > _windowsById.size())
- error("getPortById() received invalid id");
- return _windowsById[id];
+ return (id < _windowsById.size()) ? _windowsById[id] : NULL;
}
-
-
Port *GfxPorts::setPort(Port *newPort) {
Port *oldPort = _curPort;
_curPort = newPort;
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index d10bc6772f..f7f0721eb7 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -46,6 +46,7 @@ public:
~GfxPorts();
void init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *text16);
+ void reset();
void kernelSetActive(uint16 portId);
Common::Rect kernelGetPicWindow(int16 &picTop, int16 &picLeft);
@@ -57,9 +58,10 @@ public:
int16 isFrontWindow(Window *wnd);
void beginUpdate(Window *wnd);
void endUpdate(Window *wnd);
- Window *newWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw);
+ Window *addWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw);
void drawWindow(Window *wnd);
- void disposeWindow(Window *pWnd, bool reanimate);
+ void removeWindow(Window *pWnd, bool reanimate);
+ void freeWindow(Window *pWnd);
void updateWindow(Window *wnd);
Port *getPortById(uint16 id);
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 131a3d2eb8..839b9975c5 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -534,6 +534,22 @@ void GfxScreen::setVerticalShakePos(uint16 shakePos) {
g_system->setShakePos(shakePos * 2);
}
+void GfxScreen::kernelShakeScreen(uint16 shakeCount, uint16 directions) {
+ while (shakeCount--) {
+ if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
+ setVerticalShakePos(10);
+ // TODO: horizontal shakes
+ g_system->updateScreen();
+ g_sci->getEngineState()->wait(3);
+
+ if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
+ setVerticalShakePos(0);
+
+ g_system->updateScreen();
+ g_sci->getEngineState()->wait(3);
+ }
+}
+
void GfxScreen::dither(bool addToFlag) {
int y, x;
byte color, ditheredColor;
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index f1e3d028a8..97f5736289 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -109,8 +109,6 @@ public:
void getPalette(Palette *pal);
void setPalette(Palette *pal);
- void setVerticalShakePos(uint16 shakePos);
-
void scale2x(const byte *src, byte *dst, int16 srcWidth, int16 srcHeight);
void adjustToUpscaledCoordinates(int16 &y, int16 &x);
@@ -126,6 +124,7 @@ public:
int _picNotValidSci11; // another variable that is used by kPicNotValid in sci1.1
int16 kernelPicNotValid(int16 newPicNotValid);
+ void kernelShakeScreen(uint16 shakeCount, uint16 direction);
private:
uint16 _width;
@@ -143,6 +142,8 @@ private:
void bitsSaveScreen(Common::Rect rect, byte *screen, uint16 screenWidth, byte *&memoryPtr);
void bitsSaveDisplayScreen(Common::Rect rect, byte *&memoryPtr);
+ void setVerticalShakePos(uint16 shakePos);
+
bool _unditherState;
int16 _unditherMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE];
diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index 08be203230..fc07febe14 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -142,8 +142,8 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
uint16 curChar = 0;
int16 maxChars = 0, curCharCount = 0;
uint16 width = 0;
- GuiResourceId oldFontId = GetFontId();
- int16 oldPenColor = _ports->_curPort->penClr;
+ GuiResourceId previousFontId = GetFontId();
+ int16 previousPenColor = _ports->_curPort->penClr;
GetFont();
if (!_font)
@@ -159,7 +159,7 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
case 0x7C:
if (getSciVersion() >= SCI_VERSION_1_1) {
curCharCount++;
- curCharCount += CodeProcessing(text, orgFontId, oldPenColor);
+ curCharCount += CodeProcessing(text, orgFontId, previousPenColor);
continue;
}
break;
@@ -180,8 +180,8 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
curCharCount++;
// and it's also meant to pass through here
case 0:
- SetFont(oldFontId);
- _ports->penColor(oldPenColor);
+ SetFont(previousFontId);
+ _ports->penColor(previousPenColor);
return curCharCount;
case ' ':
@@ -226,15 +226,15 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
}
}
}
- SetFont(oldFontId);
- _ports->penColor(oldPenColor);
+ SetFont(previousFontId);
+ _ports->penColor(previousPenColor);
return maxChars;
}
-void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight) {
+void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont) {
uint16 curChar;
- GuiResourceId oldFontId = GetFontId();
- int16 oldPenColor = _ports->_curPort->penClr;
+ GuiResourceId previousFontId = GetFontId();
+ int16 previousPenColor = _ports->_curPort->penClr;
textWidth = 0; textHeight = 0;
@@ -264,13 +264,18 @@ void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId org
}
}
}
- SetFont(oldFontId);
- _ports->penColor(oldPenColor);
+ // When calculating size, we do not restore font because we need the current (code modified) font active
+ // If we are drawing this is called inbetween, so font needs to get restored
+ // If we are calculating size of just one fixed string (::StringWidth), then we need to restore
+ if (restoreFont) {
+ SetFont(previousFontId);
+ _ports->penColor(previousPenColor);
+ }
return;
}
void GfxText16::StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight) {
- Width(str, 0, (int16)strlen(str), orgFontId, textWidth, textHeight);
+ Width(str, 0, (int16)strlen(str), orgFontId, textWidth, textHeight, true);
}
void GfxText16::ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor) {
@@ -281,8 +286,8 @@ void GfxText16::DrawString(const char *str, GuiResourceId orgFontId, int16 orgPe
}
int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) {
- GuiResourceId oldFontId = GetFontId();
- int16 oldPenColor = _ports->_curPort->penClr;
+ GuiResourceId previousFontId = GetFontId();
+ int16 previousPenColor = _ports->_curPort->penClr;
int16 charCount;
int16 maxTextWidth = 0, textWidth;
int16 totalHeight = 0, textHeight;
@@ -290,7 +295,7 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId
if (fontId != -1)
SetFont(fontId);
else
- fontId = oldFontId;
+ fontId = previousFontId;
if (g_sci->getLanguage() == Common::JA_JPN)
SwitchToFont900OnSjis(text);
@@ -307,10 +312,10 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId
rect.right = (maxWidth ? maxWidth : 192);
const char *curPos = text;
while (*curPos) {
- charCount = GetLongest(curPos, rect.right, oldFontId);
+ charCount = GetLongest(curPos, rect.right, fontId);
if (charCount == 0)
break;
- Width(curPos, 0, charCount, fontId, textWidth, textHeight);
+ Width(curPos, 0, charCount, fontId, textWidth, textHeight, false);
maxTextWidth = MAX(textWidth, maxTextWidth);
totalHeight += textHeight;
curPos += charCount;
@@ -320,8 +325,8 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId
rect.bottom = totalHeight;
rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth);
}
- SetFont(oldFontId);
- _ports->penColor(oldPenColor);
+ SetFont(previousFontId);
+ _ports->penColor(previousPenColor);
return rect.right;
}
@@ -386,14 +391,14 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex
int16 textWidth, maxTextWidth, textHeight, charCount;
int16 offset = 0;
int16 hline = 0;
- GuiResourceId orgFontId = GetFontId();
- int16 orgPenColor = _ports->_curPort->penClr;
+ GuiResourceId previousFontId = GetFontId();
+ int16 previousPenColor = _ports->_curPort->penClr;
bool doubleByteMode = false;
if (fontId != -1)
SetFont(fontId);
else
- fontId = orgFontId;
+ fontId = previousFontId;
if (g_sci->getLanguage() == Common::JA_JPN) {
if (SwitchToFont900OnSjis(text))
@@ -402,10 +407,10 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex
maxTextWidth = 0;
while (*text) {
- charCount = GetLongest(text, rect.width(), orgFontId);
+ charCount = GetLongest(text, rect.width(), fontId);
if (charCount == 0)
break;
- Width(text, 0, charCount, orgFontId, textWidth, textHeight);
+ Width(text, 0, charCount, fontId, textWidth, textHeight, true);
maxTextWidth = MAX<int16>(maxTextWidth, textWidth);
switch (alignment) {
case SCI_TEXT16_ALIGNMENT_RIGHT:
@@ -424,9 +429,9 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex
_ports->moveTo(rect.left + offset, rect.top + hline);
if (bshow) {
- Show(text, 0, charCount, fontId, orgPenColor);
+ Show(text, 0, charCount, fontId, previousPenColor);
} else {
- Draw(text, 0, charCount, fontId, orgPenColor);
+ Draw(text, 0, charCount, fontId, previousPenColor);
}
hline += textHeight;
@@ -434,8 +439,8 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex
if (*text == ' ')
text++; // skip over breaking space
}
- SetFont(orgFontId);
- _ports->penColor(orgPenColor);
+ SetFont(previousFontId);
+ _ports->penColor(previousPenColor);
if (doubleByteMode) {
// Kanji is written by pc98 rom to screen directly. Because of
@@ -458,12 +463,12 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex
}
void GfxText16::Draw_String(const char *text) {
- GuiResourceId orgFontId = GetFontId();
- int16 orgPenColor = _ports->_curPort->penClr;
+ GuiResourceId previousFontId = GetFontId();
+ int16 previousPenColor = _ports->_curPort->penClr;
- Draw(text, 0, strlen(text), orgFontId, orgPenColor);
- SetFont(orgFontId);
- _ports->penColor(orgPenColor);
+ Draw(text, 0, strlen(text), previousFontId, previousPenColor);
+ SetFont(previousFontId);
+ _ports->penColor(previousPenColor);
}
// Sierra did this in their PC98 interpreter only, they identify a text as being
diff --git a/engines/sci/graphics/text16.h b/engines/sci/graphics/text16.h
index 71b602d116..9b8b6d9f19 100644
--- a/engines/sci/graphics/text16.h
+++ b/engines/sci/graphics/text16.h
@@ -53,7 +53,7 @@ public:
void ClearChar(int16 chr);
int16 GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId);
- void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight);
+ void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont);
void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight);
void ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor);
void DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor);
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index d32e60335f..1c865f6bcf 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -84,6 +84,10 @@ void GfxView::initData(GuiResourceId resourceId) {
_embeddedPal = false;
_EGAmapping = NULL;
_isSci2Hires = false;
+ _isScaleable = true;
+
+ // we adjust inside getCelRect for SCI0EARLY (that version didn't have the +1 when calculating bottom)
+ _adjustForSci0Early = getSciVersion() == SCI_VERSION_0_EARLY ? -1 : 0;
// If we find an SCI1/SCI1.1 view (not amiga), we switch to that type for
// EGA. This could get used to make view patches for EGA games, where the
@@ -189,15 +193,30 @@ void GfxView::initData(GuiResourceId resourceId) {
break;
case kViewVga11: // View-format SCI1.1+
- // HeaderSize:WORD LoopCount:BYTE Unknown:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD
+ // HeaderSize:WORD LoopCount:BYTE Flags:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD
headerSize = READ_SCI11ENDIAN_UINT16(_resourceData + 0) + 2; // headerSize is not part of the header, so it's added
assert(headerSize >= 16);
_loopCount = _resourceData[2];
assert(_loopCount);
_isSci2Hires = _resourceData[5] == 1 ? true : false;
palOffset = READ_SCI11ENDIAN_UINT32(_resourceData + 8);
- // FIXME: After LoopCount there is another byte and its set for view 50
- // within Laura Bow 2 CD, check what it means.
+ // flags is actually a bit-mask
+ // it seems it was only used for some early sci1.1 games (or even just laura bow 2)
+ // later interpreters dont support it at all anymore
+ // we assume that if flags is 0h the view does not support flags and default to scaleable
+ // if it's 1h then we assume that the view is not to be scaled
+ // if it's 40h then we assume that the view is scaleable
+ switch (_resourceData[3]) {
+ case 1:
+ _isScaleable = false;
+ break;
+ case 0x40:
+ case 0:
+ break; // don't do anything, we already have _isScaleable set
+ default:
+ error("unsupported flags byte inside sci1.1 view");
+ break;
+ }
loopData = _resourceData + headerSize;
loopSize = _resourceData[12];
@@ -318,11 +337,15 @@ bool GfxView::isSci2Hires() {
return _isSci2Hires;
}
+bool GfxView::isScaleable() {
+ return _isScaleable;
+}
+
void GfxView::getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const {
const CelInfo *celInfo = getCelInfo(loopNo, celNo);
outRect.left = x + celInfo->displaceX - (celInfo->width >> 1);
outRect.right = outRect.left + celInfo->width;
- outRect.bottom = y + celInfo->displaceY - z + 1;
+ outRect.bottom = y + celInfo->displaceY - z + 1 + _adjustForSci0Early;
outRect.top = outRect.bottom - celInfo->height;
}
@@ -637,7 +660,7 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
uint16 scalingX[640];
uint16 scalingY[480];
int16 scaledWidth, scaledHeight;
- int16 pixelNo, scaledPixel, scaledPixelNo, prevScaledPixelNo;
+ int pixelNo, scaledPixel, scaledPixelNo, prevScaledPixelNo;
if (_embeddedPal) {
// Merge view palette in...
@@ -650,8 +673,8 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
scaledHeight = CLIP<int16>(scaledHeight, 0, _screen->getHeight());
// Do we really need to do this?!
- memset(scalingX, 0, sizeof(scalingX));
- memset(scalingY, 0, sizeof(scalingY));
+ //memset(scalingX, 0, sizeof(scalingX));
+ //memset(scalingY, 0, sizeof(scalingY));
// Create height scaling table
pixelNo = 0;
@@ -659,16 +682,15 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
while (pixelNo < celHeight) {
scaledPixelNo = scaledPixel >> 7;
assert(scaledPixelNo < ARRAYSIZE(scalingY));
- if (prevScaledPixelNo < scaledPixelNo)
- memset(&scalingY[prevScaledPixelNo], pixelNo, scaledPixelNo - prevScaledPixelNo);
- scalingY[scaledPixelNo] = pixelNo;
- prevScaledPixelNo = scaledPixelNo + 1;
+ for (; prevScaledPixelNo <= scaledPixelNo; prevScaledPixelNo++)
+ scalingY[prevScaledPixelNo] = pixelNo;
pixelNo++;
scaledPixel += scaleY;
}
+ pixelNo--;
scaledPixelNo++;
- if (scaledPixelNo < scaledHeight)
- memset(&scalingY[scaledPixelNo], pixelNo - 1, scaledHeight - scaledPixelNo);
+ for (; scaledPixelNo < scaledHeight; scaledPixelNo++)
+ scalingY[scaledPixelNo] = pixelNo;
// Create width scaling table
pixelNo = 0;
@@ -676,16 +698,15 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
while (pixelNo < celWidth) {
scaledPixelNo = scaledPixel >> 7;
assert(scaledPixelNo < ARRAYSIZE(scalingX));
- if (prevScaledPixelNo < scaledPixelNo)
- memset(&scalingX[prevScaledPixelNo], pixelNo, scaledPixelNo - prevScaledPixelNo);
- scalingX[scaledPixelNo] = pixelNo;
- prevScaledPixelNo = scaledPixelNo + 1;
+ for (; prevScaledPixelNo <= scaledPixelNo; prevScaledPixelNo++)
+ scalingX[prevScaledPixelNo] = pixelNo;
pixelNo++;
scaledPixel += scaleX;
}
+ pixelNo--;
scaledPixelNo++;
- if (scaledPixelNo < scaledWidth)
- memset(&scalingX[scaledPixelNo], pixelNo - 1, scaledWidth - scaledPixelNo);
+ for (; scaledPixelNo < scaledWidth; scaledPixelNo++)
+ scalingX[scaledPixelNo] = pixelNo;
scaledWidth = MIN(clipRect.width(), scaledWidth);
scaledHeight = MIN(clipRect.height(), scaledHeight);
diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h
index 25e110ad13..990a7e2f71 100644
--- a/engines/sci/graphics/view.h
+++ b/engines/sci/graphics/view.h
@@ -74,6 +74,7 @@ public:
uint16 getCelCount(int16 loopNo) const;
Palette *getPalette();
+ bool isScaleable();
bool isSci2Hires();
private:
@@ -100,6 +101,13 @@ private:
bool _isSci2Hires;
byte *_EGAmapping;
+
+ // this is set for sci0early to adjust for the getCelRect() change
+ int16 _adjustForSci0Early;
+
+ // this is not set for some views in laura bow 2 floppy and signals that the view shall never get scaled
+ // even if scaleX/Y are set (inside kAnimate)
+ bool _isScaleable;
};
} // End of namespace Sci
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 111bf6ad9b..4bf26ff0bf 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -182,7 +182,7 @@ ResourceType ResourceManager::convertResType(byte type) {
}
//-- Resource main functions --
-Resource::Resource(ResourceId id) : _id(id) {
+Resource::Resource(ResourceManager *resMan, ResourceId id) : _resMan(resMan), _id(id) {
data = NULL;
size = 0;
_fileOffset = 0;
@@ -665,6 +665,7 @@ int ResourceManager::addInternalSources() {
++itr;
}
+ delete resources;
return 1;
}
@@ -704,6 +705,86 @@ void IntMapResourceSource::scanSource(ResourceManager *resMan) {
resMan->readAudioMapSCI11(this);
}
+#ifdef ENABLE_SCI32
+
+// Chunk resources are resources that hold other resources. They are normally called
+// when using the kLoadChunk SCI2.1 kernel function. However, for example, the Lighthouse
+// SCI2.1 demo has a chunk but no scripts outside of the chunk.
+
+// A chunk resource is pretty straightforward in terms of layout
+// It begins with 11-byte entries in the header:
+// =========
+// b resType
+// w nEntry
+// dw offset
+// dw length
+
+ChunkResourceSource::ChunkResourceSource(const Common::String &name, uint16 number)
+ : ResourceSource(kSourceChunk, name) {
+
+ _number = 0;
+}
+
+void ChunkResourceSource::scanSource(ResourceManager *resMan) {
+ Resource *chunk = resMan->findResource(ResourceId(kResourceTypeChunk, _number), false);
+
+ if (!chunk)
+ error("Trying to load non-existent chunk");
+
+ byte *ptr = chunk->data;
+ uint32 firstOffset = 0;
+
+ for (;;) {
+ ResourceType type = resMan->convertResType(*ptr);
+ uint16 number = READ_LE_UINT16(ptr + 1);
+ ResourceId id(type, number);
+
+ ResourceEntry entry;
+ entry.offset = READ_LE_UINT32(ptr + 3);
+ entry.length = READ_LE_UINT32(ptr + 7);
+
+ _resMap[id] = entry;
+ ptr += 11;
+
+ debugC(kDebugLevelResMan, 2, "Found %s in chunk %d", id.toString().c_str(), _number);
+
+ resMan->updateResource(id, this, entry.length);
+
+ // There's no end marker to the data table, but the first resource
+ // begins directly after the entry table. So, when we hit the first
+ // resource, we're at the end of the entry table.
+
+ if (!firstOffset)
+ firstOffset = entry.offset;
+
+ if ((size_t)(ptr - chunk->data) >= firstOffset)
+ break;
+ }
+}
+
+void ChunkResourceSource::loadResource(ResourceManager *resMan, Resource *res) {
+ Resource *chunk = resMan->findResource(ResourceId(kResourceTypeChunk, _number), false);
+
+ if (!_resMap.contains(res->_id))
+ error("Trying to load non-existent resource from chunk %d: %s %d", _number, getResourceTypeName(res->_id.getType()), res->_id.getNumber());
+
+ ResourceEntry entry = _resMap[res->_id];
+ res->data = new byte[entry.length];
+ res->size = entry.length;
+ res->_header = 0;
+ res->_headerSize = 0;
+ res->_status = kResStatusAllocated;
+
+ // Copy the resource data over
+ memcpy(res->data, chunk->data + entry.offset, entry.length);
+}
+
+void ResourceManager::addResourcesFromChunk(uint16 id) {
+ addSource(new ChunkResourceSource(Common::String::printf("Chunk %d", id), id));
+ scanNewSources();
+}
+
+#endif
void ResourceManager::freeResourceSources() {
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it)
@@ -769,6 +850,21 @@ void ResourceManager::init() {
default:
error("resMan: Couldn't determine view type");
}
+
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2_1) {
+ // If we have no scripts, but chunk 0 is present, open up the chunk
+ // to try to get to any scripts in there. The Lighthouse SCI2.1 demo
+ // does exactly this.
+
+ Common::List<ResourceId> *scriptList = listResources(kResourceTypeScript);
+
+ if (scriptList->empty() && testResource(ResourceId(kResourceTypeChunk, 0)))
+ addResourcesFromChunk(0);
+
+ delete scriptList;
+ }
+#endif
}
ResourceManager::~ResourceManager() {
@@ -1543,7 +1639,7 @@ void MacResourceForkResourceSource::scanSource(ResourceManager *resMan) {
void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size) {
// Adding new resource only if it does not exist
if (_resMap.contains(resId) == false) {
- Resource *res = new Resource(resId);
+ Resource *res = new Resource(this, resId);
_resMap.setVal(resId, res);
res->_source = src;
res->_fileOffset = offset;
@@ -1558,7 +1654,7 @@ Resource *ResourceManager::updateResource(ResourceId resId, ResourceSource *src,
if (_resMap.contains(resId)) {
res = _resMap.getVal(resId);
} else {
- res = new Resource(resId);
+ res = new Resource(this, resId);
_resMap.setVal(resId, res);
}
@@ -1584,21 +1680,21 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream
case kResVersionSci0Sci1Early:
case kResVersionSci1Middle:
w = file->readUint16LE();
- type = (ResourceType)(w >> 11);
+ type = _resMan->convertResType(w >> 11);
number = w & 0x7FF;
szPacked = file->readUint16LE() - 4;
szUnpacked = file->readUint16LE();
wCompression = file->readUint16LE();
break;
case kResVersionSci1Late:
- type = (ResourceType)(file->readByte() & 0x7F);
+ type = _resMan->convertResType(file->readByte());
number = file->readUint16LE();
szPacked = file->readUint16LE() - 4;
szUnpacked = file->readUint16LE();
wCompression = file->readUint16LE();
break;
case kResVersionSci11:
- type = (ResourceType)(file->readByte() & 0x7F);
+ type = _resMan->convertResType(file->readByte());
number = file->readUint16LE();
szPacked = file->readUint16LE();
szUnpacked = file->readUint16LE();
@@ -1615,7 +1711,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream
break;
#ifdef ENABLE_SCI32
case kResVersionSci32:
- type = (ResourceType)(file->readByte() & 0x7F);
+ type = _resMan->convertResType(file->readByte());
number = file->readUint16LE();
szPacked = file->readUint32LE();
szUnpacked = file->readUint32LE();
@@ -1907,18 +2003,18 @@ void ResourceManager::detectSciVersion() {
return;
}
+ if (hasSci0Voc999()) {
+ s_sciVersion = SCI_VERSION_0_LATE;
+ return;
+ }
+
if (oldDecompressors) {
// It's either SCI_VERSION_0_LATE or SCI_VERSION_01
// We first check for SCI1 vocab.999
if (testResource(ResourceId(kResourceTypeVocab, 999))) {
- if (hasSci0Voc999()) {
- s_sciVersion = SCI_VERSION_0_LATE;
- return;
- } else {
- s_sciVersion = SCI_VERSION_01;
- return;
- }
+ s_sciVersion = SCI_VERSION_01;
+ return;
}
// If vocab.999 is missing, we try vocab.900
@@ -1938,15 +2034,10 @@ void ResourceManager::detectSciVersion() {
return;
}
- // New decompressors. It's either SCI_VERSION_0_LATE, SCI_VERSION_1_EGA or SCI_VERSION_1_EARLY.
- if (testResource(ResourceId(kResourceTypeVocab, 900))) {
- if (hasSci1Voc900()) {
- s_sciVersion = SCI_VERSION_1_EGA;
- return;
- } else {
- s_sciVersion = SCI_VERSION_0_LATE;
- return;
- }
+ // New decompressors. It's either SCI_VERSION_1_EGA or SCI_VERSION_1_EARLY.
+ if (hasSci1Voc900()) {
+ s_sciVersion = SCI_VERSION_1_EGA;
+ return;
}
// SCI_VERSION_1_EARLY EGA versions lack the parser vocab
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index f1ea2f15f9..48210b835f 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -193,6 +193,9 @@ class Resource {
friend class WaveResourceSource;
friend class AudioVolumeResourceSource;
friend class MacResourceForkResourceSource;
+#ifdef ENABLE_SCI32
+ friend class ChunkResourceSource;
+#endif
// NOTE : Currently most member variables lack the underscore prefix and have
// public visibility to let the rest of the engine compile without changes.
@@ -203,7 +206,7 @@ public:
uint32 _headerSize;
public:
- Resource(ResourceId id);
+ Resource(ResourceManager *resMan, ResourceId id);
~Resource();
void unalloc();
@@ -227,6 +230,7 @@ protected:
ResourceStatus _status;
uint16 _lockers; /**< Number of places where this resource was locked */
ResourceSource *_source;
+ ResourceManager *_resMan;
bool loadPatch(Common::SeekableReadStream *file);
bool loadFromPatchFile();
@@ -251,6 +255,9 @@ class ResourceManager {
friend class ExtAudioMapResourceSource;
friend class WaveResourceSource;
friend class MacResourceForkResourceSource;
+#ifdef ENABLE_SCI32
+ friend class ChunkResourceSource;
+#endif
public:
/**
@@ -324,6 +331,14 @@ public:
*/
void addNewGMPatch(SciGameId gameId);
+#ifdef ENABLE_SCI32
+ /**
+ * Parses all resources from a SCI2.1 chunk resource and adds them to the
+ * resource manager.
+ */
+ void addResourcesFromChunk(uint16 id);
+#endif
+
bool detectHires();
// Detects, if standard font of current game includes extended characters (>0x80)
bool detectFontExtended();
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 08e05f5ccd..a25505fe47 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -93,13 +93,13 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
uint32 riffTag = file->readUint32BE();
if (riffTag == MKID_BE('RIFF')) {
_headerSize = 0;
- size = file->readUint32LE();
+ size = file->readUint32LE() + 8;
file->seek(-8, SEEK_CUR);
return loadFromWaveFile(file);
}
file->seek(-4, SEEK_CUR);
- ResourceType type = (ResourceType)(file->readByte() & 0x7f);
+ ResourceType type = _resMan->convertResType(file->readByte());
if (((getType() == kResourceTypeAudio || getType() == kResourceTypeAudio36) && (type != kResourceTypeAudio))
|| ((getType() == kResourceTypeSync || getType() == kResourceTypeSync36) && (type != kResourceTypeSync))) {
warning("Resource type mismatch loading %s", _id.toString().c_str());
@@ -235,6 +235,20 @@ void ResourceManager::removeAudioResource(ResourceId resId) {
// w nEntry
// tb offset (cumulative)
+// QFG3 Demo 0.MAP structure:
+// =========
+// 10-byte entries:
+// w nEntry
+// dw offset
+// dw size
+
+// LB2 Floppy/Mother Goose SCI1.1 0.MAP structure:
+// =========
+// 8-byte entries:
+// w nEntry
+// w 0xffff
+// dw offset
+
// Early SCI1.1 MAP structure:
// ===============
// 10-byte entries:
@@ -318,6 +332,31 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
}
+ } else if (map->_volumeNumber == 0 && entrySize == 8 && READ_LE_UINT16(ptr + 2) == 0xffff) {
+ // LB2 Floppy/Mother Goose SCI1.1 format
+ Common::SeekableReadStream *stream = getVolumeFile(src);
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint16 n = READ_LE_UINT16(ptr);
+ ptr += 4;
+
+ if (n == 0xffff)
+ break;
+
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+
+ // The size is not stored in the map and the entries have no order.
+ // We need to dig into the audio resource in the volume to get the size.
+ stream->seek(offset + 1);
+ byte headerSize = stream->readByte();
+ assert(headerSize == 11 || headerSize == 12);
+
+ stream->skip(5);
+ uint32 size = stream->readUint32LE() + headerSize + 2;
+
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
+ }
} else {
bool isEarly = (entrySize != 11);
diff --git a/engines/sci/resource_intern.h b/engines/sci/resource_intern.h
index 73986444a4..14f872b46e 100644
--- a/engines/sci/resource_intern.h
+++ b/engines/sci/resource_intern.h
@@ -43,7 +43,8 @@ enum ResSourceType {
kSourceAudioVolume,
kSourceExtAudioMap,
kSourceWave,
- kSourceMacResourceFork
+ kSourceMacResourceFork,
+ kSourceChunk
};
@@ -188,6 +189,31 @@ public:
virtual void loadResource(ResourceManager *resMan, Resource *res);
};
+#ifdef ENABLE_SCI32
+
+/**
+ * Reads resources from SCI2.1+ chunk resources
+ */
+class ChunkResourceSource : public ResourceSource {
+public:
+ ChunkResourceSource(const Common::String &name, uint16 number);
+
+ virtual void scanSource(ResourceManager *resMan);
+ virtual void loadResource(ResourceManager *resMan, Resource *res);
+
+protected:
+ uint16 _number;
+
+ struct ResourceEntry {
+ uint32 offset;
+ uint32 length;
+ };
+
+ Common::HashMap<ResourceId, ResourceEntry, ResourceIdHash> _resMap;
+};
+
+#endif
+
} // End of namespace Sci
#endif // SCI_RESOURCE_INTERN_H
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index f07cc257bd..d0c578bd45 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -26,6 +26,8 @@
#include "common/system.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
+#include "common/EventRecorder.h"
+#include "common/file.h" // for Common::File::exists()
#include "engines/advancedDetector.h"
#include "engines/util.h"
@@ -117,12 +119,15 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
SearchMan.addSubDirectoryMatching(gameDataDir, "actors"); // KQ6 hi-res portraits
SearchMan.addSubDirectoryMatching(gameDataDir, "aud"); // resource.aud and audio files
+ SearchMan.addSubDirectoryMatching(gameDataDir, "audio");// resource.aud and audio files
+ SearchMan.addSubDirectoryMatching(gameDataDir, "audiosfx");// resource.aud and audio files
SearchMan.addSubDirectoryMatching(gameDataDir, "wav"); // speech files in WAV format
SearchMan.addSubDirectoryMatching(gameDataDir, "sfx"); // music/sound files in WAV format
SearchMan.addSubDirectoryMatching(gameDataDir, "avi"); // AVI movie files for Windows versions
SearchMan.addSubDirectoryMatching(gameDataDir, "seq"); // SEQ movie files for DOS versions
SearchMan.addSubDirectoryMatching(gameDataDir, "robot"); // robot movie files
SearchMan.addSubDirectoryMatching(gameDataDir, "robots"); // robot movie files
+ SearchMan.addSubDirectoryMatching(gameDataDir, "movie"); // vmd movie files
SearchMan.addSubDirectoryMatching(gameDataDir, "movies"); // vmd movie files
SearchMan.addSubDirectoryMatching(gameDataDir, "vmd"); // vmd movie files
@@ -169,6 +174,8 @@ SciEngine::~SciEngine() {
}
Common::Error SciEngine::run() {
+ g_eventRec.registerRandomSource(_rng, "sci");
+
// Assign default values to the config manager, in case settings are missing
ConfMan.registerDefault("undither", "true");
ConfMan.registerDefault("enable_fb01", "false");
@@ -232,12 +239,34 @@ Common::Error SciEngine::run() {
debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion()));
+ if (_gameDescription->flags & ADGF_ADDENGLISH) {
+ // if game is multilingual
+ Common::Language selectedLanguage = Common::parseLanguage(ConfMan.get("language"));
+ if (selectedLanguage == Common::EN_ANY) {
+ // and english was selected as language
+ if (SELECTOR(printLang) != -1) // set text language to english
+ writeSelectorValue(segMan, _gameObj, SELECTOR(printLang), 1);
+ if (SELECTOR(parseLang) != -1) // and set parser language to english as well
+ writeSelectorValue(segMan, _gameObj, SELECTOR(parseLang), 1);
+ }
+ }
+
// Check whether loading a savestate was requested
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot >= 0) {
reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
kRestoreGame(_gamestate, 2, restoreArgv);
+ // TODO: The best way to do the following would be to invoke Game::init
+ // here and stop when the room is about to be changed, otherwise some
+ // game initialization won't take place
+
+ // Set audio language for KQ5CD (bug #3039477)
+ if (g_sci->getGameId() == GID_KQ5 && Common::File::exists("AUDIO001.002")) {
+ reg_t doAudioArgv[2] = { make_reg(0, 9), make_reg(0, 1) };
+ kDoAudio(_gamestate, 2, doAudioArgv);
+ }
+
// Initialize the game menu, if there is one.
// This is not done when loading, so we must do it manually.
reg_t menuBarObj = _gamestate->_segMan->findObjectByName("MenuBar");
@@ -287,7 +316,7 @@ bool SciEngine::initGame() {
_gamestate->_executionStackPosChanged = false;
_gamestate->abortScriptProcessing = kAbortNone;
- _gamestate->gameWasRestarted = false;
+ _gamestate->gameIsRestarting = GAMEISRESTARTING_NONE;
_gamestate->stack_base = stack->_entries;
_gamestate->stack_top = stack->_entries + stack->_capacity;
@@ -304,8 +333,6 @@ bool SciEngine::initGame() {
_gamestate->gameStartTime = _gamestate->lastWaitTime = _gamestate->_screenUpdateTime = g_system->getMillis();
- srand(g_system->getMillis()); // Initialize random number generator
-
// Load game language into printLang property of game object
setSciLanguage();
@@ -415,7 +442,7 @@ void SciEngine::runGame() {
_gamestate->_segMan->resetSegMan();
initGame();
initStackBaseWithSelector(SELECTOR(play));
- _gamestate->gameWasRestarted = true;
+ _gamestate->gameIsRestarting = GAMEISRESTARTING_RESTART;
if (_gfxMenu)
_gfxMenu->reset();
_gamestate->abortScriptProcessing = kAbortNone;
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 13c9d03614..72d6e7e0cb 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -28,6 +28,7 @@
#include "engines/engine.h"
#include "common/util.h"
+#include "common/random.h"
#include "sci/engine/vm_types.h" // for Selector
#include "sci/debug.h" // for DebugState
@@ -233,6 +234,8 @@ public:
inline EventManager *getEventManager() const { return _eventMan; }
inline reg_t getGameObject() const { return _gameObj; }
+ Common::RandomSource &getRNG() { return _rng; }
+
Common::String getSavegameName(int nr) const;
Common::String getSavegamePattern() const;
@@ -340,6 +343,7 @@ private:
EventManager *_eventMan;
reg_t _gameObj; /**< Pointer to the game object */
Console *_console;
+ Common::RandomSource _rng;
};
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index e58fa5120b..6ec28a8b02 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -425,7 +425,8 @@ void MidiParser_SCI::sendToDriver(uint32 midi) {
// Channel remapping
int16 realChannel = _channelRemap[midiChannel];
- assert(realChannel != -1);
+ if (realChannel == -1)
+ return;
midi = (midi & 0xFFFFFFF0) | realChannel;
if (_mainThreadCalled)
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index c3315bd2b5..061f380ebc 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -293,7 +293,10 @@ int16 SciMusic::tryToOwnChannel(MusicEntry *caller, int16 bestChannel) {
return channelNr;
}
}
- error("no free channels");
+ // nothing found, don't map channel at all
+ // sierra did this as well, although i'm not sure if we act exactly the same way
+ // maybe they removed channels from previous playing music
+ return -1;
}
void SciMusic::freeChannels(MusicEntry *caller) {
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index bd88a5fca8..567a1605f3 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -147,6 +147,12 @@ void SoundCommandParser::processPlaySound(reg_t obj) {
_music->soundPlay(musicSlot);
}
+reg_t SoundCommandParser::kDoSoundRestore(int argc, reg_t *argv, reg_t acc) {
+ // Called after loading, to restore the playlist
+ // We don't really use or need this
+ return acc;
+}
+
reg_t SoundCommandParser::kDoSoundDummy(int argc, reg_t *argv, reg_t acc) {
warning("cmdDummy invoked"); // not supposed to occur
return acc;
@@ -246,7 +252,8 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) {
} else { // pause a playlist slot
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("kDoSound(pause): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ // This happens quite frequently
+ debugC(2, kDebugLevelSound, "kDoSound(pause): Slot not found (%04x:%04x)", PRINT_REG(obj));
return acc;
}
@@ -263,12 +270,13 @@ reg_t SoundCommandParser::kDoSoundResumeAfterRestore(int argc, reg_t *argv, reg_
}
reg_t SoundCommandParser::kDoSoundMute(int argc, reg_t *argv, reg_t acc) {
+ uint16 previousState = _music->soundGetSoundOn();
if (argc > 0) {
debugC(2, kDebugLevelSound, "kDoSound(mute): %d", argv[0].toUint16());
_music->soundSetSoundOn(argv[0].toUint16());
}
- return make_reg(0, _music->soundGetSoundOn());
+ return make_reg(0, previousState);
}
reg_t SoundCommandParser::kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc) {
@@ -316,7 +324,11 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
case 4: // SCI01+
case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue
musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX);
- musicSlot->fadeStep = volume > argv[1].toUint16() ? -argv[3].toUint16() : argv[3].toUint16();
+ // sometimes we get objects in that position, fix it up (ffs. workarounds)
+ if (!argv[1].segment)
+ musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16();
+ else
+ musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5;
musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo();
musicSlot->fadeTicker = 0;
musicSlot->stopAfterFading = (argc == 5) ? (argv[4].toUint16() != 0) : false;
@@ -557,7 +569,7 @@ reg_t SoundCommandParser::kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc)
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("kDoSound(setPriority): Slot not found (%04x:%04x)", PRINT_REG(obj));
+ debugC(2, kDebugLevelSound, "kDoSound(setPriority): Slot not found (%04x:%04x)", PRINT_REG(obj));
return acc;
}
diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h
index 10915e8ea9..8e6fb81762 100644
--- a/engines/sci/sound/soundcmd.h
+++ b/engines/sci/sound/soundcmd.h
@@ -82,7 +82,7 @@ public:
reg_t kDoSoundInit(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundPlay(int argc, reg_t *argv, reg_t acc);
- reg_t kDoSoundDummy(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundRestore(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundMute(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundPause(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundResumeAfterRestore(int argc, reg_t *argv, reg_t acc);
@@ -97,6 +97,7 @@ public:
reg_t kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundReverb(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundSetHold(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundDummy(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundGetAudioCapability(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc);
diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp
index 2c117ae329..58fd60621d 100644
--- a/engines/sci/video/seq_decoder.cpp
+++ b/engines/sci/video/seq_decoder.cpp
@@ -55,10 +55,10 @@ SeqDecoder::~SeqDecoder() {
close();
}
-bool SeqDecoder::load(Common::SeekableReadStream &stream) {
+bool SeqDecoder::load(Common::SeekableReadStream *stream) {
close();
- _fileStream = &stream;
+ _fileStream = stream;
_surface = new Graphics::Surface();
_surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, 1);
@@ -76,6 +76,7 @@ bool SeqDecoder::load(Common::SeekableReadStream &stream) {
uint16 palColorCount = READ_LE_UINT16(paletteData + 29);
int palOffset = 37;
+ memset(_palette, 0, 256 * 3);
for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
if (palFormat == kSeqPalVariable)
diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h
index 416abb78fa..1714477083 100644
--- a/engines/sci/video/seq_decoder.h
+++ b/engines/sci/video/seq_decoder.h
@@ -38,7 +38,7 @@ public:
SeqDecoder();
virtual ~SeqDecoder();
- bool load(Common::SeekableReadStream &stream);
+ bool load(Common::SeekableReadStream *stream);
void close();
void setFrameDelay(int frameDelay) { _frameDelay = frameDelay; }
diff --git a/engines/sci/video/vmd_decoder.cpp b/engines/sci/video/vmd_decoder.cpp
index 93132bc5d6..680a449207 100644
--- a/engines/sci/video/vmd_decoder.cpp
+++ b/engines/sci/video/vmd_decoder.cpp
@@ -50,13 +50,13 @@ VMDDecoder::~VMDDecoder() {
close();
}
-bool VMDDecoder::load(Common::SeekableReadStream &stream) {
+bool VMDDecoder::load(Common::SeekableReadStream *stream) {
close();
if (!_vmdDecoder->load(stream))
return false;
- _fileStream = &stream;
+ _fileStream = stream;
if (_vmdDecoder->getFeatures() & Graphics::CoktelVideo::kFeaturesPalette)
loadPaletteFromVMD();
diff --git a/engines/sci/video/vmd_decoder.h b/engines/sci/video/vmd_decoder.h
index 231da9202e..e79064b1f7 100644
--- a/engines/sci/video/vmd_decoder.h
+++ b/engines/sci/video/vmd_decoder.h
@@ -56,7 +56,7 @@ public:
uint32 getFrameWaitTime();
- bool load(Common::SeekableReadStream &stream);
+ bool load(Common::SeekableReadStream *stream);
void close();
bool isVideoLoaded() const { return _fileStream != 0; }
diff --git a/engines/scumm/player_nes.cpp b/engines/scumm/player_nes.cpp
index 4618de3175..96396e7a08 100644
--- a/engines/scumm/player_nes.cpp
+++ b/engines/scumm/player_nes.cpp
@@ -23,6 +23,7 @@
*
*/
+#ifndef DISABLE_NES_APU
#include "engines/engine.h"
#include "scumm/player_nes.h"
@@ -1065,3 +1066,5 @@ byte Player_NES::APU_readStatus() {
}
} // End of namespace Scumm
+
+#endif // DISABLE_NES_APU
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 1d064cdf6a..81762d87a8 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -363,7 +363,7 @@ bool ScummEngine::loadState(int slot, bool compat) {
}
}
- Graphics::skipThumbnailHeader(*in);
+ Graphics::skipThumbnail(*in);
}
// Since version 56 we save additional information about the creation of
@@ -720,7 +720,7 @@ bool ScummEngine::loadInfosFromSlot(const char *target, int slot, InfoStuff *stu
return false;
}
- if (!Graphics::skipThumbnailHeader(*in)) {
+ if (!Graphics::skipThumbnail(*in)) {
delete in;
return false;
}
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 7e2db22c5b..ab7be02c48 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1723,7 +1723,9 @@ void ScummEngine::setupMusic(int midi) {
_musicEngine = new Player_SID(this, _mixer);
#endif
} else if (_game.platform == Common::kPlatformNES && _game.version == 1) {
+#ifndef DISABLE_NES_APU
_musicEngine = new Player_NES(this, _mixer);
+#endif
} else if (_game.platform == Common::kPlatformAmiga && _game.version == 2) {
_musicEngine = new Player_V2A(this, _mixer);
} else if (_game.platform == Common::kPlatformAmiga && _game.version == 3) {
diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp
index d6a04513a8..8d9ca85829 100644
--- a/engines/sword1/control.cpp
+++ b/engines/sword1/control.cpp
@@ -1175,8 +1175,7 @@ bool Control::restoreGameFromFile(uint8 slot) {
if (saveVersion < 2) // These older version of the savegames used a flag to signal presence of thumbnail
inf->skip(1);
- if (Graphics::checkThumbnailHeader(*inf))
- Graphics::skipThumbnailHeader(*inf);
+ Graphics::skipThumbnail(*inf);
inf->readUint32BE(); // save date
inf->readUint16BE(); // save time