diff options
48 files changed, 883 insertions, 558 deletions
@@ -323,7 +323,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see: - Renamed Simon engine to AGOS. Kyrandia: - - Added support for FM-Towns version (both English and Japanese). + - Added support for FM-TOWNS version (both English and Japanese). BASS: - Fixed long-standing font bug. We were using the control panel font for diff --git a/dists/msvc7/gob.vcproj b/dists/msvc7/gob.vcproj index fd1cbb9dfe..9919d09c9f 100644 --- a/dists/msvc7/gob.vcproj +++ b/dists/msvc7/gob.vcproj @@ -398,6 +398,9 @@ RelativePath="..\..\engines\gob\save\saveload_v6.cpp"> </File> <File + RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp"> + </File> + <File RelativePath="..\..\engines\gob\scenery.cpp"> </File> <File diff --git a/dists/msvc71/gob.vcproj b/dists/msvc71/gob.vcproj index b005dbbd6e..0a5f869970 100644 --- a/dists/msvc71/gob.vcproj +++ b/dists/msvc71/gob.vcproj @@ -412,6 +412,9 @@ RelativePath="..\..\engines\gob\save\saveload_v6.cpp"> </File> <File + RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp"> + </File> + <File RelativePath="..\..\engines\gob\scenery.cpp"> </File> <File diff --git a/dists/msvc8/gob.vcproj b/dists/msvc8/gob.vcproj index 14259ac2fd..0375f339d2 100644 --- a/dists/msvc8/gob.vcproj +++ b/dists/msvc8/gob.vcproj @@ -519,6 +519,10 @@ > </File> <File + RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp" + > + </File> + <File RelativePath="..\..\engines\gob\save\savefile.cpp" > </File> diff --git a/dists/msvc9/gob.vcproj b/dists/msvc9/gob.vcproj index 60385473a5..7b339fbad9 100644 --- a/dists/msvc9/gob.vcproj +++ b/dists/msvc9/gob.vcproj @@ -536,6 +536,10 @@ > </File> <File + RelativePath="..\..\engines\gob\save\saveconverter.h" + > + </File> + <File RelativePath="..\..\engines\gob\save\saveload.cpp" > </File> @@ -560,6 +564,10 @@ > </File> <File + RelativePath="..\..\engines\gob\save\saveload_playtoons.cpp" + > + </File> + <File RelativePath="..\..\engines\gob\scenery.cpp" > </File> diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp index fb67cef91c..6fe82f76d4 100644 --- a/engines/cruise/function.cpp +++ b/engines/cruise/function.cpp @@ -815,11 +815,6 @@ int16 Op_AddMessage(void) { createTextObject(&cellHead, overlayIdx, var_8, var_6, var_4, var_2, color, masterScreen, currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber); - // WORKAROUND: The first message in the 'shooting cutscene' goes too fast on newer systems, - // so this introduces a delay so the user has more time to read the message - if ((overlayIdx == 46) && (var_8 == 0)) - userDelay = 3 * (1000 / GAME_FRAME_DELAY_2); - return 0; } diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 9426c01ef2..3827c3635c 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -71,6 +71,7 @@ static const PlainGameDescriptor gobGames[] = { {"bambou", "Playtoons Limited Edition - Bambou le sauveur de la jungle"}, {"fascination", "Fascination"}, {"geisha", "Geisha"}, + {"magicstones", "The Land of the Magic Stones"}, {"adibou4", "Adibou v4"}, {"adibouunknown", "Adibou (not yet supported)"}, {0, 0} @@ -3438,6 +3439,24 @@ static const GOBGameDescription gameDescriptions[] = { "playtoons2", "", { + {"playtoon.stk", 0, "4772c96be88a57f0561519e4a1526c62", 24406262}, + {"spirou.stk", 0, "5d9c7644d0c47840169b4d016765cc1a", 9816201}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypePlaytoon, + kFeatures640, + "intro2.stk", 0, 0 + }, + { + { + "playtoons2", + "", + { {"playtoon.stk", 0, "55a85036dd93cce93532d8f743d90074", 17467154}, {"spirou.stk", 0, "e3e1b6148dd72fafc3637f1a8e5764f5", 9812043}, {0, 0, 0, 0} @@ -3634,6 +3653,24 @@ static const GOBGameDescription gameDescriptions[] = { }, { { + "magicstones", + "", + { + {"ed4.stk", 0, "98721a7cfdc5a358d7ac56b7c6d3ba3d", 541882}, + {"ed4cd.itk", 0, "0627a91d9a6f4772c33747ce752024c2", 606993908}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeMagicStones, + kFeatures800x600, + "ed4.stk", "main.obc", 0 + }, + { + { "adibou4", "", AD_ENTRY1s("intro.stk", "a3c35d19b2d28ea261d96321d208cb5a", 6021466), @@ -4189,6 +4226,20 @@ static const GOBGameDescription fallbackDescs[] = { }, { { + "magicstones", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeMagicStones, + kFeatures800x600, + "ed4.stk", "main.obc", 0 + }, + { + { "adibou4", "", AD_ENTRY1(0, 0), @@ -4241,8 +4292,9 @@ static const ADFileBasedFallback fileBased[] = { { &fallbackDescs[19], { "intro.stk", "bambou.itk", 0 } }, { &fallbackDescs[20], { "disk0.stk", "disk1.stk", "disk2.stk", "disk3.stk", 0 } }, { &fallbackDescs[21], { "disk1.stk", "disk2.stk", "disk3.stk", 0 } }, - { &fallbackDescs[22], { "adif41.stk", "adim41.stk", 0 } }, - { &fallbackDescs[23], { "coktelplayer.scn", 0 } }, + { &fallbackDescs[22], { "ed4.stk", 0 } }, + { &fallbackDescs[23], { "adif41.stk", "adim41.stk", 0 } }, + { &fallbackDescs[24], { "coktelplayer.scn", 0 } }, { 0, { 0 } } }; diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 8605dfbd52..94255b1277 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -205,6 +205,10 @@ bool GobEngine::isBATDemo() const { return (_features & kFeaturesBATDemo) != 0; } +bool GobEngine::is800x600() const { + return (_features & kFeatures800x600) != 0; +} + bool GobEngine::isDemo() const { return (isSCNDemo() || isBATDemo()); } @@ -421,9 +425,6 @@ bool GobEngine::initGameParts() { _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); break; - case kGameTypePlaytoon: - case kGameTypePlaytnCk: - case kGameTypeBambou: case kGameTypeDynasty: _init = new Init_v3(this); _video = new Video_v2(this); @@ -449,6 +450,21 @@ bool GobEngine::initGameParts() { _saveLoad = new SaveLoad_v6(this, _targetName.c_str()); break; + case kGameTypePlaytoon: + case kGameTypePlaytnCk: + case kGameTypeBambou: + _init = new Init_v2(this); + _video = new Video_v2(this); +// _inter = new Inter_Playtoons(this); + _inter = new Inter_v4(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_Playtoons(this); + break; + default: deinitGameParts(); return false; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 5047382316..02f6af51bf 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -108,6 +108,7 @@ enum GameType { kGameTypeBambou, kGameTypeFascination, kGameTypeGeisha, + kGameTypeMagicStones, kGameTypeAdibou4, kGameTypeAdibouUnknown }; @@ -119,7 +120,8 @@ enum Features { kFeaturesAdlib = 1 << 2, kFeatures640 = 1 << 3, kFeaturesSCNDemo = 1 << 4, - kFeaturesBATDemo = 1 << 5 + kFeaturesBATDemo = 1 << 5, + kFeatures800x600 = 1 << 6 }; enum { @@ -216,6 +218,7 @@ public: bool hasAdlib() const; bool isSCNDemo() const; bool isBATDemo() const; + bool is800x600() const; bool isDemo() const; GobEngine(OSystem *syst); diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 66c1b0dbaf..611abb6038 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -64,6 +64,7 @@ MODULE_OBJS := \ save/saveload_v3.o \ save/saveload_v4.o \ save/saveload_v6.o \ + save/saveload_playtoons.o \ save/saveconverter.o \ save/saveconverter_v2.o \ save/saveconverter_v3.o \ diff --git a/engines/gob/save/saveload.h b/engines/gob/save/saveload.h index a74b64b883..8d785c7233 100644 --- a/engines/gob/save/saveload.h +++ b/engines/gob/save/saveload.h @@ -445,6 +445,32 @@ protected: SaveFile *getSaveFile(const char *fileName); }; +/** Save/Load class for Playtoons. */ +/** Only used for the moment to check file presence */ + +class SaveLoad_Playtoons : public SaveLoad { +public: + SaveLoad_Playtoons(GobEngine *vm); + virtual ~SaveLoad_Playtoons(); + +protected: + struct SaveFile { + const char *sourceName; + SaveMode mode; + SaveHandler *handler; + const char *description; + }; + + static SaveFile _saveFiles[]; + + SaveMode getSaveMode(const char *fileName) const; + + const SaveFile *getSaveFile(const char *fileName) const; + + SaveFile *getSaveFile(const char *fileName); + +}; + } // End of namespace Gob #endif // GOB_SAVE_SAVELOAD_H diff --git a/engines/gob/save/saveload_playtoons.cpp b/engines/gob/save/saveload_playtoons.cpp new file mode 100644 index 0000000000..97da909e7c --- /dev/null +++ b/engines/gob/save/saveload_playtoons.cpp @@ -0,0 +1,88 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/save/saveload.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +SaveLoad_Playtoons::SaveFile SaveLoad_Playtoons::_saveFiles[] = { + { "disk.001", kSaveModeExists, 0, 0}, // Playtoons 1 identification file + { "disk.002", kSaveModeExists, 0, 0}, // Playtoons 2 identification file + { "disk.003", kSaveModeExists, 0, 0}, // Playtoons 3 identification file + { "disk.004", kSaveModeExists, 0, 0}, // Playtoons 4 identification file + { "disk.005", kSaveModeExists, 0, 0}, // Playtoons 5 identification file + { "disk.006", kSaveModeExists, 0, 0}, // Playtoons CK 1 identification file + { "disk.007", kSaveModeExists, 0, 0}, // Playtoons CK 2 identification file + { "disk.008", kSaveModeExists, 0, 0}, // Playtoons CK 3 identification file + { "titre.001", kSaveModeExists, 0, 0}, // Playtoons 1 titles + { "titre.002", kSaveModeExists, 0, 0}, // Playtoons 2 titles + { "titre.003", kSaveModeExists, 0, 0}, // Playtoons 3 titles + { "titre.004", kSaveModeExists, 0, 0}, // Playtoons 4 titles + { "titre.005", kSaveModeExists, 0, 0}, // Playtoons 5 titles + { "titre.006", kSaveModeExists, 0, 0}, // Playtoons CK 1 empty title (???) + { "titre.007", kSaveModeExists, 0, 0}, // Playtoons CK 2 empty title (???) + { "titre.008", kSaveModeExists, 0, 0}, // Playtoons CK 3 empty title (???) + { "mdo.def", kSaveModeExists, 0, 0}, +}; + +SaveLoad::SaveMode SaveLoad_Playtoons::getSaveMode(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->mode; + + return kSaveModeNone; +} + +SaveLoad_Playtoons::SaveLoad_Playtoons(GobEngine *vm) : + SaveLoad(vm) { +} + +SaveLoad_Playtoons::~SaveLoad_Playtoons() { +} + +const SaveLoad_Playtoons::SaveFile *SaveLoad_Playtoons::getSaveFile(const char *fileName) const { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveLoad_Playtoons::SaveFile *SaveLoad_Playtoons::getSaveFile(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +} // End of namespace Gob diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 63d15419d2..3199a043e7 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -230,7 +230,7 @@ const KYRAGameDescription adGameDescs[] = { KYRA1_FLOPPY_FLAGS }, - { // FM-Towns version + { // FM-TOWNS version { "kyra1", 0, @@ -638,7 +638,7 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_DEMO_FLAGS }, - { // FM-Towns + { // FM-TOWNS { "kyra2", 0, diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index ecd6bbe450..a1aaf77d51 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -168,7 +168,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena delete in; return 0; } else if ((header.flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) { - warning("Can not load FM-Towns/PC98 savefile for this (non FM-Towns/PC98) gameversion"); + warning("Can not load FM-TOWNS/PC98 savefile for this (non FM-TOWNS/PC98) gameversion"); delete in; return 0; } diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 963dc3f4d6..426907c871 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -26,7 +26,10 @@ #include "common/endian.h" #include "common/system.h" + #include "graphics/cursorman.h" +#include "graphics/sjis.h" + #include "kyra/screen.h" #include "kyra/kyra_v1.h" #include "kyra/resource.h" @@ -43,6 +46,8 @@ Screen::Screen(KyraEngine_v1 *vm, OSystem *system) _drawShapeVar3 = 1; _drawShapeVar4 = 0; _drawShapeVar5 = 0; + + _sjisFont = 0; } Screen::~Screen() { @@ -56,8 +61,7 @@ Screen::~Screen() { _fonts[f].fontData = NULL; } - delete[] _sjisFontData; - delete[] _sjisTempPage; + delete _sjisFont; delete _screenPalette; delete _internFadePalette; delete[] _decodeShapeBuffer; @@ -78,8 +82,6 @@ bool Screen::init() { _useSJIS = false; _use16ColorMode = _vm->gameFlags().use16ColorMode; - _sjisTempPage = _sjisFontData = 0; - if (_vm->gameFlags().useHiResOverlay) { _useOverlays = true; _useSJIS = (_vm->gameFlags().lang == Common::JA_JPN); @@ -94,14 +96,17 @@ bool Screen::init() { } if (_useSJIS) { - if (!_sjisFontData) { - // we use the FM-Towns font rom for PC-98, too, until we feel + if (!_sjisFont) { + // we use the FM-TOWNS font rom for PC-98, too, until we feel // like adding support for the PC-98 font //if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { - // FM-Towns - _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0); - if (!_sjisFontData) - error("missing font rom ('FMT_FNT.ROM') required for this version"); + // FM-TOWNS + Common::SeekableReadStream *rom = _vm->resource()->createReadStream("FMT_FNT.ROM"); + Graphics::FontTowns *townsFont = new Graphics::FontTowns(); + if (!rom || !townsFont || !townsFont->loadFromStream(*rom)) + error("Could not load font rom ('FMT_FNT.ROM') required for this version"); + _sjisFont = townsFont; + delete rom; /*} else { // PC-98 _sjisFontData = _vm->resource()->fileData("FONT.ROM", 0); @@ -109,16 +114,12 @@ bool Screen::init() { error("missing font rom ('FONT.ROM') required for this version"); }*/ } - - if (!_sjisTempPage) { - _sjisTempPage = new uint8[420]; - assert(_sjisTempPage); - _sjisTempPage2 = _sjisTempPage + 60; - _sjisSourceChar = _sjisTempPage + 384; - } + + _sjisFont->enableOutline(!_use16ColorMode); } } + _curPage = 0; uint8 *pagePtr = new uint8[SCREEN_PAGE_SIZE * 8]; for (int pageNum = 0; pageNum < SCREEN_PAGE_NUM; pageNum += 2) @@ -657,7 +658,7 @@ void Screen::copyToPage0(int y, int h, uint8 page, uint8 *seqBuf) { } addDirtyRect(0, y, SCREEN_W, h); // This would remove the text in the end sequence of - // the (Kyrandia 1) FM-Towns version. + // the (Kyrandia 1) FM-TOWNS version. // Since this method is just used for the Seqplayer // this shouldn't be a problem anywhere else, so it's // safe to disable the call here. @@ -1027,8 +1028,8 @@ int Screen::getCharWidth(uint16 c) const { if (_vm->gameFlags().platform == Common::kPlatformAmiga) return 0; - if (c & 0xFF00) - return SJIS_CHARSIZE >> 1; + if ((c & 0xFF00) && _sjisFont) + return _sjisFont->getFontWidth() >> 1; if (_fonts[_currentFont].lastGlyph < c) return 0; @@ -1115,7 +1116,7 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 c = READ_LE_UINT16(str - 1); ++str; charWidth = getCharWidth(c); - charHeight = SJIS_CHARSIZE >> 1; + charHeight = _sjisFont->getFontHeight() >> 1; drawCharSJIS(c, x, y); } @@ -3007,93 +3008,6 @@ void Screen::copyOverlayRegion(int x, int y, int x2, int y2, int w, int h, int s } } -// SJIS rendering - -namespace { -int SJIStoFMTChunk(int f, int s) { // copied from scumm\charset.cpp - enum { - KANA = 0, - KANJI = 1, - EKANJI = 2 - }; - int base = s - ((s + 1) % 32); - int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA; - - if (f >= 0x81 && f <= 0x84) kanjiType = KANA; - if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI; - if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI; - - if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) { - c = 48; //correction - p = -8; //correction - } - - if (kanjiType == KANA) {//Kana - chunk_f = (f - 0x81) * 2; - } else if (kanjiType == KANJI) {//Standard Kanji - p += f - 0x88; - chunk_f = c + 2 * p; - } else if (kanjiType == EKANJI) {//Enhanced Kanji - p += f - 0xe0; - chunk_f = c + 2 * p; - } - - // Base corrections - if (base == 0x7f && s == 0x7f) - base -= 0x20; - if (base == 0x9f && s == 0xbe) - base += 0x20; - if (base == 0xbf && s == 0xde) - base += 0x20; - //if (base == 0x7f && s == 0x9e) - // base += 0x20; - - switch (base) { - case 0x3f: - cr = 0; //3f - if (kanjiType == KANA) chunk = 1; - else if (kanjiType == KANJI) chunk = 31; - else if (kanjiType == EKANJI) chunk = 111; - break; - case 0x5f: - cr = 0; //5f - if (kanjiType == KANA) chunk = 17; - else if (kanjiType == KANJI) chunk = 47; - else if (kanjiType == EKANJI) chunk = 127; - break; - case 0x7f: - cr = -1; //80 - if (kanjiType == KANA) chunk = 9; - else if (kanjiType == KANJI) chunk = 63; - else if (kanjiType == EKANJI) chunk = 143; - break; - case 0x9f: - cr = 1; //9e - if (kanjiType == KANA) chunk = 2; - else if (kanjiType == KANJI) chunk = 32; - else if (kanjiType == EKANJI) chunk = 112; - break; - case 0xbf: - cr = 1; //be - if (kanjiType == KANA) chunk = 18; - else if (kanjiType == KANJI) chunk = 48; - else if (kanjiType == EKANJI) chunk = 128; - break; - case 0xdf: - cr = 1; //de - if (kanjiType == KANA) chunk = 10; - else if (kanjiType == KANJI) chunk = 64; - else if (kanjiType == EKANJI) chunk = 144; - break; - default: - debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p); - } - - debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr); - return ((chunk_f + chunk) * 32 + (s - base)) + cr; -} -} // end of anonymous namespace - void Screen::drawCharSJIS(uint16 c, int x, int y) { int color1, color2; @@ -3105,14 +3019,13 @@ void Screen::drawCharSJIS(uint16 c, int x, int y) { } else { color1 = _textColorsMap[1]; color2 = _textColorsMap[0]; - } - memset(_sjisTempPage2, _sjisInvisibleColor, 324); - memset(_sjisSourceChar, 0, 36); - memcpy(_sjisSourceChar, _sjisFontData + 0x20 * SJIStoFMTChunk(c & 0xff, c >> 8), 0x20); + if (color2 == _sjisInvisibleColor) + _sjisFont->enableOutline(false); + } if (_curPage == 0 || _curPage == 1) - addDirtyRect(x, y, SJIS_CHARSIZE >> 1, SJIS_CHARSIZE >> 1); + addDirtyRect(x, y, _sjisFont->getFontWidth() >> 1, _sjisFont->getFontHeight() >> 1); x <<= 1; y <<= 1; @@ -3124,154 +3037,10 @@ void Screen::drawCharSJIS(uint16 c, int x, int y) { } destPage += y * 640 + x; - uint8 *src = 0, *dst = 0; - - if (color2 != _sjisInvisibleColor) { - // draw color2 shadow - src = _sjisSourceChar; - dst = _sjisTempPage2; - - for (int i = 0; i < SJIS_CHARSIZE; i++) { - *((uint16*)dst) = READ_LE_UINT16(src); - dst += 2; src += 2; - *dst++ = 0; - } - - src = _sjisTempPage2; - dst = _sjisTempPage; - memset(dst, 0, 60); - for (int i = 0; i < 48; i++) - *dst++ |= *src++; - - src = _sjisTempPage2; - dst = _sjisTempPage + 3; - for (int i = 0; i < 48; i++) - *dst++ |= *src++; - - src = _sjisTempPage2; - dst = _sjisTempPage + 6; - for (int i = 0; i < 48; i++) - *dst++ |= *src++; - - for (int i = 0; i < 2; i++) { - src = _sjisTempPage; - for (int ii = 0; ii < SJIS_CHARSIZE; ii++) { - uint8 cy2 = 0; - uint8 cy1 = 0; - for (int iii = 0; iii < 3; iii++) { - cy1 = *src & 1; - *src |= ((*src >> 1) | (cy2 << 7)); - cy2 = cy1; - src++; - } - } - } - - src = _sjisTempPage2; - for (int i = 0; i < SJIS_CHARSIZE; i++) { - uint8 cy2 = 0; - uint8 cy1 = 0; - for (int ii = 0; ii < 3; ii++) { - cy1 = *src & 1; - *src = ((*src >> 1) | (cy2 << 7)); - cy2 = cy1; - src++; - } - } - src = _sjisTempPage2; - dst = _sjisTempPage + 3; - for (int i = 0; i < 48; i++) - *dst++ ^= *src++; - - memset(_sjisTempPage2, _sjisInvisibleColor, 324); - src = _sjisTempPage; - dst = _sjisTempPage2; - - uint8 height = SJIS_CHARSIZE * 3; - uint8 width = SJIS_CHARSIZE; - if (color2 & 0xff00) { - height -= 3; - width--; - dst += 0x13; - } - - for (int i = 0; i < height; i++) { - uint8 rs = *src++; - for (int ii = 0; ii < 8; ii++) { - if (rs & 0x80) - *dst = (color2 & 0xff); - rs <<= 1; - dst++; - - if (!--width) { - width = SJIS_CHARSIZE; - if (color2 & 0xff00) { - width--; - dst++; - } - break; - } - } - } - } - - // draw color1 char - src = _sjisSourceChar; - dst = _sjisTempPage; - - for (int i = 0; i < SJIS_CHARSIZE; i++) { - *(uint16*)dst = READ_LE_UINT16(src); - dst += 2; src += 2; - *dst++ = 0; - } + _sjisFont->drawChar(destPage, c, 640, 1, color1, color2); - src = _sjisTempPage; - dst = _sjisTempPage2; - if (color2 != _sjisInvisibleColor) - color1 = (color1 & 0xff) | 0x100; - - uint8 height = SJIS_CHARSIZE * 3; - uint8 width = SJIS_CHARSIZE; - if (color1 & 0xff00) { - height -= 3; - width--; - dst += 0x13; - } - - for (int i = 0; i < height; i++) { - uint8 rs = *src++; - for (int ii = 0; ii < 8; ii++) { - if (rs & 0x80) - *dst = (color1 & 0xff); - rs <<= 1; - dst++; - - if (!--width) { - width = SJIS_CHARSIZE; - if (color1 & 0xff00) { - width--; - dst++; - } - break; - } - } - } - - // copy char to surface - src = _sjisTempPage2; - dst = destPage; - int pitch = 640 - SJIS_CHARSIZE; - - for (int i = 0; i < SJIS_CHARSIZE; i++) { - for (int ii = 0; ii < SJIS_CHARSIZE; ii++) { - if (*src != _sjisInvisibleColor) - *dst = *src; - src++; - dst++; - } - dst += pitch; - } + _sjisFont->enableOutline(!_use16ColorMode); } #pragma mark - diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 956bd7107e..a7a7efa7ca 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -35,6 +35,10 @@ class OSystem; +namespace Graphics { +class FontSJIS; +} // end of namespace Graphics + namespace Kyra { typedef Common::Functor0<void> UpdateFunctor; @@ -360,11 +364,6 @@ protected: void drawCharANSI(uint8 c, int x, int y); void drawCharSJIS(uint16 c, int x, int y); - enum { - SJIS_CHARSIZE = 18, - SJIS_CHARS = 8192 - }; - int16 encodeShapeAndCalculateSize(uint8 *from, uint8 *to, int size); template<bool noXor> static void wrapped_decodeFrameDelta(uint8 *dst, const uint8 *src); @@ -377,10 +376,7 @@ protected: bool _useSJIS; bool _use16ColorMode; - uint8 *_sjisFontData; - uint8 *_sjisTempPage; - uint8 *_sjisTempPage2; - uint8 *_sjisSourceChar; + Graphics::FontSJIS *_sjisFont; uint8 _sjisInvisibleColor; Palette *_screenPalette; diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index 90b2fdd580..81ab237e0f 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -770,12 +770,12 @@ int KyraEngine_HoF::seq_introDragon(WSAMovie_v2 *wsaObj, int x, int y, int frm) } int KyraEngine_HoF::seq_introDarm(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - //NULLSUB (at least in fm-towns version) + //NULLSUB (at least in FM-TOWNS version) return frm; } int KyraEngine_HoF::seq_introLibrary2(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - //NULLSUB (at least in fm-towns version) + //NULLSUB (at least in FM-TOWNS version) return frm; } @@ -788,7 +788,7 @@ int KyraEngine_HoF::seq_introMarco(WSAMovie_v2 *wsaObj, int x, int y, int frm) { } int KyraEngine_HoF::seq_introHand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - //NULLSUB (at least in fm-towns version) + //NULLSUB (at least in FM-TOWNS version) return frm; } @@ -805,12 +805,12 @@ int KyraEngine_HoF::seq_introHand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm) } int KyraEngine_HoF::seq_introHand2(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - //NULLSUB (at least in fm-towns version) + //NULLSUB (at least in FM-TOWNS version) return frm; } int KyraEngine_HoF::seq_introHand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - //NULLSUB (at least in fm-towns version) + //NULLSUB (at least in FM-TOWNS version) return frm; } diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index d483409090..0279831c9d 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -1049,7 +1049,7 @@ void KyraEngine_LoK::seq_playCredits() { _screen->setTextColorMap(colorMap); _screen->_charWidth = -1; - // we only need this for the fm-towns version + // we only need this for the FM-TOWNS version if (_flags.platform == Common::kPlatformFMTowns && _configMusic == 1) snd_playWanderScoreViaMap(53, 1); diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 8f977c04c2..2d11f39835 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -374,10 +374,8 @@ const char *selector_name(EngineState *s, int selector) { } bool Console::cmdGetVersion(int argc, const char **argv) { - int ver = _vm->getVersion(); - - DebugPrintf("Resource file version: %s\n", sci_version_types[_vm->getResMgr()->_sciVersion]); - DebugPrintf("Emulated interpreter version: %s\n", versionNames[ver]); + DebugPrintf("Resource file version: %s\n", versionNames[_vm->getResMgr()->_sciVersion]); + DebugPrintf("Emulated interpreter version: %s\n", versionNames[_vm->getVersion()]); return true; } diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index f86810e6b9..a9dac98572 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -31,7 +31,6 @@ namespace Sci { -#define GF_FOR_SCI0_BEFORE_395 (GF_SCI0_OLD | GF_SCI0_OLDGETTIME) #define GF_FOR_SCI0_BEFORE_629 GF_SCI0_OLDGETTIME // Titles of the games @@ -219,7 +218,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.map", 0, "39485580d34a72997f3d5b3aba4d24f1", 426}, {"resource.001", 0, "11391434f41c834090d7a1e9488ce936", 129739}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, - GF_FOR_SCI0_BEFORE_395, + GF_FOR_SCI0_BEFORE_629, SCI_VERSION_AUTODETECT, SCI_VERSION_0 }, @@ -457,7 +456,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.005", 0, "58942b1aa6d6ffeb66e9f8897fd4435f", 469243}, {"resource.006", 0, "8c767b3939add63d11274065e46aad04", 713158}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, - GF_SCI1_EGA, + 0, SCI_VERSION_AUTODETECT, SCI_VERSION_1 }, @@ -949,8 +948,8 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.004", 0, "9ae2a13708d691cd42f9129173c4b39d", 820443}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH}, 0, - SCI_VERSION_01_EGA, - SCI_VERSION_01_EGA + SCI_VERSION_01, + SCI_VERSION_01 }, // King's Quest 1 SCI Remake - English DOS Non-Interactive Demo @@ -1032,7 +1031,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.006", 0, "851a62d00972dc4002f472cc0d84e71d", 333777}, {"resource.007", 0, "851a62d00972dc4002f472cc0d84e71d", 341038}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, - GF_FOR_SCI0_BEFORE_395, + GF_FOR_SCI0_BEFORE_629, SCI_VERSION_AUTODETECT, SCI_VERSION_0 }, @@ -1049,7 +1048,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.006", 0, "0c8566848a76eea19a6d6220914030a7", 337288}, {"resource.007", 0, "0c8566848a76eea19a6d6220914030a7", 343882}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, - GF_FOR_SCI0_BEFORE_395, + GF_FOR_SCI0_BEFORE_629, SCI_VERSION_AUTODETECT, SCI_VERSION_0 }, @@ -1616,7 +1615,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.005", 0, "96033f57accfca903750413fd09193c8", 274953}, {"resource.006", 0, "96033f57accfca903750413fd09193c8", 345818}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, - GF_FOR_SCI0_BEFORE_395, + GF_FOR_SCI0_BEFORE_629, SCI_VERSION_AUTODETECT, SCI_VERSION_0 }, @@ -2066,8 +2065,8 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.001", 0, "9e33566515b18bee7915db448063bba2", 871853}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH}, 0, - SCI_VERSION_01_EGA, - SCI_VERSION_01_EGA + SCI_VERSION_01, + SCI_VERSION_01 }, // Mixed-Up Fairy Tales v1.000 - English DOS (supplied by markcoolio in bug report #2723791) @@ -2081,8 +2080,8 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.004", 0, "f79daa70390d73746742ffcfc3dc4471", 937580}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, 0, - SCI_VERSION_01_EGA, - SCI_VERSION_01_EGA + SCI_VERSION_01, + SCI_VERSION_01 }, // Mixed-Up Fairy Tales - English DOS Floppy (from jvprat) @@ -2095,8 +2094,8 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.003", 0, "dd6cef0c592eadb7e6be9a25307c57a2", 1344719}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, 0, - SCI_VERSION_01_EGA, - SCI_VERSION_01_EGA + SCI_VERSION_01, + SCI_VERSION_01 }, // Mixed-Up Mother Goose - English Amiga (from www.back2roots.org) @@ -2108,8 +2107,8 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.002", 0, "fb552ae550ca1dac19ed8f6a3767612d", 817191}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH}, 0, - SCI_VERSION_01_EGA, - SCI_VERSION_01_EGA + SCI_VERSION_01, + SCI_VERSION_01 }, // Mixed-Up Mother Goose v2.000 - English DOS Floppy (supplied by markcoolio in bug report #2723795) @@ -2119,8 +2118,8 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.000", 0, "b7ecd8ae9e254e80310b5a668b276e6e", 2948975}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, 0, - SCI_VERSION_01_EGA, - SCI_VERSION_01_EGA + SCI_VERSION_01, + SCI_VERSION_01 }, // Mixed-Up Mother Goose - English DOS CD (from jvprat) @@ -2520,7 +2519,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, 0, SCI_VERSION_AUTODETECT, - SCI_VERSION_01_EGA + SCI_VERSION_01 }, // Quest for Glory 1 - Japanese PC-98 5.25" Floppy @@ -2533,7 +2532,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, 0, SCI_VERSION_AUTODETECT, - SCI_VERSION_01_EGA + SCI_VERSION_01 }, // Quest for Glory 1 - English Amiga @@ -2606,7 +2605,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH}, 0, SCI_VERSION_AUTODETECT, - SCI_VERSION_01_EGA + SCI_VERSION_01 }, // Quest for Glory 2 - English (from FRG) @@ -2621,7 +2620,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, 0, SCI_VERSION_AUTODETECT, - SCI_VERSION_01_EGA + SCI_VERSION_01 }, // Quest for Glory 2 - English DOS @@ -2639,7 +2638,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, 0, SCI_VERSION_AUTODETECT, - SCI_VERSION_01_EGA + SCI_VERSION_01 }, // Quest for Glory 3 - English DOS Non-Interactive Demo (from FRG) @@ -3125,7 +3124,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088}, {"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249}, {NULL, 0, NULL, 0}}, Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, - GF_SCI1_EGA, + 0, SCI_VERSION_AUTODETECT, SCI_VERSION_1 }, @@ -3138,7 +3137,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088}, {"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, - GF_SCI1_EGA, + 0, SCI_VERSION_AUTODETECT, SCI_VERSION_1 }, diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 7eb4c6731a..861294cfa6 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -43,10 +43,8 @@ int _reset_graphics_input(EngineState *s) { gfx_color_t transparent = { PaletteEntry(), 0, -1, -1, 0 }; debug(2, "Initializing graphics"); - if (s->resmgr->_sciVersion <= SCI_VERSION_01_EGA || (s->_flags & GF_SCI1_EGA)) { - int i; - - for (i = 0; i < 16; i++) { + if (!s->resmgr->isVGA()) { + for (int i = 0; i < 16; i++) { if (gfxop_set_color(s->gfx_state, &(s->ega_colors[i]), gfx_sci0_image_colors[sci0_palette][i].r, gfx_sci0_image_colors[sci0_palette][i].g, gfx_sci0_image_colors[sci0_palette][i].b, 0, -1, -1)) { return 1; @@ -97,7 +95,7 @@ int _reset_graphics_input(EngineState *s) { font_nr = -1; do { resource = s->resmgr->testResource(ResourceId(kResourceTypeFont, ++font_nr)); - } while ((!resource) && (font_nr < sci_max_resource_nr[s->resmgr->_sciVersion])); + } while ((!resource) && (font_nr < 65536)); if (!resource) { debug(2, "No text font was found."); @@ -111,7 +109,7 @@ int _reset_graphics_input(EngineState *s) { s->iconbar_port = new GfxPort(s->visual, gfx_rect(0, 0, 320, 200), s->ega_colors[0], transparent); s->iconbar_port->_flags |= GFXW_FLAG_NO_IMPLICIT_SWITCH; - if (s->resmgr->_sciVersion >= SCI_VERSION_01_VGA) { + if (s->resmgr->isVGA()) { // This bit sets the foreground and background colors in VGA SCI games gfx_color_t fgcolor; gfx_color_t bgcolor; @@ -181,7 +179,7 @@ static void _free_graphics_input(EngineState *s) { } int game_init_sound(EngineState *s, int sound_flags) { - if (s->resmgr->_sciVersion >= SCI_VERSION_01_EGA) + if (s->resmgr->_sciVersion >= SCI_VERSION_01) sound_flags |= SFX_STATE_FLAG_MULTIPLAY; s->sfx_init_flags = sound_flags; @@ -259,7 +257,7 @@ static int create_class_table_sci0(EngineState *s) { Resource *script = s->resmgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0); if (script) { - if (s->_flags & GF_SCI0_OLD) + if (s->_kernel->hasOldScriptHeader()) magic_offset = seeker = 2; else magic_offset = seeker = 0; @@ -329,6 +327,9 @@ int script_init_engine(EngineState *s) { s->kernel_opt_flags = 0; + s->_kernel = new Kernel(s->resmgr); + s->_vocabulary = new Vocabulary(s->resmgr); + if (s->_version >= SCI_VERSION_1_1) result = create_class_table_sci11(s); else @@ -369,9 +370,6 @@ int script_init_engine(EngineState *s) { s->_executionStack.clear(); // Start without any execution stack s->execution_stack_base = -1; // No vm is running yet - s->_kernel = new Kernel(s->resmgr, (s->_flags & GF_SCI0_OLD)); - s->_vocabulary = new Vocabulary(s->resmgr); - s->restarting_flags = SCI_GAME_IS_NOT_RESTARTING; s->bp_list = NULL; // No breakpoints defined @@ -466,7 +464,7 @@ int game_init(EngineState *s) { s->successor = NULL; // No successor s->_statusBarText.clear(); // Status bar is blank s->status_bar_foreground = 0; - s->status_bar_background = (s->resmgr->_sciVersion >= SCI_VERSION_01_VGA) ? 255 : 15; + s->status_bar_background = !s->resmgr->isVGA() ? 15 : 255; SystemString *str = &s->sys_strings->strings[SYS_STRING_PARSER_BASE]; str->name = strdup("parser-base"); diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 80071b2847..dd2d0dc61a 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -367,59 +367,102 @@ static const char *argtype_description[] = { "Arithmetic" }; -Kernel::Kernel(ResourceManager *resmgr, bool isOldSci0) : _resmgr(resmgr) { +Kernel::Kernel(ResourceManager *resmgr) : _resmgr(resmgr) { memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t - loadSelectorNames(isOldSci0); - mapSelectors(); // Map a few special selectors for later use + detectSciFeatures(); // must be called before loadSelectorNames() + loadSelectorNames(); + mapSelectors(); // Map a few special selectors for later use loadOpcodes(); loadKernelNames(); - mapFunctions(); // Map the kernel functions - - // SCI0 games using old graphics functions (before version 0.000.502) did not have a - // motionCue selector - _oldGfxFunctions = (_selectorMap.motionCue == -1 && _resmgr->_sciVersion == SCI_VERSION_0); - - // SCI1 games which use absolute lofs have the egoMoveSpeed selector - _hasLofsAbsolute = (_selectorMap.egoMoveSpeed != -1 && _resmgr->_sciVersion < SCI_VERSION_1_1); - - printAutoDetectedFeatures(); + mapFunctions(); // Map the kernel functions } Kernel::~Kernel() { } -void Kernel::printAutoDetectedFeatures() { - if (_oldGfxFunctions) - printf("Kernel auto-detection: game found to be using old graphics functions\n"); +void Kernel::detectSciFeatures() { + Resource *r = _resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES), 0); + + if (!r) // No such resource? + error("Kernel: Could not retrieve selector names"); + + int count = READ_LE_UINT16(r->data) + 1; // Counter is slightly off + features = 0; + + // Initialize features based on SCI version + if (_resmgr->_sciVersion == SCI_VERSION_0) { + features |= kFeatureOldScriptHeader; + features |= kFeatureOldGfxFunctions; + } + + for (int i = 0; i < count; i++) { + int offset = READ_LE_UINT16(r->data + 2 + i * 2); + int len = READ_LE_UINT16(r->data + offset); + + Common::String tmp((const char *)r->data + offset + 2, len); + + if (tmp == "setTarget") // "motionInited" can also be used + features &= ~kFeatureOldScriptHeader; + + if (tmp == "motionCue") + features &= ~kFeatureOldGfxFunctions; + + if (tmp == "egoMoveSpeed" && _resmgr->_sciVersion < SCI_VERSION_1_1) + features |= kFeatureLofsAbsolute; + + if (tmp == "sightAngle" && _resmgr->_sciVersion == SCI_VERSION_0) + features |= kFeatureSci0Sci1Table; + + if (tmp == "setVol") + features |= kFeatureSci1Sound; + + if (tmp == "nodePtr") + features |= kFeatureSci01Sound; + } + + if (features & kFeatureSci1Sound) + features &= ~kFeatureSci01Sound; + + printf("Kernel auto-detected features:\n"); + + printf("Script block headers: "); + if (features & kFeatureOldScriptHeader) + printf("old\n"); else - printf("Kernel auto-detection: game found to be using newer graphics functions\n"); + printf("new\n"); - if (_hasLofsAbsolute) - printf("Kernel auto-detection: game found to be using absolute parameters for lofs\n"); + printf("Graphics functions: "); + if (features & kFeatureOldGfxFunctions) + printf("old\n"); else - printf("Kernel auto-detection: game found to be using relative parameters for lofs\n"); + printf("new\n"); - if (_selectorMap.setVol != -1) - printf("Kernel auto-detection: using SCI1 sound functions\n"); - else if (_selectorMap.nodePtr != -1) - printf("Kernel auto-detection: using SCI01 sound functions\n"); + printf("lofs parameters: "); + if (features & kFeatureLofsAbsolute) + printf("absolute\n"); else - printf("Kernel auto-detection: using SCI0 sound functions\n"); + printf("relative\n"); - if (_resmgr->_sciVersion == SCI_VERSION_0 && _selectorMap.sightAngle != -1) - printf("Kernel auto-detection: found SCI0 game using a SCI1 kernel table\n"); -} + printf("Sound functions: "); + if (features & kFeatureSci1Sound) + printf("SCI1\n"); + else if (features & kFeatureSci01Sound) + printf("SCI01\n"); + else + printf("SCI0\n"); -void Kernel::loadSelectorNames(bool isOldSci0) { - int count; + if (features & kFeatureSci0Sci1Table) + printf("Found SCI0 game using a SCI1 kernel table\n"); +} +void Kernel::loadSelectorNames() { Resource *r = _resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES), 0); if (!r) // No such resource? error("Kernel: Could not retrieve selector names"); - count = READ_LE_UINT16(r->data) + 1; // Counter is slightly off + int count = READ_LE_UINT16(r->data) + 1; // Counter is slightly off for (int i = 0; i < count; i++) { int offset = READ_LE_UINT16(r->data + 2 + i * 2); @@ -431,7 +474,7 @@ void Kernel::loadSelectorNames(bool isOldSci0) { // Early SCI versions used the LSB in the selector ID as a read/write // toggle. To compensate for that, we add every selector name twice. - if (isOldSci0) + if (features & kFeatureOldScriptHeader) _selectorNames.push_back(tmp); } } @@ -771,7 +814,7 @@ void Kernel::setDefaultKernelNames() { // Check if we have a SCI01 game which uses a SCI1 kernel table (e.g. the KQ1 demo // and full version). We do this by checking if the sightAngle selector exists, as no // SCI0 game seems to have it - if (_selectorMap.sightAngle != -1 && isSci0) + if (features & kFeatureSci0Sci1Table) isSci0 = false; _kernelNames.resize(SCI_KNAMES_DEFAULT_ENTRIES_NR + (isSci0 ? 4 : 0)); @@ -832,8 +875,7 @@ bool Kernel::loadKernelNames() { switch (_resmgr->_sciVersion) { case SCI_VERSION_0: - case SCI_VERSION_01_EGA: - case SCI_VERSION_01_VGA: + case SCI_VERSION_01: case SCI_VERSION_01_VGA_ODD: case SCI_VERSION_1: case SCI_VERSION_1_1: diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 9c92519cf0..4814bd0317 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -55,9 +55,18 @@ struct KernelFuncWithSignature { Common::String orig_name; /**< Original name, in case we couldn't map it */ }; +enum AutoDetectedFeatures { + kFeatureOldScriptHeader = 1 << 0, + kFeatureOldGfxFunctions = 1 << 1, + kFeatureLofsAbsolute = 1 << 2, + kFeatureSci01Sound = 1 << 3, + kFeatureSci1Sound = 1 << 4, + kFeatureSci0Sci1Table = 1 << 5 +}; + class Kernel { public: - Kernel(ResourceManager *resmgr, bool isOldSci0); + Kernel(ResourceManager *resmgr); ~Kernel(); uint getOpcodesSize() const { return _opcodes.size(); } @@ -84,20 +93,40 @@ public: bool hasKernelFunction(const char *functionName) const; /** + * Applies to all versions before 0.000.395 (i.e. KQ4 old, XMAS 1988 and LSL2). + * Old SCI versions used two word header for script blocks (first word equal + * to 0x82, meaning of the second one unknown). New SCI versions used one + * word header. + * Also, old SCI versions assign 120 degrees to left & right, and 60 to up + * and down. Later versions use an even 90 degree distribution. + */ + bool hasOldScriptHeader() const { return (features & kFeatureOldScriptHeader); } + + /** * Applies to all versions before 0.000.502 * Old SCI versions used to interpret the third DrawPic() parameter inversely, * with the opposite default value (obviously). * Also, they used 15 priority zones from 42 to 200 instead of 14 priority * zones from 42 to 190. */ - bool usesOldGfxFunctions() const { return _oldGfxFunctions; } + bool usesOldGfxFunctions() const { return (features & kFeatureOldGfxFunctions); } /** * Applies to all SCI1 versions after 1.000.200 * In late SCI1 versions, the argument of lofs[as] instructions * is absolute rather than relative. */ - bool hasLofsAbsolute() const { return _hasLofsAbsolute; } + bool hasLofsAbsolute() const { return (features & kFeatureLofsAbsolute); } + + /** + * Determines if the game is using SCI01 sound functions + */ + bool usesSci01SoundFunctions() const { return (features & kFeatureSci01Sound); } + + /** + * Determines if the game is using SCI1 sound functions + */ + bool usesSci1SoundFunctions() const { return (features & kFeatureSci1Sound); } // Script dissection/dumping functions void dissectScript(int scriptNumber, Vocabulary *vocab); @@ -127,17 +156,17 @@ private: /** * Loads the kernel selector names. */ - void loadSelectorNames(bool isOldSci0); + void loadSelectorNames(); /** - * Prints auto-detected features from selectors + * Maps special selectors */ - void printAutoDetectedFeatures(); + void mapSelectors(); /** - * Maps special selectors + * Detects SCI features based on the existence of certain selectors */ - void mapSelectors(); + void detectSciFeatures(); /** * Maps kernel functions @@ -151,8 +180,7 @@ private: bool loadOpcodes(); ResourceManager *_resmgr; - bool _oldGfxFunctions; - bool _hasLofsAbsolute; + uint32 features; // Kernel-related lists /** diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 487813a4c7..d46ce3b938 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -269,7 +269,7 @@ void graph_restore_box(EngineState *s, reg_t handle) { } PaletteEntry get_pic_color(EngineState *s, int color) { - if (s->resmgr->_sciVersion < SCI_VERSION_01_VGA) + if (!s->resmgr->isVGA()) return s->ega_colors[color].visual; if (color == -1 || color == 255) // -1 occurs in Eco Quest 1. Not sure if this is the best approach, but it seems to work @@ -286,7 +286,7 @@ PaletteEntry get_pic_color(EngineState *s, int color) { static gfx_color_t graph_map_color(EngineState *s, int color, int priority, int control) { gfx_color_t retval; - if (s->resmgr->_sciVersion < SCI_VERSION_01_VGA) { + if (!s->resmgr->isVGA()) { retval = s->ega_colors[(color >=0 && color < 16)? color : 0]; gfxop_set_color(s->gfx_state, &retval, (color < 0) ? -1 : retval.visual.r, retval.visual.g, retval.visual.b, (color == -1) ? 255 : 0, priority, control); @@ -502,7 +502,7 @@ reg_t kGraph(EngineState *s, int funct_nr, int argc, reg_t *argv) { case K_GRAPH_GET_COLORS_NR: - return make_reg(0, s->resmgr->_sciVersion < SCI_VERSION_01_VGA ? 0x10 : 0x100); + return make_reg(0, !s->resmgr->isVGA() ? 0x10 : 0x100); break; case K_GRAPH_DRAW_LINE: { @@ -696,7 +696,7 @@ void _k_dirloop(reg_t obj, uint16 angle, EngineState *s, int funct_nr, int argc, angle %= 360; - if (!(s->_flags & GF_SCI0_OLD)) { + if (!s->_kernel->hasOldScriptHeader()) { if (angle < 45) loop = 3; else if (angle < 136) @@ -2502,7 +2502,7 @@ reg_t kNewWindow(EngineState *s, int funct_nr, int argc, reg_t *argv) { int16 bgColor = (argc > 8 + argextra) ? argv[8 + argextra].toSint16() : 255; if (bgColor >= 0) { - if (s->resmgr->_sciVersion < SCI_VERSION_01_VGA) + if (!s->resmgr->isVGA()) bgcolor.visual = get_pic_color(s, MIN<int>(bgColor, 15)); else bgcolor.visual = get_pic_color(s, bgColor); @@ -2528,7 +2528,7 @@ reg_t kNewWindow(EngineState *s, int funct_nr, int argc, reg_t *argv) { black.alpha = 0; black.control = -1; black.priority = -1; - lWhite.visual = get_pic_color(s, s->resmgr->_sciVersion < SCI_VERSION_01_VGA ? 15 : 255); + lWhite.visual = get_pic_color(s, !s->resmgr->isVGA() ? 15 : 255); lWhite.mask = GFX_MASK_VISUAL; lWhite.alpha = 0; lWhite.priority = -1; @@ -3149,7 +3149,7 @@ reg_t kDisplay(EngineState *s, int funct_nr, int argc, reg_t *argv) { bg_color = port->_bgcolor; // TODO: in SCI1VGA the default colors for text and background are #0 (black) // SCI0 case should be checked - if (s->resmgr->_sciVersion >= SCI_VERSION_01_VGA) { + if (s->resmgr->isVGA()) { // This priority check fixes the colors in the menus in KQ5 // TODO/FIXME: Is this correct? if (color0.priority >= 0) @@ -3191,10 +3191,10 @@ reg_t kDisplay(EngineState *s, int funct_nr, int argc, reg_t *argv) { temp = argv[argpt++].toSint16(); debugC(2, kDebugLevelGraphics, "Display: set_color(%d)\n", temp); - if ((s->resmgr->_sciVersion < SCI_VERSION_01_VGA) && temp >= 0 && temp <= 15) + if (!s->resmgr->isVGA() && temp >= 0 && temp <= 15) color0 = (s->ega_colors[temp]); else - if (s->resmgr->_sciVersion >= SCI_VERSION_01_VGA && temp >= 0 && temp < 256) { + if (s->resmgr->isVGA() && temp >= 0 && temp < 256) { color0.visual = get_pic_color(s, temp); color0.mask = GFX_MASK_VISUAL; } else @@ -3208,10 +3208,10 @@ reg_t kDisplay(EngineState *s, int funct_nr, int argc, reg_t *argv) { temp = argv[argpt++].toSint16(); debugC(2, kDebugLevelGraphics, "Display: set_bg_color(%d)\n", temp); - if (s->resmgr->_sciVersion < SCI_VERSION_01_VGA && temp >= 0 && temp <= 15) + if (!s->resmgr->isVGA() && temp >= 0 && temp <= 15) bg_color = s->ega_colors[temp]; else - if ((s->resmgr->_sciVersion >= SCI_VERSION_01_VGA) && temp >= 0 && temp <= 256) { + if (s->resmgr->isVGA() && temp >= 0 && temp <= 256) { bg_color.visual = get_pic_color(s, temp); bg_color.mask = GFX_MASK_VISUAL; } else diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index ef02f8ee21..7614b2bc10 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -154,7 +154,7 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their SongHandle handle; int cue; - if (s->_version >= SCI_VERSION_01_EGA) + if (s->_version >= SCI_VERSION_01) return; /* SCI01 and later explicitly poll for everything */ @@ -940,14 +940,14 @@ reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { case SI_ABSOLUTE_CUE: signal = cue; - fprintf(stderr, "[CUE] %04x:%04x Absolute Cue: %d\n", + debugC(2, kDebugLevelSound, "[CUE] %04x:%04x Absolute Cue: %d\n", PRINT_REG(obj), signal); PUT_SEL32V(obj, signal, signal); break; case SI_RELATIVE_CUE: - fprintf(stderr, "[CUE] %04x:%04x Relative Cue: %d\n", + debugC(2, kDebugLevelSound, "[CUE] %04x:%04x Relative Cue: %d\n", PRINT_REG(obj), cue); PUT_SEL32V(obj, dataInc, cue); @@ -982,9 +982,9 @@ reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { * Used for synthesized music playback */ reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) { - if (s->_kernel->_selectorMap.setVol != -1) + if (s->_kernel->usesSci1SoundFunctions()) return kDoSound_SCI1(s, funct_nr, argc, argv); - else if (s->_kernel->_selectorMap.nodePtr != -1) + else if (s->_kernel->usesSci01SoundFunctions()) return kDoSound_SCI01(s, funct_nr, argc, argv); else return kDoSound_SCI0(s, funct_nr, argc, argv); diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index ade0304683..f44af2b1cd 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -497,7 +497,7 @@ static SegmentId find_unique_seg_by_type(SegManager *self, int type) { } static byte *find_unique_script_block(EngineState *s, byte *buf, int type) { - if (s->_flags & GF_SCI0_OLD) + if (s->_kernel->hasOldScriptHeader()) buf += 2; do { @@ -693,7 +693,7 @@ int _reset_graphics_input(EngineState *s); static void reconstruct_sounds(EngineState *s) { Song *seeker; - SongIteratorType it_type = s->resmgr->_sciVersion >= SCI_VERSION_01_EGA ? SCI_SONG_ITERATOR_TYPE_SCI1 : SCI_SONG_ITERATOR_TYPE_SCI0; + SongIteratorType it_type = s->resmgr->_sciVersion >= SCI_VERSION_01 ? SCI_SONG_ITERATOR_TYPE_SCI1 : SCI_SONG_ITERATOR_TYPE_SCI0; seeker = s->_sound._songlib._lib; diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index e78f3fd77f..b7529c33bd 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -91,9 +91,8 @@ opcode_format g_opcode_formats[128][4] = { void script_adjust_opcode_formats(int res_version) { switch (res_version) { case SCI_VERSION_0: - case SCI_VERSION_01_EGA: break; - case SCI_VERSION_01_VGA: + case SCI_VERSION_01: case SCI_VERSION_01_VGA_ODD: case SCI_VERSION_1: case SCI_VERSION_1_1: @@ -200,10 +199,6 @@ void Kernel::mapSelectors() { FIND_SELECTOR(printLang); FIND_SELECTOR(subtitleLang); FIND_SELECTOR(parseLang); - FIND_SELECTOR(motionCue); - FIND_SELECTOR(sightAngle); - FIND_SELECTOR(setVol); - FIND_SELECTOR(egoMoveSpeed); } void Kernel::dumpScriptObject(char *data, int seeker, int objsize) { diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index a524ddd365..d5f0a21385 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -243,7 +243,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod int stackframe = (scr[pos.offset + 2] >> 1) + (*debugState.p_restadjust); int argc = ((*debugState.p_sp)[- stackframe - 1]).offset; - if (!(s->_flags & GF_SCI0_OLD)) + if (!s->_kernel->hasOldScriptHeader()) argc += (*debugState.p_restadjust); printf(" Kernel params: ("); diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index d81768c9c8..74486ef015 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -138,7 +138,7 @@ void SegManager::setScriptSize(Script &scr, EngineState *s, int script_nr) { if (!script || (s->_version >= SCI_VERSION_1_1 && !heap)) { error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap"); } - if (s->_flags & GF_SCI0_OLD) { + if (s->_kernel->hasOldScriptHeader()) { scr.buf_size = script->size + READ_LE_UINT16(script->data) * 2; //locals_size = READ_LE_UINT16(script->data) * 2; } else if (s->_version < SCI_VERSION_1_1) { diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 09ed541d17..c6643b8a90 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -961,7 +961,7 @@ void run_vm(EngineState *s, int restoring) { gc_countdown(s); xs->sp -= (opparams[1] >> 1) + 1; - if (!(s->_flags & GF_SCI0_OLD)) { + if (!s->_kernel->hasOldScriptHeader()) { xs->sp -= restadjust; s->r_amp_rest = 0; // We just used up the restadjust, remember? } @@ -971,7 +971,7 @@ void run_vm(EngineState *s, int restoring) { } else { int argc = ASSERT_ARITHMETIC(xs->sp[0]); - if (!(s->_flags & GF_SCI0_OLD)) + if (!s->_kernel->hasOldScriptHeader()) argc += restadjust; if (s->_kernel->_kernelFuncs[opparams[0]].signature @@ -988,7 +988,7 @@ void run_vm(EngineState *s, int restoring) { xs_new = &(s->_executionStack.back()); s->_executionStackPosChanged = true; - if (!(s->_flags & GF_SCI0_OLD)) + if (!s->_kernel->hasOldScriptHeader()) restadjust = s->r_amp_rest; } @@ -1211,10 +1211,15 @@ void run_vm(EngineState *s, int restoring) { case 0x3a: // lofss r_temp.segment = xs->addr.pc.segment; - if (s->_kernel->hasLofsAbsolute()) - r_temp.offset = opparams[0]; - else - r_temp.offset = xs->addr.pc.offset + opparams[0]; + if (s->_version >= SCI_VERSION_1_1) { + r_temp.offset = opparams[0] + local_script->script_size; + } else { + if (s->_kernel->hasLofsAbsolute()) + r_temp.offset = opparams[0]; + else + r_temp.offset = xs->addr.pc.offset + opparams[0]; + } + #ifndef DISABLE_VALIDATIONS if (r_temp.offset >= code_buf_size) { error("VM: lofss operation overflowed: %04x:%04x beyond end" @@ -1495,7 +1500,7 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select // Early SCI versions used the LSB in the selector ID as a read/write // toggle, meaning that we must remove it for selector lookup. - if (s->_flags & GF_SCI0_OLD) + if (s->_kernel->hasOldScriptHeader()) selector_id &= ~1; if (!obj) { @@ -1654,7 +1659,7 @@ int script_instantiate_sci0(EngineState *s, int script_nr) { Script *scr = s->seg_manager->getScript(seg_id); - if (s->_flags & GF_SCI0_OLD) { + if (s->_kernel->hasOldScriptHeader()) { // int locals_nr = READ_LE_UINT16(script->data); @@ -1830,7 +1835,7 @@ int script_instantiate(EngineState *s, int script_nr) { } void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) { - reg_t reg = make_reg(seg, (s->_flags & GF_SCI0_OLD) ? 2 : 0); + reg_t reg = make_reg(seg, s->_kernel->hasOldScriptHeader() ? 2 : 0); int objtype, objlength; Script *scr = s->seg_manager->getScript(seg); @@ -1874,7 +1879,7 @@ void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) { } void script_uninstantiate(EngineState *s, int script_nr) { - reg_t reg = make_reg(0, (s->_flags & GF_SCI0_OLD) ? 2 : 0); + reg_t reg = make_reg(0, s->_kernel->hasOldScriptHeader() ? 2 : 0); reg.segment = s->seg_manager->segGet(script_nr); Script *scr = script_locate_by_segment(s, reg.segment); diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index adaa064a6c..a3fabbe44b 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -203,10 +203,6 @@ struct selector_map_t { Selector printLang; /**< Used for i18n */ Selector subtitleLang; Selector parseLang; - Selector motionCue; // Used to detect newer graphics functions semantics. - Selector sightAngle; // Used to detect some SCI0/SCI01 games which need a SCI1 table - Selector setVol; // Used to detect newer sound semantics - Selector egoMoveSpeed; // Used to detect SCI1 games which use absolute values in lofs }; // A reference to an object's variable. diff --git a/engines/sci/gfx/gfx_resmgr.cpp b/engines/sci/gfx/gfx_resmgr.cpp index 4abcc1fb78..9343b66cb8 100644 --- a/engines/sci/gfx/gfx_resmgr.cpp +++ b/engines/sci/gfx/gfx_resmgr.cpp @@ -49,14 +49,14 @@ struct param_struct { GfxDriver *driver; }; -GfxResManager::GfxResManager(int version, bool isVGA, gfx_options_t *options, GfxDriver *driver, ResourceManager *resManager) : - _version(version), _isVGA(isVGA), _options(options), _driver(driver), _resManager(resManager), +GfxResManager::GfxResManager(int version, gfx_options_t *options, GfxDriver *driver, ResourceManager *resManager) : + _version(version), _options(options), _driver(driver), _resManager(resManager), _lockCounter(0), _tagLockCounter(0), _staticPalette(0) { gfxr_init_static_palette(); _portBounds = Common::Rect(0, 10, 320, 200); // default value, with a titlebar of 10px - if (_version < SCI_VERSION_01_VGA || !_isVGA) { + if (!_resManager->isVGA()) { _staticPalette = gfx_sci0_pic_colors->getref(); } else if (_version == SCI_VERSION_1_1) { debugC(2, kDebugLevelGraphics, "Palettes are not yet supported in this SCI version\n"); @@ -99,7 +99,7 @@ int GfxResManager::calculatePic(gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic if (_version == SCI_VERSION_1_1) gfxr_draw_pic11(unscaled_pic, flags, default_palette, res->size, res->data, &basic_style, res->id.number, _staticPalette, _portBounds); else - gfxr_draw_pic01(unscaled_pic, flags, default_palette, res->size, res->data, &basic_style, res->id.number, _isVGA, _staticPalette, _portBounds); + gfxr_draw_pic01(unscaled_pic, flags, default_palette, res->size, res->data, &basic_style, res->id.number, _resManager->isVGA(), _staticPalette, _portBounds); } if (scaled_pic && scaled_pic->undithered_buffer) @@ -108,9 +108,9 @@ int GfxResManager::calculatePic(gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic if (_version == SCI_VERSION_1_1) gfxr_draw_pic11(scaled_pic, flags, default_palette, res->size, res->data, &style, res->id.number, _staticPalette, _portBounds); else - gfxr_draw_pic01(scaled_pic, flags, default_palette, res->size, res->data, &style, res->id.number, _isVGA, _staticPalette, _portBounds); + gfxr_draw_pic01(scaled_pic, flags, default_palette, res->size, res->data, &style, res->id.number, _resManager->isVGA(), _staticPalette, _portBounds); - if (!_isVGA) { + if (!_resManager->isVGA()) { if (need_unscaled) gfxr_remove_artifacts_pic0(scaled_pic, unscaled_pic); @@ -144,7 +144,7 @@ int GfxResManager::getOptionsHash(gfx_resource_type_t type) { case GFX_RESOURCE_TYPE_PIC: #ifdef CUSTOM_GRAPHICS_OPTIONS - if (_version >= SCI_VERSION_01_VGA) + if (_resManager->isVGA()) // NOTE: here, it is assumed that the upper port bound is always 10, but this doesn't seem to matter for the // generated options hash anyway return 10; @@ -153,7 +153,7 @@ int GfxResManager::getOptionsHash(gfx_resource_type_t type) { | (_options->pic0_dither_pattern << 8) | (_options->pic0_brush_mode << 4) | (_options->pic0_line_mode); #else - if (_version >= SCI_VERSION_01_VGA) + if (_resManager->isVGA()) return 10; else return 0x10000 | (GFXR_DITHER_PATTERN_SCALED << 8) | (GFX_BRUSH_MODE_RANDOM_ELLIPSES << 4) | GFX_LINE_MODE_CORRECT; @@ -341,12 +341,12 @@ gfxr_pic_t *GfxResManager::getPic(int num, int maps, int flags, int default_pale #ifdef CUSTOM_GRAPHICS_OPTIONS if (_options->pic0_unscaled) { need_unscaled = 0; - pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _version >= SCI_VERSION_01_VGA); + pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _resManager->isVGA()); } else - pic = gfxr_init_pic(_driver->getMode(), GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _version >= SCI_VERSION_01_VGA); + pic = gfxr_init_pic(_driver->getMode(), GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _resManager->isVGA()); #else need_unscaled = 0; - pic = gfxr_init_pic(_driver->getMode(), GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _version >= SCI_VERSION_01_VGA); + pic = gfxr_init_pic(_driver->getMode(), GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _resManager->isVGA()); #endif if (!pic) { @@ -357,7 +357,7 @@ gfxr_pic_t *GfxResManager::getPic(int num, int maps, int flags, int default_pale gfxr_clear_pic0(pic, SCI_TITLEBAR_SIZE); if (need_unscaled) { - unscaled_pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _version >= SCI_VERSION_01_VGA); + unscaled_pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _resManager->isVGA()); if (!unscaled_pic) { error("Failed to allocate unscaled pic"); return NULL; @@ -530,17 +530,16 @@ gfxr_view_t *GfxResManager::getView(int nr, int *loop, int *cel, int palette) { return NULL; int resid = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr); + + if (!_resManager->isVGA()) { + int pal = (_version == SCI_VERSION_0) ? -1 : palette; + view = getEGAView(resid, viewRes->data, viewRes->size, pal); + } else { + if (_version < SCI_VERSION_1_1) + view = getVGAView(resid, viewRes->data, viewRes->size, _staticPalette, false); + else + view = getVGAView(resid, viewRes->data, viewRes->size, 0, true); - if (_version < SCI_VERSION_01_EGA) - view = gfxr_draw_view0(resid, viewRes->data, viewRes->size, -1); - else if (_version == SCI_VERSION_01_EGA || !_isVGA) - view = gfxr_draw_view0(resid, viewRes->data, viewRes->size, palette); - else if (_version >= SCI_VERSION_01_VGA && _version <= SCI_VERSION_1) - view = gfxr_draw_view1(resid, viewRes->data, viewRes->size, _staticPalette, false); - else if (_version >= SCI_VERSION_1_1) - view = gfxr_draw_view1(resid, viewRes->data, viewRes->size, 0, true); - - if (_isVGA) { if (!view->palette) { view->palette = new Palette(_staticPalette->size()); view->palette->name = "interpreter_get_view"; @@ -554,7 +553,6 @@ gfxr_view_t *GfxResManager::getView(int nr, int *loop, int *cel, int palette) { view->palette->setColor(i, sc.r, sc.g, sc.b); } } - } if (!res) { @@ -619,6 +617,11 @@ gfx_bitmap_font_t *GfxResManager::getFont(int num, bool scaled) { gfx_resource_t *res = NULL; int hash = getOptionsHash(GFX_RESOURCE_TYPE_FONT); + // Workaround: LSL1VGA mixes its own internal fonts with the global + // SCI ones, so we translate them here, by removing their extra bits + if (!resMap.contains(num) && !_resManager->testResource(ResourceId(kResourceTypeFont, num))) + num = num & 0x7ff; + res = resMap.contains(num) ? resMap[num] : NULL; if (!res || res->mode != hash) { diff --git a/engines/sci/gfx/gfx_resmgr.h b/engines/sci/gfx/gfx_resmgr.h index 1f0f58dce9..8230e84aa0 100644 --- a/engines/sci/gfx/gfx_resmgr.h +++ b/engines/sci/gfx/gfx_resmgr.h @@ -90,7 +90,7 @@ typedef Common::HashMap<int, gfx_resource_t *> IntResMap; /** Graphics resource manager */ class GfxResManager { public: - GfxResManager(int version, bool isVGA, gfx_options_t *options, + GfxResManager(int version, gfx_options_t *options, GfxDriver *driver, ResourceManager *resManager); ~GfxResManager(); @@ -311,14 +311,12 @@ public: * * @return Number of pallete entries */ - int getColorCount() - { + int getColorCount() { return _staticPalette ? _staticPalette->size() : 0; } private: int _version; - bool _isVGA; gfx_options_t *_options; GfxDriver *_driver; Palette *_staticPalette; diff --git a/engines/sci/gfx/gfx_resource.h b/engines/sci/gfx/gfx_resource.h index 780060bc4f..9c83cf07cd 100644 --- a/engines/sci/gfx/gfx_resource.h +++ b/engines/sci/gfx/gfx_resource.h @@ -245,7 +245,7 @@ void gfxr_remove_artifacts_pic0(gfxr_pic_t *dest, gfxr_pic_t *src); void gfxr_dither_pic0(gfxr_pic_t *pic, int mode, int pattern); /** - * Calculates a SCI0 view. + * Calculates an EGA view. * * @param[in] id Resource ID of the view * @param[in] resource Pointer to the resource to read @@ -253,7 +253,7 @@ void gfxr_dither_pic0(gfxr_pic_t *pic, int mode, int pattern); * @param[in] palette The palette to use * @return The resulting view */ -gfxr_view_t *gfxr_draw_view0(int id, byte *resource, int size, int palette); +gfxr_view_t *getEGAView(int id, byte *resource, int size, int palette); /** * Calculates a SCI cursor. @@ -265,8 +265,7 @@ gfxr_view_t *gfxr_draw_view0(int id, byte *resource, int size, int palette); * @return A newly allocated pixmap containing an index color * representation of the cursor */ -gfx_pixmap_t *gfxr_draw_cursor(int id, byte *resource, int size, - bool isSci01); +gfx_pixmap_t *gfxr_draw_cursor(int id, byte *resource, int size, bool isSci01); /** @} */ @@ -304,7 +303,7 @@ Palette *gfxr_read_pal1_amiga(Common::File &file); Palette *gfxr_read_pal11(int id, byte *resource, int size); /** - * Calculates an SCI1 view. + * Calculates a VGA view. * * @param[in] id Resource ID of the view * @param[in] resource Pointer to the resource to read @@ -313,7 +312,7 @@ Palette *gfxr_read_pal11(int id, byte *resource, int size); * @param[in] isSci11 true if SCI1.1, false otherwise * @return The resulting view */ -gfxr_view_t *gfxr_draw_view1(int id, byte *resource, int size, Palette *static_pal, bool isSci11); +gfxr_view_t *getVGAView(int id, byte *resource, int size, Palette *static_pal, bool isSci11); gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, byte *cel_base, int size, gfxr_view_t *view, bool isAmiga, bool isSci11); /** @} */ diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index 80adb9eddb..057f28b56f 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -404,7 +404,7 @@ static void init_aux_pixmap(gfx_pixmap_t **pixmap) { (*pixmap)->palette = new Palette(default_colors, DEFAULT_COLORS_NR); } -int gfxop_init(int version, bool isVGA, GfxState *state, +int gfxop_init(int version, GfxState *state, gfx_options_t *options, ResourceManager *resManager, Graphics::PixelFormat mode, int xfact, int yfact) { //int color_depth = bpp ? bpp : 1; @@ -424,8 +424,8 @@ int gfxop_init(int version, bool isVGA, GfxState *state, state->driver = new GfxDriver(xfact, yfact, mode); - state->gfxResMan = new GfxResManager(version, isVGA, state->options, state->driver, resManager); - + state->gfxResMan = new GfxResManager(version, state->options, state->driver, resManager); + gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200)); init_aux_pixmap(&(state->control_map)); diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h index d567934ceb..ec0a810224 100644 --- a/engines/sci/gfx/operations.h +++ b/engines/sci/gfx/operations.h @@ -135,7 +135,6 @@ struct GfxState { * Initializes a graphics mode. * * @param[in] version The interpreter version - * @param[in] isVGA true if using VGA resolution * @param[in] state The state to initialize * @param[in] xfact Horizontal scale factor * @param[in] yfact Vertical scale factors @@ -146,7 +145,7 @@ struct GfxState { * is unavailable, or GFX_FATAL if the graphics driver * is unable to provide any useful graphics support */ -int gfxop_init(int version, bool isVGA, GfxState *state, +int gfxop_init(int version, GfxState *state, gfx_options_t *options, ResourceManager *resManager, Graphics::PixelFormat mode, int xfact = 1, int yfact = 1); diff --git a/engines/sci/gfx/res_view.cpp b/engines/sci/gfx/res_view.cpp index 41cb55fa75..d484136f8e 100644 --- a/engines/sci/gfx/res_view.cpp +++ b/engines/sci/gfx/res_view.cpp @@ -135,7 +135,7 @@ gfx_pixmap_t *gfxr_draw_cel0(int id, int loop, int cel, byte *resource, int size return retval; } -gfxr_view_t *gfxr_draw_view0(int id, byte *resource, int size, int palette) { +gfxr_view_t *getEGAView(int id, byte *resource, int size, int palette) { int i; gfxr_view_t *view; int mirror_bitpos = 1; @@ -365,7 +365,7 @@ gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *reso return retval; } -gfxr_view_t *gfxr_draw_view1(int id, byte *resource, int size, Palette *static_pal, bool isSci11) { +gfxr_view_t *getVGAView(int id, byte *resource, int size, Palette *static_pal, bool isSci11) { uint16 palOffset = READ_LE_UINT16(resource + V1_PALETTE_OFFSET + (isSci11 ? 2 : 0)); uint16 headerSize = isSci11 ? READ_LE_UINT16(resource + V2_HEADER_SIZE) : 0; byte* seeker = resource + headerSize; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 15e05ea656..30e917557d 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -42,19 +42,6 @@ namespace Sci { //#define SCI_VERBOSE_RESMGR 1 -const char *sci_version_types[] = { - "SCI version undetermined (Autodetect failed / not run)", - "SCI version 0.xxx", - "SCI version 0.xxx w/ 1.000 compression", - "SCI version 1.000 w/ 0.xxx resource.map", - "SCI version 1.000 w/ special resource.map", - "SCI version 1.000", - "SCI version 1.001", - "SCI WIN/32" -}; - -const int sci_max_resource_nr[] = {65536, 1000, 2048, 2048, 2048, 65536, 65536, 65536}; - static const char *sci_error_types[] = { "No error", "I/O error", @@ -358,7 +345,7 @@ int ResourceManager::guessSciVersion() { file.close(); if (compression == 3) { - return SCI_VERSION_01_VGA; + return SCI_VERSION_01; } } @@ -382,7 +369,7 @@ int ResourceManager::guessSciVersion() { file.close(); if (compression == 3) { - return SCI_VERSION_01_VGA; + return SCI_VERSION_01; } } @@ -484,8 +471,8 @@ ResourceManager::ResourceManager(int version, int maxMemory) { _mapVersion = detectMapVersion(); _volVersion = detectVolVersion(); } - debug("Using resource map version %d %s", _mapVersion, sci_version_types[_mapVersion]); - debug("Using volume version %d %s", _volVersion, sci_version_types[_volVersion]); + debug("Using resource map version %d %s", _mapVersion, versionNames[_mapVersion]); + debug("Using volume version %d %s", _volVersion, versionNames[_volVersion]); scanNewSources(); addInternalSources(); @@ -495,14 +482,14 @@ ResourceManager::ResourceManager(int version, int maxMemory) { switch (_mapVersion) { case SCI_VERSION_0: if (testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SCI0_MAIN_VOCAB))) { - version = guessSciVersion() ? SCI_VERSION_01_VGA : SCI_VERSION_0; + version = guessSciVersion() ? SCI_VERSION_01 : SCI_VERSION_0; } else if (testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SCI1_MAIN_VOCAB))) { version = guessSciVersion(); - if (version != SCI_VERSION_01_VGA) { - version = testResource(ResourceId(kResourceTypeVocab, 912)) ? SCI_VERSION_0 : SCI_VERSION_01_EGA; + if (version != SCI_VERSION_01) { + version = testResource(ResourceId(kResourceTypeVocab, 912)) ? SCI_VERSION_0 : SCI_VERSION_01; } } else { - version = guessSciVersion() ? SCI_VERSION_01_VGA : SCI_VERSION_0; + version = guessSciVersion() ? SCI_VERSION_01 : SCI_VERSION_0; } break; case SCI_VERSION_01_VGA_ODD: @@ -519,18 +506,37 @@ ResourceManager::ResourceManager(int version, int maxMemory) { version = SCI_VERSION_AUTODETECT; } + _isVGA = false; + + // Determine if the game is using EGA graphics or not + if (version == SCI_VERSION_0) { + _isVGA = false; // There is no SCI0 VGA game + } else if (version >= SCI_VERSION_1_1) { + _isVGA = true; // There is no SCI11 EGA game + } else { + // SCI01 or SCI1: EGA games have the second byte of their views set + // to 0, VGA ones to non-zero + int i = 0; + + while (true) { + Resource *res = findResource(ResourceId(kResourceTypeView, i), 0); + if (res) { + _isVGA = (res->data[1] != 0); + break; + } + i++; + } + } + _sciVersion = version; // temporary version printout - should be reworked later switch (_sciVersion) { case SCI_VERSION_0: debug("Resmgr: Detected SCI0"); break; - case SCI_VERSION_01_EGA: + case SCI_VERSION_01: debug("Resmgr: Detected SCI01"); break; - case SCI_VERSION_01_VGA: - debug("Resmgr: Detected SCI01VGA - KQ5 or similar"); - break; case SCI_VERSION_01_VGA_ODD: debug("Resmgr: Detected SCI01VGA - Jones/CD or similar"); break; @@ -549,6 +555,11 @@ ResourceManager::ResourceManager(int version, int maxMemory) { debug("Resmgr: Couldn't determine SCI version"); break; } + + if (_isVGA) + debug("Resmgr: Detected VGA graphic resources"); + else + debug("Resmgr: Detected non-VGA/EGA graphic resources"); } ResourceManager::~ResourceManager() { @@ -636,16 +647,7 @@ Common::List<ResourceId> *ResourceManager::listResources(ResourceType type, int } Resource *ResourceManager::findResource(ResourceId id, bool lock) { - Resource *retval; - - if (id.number >= sci_max_resource_nr[_sciVersion]) { - ResourceId moddedId = ResourceId(id.type, id.number % sci_max_resource_nr[_sciVersion], id.tuple); - warning("[resmgr] Requested invalid resource %s, mapped to %s", - id.toString().c_str(), moddedId.toString().c_str()); - id = moddedId; - } - - retval = testResource(id); + Resource *retval = testResource(id); if (!retval) return NULL; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 8ef42b171d..b212a36710 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -82,10 +82,6 @@ enum ResSourceType { #define SCI1_RESMAP_ENTRIES_SIZE 6 #define SCI11_RESMAP_ENTRIES_SIZE 5 -extern const char *sci_version_types[]; -extern const int sci_max_resource_nr[]; /**< Highest possible resource numbers */ - - enum ResourceType { kResourceTypeView = 0, kResourceTypePic, @@ -214,6 +210,8 @@ public: int _mapVersion; //!< RESOURCE.MAP version int _volVersion; //!< RESOURCE.0xx version + bool isVGA() const { return _isVGA; } + /** * Creates a new SCI resource manager. * @param version The SCI version to look for; use SCI_VERSION_AUTODETECT @@ -265,6 +263,7 @@ public: void setAudioLanguage(int language); protected: + bool _isVGA; // Used to determine if the game has EGA or VGA graphics int _maxMemory; //!< Config option: Maximum total byte number allocated Common::List<ResourceSource *> _sources; int _memoryLocked; //!< Amount of resource bytes in locked memory diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 7e2940dbd1..2992a1b347 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -43,11 +43,10 @@ namespace Sci { class GfxDriver; -const char *versionNames[8] = { +const char *versionNames[7] = { "Autodetected", "SCI0", - "SCI01 EGA", - "SCI01 VGA", + "SCI01", "SCI01 VGA ODD", "SCI1", "SCI1.1", @@ -158,27 +157,14 @@ Common::Error SciEngine::run() { // Verify that we haven't got an invalid game detection entry if (version < SCI_VERSION_1) { // SCI0/SCI01 - if (flags & GF_SCI1_EGA) { - error("This game entry is erroneous. It's marked as SCI0/SCI01, but it has SCI1 flags set"); - } } else if (version == SCI_VERSION_1) { - // SCI1 - - if (flags & GF_SCI0_OLD || - flags & GF_SCI0_OLDGETTIME) { + if (flags & GF_SCI0_OLDGETTIME) { error("This game entry is erroneous. It's marked as SCI1, but it has SCI0 flags set"); } } else if (version == SCI_VERSION_1_1 || version == SCI_VERSION_32) { - if (flags & GF_SCI1_EGA) { - error("This game entry is erroneous. It's marked as SCI1.1/SCI32, but it has SCI1 flags set"); - } - - if (flags & GF_SCI0_OLD || - flags & GF_SCI0_OLDGETTIME) { + if (flags & GF_SCI0_OLDGETTIME) { error("This game entry is erroneous. It's marked as SCI1.1/SCI32, but it has SCI0 flags set"); } - - // SCI1.1 / SCI32 } else { error ("Unknown SCI version in game entry"); } @@ -225,8 +211,7 @@ Common::Error SciEngine::run() { // Default config ends #endif - bool isVGA = _resmgr->_sciVersion >= SCI_VERSION_01_VGA && !(getFlags() & GF_SCI1_EGA); - if (gfxop_init(_resmgr->_sciVersion, isVGA, &gfx_state, &gfx_options, _resmgr, gfxmode, 1, 1)) { + if (gfxop_init(_resmgr->_sciVersion, &gfx_state, &gfx_options, _resmgr, gfxmode, 1, 1)) { warning("Graphics initialization failed. Aborting..."); return Common::kUnknownError; } diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 4404165c53..a2de5c3136 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -71,41 +71,22 @@ struct SciGameDescription { enum SciGameVersions { SCI_VERSION_AUTODETECT = 0, SCI_VERSION_0 = 1, - SCI_VERSION_01_EGA = 2, - SCI_VERSION_01_VGA = 3, - SCI_VERSION_01_VGA_ODD = 4, - SCI_VERSION_1 = 5, - SCI_VERSION_1_1 = 6, - SCI_VERSION_32 = 7 + SCI_VERSION_01 = 2, + SCI_VERSION_01_VGA_ODD = 3, + SCI_VERSION_1 = 4, + SCI_VERSION_1_1 = 5, + SCI_VERSION_32 = 6 }; -extern const char *versionNames[8]; +extern const char *versionNames[7]; enum SciGameFlags { // SCI0 flags - /* Applies to all versions before 0.000.395 (i.e. KQ4 old, XMAS 1988 and LSL2) - * Old SCI versions used two word header for script blocks (first word equal - * to 0x82, meaning of the second one unknown). New SCI versions used one - * word header. - * Also, old SCI versions assign 120 degrees to left & right, and 60 to up - * and down. Later versions use an even 90 degree distribution. - */ - GF_SCI0_OLD = (1 << 0), - /* Applies to all versions before 0.000.629 * Older SCI versions had simpler code for GetTime() */ - GF_SCI0_OLDGETTIME = (1 << 1), - - // ---------------------------------------------------------------------------- - - // SCI1 flags - - /* - * Used to distinguish SCI1 EGA games - */ - GF_SCI1_EGA = (1 << 2) + GF_SCI0_OLDGETTIME = (1 << 0) }; class SciEngine : public Engine { diff --git a/engines/sci/sfx/iterator.cpp b/engines/sci/sfx/iterator.cpp index 4e5b20a5d2..ebba4bceac 100644 --- a/engines/sci/sfx/iterator.cpp +++ b/engines/sci/sfx/iterator.cpp @@ -27,6 +27,7 @@ #include "common/util.h" +#include "sci/sci.h" #include "sci/sfx/iterator_internal.h" #include "sci/sfx/misc.h" // for sfx_player_tell_synth #include "sci/tools.h" @@ -233,7 +234,7 @@ int BaseSongIterator::parseMidiCommand(byte *buf, int *result, SongIteratorChann channel->state = SI_STATE_DELTA_TIME; channel->total_timepos = channel->loop_timepos; channel->last_cmd = 0xfe; - fprintf(stderr, "Looping song iterator %08lx.\n", ID); + debugC(2, kDebugLevelSound, "Looping song iterator %08lx.\n", ID); return SI_LOOP; } else { channel->state = SI_STATE_FINISHED; @@ -379,7 +380,7 @@ int BaseSongIterator::processMidi(byte *buf, int *result, channel->state = SI_STATE_FINISHED; delay = (size * 50 + format.rate - 1) / format.rate; /* number of ticks to completion*/ - fprintf(stderr, "delaying %d ticks\n", delay); + debugC(2, kDebugLevelSound, "delaying %d ticks\n", delay); return delay; } @@ -523,7 +524,7 @@ static int _sci0_get_pcm_data(Sci0SongIterator *self, } static Audio::AudioStream *makeStream(byte *data, int size, sfx_pcm_config_t conf) { - printf("Playing PCM data of size %d, rate %d\n", size, conf.rate); + debugC(2, kDebugLevelSound, "Playing PCM data of size %d, rate %d\n", size, conf.rate); // Duplicate the data byte *sound = (byte *)malloc(size); @@ -563,7 +564,7 @@ SongIterator *Sci0SongIterator::handleMessage(Message msg) { case _SIMSG_BASEMSG_PRINT: print_tabs_id(msg._arg.i, ID); - fprintf(stderr, "SCI0: dev=%d, active-chan=%d, size=%d, loops=%d\n", + debugC(2, kDebugLevelSound, "SCI0: dev=%d, active-chan=%d, size=%d, loops=%d\n", _deviceId, _numActiveChannels, _data.size(), _loops); break; @@ -980,7 +981,7 @@ SongIterator *Sci1SongIterator::handleMessage(Message msg) { playmask |= _channels[i].playmask; print_tabs_id(msg._arg.i, ID); - fprintf(stderr, "SCI1: chan-nr=%d, playmask=%04x\n", + debugC(2, kDebugLevelSound, "SCI1: chan-nr=%d, playmask=%04x\n", _numChannels, playmask); } break; @@ -1142,7 +1143,7 @@ public: SongIterator *CleanupSongIterator::handleMessage(Message msg) { if (msg._class == _SIMSG_BASEMSG_PRINT && msg._type == _SIMSG_BASEMSG_PRINT) { print_tabs_id(msg._arg.i, ID); - fprintf(stderr, "CLEANUP\n"); + debugC(2, kDebugLevelSound, "CLEANUP\n"); } return NULL; @@ -1208,7 +1209,7 @@ SongIterator *FastForwardSongIterator::handleMessage(Message msg) { if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) { print_tabs_id(msg._arg.i, ID); - fprintf(stderr, "FASTFORWARD:\n"); + debugC(2, kDebugLevelSound, "FASTFORWARD:\n"); msg._arg.i++; } @@ -1532,7 +1533,7 @@ SongIterator *TeeSongIterator::handleMessage(Message msg) { if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) { print_tabs_id(msg._arg.i, ID); - fprintf(stderr, "TEE:\n"); + debugC(2, kDebugLevelSound, "TEE:\n"); msg._arg.i++; } @@ -1576,15 +1577,15 @@ int songit_next(SongIterator **it, byte *buf, int *result, int mask) { do { retval = (*it)->nextCommand(buf, result); if (retval == SI_MORPH) { - fprintf(stderr, " Morphing %p (stored at %p)\n", (void *)*it, (void *)it); + debugC(2, kDebugLevelSound, " Morphing %p (stored at %p)\n", (void *)*it, (void *)it); if (!SIMSG_SEND((*it), SIMSG_ACK_MORPH)) { error("SI_MORPH failed. Breakpoint in %s, line %d", __FILE__, __LINE__); } else - fprintf(stderr, "SI_MORPH successful\n"); + debugC(2, kDebugLevelSound, "SI_MORPH successful\n"); } if (retval == SI_FINISHED) - fprintf(stderr, "[song-iterator] Song finished. mask = %04x, cm=%04x\n", + debugC(2, kDebugLevelSound, "[song-iterator] Song finished. mask = %04x, cm=%04x\n", mask, (*it)->channel_mask); if (retval == SI_FINISHED && (mask & IT_READER_MAY_CLEAN) diff --git a/engines/sci/vocabulary.cpp b/engines/sci/vocabulary.cpp index dd56cdf88a..5253e7885b 100644 --- a/engines/sci/vocabulary.cpp +++ b/engines/sci/vocabulary.cpp @@ -91,7 +91,7 @@ Vocabulary::Vocabulary(ResourceManager *resmgr) : _resmgr(resmgr) { debug(2, "Initializing vocabulary"); - if (_resmgr->_sciVersion < SCI_VERSION_01_VGA && loadParserWords()) { + if (_resmgr->_sciVersion <= SCI_VERSION_01 && loadParserWords()) { loadSuffixes(); if (loadBranches()) // Now build a GNF grammar out of this diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp index e62d9406d3..81b28ce563 100644 --- a/engines/scumm/verbs.cpp +++ b/engines/scumm/verbs.cpp @@ -567,7 +567,7 @@ void ScummEngine::checkExecVerbs() { } if (_game.platform == Common::kPlatformFMTowns && _game.version == 3) { - // HACK: In the FM-Towns games Indy3, Loom and Zak the most significant bit is set for special keys + // HACK: In the FM-TOWNS games Indy3, Loom and Zak the most significant bit is set for special keys // like F5 (=0x8005) or joystick buttons (mask 0xFE00, e.g. SELECT=0xFE40 for the save/load menu). // Hence the distinction with (_mouseAndKeyboardStat < MBS_MAX_KEY) between mouse- and key-events is not applicable // to this games, so we have to remap the special keys here. diff --git a/graphics/module.mk b/graphics/module.mk index 8d7f2031c0..2387bb708c 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -16,6 +16,7 @@ MODULE_OBJS := \ primitives.o \ scaler.o \ scaler/thumbnail_intern.o \ + sjis.o \ surface.o \ thumbnail.o \ VectorRenderer.o \ diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp new file mode 100644 index 0000000000..5392a1c9a4 --- /dev/null +++ b/graphics/sjis.cpp @@ -0,0 +1,197 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "graphics/sjis.h" + +#ifdef GRAPHICS_SJIS_H + +#include "common/debug.h" + +namespace Graphics { + +bool FontTowns::loadFromStream(Common::ReadStream &stream) { + for (uint i = 0; i < (kFontRomSize / 2); ++i) + _fontData[i] = stream.readUint16BE(); + return !stream.err(); +} + +template<typename Color> +void FontTowns::drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch, Color c1, Color c2) const { + uint32 outlineGlyph[18]; + memset(outlineGlyph, 0, sizeof(outlineGlyph)); + + // Create an outline map including the original character + const uint16 *src = glyph; + for (int i = 0; i < 16; ++i) { + uint32 line = *src++; + line = (line << 2) | (line << 1) | (line << 0); + + outlineGlyph[i + 0] |= line; + outlineGlyph[i + 1] |= line; + outlineGlyph[i + 2] |= line; + } + + uint8 *dstLine = dst; + for (int y = 0; y < 18; ++y) { + Color *lineBuf = (Color *)dstLine; + uint32 line = outlineGlyph[y]; + + for (int x = 0; x < 18; ++x) { + if (line & 0x20000) + *lineBuf = c2; + line <<= 1; + ++lineBuf; + } + + dstLine += pitch; + } + + // draw the original char + drawCharIntern<Color>(glyph, dst + pitch + 1, pitch, c1); +} + +template<typename Color> +void FontTowns::drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const { + for (int y = 0; y < 16; ++y) { + Color *lineBuf = (Color *)dst; + uint16 line = *glyph++; + + for (int x = 0; x < 16; ++x) { + if (line & 0x8000) + *lineBuf = c1; + line <<= 1; + ++lineBuf; + } + + dst += pitch; + } +} + +void FontTowns::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const { + const uint16 *glyphSource = _fontData + sjisToChunk(ch & 0xFF, ch >> 8) * 16; + + if (bpp == 1) { + if (!_outlineEnabled) + drawCharIntern<uint8>(glyphSource, (uint8 *)dst, pitch, c1); + else + drawCharInternOutline<uint8>(glyphSource, (uint8 *)dst, pitch, c1, c2); + } else if (bpp == 2) { + if (!_outlineEnabled) + drawCharIntern<uint16>(glyphSource, (uint8 *)dst, pitch, c1); + else + drawCharInternOutline<uint16>(glyphSource, (uint8 *)dst, pitch, c1, c2); + } else { + error("FontTowns::drawChar: unsupported bpp: %d", bpp); + } +} + +uint FontTowns::sjisToChunk(uint8 f, uint8 s) { + // copied from scumm\charset.cpp + enum { + KANA = 0, + KANJI = 1, + EKANJI = 2 + }; + + int base = s - ((s + 1) % 32); + int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA; + + if (f >= 0x81 && f <= 0x84) kanjiType = KANA; + if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI; + if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI; + + if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) { + c = 48; //correction + p = -8; //correction + } + + if (kanjiType == KANA) {//Kana + chunk_f = (f - 0x81) * 2; + } else if (kanjiType == KANJI) {//Standard Kanji + p += f - 0x88; + chunk_f = c + 2 * p; + } else if (kanjiType == EKANJI) {//Enhanced Kanji + p += f - 0xe0; + chunk_f = c + 2 * p; + } + + // Base corrections + if (base == 0x7f && s == 0x7f) + base -= 0x20; + if (base == 0x9f && s == 0xbe) + base += 0x20; + if (base == 0xbf && s == 0xde) + base += 0x20; + //if (base == 0x7f && s == 0x9e) + // base += 0x20; + + switch (base) { + case 0x3f: + cr = 0; //3f + if (kanjiType == KANA) chunk = 1; + else if (kanjiType == KANJI) chunk = 31; + else if (kanjiType == EKANJI) chunk = 111; + break; + case 0x5f: + cr = 0; //5f + if (kanjiType == KANA) chunk = 17; + else if (kanjiType == KANJI) chunk = 47; + else if (kanjiType == EKANJI) chunk = 127; + break; + case 0x7f: + cr = -1; //80 + if (kanjiType == KANA) chunk = 9; + else if (kanjiType == KANJI) chunk = 63; + else if (kanjiType == EKANJI) chunk = 143; + break; + case 0x9f: + cr = 1; //9e + if (kanjiType == KANA) chunk = 2; + else if (kanjiType == KANJI) chunk = 32; + else if (kanjiType == EKANJI) chunk = 112; + break; + case 0xbf: + cr = 1; //be + if (kanjiType == KANA) chunk = 18; + else if (kanjiType == KANJI) chunk = 48; + else if (kanjiType == EKANJI) chunk = 128; + break; + case 0xdf: + cr = 1; //de + if (kanjiType == KANA) chunk = 10; + else if (kanjiType == KANJI) chunk = 64; + else if (kanjiType == EKANJI) chunk = 144; + break; + default: + debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p); + } + + debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr); + return ((chunk_f + chunk) * 32 + (s - base)) + cr; +} + +} // end of namespace Graphics + +#endif // defined(GRAPHICS_SJIS_H) + diff --git a/graphics/sjis.h b/graphics/sjis.h new file mode 100644 index 0000000000..f7321742af --- /dev/null +++ b/graphics/sjis.h @@ -0,0 +1,135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +// The code in this file is currently only used in KYRA and SCI. +// So if neither of those is enabled, we will skip compiling it. +// If you plan to use this code in another engine, you will have +// to add the proper define check here. +// Also please add the define check at the comment after the +// matching #endif further down this file. +#if defined(ENABLE_KYRA) || defined(ENABLE_SCI) + +#ifndef GRAPHICS_SJIS_H +#define GRAPHICS_SJIS_H + +#include "common/scummsys.h" +#include "common/stream.h" + +#include "graphics/surface.h" + +namespace Graphics { + +/** + * A font that is able to draw SJIS encoded characters. + * + * The font is always monospaced. + */ +class FontSJIS { +public: + virtual ~FontSJIS() {} + + /** + * Enable outline drawing. + * + * After changing outline state, getFontHeight and getFontWidth might return + * different values! + */ + virtual void enableOutline(bool enable) {} + + /** + * Returns the height of the font. + */ + virtual uint getFontHeight() const = 0; + + /** + * Returns the width of the font. + */ + virtual uint getFontWidth() const = 0; + + /** + * Draws a SJIS encoded character on the given surface. + */ + void drawChar(Graphics::Surface &dst, uint16 ch, int x, int y, uint32 c1, uint32 c2) const { + drawChar(dst.getBasePtr(x, y), ch, c1, c2, dst.pitch, dst.bytesPerPixel); + } + + /** + * Draws a SJIS char on the given raw buffer. + * + * @param dst pointer to the destination + * @param ch character to draw + * @param pitch pitch of the destination buffer (size in *bytes*) + * @param bpp bytes per pixel of the destination buffer + * @param c1 forground color + * @param c2 outline color + */ + virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const = 0; +}; + +/** + * FM-TOWNS ROM based SJIS compatible font. + * + * This is used in KYRA and SCI. + */ +class FontTowns : public FontSJIS { +public: + FontTowns() : _outlineEnabled(false) {} + + /** + * Loads the ROM data from the given read stream. + */ + bool loadFromStream(Common::ReadStream &stream); + + void enableOutline(bool enable) { _outlineEnabled = enable; } + + uint getFontHeight() const { return _outlineEnabled ? 18 : 16; } + uint getFontWidth() const { return _outlineEnabled ? 18 : 16; } + + void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2) const; + +private: + template<typename Color> + void drawCharInternOutline(const uint16 *glyph, uint8 *dst, int pitch, Color c1, Color c2) const; + + template<typename Color> + void drawCharIntern(const uint16 *glyph, uint8 *dst, int pitch, Color c1) const; + + enum { + kFontRomSize = 262144 + }; + + bool _outlineEnabled; + uint16 _fontData[kFontRomSize / 2]; + + static uint sjisToChunk(uint8 low, uint8 high); +}; + +// TODO: Consider adding support for PC98 ROM + +} // end of namespace Graphics + +#endif + +#endif // defined(ENABLE_KYRA) || defined(ENABLE_SCI) + diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp index a87a6eeaa6..ead0c232b1 100644 --- a/tools/create_kyradat/create_kyradat.cpp +++ b/tools/create_kyradat/create_kyradat.cpp @@ -507,14 +507,14 @@ bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 if (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ || g->special == k2TownsFile1E || g->special == k2TownsFile1J || g->special == k2TownsFile2E || g->special == k2TownsFile2J || fmtPatch == 5) { - // prevents creation of empty entries (which we have mostly between all strings in the fm-towns version) + // prevents creation of empty entries (which we have mostly between all strings in the FM-TOWNS version) while (!data[++i]) { if (i == size) break; targetsize--; } if (fmtPatch == 1) { - // Here is the first step of the extra treatment for all fm-towns string arrays that + // Here is the first step of the extra treatment for all FM-TOWNS string arrays that // contain more than one string and which the original code // addresses via stringname[boolJapanese]. // We simply skip every other string @@ -593,7 +593,7 @@ bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 } if (fmtPatch == 1) { - // Here is the extra treatment for all fm-towns string arrays that + // Here is the extra treatment for all FM-TOWNS string arrays that // contain more than one string and which the original code // addresses via stringname[boolJapanese]. // We simply skip every other string @@ -637,7 +637,7 @@ bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 } bool extractRooms(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { - // different entry size for the fm-towns version + // different entry size for the FM-TOWNS version const int roomEntrySize = (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ) ? (0x69) : ((g->special == kAmigaVersion) ? 0x52 : 0x51); const int countRooms = size / roomEntrySize; |