From f49eaa5654b2ee2e41b1794a4576d24967e2f7d7 Mon Sep 17 00:00:00 2001 From: athrxx Date: Sat, 9 Jan 2016 22:00:51 +0100 Subject: KYRA: (EOB) - add support for FM-Towns version of EOB II --- engines/kyra/chargen.cpp | 65 ++++-- engines/kyra/darkmoon.cpp | 49 +++-- engines/kyra/darkmoon.h | 24 +-- engines/kyra/detection.cpp | 6 + engines/kyra/detection_tables.h | 18 +- engines/kyra/eobcommon.cpp | 384 +++++++++++++++++++++------------- engines/kyra/eobcommon.h | 19 +- engines/kyra/gui_eob.cpp | 353 ++++++++++++++++++++++++++----- engines/kyra/gui_eob.h | 7 + engines/kyra/items_eob.cpp | 2 +- engines/kyra/kyra_rpg.cpp | 18 +- engines/kyra/kyra_rpg.h | 3 +- engines/kyra/kyra_v1.cpp | 44 ++-- engines/kyra/magic_eob.cpp | 8 +- engines/kyra/module.mk | 1 + engines/kyra/resource.h | 256 ++++++++++++++++++++++- engines/kyra/saveload.cpp | 2 +- engines/kyra/saveload_eob.cpp | 83 ++++++-- engines/kyra/scene_eob.cpp | 28 ++- engines/kyra/scene_lol.cpp | 2 +- engines/kyra/scene_rpg.cpp | 141 ++++++++----- engines/kyra/screen.cpp | 54 +++-- engines/kyra/screen.h | 26 +-- engines/kyra/screen_eob.cpp | 215 +++++++++++++++++-- engines/kyra/screen_eob.h | 48 ++++- engines/kyra/script_eob.cpp | 3 +- engines/kyra/sequences_darkmoon.cpp | 323 +++++++++++++++++++++------- engines/kyra/sound.h | 7 + engines/kyra/sound_intern.h | 53 +++++ engines/kyra/sound_towns_darkmoon.cpp | 276 ++++++++++++++++++++++++ engines/kyra/sprites_eob.cpp | 46 +++- engines/kyra/staticres.cpp | 2 +- engines/kyra/staticres_eob.cpp | 144 ++++++------- engines/kyra/staticres_rpg.cpp | 2 +- engines/kyra/text_rpg.cpp | 34 ++- 35 files changed, 2127 insertions(+), 619 deletions(-) create mode 100644 engines/kyra/sound_towns_darkmoon.cpp (limited to 'engines') diff --git a/engines/kyra/chargen.cpp b/engines/kyra/chargen.cpp index 2454909440..4724770782 100644 --- a/engines/kyra/chargen.cpp +++ b/engines/kyra/chargen.cpp @@ -66,7 +66,7 @@ private: int getNextFreeFaceShape(int shpIndex, int charSex, int step, int8 *selectedPortraits); void processFaceMenuSelection(int index); void printStats(int index, int mode); - void processNameInput(int index, int len, int textColor); + void processNameInput(int index, int textColor); int rollDice(); int modifyStat(int index, int8 *stat1, int8 *stat2); int getMaxHp(int cclass, int constitution, int level1, int level2, int level3); @@ -99,7 +99,10 @@ private: const uint8 *_chargenRaceMinStats; const uint16 *_chargenRaceMaxStats; - static const EoBChargenButtonDef _chargenButtonDefs[]; + const EoBChargenButtonDef *_chargenButtonDefs; + + static const EoBChargenButtonDef _chargenButtonDefsDOS[]; + static const uint16 _chargenButtonKeyCodesFMTOWNS[]; static const CreatePartyModButton _chargenModButtons[]; static const EoBRect8 _chargenButtonBodyCoords[]; static const int16 _chargenBoxX[]; @@ -141,6 +144,19 @@ CharacterGenerator::CharacterGenerator(EoBCoreEngine *vm, Screen_EoB *screen) : _chargenClassMinStats = _vm->staticres()->loadRawData(kEoBBaseChargenClassMinStats, temp); _chargenRaceMinStats = _vm->staticres()->loadRawData(kEoBBaseChargenRaceMinStats, temp); _chargenRaceMaxStats = _vm->staticres()->loadRawDataBe16(kEoBBaseChargenRaceMaxStats, temp); + + EoBChargenButtonDef *chargenButtonDefs = new EoBChargenButtonDef[41]; + memcpy(chargenButtonDefs, _chargenButtonDefsDOS, 41 * sizeof(EoBChargenButtonDef)); + + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + const uint16 *c = _chargenButtonKeyCodesFMTOWNS; + for (int i = 0; i < 41; ++i) { + if (chargenButtonDefs[i].keyCode) + chargenButtonDefs[i].keyCode = *c++; + } + } + + _chargenButtonDefs = chargenButtonDefs; } CharacterGenerator::~CharacterGenerator() { @@ -152,6 +168,10 @@ CharacterGenerator::~CharacterGenerator() { for (int i = 0; i < 17; i++) delete[] _chargenButtonLabels[i]; + + delete[] _chargenButtonDefs; + + _screen->clearPage(2); } bool CharacterGenerator::start(EoBCharacter *characters, uint8 ***faceShapes) { @@ -241,6 +261,10 @@ bool CharacterGenerator::start(EoBCharacter *characters, uint8 ***faceShapes) { } void CharacterGenerator::init() { + /*_screen->loadEoBBitmap("MENU", 0, 3, 3, 2); + Common::SeekableReadStream *s = _res->createReadStream("facedat.dmp"); + _screen->loadFileDataToPage(s, 2, 64000);*/ + _screen->loadShapeSetBitmap("CHARGENA", 3, 3); if (_faceShapes) { for (int i = 0; i < 44; i++) @@ -269,9 +293,11 @@ void CharacterGenerator::init() { const CreatePartyModButton *c = &_chargenModButtons[i]; _chargenButtonLabels[i] = c->labelW ? _screen->encodeShape(c->encodeLabelX, c->encodeLabelY, c->labelW, c->labelH, true, _vm->_cgaMappingDefault) : 0; } - + _screen->convertPage(3, 2, _vm->_cgaMappingDefault); _screen->_curPage = 0; + _screen->convertToHiColor(2); + _screen->shadeRect(142, 63, 306, 193, 4); _screen->copyRegion(144, 64, 0, 0, 180, 128, 0, 2, Screen::CR_NO_P_CHECK); _screen->updateScreen(); } @@ -323,7 +349,8 @@ void CharacterGenerator::initButton(int index, int x, int y, int w, int h, int k void CharacterGenerator::checkForCompleteParty() { _screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK); int cp = _screen->setCurPage(2); - _screen->printShadedText(_chargenStrings1[8], 168, 16, 15, 0); + int x = (_vm->gameFlags().platform == Common::kPlatformFMTowns) ? 184 : 168; + _screen->printShadedText(_chargenStrings1[8], x, 16, 15, 0); _screen->setCurPage(cp); _screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK); @@ -335,7 +362,7 @@ void CharacterGenerator::checkForCompleteParty() { if (numChars == 4) { _screen->setCurPage(2); - _screen->printShadedText(_chargenStrings1[0], 168, 61, 15, 0); + _screen->printShadedText(_chargenStrings1[0], x, 61, 15, 0); _screen->setCurPage(0); _screen->copyRegion(168, 61, 152, 125, 136, 40, 2, 0, Screen::CR_NO_P_CHECK); toggleSpecialButton(15, 0, 0); @@ -416,7 +443,7 @@ int CharacterGenerator::viewDeleteCharacter() { if (_characters[_activeBox].name[0]) { processSpecialButton(16); _characters[_activeBox].name[0] = 0; - processNameInput(_activeBox, 1, 12); + processNameInput(_activeBox, 12); processFaceMenuSelection(_activeBox + 50); } } else { @@ -478,8 +505,10 @@ void CharacterGenerator::createPartyMember() { processFaceMenuSelection(_chargenMinStats[6]); printStats(_activeBox, 0); _screen->printShadedText(_chargenStrings2[11], 149, 100, 9, 0); - if (!_vm->shouldQuit()) - processNameInput(_activeBox, _vm->_gui->getTextInput(_characters[_activeBox].name, 24, 100, 10, 15, 0, 8), 2); + if (!_vm->shouldQuit()) { + _vm->_gui->getTextInput(_characters[_activeBox].name, 24, 100, 10, 15, 0, 8); + processNameInput(_activeBox, 2); + } } } } @@ -887,7 +916,7 @@ void CharacterGenerator::printStats(int index, int mode) { if (mode != 4) _screen->drawShape(2, c->faceShape, 224, 2, 0); - _screen->printShadedText(c->name, 160 + ((20 - strlen(c->name)) << 2), 35, 15, 0); + _screen->printShadedText(c->name, 160 + ((160 - _screen->getTextWidth(c->name)) / 2), 35, 15, 0); _screen->printShadedText(_chargenRaceSexStrings[c->raceSex], 160 + ((20 - strlen(_chargenRaceSexStrings[c->raceSex])) << 2), 45, 15, 0); _screen->printShadedText(_chargenClassStrings[c->cClass], 160 + ((20 - strlen(_chargenClassStrings[c->cClass])) << 2), 54, 15, 0); @@ -937,14 +966,10 @@ void CharacterGenerator::printStats(int index, int mode) { _screen->_curPage = 0; } -void CharacterGenerator::processNameInput(int index, int len, int textColor) { +void CharacterGenerator::processNameInput(int index, int textColor) { Screen::FontId of = _screen->setFont(Screen::FID_6_FNT); - - // WORKAROUND for bug in original code: - len = strlen(_characters[index].name); - - int xOffs = (60 - _screen->getFontWidth() * len) >> 1; - _screen->printText(_chargenStrings1[1], _chargenNameFieldX[index], _chargenNameFieldY[index], 12, 12); + _screen->fillRect(_chargenNameFieldX[index], _chargenNameFieldY[index], _chargenNameFieldX[index] + 59, _chargenNameFieldY[index] + 5, 12); + int xOffs = (60 - _screen->getTextWidth(_characters[index].name)) >> 1; _screen->printText(_characters[index].name, _chargenNameFieldX[index] + xOffs, _chargenNameFieldY[index], textColor, 0); _screen->updateScreen(); _screen->setFont(of); @@ -1140,7 +1165,7 @@ int CharacterGenerator::getMinHp(int cclass, int constitution, int level1, int l void CharacterGenerator::finish() { _screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK); int cp = _screen->setCurPage(2); - _screen->printShadedText(_chargenEnterGameStrings[0], 168, 32, 15, 0); + _screen->printShadedText(_chargenEnterGameStrings[0], (_vm->gameFlags().platform == Common::kPlatformFMTowns) ? 184 : 168, 32, 15, 0); _screen->setCurPage(cp); _screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); @@ -1341,7 +1366,7 @@ void CharacterGenerator::finish() { } } -const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefs[] = { +const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefsDOS[] = { { 0x01, 0x37, 0x31, 0x32, 0x70 }, { 0x09, 0x37, 0x31, 0x32, 0x71 }, { 0x01, 0x77, 0x31, 0x32, 0x72 }, @@ -1385,6 +1410,10 @@ const EoBChargenButtonDef CharacterGenerator::_chargenButtonDefs[] = { { 0x21, 0xAC, 0x25, 0x10, 0x19 } }; +const uint16 CharacterGenerator::_chargenButtonKeyCodesFMTOWNS[] = { + 93, 94, 95, 96, 80, 79, 68, 66, 82, 77, 70, 75, 43, 45, 79 +}; + const CreatePartyModButton CharacterGenerator::_chargenModButtons[] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x40 }, diff --git a/engines/kyra/darkmoon.cpp b/engines/kyra/darkmoon.cpp index e15a290f86..12508546a0 100644 --- a/engines/kyra/darkmoon.cpp +++ b/engines/kyra/darkmoon.cpp @@ -29,23 +29,17 @@ namespace Kyra { DarkMoonEngine::DarkMoonEngine(OSystem *system, const GameFlags &flags) : EoBCoreEngine(system, flags) { - _animIntro = _animFinale = 0; - _shapesIntro = _shapesFinale = 0; _dscDoorType5Offs = 0; _numSpells = 70; _menuChoiceInit = 4; - _introStrings = _cpsFilesIntro = _cpsFilesFinale = _finaleStrings = _kheldranStrings = _npcStrings[0] = _npcStrings[1] = _hornStrings = 0; - _shapesIntro = _shapesFinale = 0; - _creditsData = _npcShpData = _dscDoorType5Offs = _hornSounds = 0; + _kheldranStrings = _npcStrings[0] = _npcStrings[1] = _hornStrings = 0; + _utilMenuStrings = _ascii2SjisTables = _ascii2SjisTables2 = 0; + _npcShpData = _dscDoorType5Offs = _hornSounds = 0; _dreamSteps = 0; } DarkMoonEngine::~DarkMoonEngine() { - delete[] _animIntro; - delete[] _animFinale; - delete[] _shapesIntro; - delete[] _shapesFinale; } Common::Error DarkMoonEngine::init() { @@ -63,9 +57,15 @@ Common::Error DarkMoonEngine::init() { _screen->setScreenPalette(pal); } - _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); + _screen->loadPalette(_flags.platform == Common::kPlatformFMTowns ? "MENU.PAL" : "PALETTE.COL", _screen->getPalette(0)); _screen->setScreenPalette(_screen->getPalette(0)); + // adjust menu settings for EOB II FM-Towns + if (_flags.platform == Common::kPlatformFMTowns) { + _screen->modifyScreenDim(6, 10, 100, 21, 40); + _screen->modifyScreenDim(27, 0, 0, 21, 2); + } + return Common::kNoError; } @@ -193,29 +193,32 @@ void DarkMoonEngine::generateMonsterPalettes(const char *file, int16 monsterInde _screen->setCurPage(cp); } -void DarkMoonEngine::loadMonsterDecoration(const char *file, int16 monsterIndex) { - Common::SeekableReadStream *s = _res->createReadStream(Common::String::format("%s.dcr", file)); - if (!s) - return; - - int len = s->readUint16LE(); +void DarkMoonEngine::loadMonsterDecoration(Common::SeekableReadStream *stream, int16 monsterIndex) { + int len = stream->readUint16LE(); + Common::List activeDecorations; for (int i = 0; i < len; i++) { for (int ii = 0; ii < 6; ii++) { uint8 dc[6]; - s->read(dc, 6); + stream->read(dc, 6); if (!dc[2] || !dc[3]) continue; SpriteDecoration *m = &_monsterDecorations[i * 6 + ii + monsterIndex]; - - m->shp = _screen->encodeShape(dc[0], dc[1], dc[2], dc[3]); + if (_flags.platform != Common::kPlatformFMTowns) + m->shp = _screen->encodeShape(dc[0], dc[1], dc[2], dc[3]); m->x = (int8)dc[4]; m->y = (int8)dc[5]; + activeDecorations.push_back(m); } } - delete s; + if (_flags.platform == Common::kPlatformFMTowns) { + while (!activeDecorations.empty()) { + activeDecorations.front()->shp = loadTownsShape(stream); + activeDecorations.pop_front(); + } + } } void DarkMoonEngine::replaceMonster(int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem) { @@ -382,6 +385,10 @@ void DarkMoonEngine::restParty_npc() { gui_drawAllCharPortraitsWithStats(); _screen->setClearScreenDim(10); + _screen->set16bitShadingLevel(4); + gui_drawBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, guiSettings()->colors.frame1, guiSettings()->colors.frame2, -1); + gui_drawBox((_screen->_curDim->sx << 3) + 1, _screen->_curDim->sy + 1, (_screen->_curDim->w << 3) - 2, _screen->_curDim->h - 2, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); _gui->messageDialogue2(11, 63, 6); _gui->messageDialogue2(11, 64, 6); } @@ -478,7 +485,7 @@ void DarkMoonEngine::characterLevelGain(int charIndex) { } const KyraRpgGUISettings *DarkMoonEngine::guiSettings() { - return &_guiSettings; + return (_flags.platform == Common::kPlatformFMTowns) ? &_guiSettingsFMTowns : &_guiSettingsDOS; } } // End of namespace Kyra diff --git a/engines/kyra/darkmoon.h b/engines/kyra/darkmoon.h index f23787d865..f7065da8d6 100644 --- a/engines/kyra/darkmoon.h +++ b/engines/kyra/darkmoon.h @@ -60,6 +60,7 @@ private: // Main Menu int mainMenu(); int mainMenuLoop(); + void townsUtilitiesMenu(); int _menuChoiceInit; @@ -72,22 +73,6 @@ private: void seq_playFinale(); void seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *data, int sd, int backupPage, int tempPage, int speed); - const char *const *_introStrings; - const char *const *_cpsFilesIntro; - const DarkMoonAnimCommand **_animIntro; - const DarkMoonShapeDef **_shapesIntro; - - const char *const *_finaleStrings; - const uint8 *_creditsData; - const char *const *_cpsFilesFinale; - const DarkMoonAnimCommand **_animFinale; - const DarkMoonShapeDef **_shapesFinale; - - static const char *const _palFilesIntroVGA[]; - static const char *const _palFilesIntroEGA[]; - static const char *const _palFilesFinaleVGA[]; - static const char *const _palFilesFinaleEGA[]; - // Ingame sequence void seq_nightmare(); void seq_kheldran(); @@ -108,7 +93,7 @@ private: // Monsters void generateMonsterPalettes(const char *file, int16 monsterIndex); - void loadMonsterDecoration(const char *file, int16 monsterIndex); + void loadMonsterDecoration(Common::SeekableReadStream *stream, int16 monsterIndex); void replaceMonster(int unit, uint16 block, int d, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem); bool killMonsterExtra(EoBMonsterInPlay *m); @@ -140,7 +125,10 @@ private: const char *const *_hornStrings; const uint8 *_hornSounds; - static const KyraRpgGUISettings _guiSettings; + const char *const *_utilMenuStrings; + + static const KyraRpgGUISettings _guiSettingsDOS; + static const KyraRpgGUISettings _guiSettingsFMTowns; static const uint8 _egaDefaultPalette[]; }; diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 79e1d9f494..9f1b694006 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -206,6 +206,10 @@ bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame flags.lang = Common::EN_ANY; } +#ifndef USE_RGB_COLOR + flags.useHiColorMode = false; +#endif + switch (flags.gameID) { case Kyra::GI_KYRA1: *engine = new Kyra::KyraEngine_LoK(syst, flags); @@ -228,6 +232,8 @@ bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame case Kyra::GI_EOB2: if (Common::parseRenderMode(ConfMan.get("render_mode")) == Common::kRenderEGA) flags.useHiRes = true; + if (platform == Common::kPlatformFMTowns && !flags.useHiColorMode) + error("EOB ĢI FM-TOWNS requires support of 16bit color modes which has not been activated in your ScummVM build (The 'USE_RGB_COLOR' define has not been set)."); *engine = new Kyra::DarkMoonEngine(syst, flags); break; #endif // ENABLE_EOB diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h index 0b45977d22..81dd56f798 100644 --- a/engines/kyra/detection_tables.h +++ b/engines/kyra/detection_tables.h @@ -22,7 +22,6 @@ namespace { -#define EOB2_SJIS_FLAGS FLAGS(false, false, false, false, true, false, false, false, Kyra::GI_EOB2) #define FLAGS(x, y, z, a, b, c, d, e, f, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, f, id } #define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, d, e, f, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, d, e, f, id } @@ -62,6 +61,7 @@ namespace { #define EOB_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_EOB1) #define EOB2_FLAGS FLAGS(false, false, false, false, false, false, false, false, false, Kyra::GI_EOB2) +#define EOB2_FMTOWNS_FLAGS FLAGS(false, false, false, false, true, false, true, false, false, Kyra::GI_EOB2) #define GAMEOPTION_KYRA3_AUDIENCE GUIO_GAMEOPTIONS1 #define GAMEOPTION_KYRA3_SKIP GUIO_GAMEOPTIONS2 @@ -1684,6 +1684,22 @@ const KYRAGameDescription adGameDescs[] = { }, EOB2_FLAGS }, + + { + { + "eob2", + 0, + { + { "AZURE.SDT", 0, "2915098f2d1bdcfa518f857a26bb3324", -1 }, + { 0, 0, 0, 0 } + }, + Common::JA_JPN, + Common::kPlatformFMTowns, + ADGF_NO_FLAGS, + GUIO4(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_RENDERFMTOWNS, GAMEOPTION_EOB_HPGRAPHS) + }, + EOB2_FMTOWNS_FLAGS + }, #endif // ENABLE_EOB { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) } diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp index 4f5dfcdd47..11bdafabb3 100644 --- a/engines/kyra/eobcommon.cpp +++ b/engines/kyra/eobcommon.cpp @@ -24,7 +24,7 @@ #include "kyra/kyra_rpg.h" #include "kyra/resource.h" -#include "engines/kyra/sound.h" +#include "engines/kyra/sound_intern.h" #include "engines/kyra/sound_adlib.h" #include "kyra/script_eob.h" #include "kyra/timer.h" @@ -52,7 +52,7 @@ EoBCoreEngine::EoBCoreEngine(OSystem *system, const GameFlags &flags) _playFinale = false; _runFlag = true; - _configMouse = true; + _configMouse = _config2431 = true; _loading = false; _enableHiResDithering = false; @@ -195,7 +195,7 @@ EoBCoreEngine::EoBCoreEngine(OSystem *system, const GameFlags &flags) _abortStrings = _saveLoadStrings = _mnWord = _mnPrompt = _bookNumbers = 0; _mageSpellList = _clericSpellList = _spellNames = _magicStrings1 = 0; _magicStrings2 = _magicStrings3 = _magicStrings4 = _magicStrings6 = 0; - _magicStrings7 = _magicStrings8 = 0; + _magicStrings7 = _magicStrings8 = _saveNamePatterns = 0; _spellAnimBuffer = 0; _sparkEffectDefSteps = _sparkEffectDefSubSteps = _sparkEffectDefShift = 0; _sparkEffectDefAdd = _sparkEffectDefX = _sparkEffectDefY = _sparkEffectOfShift = 0; @@ -211,7 +211,7 @@ EoBCoreEngine::EoBCoreEngine(OSystem *system, const GameFlags &flags) _menuStringsScribe = _menuStringsDrop2 = _menuStringsHead = _menuStringsPoison = 0; _menuStringsMgc = _menuStringsPrefs = _menuStringsRest2 = _menuStringsRest3 = 0; _menuStringsRest4 = _menuStringsDefeat = _menuStringsTransfer = _menuStringsSpec = 0; - _menuStringsSpellNo = _menuYesNoStrings = 0; + _menuStringsSpellNo = _menuYesNoStrings = _2431Strings = _katakanaLines = _katakanaSelectStrings = 0; _errorSlotEmptyString = _errorSlotNoNameString = _menuOkString = 0; _spellLevelsMage = _spellLevelsCleric = _numSpellsCleric = _numSpellsWisAdj = _numSpellsPal = _numSpellsMage = 0; _mnNumWord = _numSpells = _mageSpellListSize = _spellLevelsMageSize = _spellLevelsClericSize = 0; @@ -308,6 +308,7 @@ EoBCoreEngine::~EoBCoreEngine() { delete[] _spells; delete[] _spellAnimBuffer; delete[] _wallsOfForce; + delete[] _buttonDefs; delete _gui; _gui = 0; @@ -385,14 +386,6 @@ Common::Error EoBCoreEngine::init() { assert(_screen); _screen->setResolution(); - //MidiDriverType midiDriver = MidiDriver::detectDevice(MDT_PCSPK | MDT_ADLIB); - _sound = new SoundAdLibPC(this, _mixer); - assert(_sound); - _sound->init(); - - // Setup volume settings (and read in all ConfigManager settings) - syncSoundSettings(); - _res = new Resource(this); assert(_res); _res->reset(); @@ -402,6 +395,22 @@ Common::Error EoBCoreEngine::init() { if (!_staticres->init()) error("_staticres->init() failed"); + // SoundTowns_Darkmoon requires initialized _staticres + if (_flags.platform == Common::kPlatformDOS) { + //MidiDriverType midiDriver = MidiDriver::detectDevice(MDT_PCSPK | MDT_ADLIB); + _sound = new SoundAdLibPC(this, _mixer); + } else if (_flags.platform == Common::kPlatformFMTowns) { + _sound = new SoundTowns_Darkmoon(this, _mixer); + } else if (_flags.platform == Common::kPlatformPC98) { + + } + + assert(_sound); + _sound->init(); + + // Setup volume settings (and read in all ConfigManager settings) + syncSoundSettings(); + if (!_screen->init()) error("screen()->init() failed"); @@ -453,13 +462,14 @@ Common::Error EoBCoreEngine::init() { memset(&_wllShapeMap[3], -1, 5); memset(&_wllShapeMap[13], -1, 5); - _wllVcnOffset = 16; - - _greenFadingTable = new uint8[256]; - _blueFadingTable = new uint8[256]; - _lightBlueFadingTable = new uint8[256]; - _blackFadingTable = new uint8[256]; - _greyFadingTable = new uint8[256]; + _wllVcnOffset = (_flags.platform == Common::kPlatformFMTowns) ? 0 : 16; + int bpp = (_flags.platform == Common::kPlatformFMTowns) ? 2 : 1; + + _greenFadingTable = new uint8[256 * bpp]; + _blueFadingTable = new uint8[256 * bpp]; + _lightBlueFadingTable = new uint8[256 * bpp]; + _blackFadingTable = new uint8[256 * bpp]; + _greyFadingTable = new uint8[256 * bpp]; _monsters = new EoBMonsterInPlay[30]; memset(_monsters, 0, 30 * sizeof(EoBMonsterInPlay)); @@ -480,8 +490,9 @@ Common::Error EoBCoreEngine::init() { _flyingObjectsPtr = _flyingObjects; memset(_flyingObjects, 0, _numFlyingObjects * sizeof(EoBFlyingObject)); - _spellAnimBuffer = new uint8[4096]; - memset(_spellAnimBuffer, 0, 4096); + int bufferSize = _flags.useHiColorMode ? 8192 : 4096; + _spellAnimBuffer = new uint8[bufferSize]; + memset(_spellAnimBuffer, 0, bufferSize); _wallsOfForce = new WallOfForce[5]; memset(_wallsOfForce, 0, 5 * sizeof(WallOfForce)); @@ -518,11 +529,8 @@ Common::Error EoBCoreEngine::init() { Common::Error EoBCoreEngine::go() { _debugger->initialize(); - _txt->removePageBreakFlag(); - _screen->setFont(Screen::FID_8_FNT); - loadItemsAndDecorationsShapes(); _screen->setMouseCursor(0, 0, _itemIconShapes[0]); @@ -540,6 +548,7 @@ Common::Error EoBCoreEngine::go() { action = 0; if (_gameToLoad != -1) { + _sound->selectAudioResourceSet(kMusicIngame); if (loadGameState(_gameToLoad).getCode() != Common::kNoError) error("Couldn't load game slot %d on startup", _gameToLoad); startupLoad(); @@ -549,6 +558,8 @@ Common::Error EoBCoreEngine::go() { action = mainMenu(); } + _sound->selectAudioResourceSet(kMusicIngame); + if (action == -1) { // load game repeatLoop = _gui->runLoadMenu(72, 14); @@ -573,6 +584,7 @@ Common::Error EoBCoreEngine::go() { if (_playFinale) { // make final save for party transfer saveGameStateIntern(-1, 0, 0); + _sound->selectAudioResourceSet(kMusicFinale); seq_playFinale(); } } @@ -601,7 +613,7 @@ void EoBCoreEngine::writeSettings() { if (_sound) { if (!_configSounds) - _sound->beginFadeOut(); + _sound->haltTrack(); _sound->enableMusic(_configSounds ? 1 : 0); _sound->enableSFX(_configSounds); } @@ -683,167 +695,219 @@ bool EoBCoreEngine::checkPartyStatus(bool handleDeath) { void EoBCoreEngine::loadItemsAndDecorationsShapes() { releaseItemsAndDecorationsShapes(); - - _screen->loadShapeSetBitmap("ITEML1", 5, 3); - _largeItemShapes = new const uint8*[_numLargeItemShapes]; int div = (_flags.gameID == GI_EOB1) ? 3 : 8; int mul = (_flags.gameID == GI_EOB1) ? 64 : 24; + int size = 0; - for (int i = 0; i < _numLargeItemShapes; i++) - _largeItemShapes[i] = _screen->encodeShape((i / div) << 3, (i % div) * mul, 8, 24, false, _cgaMappingItemsL); + _largeItemShapes = new const uint8*[_numLargeItemShapes]; + if (_flags.platform == Common::kPlatformFMTowns && _flags.gameID == GI_EOB2) { + for (int i = 0; i < _numLargeItemShapes; i++) + _largeItemShapes[i] = _staticres->loadRawData(kEoB2LargeItemsShapeData00 + i, size); + } else { + _screen->loadShapeSetBitmap("ITEML1", 5, 3); + for (int i = 0; i < _numLargeItemShapes; i++) + _largeItemShapes[i] = _screen->encodeShape((i / div) << 3, (i % div) * mul, 8, 24, false, _cgaMappingItemsL); + } - _screen->loadShapeSetBitmap("ITEMS1", 5, 3); _smallItemShapes = new const uint8*[_numSmallItemShapes]; - for (int i = 0; i < _numSmallItemShapes; i++) - _smallItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24, false, _cgaMappingItemsS); + if (_flags.platform == Common::kPlatformFMTowns && _flags.gameID == GI_EOB2) { + for (int i = 0; i < _numSmallItemShapes; i++) + _smallItemShapes[i] = _staticres->loadRawData(kEoB2SmallItemsShapeData00 + i, size); + } else { + _screen->loadShapeSetBitmap("ITEMS1", 5, 3); + for (int i = 0; i < _numSmallItemShapes; i++) + _smallItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24, false, _cgaMappingItemsS); + } - _screen->loadShapeSetBitmap("THROWN", 5, 3); _thrownItemShapes = new const uint8*[_numThrownItemShapes]; - for (int i = 0; i < _numThrownItemShapes; i++) - _thrownItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24, false, _cgaMappingThrown); - _spellShapes = new const uint8*[4]; - for (int i = 0; i < 4; i++) - _spellShapes[i] = _screen->encodeShape(8, i << 5, 6, 32, false, _cgaMappingThrown); - _firebeamShapes = new const uint8*[3]; - _firebeamShapes[0] = _screen->encodeShape(16, 0, 4, 24, false, _cgaMappingThrown); - _firebeamShapes[1] = _screen->encodeShape(16, 24, 4, 24, false, _cgaMappingThrown); - _firebeamShapes[2] = _screen->encodeShape(16, 48, 3, 24, false, _cgaMappingThrown); - _redSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 144 : 72, 5, 24, false, _cgaMappingThrown); - _greenSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 168 : 96, 5, 16, false, _cgaMappingThrown); - - _screen->loadShapeSetBitmap("ITEMICN", 5, 3); - _itemIconShapes = new const uint8*[_numItemIconShapes]; - for (int i = 0; i < _numItemIconShapes; i++) - _itemIconShapes[i] = _screen->encodeShape((i % 0x14) << 1, (i / 0x14) << 4, 2, 0x10, false, _cgaMappingIcons); + if (_flags.platform == Common::kPlatformFMTowns && _flags.gameID == GI_EOB2) { + for (int i = 0; i < _numThrownItemShapes; i++) + _thrownItemShapes[i] = _staticres->loadRawData(kEoB2ThrownShapeData00 + i, size); + for (int i = 0; i < 4; i++) + _spellShapes[i] = _staticres->loadRawData(kEoB2SpellShapeData00 + i, size); + for (int i = 0; i < 3; i++) + _firebeamShapes[i] = _staticres->loadRawData(kEoB2FirebeamShapeData00 + i, size); + _redSplatShape = _staticres->loadRawData(kEoB2RedSplatShapeData, size); + _greenSplatShape = _staticres->loadRawData(kEoB2GreenSplatShapeData, size); + } else { + _screen->loadShapeSetBitmap("THROWN", 5, 3); + for (int i = 0; i < _numThrownItemShapes; i++) + _thrownItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24, false, _cgaMappingThrown); + for (int i = 0; i < 4; i++) + _spellShapes[i] = _screen->encodeShape(8, i << 5, 6, 32, false, _cgaMappingThrown); - _screen->loadShapeSetBitmap("DECORATE", 5, 3); + _firebeamShapes[0] = _screen->encodeShape(16, 0, 4, 24, false, _cgaMappingThrown); + _firebeamShapes[1] = _screen->encodeShape(16, 24, 4, 24, false, _cgaMappingThrown); + _firebeamShapes[2] = _screen->encodeShape(16, 48, 3, 24, false, _cgaMappingThrown); + _redSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 144 : 72, 5, 24, false, _cgaMappingThrown); + _greenSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 168 : 96, 5, 16, false, _cgaMappingThrown); + } - if (_flags.gameID == GI_EOB2) { - _lightningColumnShape = _screen->encodeShape(18, 88, 4, 64); - _wallOfForceShapes = new const uint8*[6]; - for (int i = 0; i < 6; i++) - _wallOfForceShapes[i] = _screen->encodeShape(_wallOfForceShapeDefs[(i << 2)], _wallOfForceShapeDefs[(i << 2) + 1], _wallOfForceShapeDefs[(i << 2) + 2], _wallOfForceShapeDefs[(i << 2) + 3]); + _itemIconShapes = new const uint8*[_numItemIconShapes]; + if (_flags.platform == Common::kPlatformFMTowns && _flags.gameID == GI_EOB2) { + for (int i = 0; i < _numItemIconShapes; i++) + _itemIconShapes[i] = _staticres->loadRawData(kEoB2ItemIconShapeData00 + i, size); + } else { + _screen->loadShapeSetBitmap("ITEMICN", 5, 3); + for (int i = 0; i < _numItemIconShapes; i++) + _itemIconShapes[i] = _screen->encodeShape((i % 0x14) << 1, (i / 0x14) << 4, 2, 0x10, false, _cgaMappingIcons); } _teleporterShapes = new const uint8*[6]; - for (int i = 0; i < 6; i++) - _teleporterShapes[i] = _screen->encodeShape(_teleporterShapeDefs[(i << 2)], _teleporterShapeDefs[(i << 2) + 1], _teleporterShapeDefs[(i << 2) + 2], _teleporterShapeDefs[(i << 2) + 3], false, _cgaMappingDefault); _sparkShapes = new const uint8*[3]; - _sparkShapes[0] = _screen->encodeShape(29, 0, 2, 16, false, _cgaMappingDeco); - _sparkShapes[1] = _screen->encodeShape(31, 0, 2, 16, false, _cgaMappingDeco); - _sparkShapes[2] = _screen->encodeShape(33, 0, 2, 16, false, _cgaMappingDeco); - _deadCharShape = _screen->encodeShape(0, 88, 4, 32, false, _cgaMappingDeco); - _disabledCharGrid = _screen->encodeShape(4, 88, 4, 32, false, _cgaMappingDeco); - _blackBoxSmallGrid = _screen->encodeShape(9, 88, 2, 8, false, _cgaMappingDeco); - _weaponSlotGrid = _screen->encodeShape(8, 88, 4, 16, false, _cgaMappingDeco); - _blackBoxWideGrid = _screen->encodeShape(8, 104, 4, 8, false, _cgaMappingDeco); - - static const uint8 dHeight[] = { 17, 10, 10 }; - static const uint8 dY[] = { 120, 137, 147 }; - _compassShapes = new const uint8*[12]; - for (int y = 0; y < 3; y++) { - for (int x = 0; x < 4; x++) - _compassShapes[(y << 2) + x] = _screen->encodeShape(x * 3, dY[y], 3, dHeight[y], false, _cgaMappingDeco); + if (_flags.gameID == GI_EOB2) + _wallOfForceShapes = new const uint8*[6]; + + if (_flags.platform == Common::kPlatformFMTowns && _flags.gameID == GI_EOB2) { + _lightningColumnShape = _staticres->loadRawData(kEoB2LightningColumnShapeData, size); + for (int i = 0; i < 6; i++) + _wallOfForceShapes[i] = _staticres->loadRawData(kEoB2WallOfForceShapeData00 + i, size); + for (int i = 0; i < 6; i++) + _teleporterShapes[i] = _staticres->loadRawData(kEoB2TeleporterShapeData00 + i, size); + for (int i = 0; i < 3; i++) + _sparkShapes[i] = _staticres->loadRawData(kEoB2SparkShapeData00 + i, size); + for (int i = 0; i < 12; i++) + _compassShapes[i] = _staticres->loadRawData(kEoB2CompassShapeData00 + i, size); + + _deadCharShape = _staticres->loadRawData(kEoB2DeadCharShapeData, size); + _disabledCharGrid = _staticres->loadRawData(kEoB2DisabledCharGridShapeData, size); + _blackBoxSmallGrid = _staticres->loadRawData(kEoB2SmallGridShapeData, size); + _weaponSlotGrid = _staticres->loadRawData(kEoB2WeaponSlotGridShapeData, size); + _blackBoxWideGrid = _staticres->loadRawData(kEoB2WideGridShapeData, size); + + } else { + _screen->loadShapeSetBitmap("DECORATE", 5, 3); + if (_flags.gameID == GI_EOB2) { + _lightningColumnShape = _screen->encodeShape(18, 88, 4, 64); + for (int i = 0; i < 6; i++) + _wallOfForceShapes[i] = _screen->encodeShape(_wallOfForceShapeDefs[(i << 2)], _wallOfForceShapeDefs[(i << 2) + 1], _wallOfForceShapeDefs[(i << 2) + 2], _wallOfForceShapeDefs[(i << 2) + 3]); + } + + for (int i = 0; i < 6; i++) + _teleporterShapes[i] = _screen->encodeShape(_teleporterShapeDefs[(i << 2)], _teleporterShapeDefs[(i << 2) + 1], _teleporterShapeDefs[(i << 2) + 2], _teleporterShapeDefs[(i << 2) + 3], false, _cgaMappingDefault); + + _sparkShapes[0] = _screen->encodeShape(29, 0, 2, 16, false, _cgaMappingDeco); + _sparkShapes[1] = _screen->encodeShape(31, 0, 2, 16, false, _cgaMappingDeco); + _sparkShapes[2] = _screen->encodeShape(33, 0, 2, 16, false, _cgaMappingDeco); + _deadCharShape = _screen->encodeShape(0, 88, 4, 32, false, _cgaMappingDeco); + _disabledCharGrid = _screen->encodeShape(4, 88, 4, 32, false, _cgaMappingDeco); + _blackBoxSmallGrid = _screen->encodeShape(9, 88, 2, 8, false, _cgaMappingDeco); + _weaponSlotGrid = _screen->encodeShape(8, 88, 4, 16, false, _cgaMappingDeco); + _blackBoxWideGrid = _screen->encodeShape(8, 104, 4, 8, false, _cgaMappingDeco); + + static const uint8 dHeight[] = { 17, 10, 10 }; + static const uint8 dY[] = { 120, 137, 147 }; + + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 4; x++) + _compassShapes[(y << 2) + x] = _screen->encodeShape(x * 3, dY[y], 3, dHeight[y], false, _cgaMappingDeco); + } } } void EoBCoreEngine::releaseItemsAndDecorationsShapes() { - if (_largeItemShapes) { - for (int i = 0; i < _numLargeItemShapes; i++) { - if (_largeItemShapes[i]) - delete[] _largeItemShapes[i]; + if (_flags.platform != Common::kPlatformFMTowns || _flags.gameID != GI_EOB2) { + if (_largeItemShapes) { + for (int i = 0; i < _numLargeItemShapes; i++) { + if (_largeItemShapes[i]) + delete[] _largeItemShapes[i]; + } } - delete[] _largeItemShapes; - } - if (_smallItemShapes) { - for (int i = 0; i < _numSmallItemShapes; i++) { - if (_smallItemShapes[i]) - delete[] _smallItemShapes[i]; + if (_smallItemShapes) { + for (int i = 0; i < _numSmallItemShapes; i++) { + if (_smallItemShapes[i]) + delete[] _smallItemShapes[i]; + } } - delete[] _smallItemShapes; - } - if (_thrownItemShapes) { - for (int i = 0; i < _numThrownItemShapes; i++) { - if (_thrownItemShapes[i]) - delete[] _thrownItemShapes[i]; + if (_thrownItemShapes) { + for (int i = 0; i < _numThrownItemShapes; i++) { + if (_thrownItemShapes[i]) + delete[] _thrownItemShapes[i]; + } } - delete[] _thrownItemShapes; - } - if (_spellShapes) { - for (int i = 0; i < 4; i++) { - if (_spellShapes[i]) - delete[] _spellShapes[i]; + if (_spellShapes) { + for (int i = 0; i < 4; i++) { + if (_spellShapes[i]) + delete[] _spellShapes[i]; + } } - delete[] _spellShapes; - } - if (_itemIconShapes) { - for (int i = 0; i < _numItemIconShapes; i++) { - if (_itemIconShapes[i]) - delete[] _itemIconShapes[i]; + if (_itemIconShapes) { + for (int i = 0; i < _numItemIconShapes; i++) { + if (_itemIconShapes[i]) + delete[] _itemIconShapes[i]; + } } - delete[] _itemIconShapes; - } - if (_sparkShapes) { - for (int i = 0; i < 3; i++) { - if (_sparkShapes[i]) - delete[] _sparkShapes[i]; + if (_sparkShapes) { + for (int i = 0; i < 3; i++) { + if (_sparkShapes[i]) + delete[] _sparkShapes[i]; + } } - delete[] _sparkShapes; - } - if (_wallOfForceShapes) { - for (int i = 0; i < 6; i++) { - if (_wallOfForceShapes[i]) - delete[] _wallOfForceShapes[i]; + if (_wallOfForceShapes) { + for (int i = 0; i < 6; i++) { + if (_wallOfForceShapes[i]) + delete[] _wallOfForceShapes[i]; + } } - delete[] _wallOfForceShapes; - } - if (_teleporterShapes) { - for (int i = 0; i < 6; i++) { - if (_teleporterShapes[i]) - delete[] _teleporterShapes[i]; + if (_teleporterShapes) { + for (int i = 0; i < 6; i++) { + if (_teleporterShapes[i]) + delete[] _teleporterShapes[i]; + } } - delete[] _teleporterShapes; - } - if (_compassShapes) { - for (int i = 0; i < 12; i++) { - if (_compassShapes[i]) - delete[] _compassShapes[i]; + if (_compassShapes) { + for (int i = 0; i < 12; i++) { + if (_compassShapes[i]) + delete[] _compassShapes[i]; + } } - delete[] _compassShapes; - } - if (_firebeamShapes) { - for (int i = 0; i < 3; i++) { - if (_firebeamShapes[i]) - delete[] _firebeamShapes[i]; + if (_firebeamShapes) { + for (int i = 0; i < 3; i++) { + if (_firebeamShapes[i]) + delete[] _firebeamShapes[i]; + } } - delete[] _firebeamShapes; + + delete[] _redSplatShape; + delete[] _greenSplatShape; + delete[] _deadCharShape; + delete[] _disabledCharGrid; + delete[] _blackBoxSmallGrid; + delete[] _weaponSlotGrid; + delete[] _blackBoxWideGrid; + delete[] _lightningColumnShape; } - delete[] _redSplatShape; - delete[] _greenSplatShape; - delete[] _deadCharShape; - delete[] _disabledCharGrid; - delete[] _blackBoxSmallGrid; - delete[] _weaponSlotGrid; - delete[] _blackBoxWideGrid; - delete[] _lightningColumnShape; + delete[] _largeItemShapes; + delete[] _smallItemShapes; + delete[] _thrownItemShapes; + delete[] _spellShapes; + delete[] _itemIconShapes; + delete[] _sparkShapes; + delete[] _wallOfForceShapes; + delete[] _teleporterShapes; + delete[] _compassShapes; + delete[] _firebeamShapes; } void EoBCoreEngine::setHandItem(Item itemIndex) { - if (itemIndex == -1) + if (itemIndex == -1) { + if (_flags.platform == Common::kPlatformFMTowns) + _screen->setMouseCursor(8, 8, _itemIconShapes[37], 0); return; + } if (_screen->curDimIndex() == 7 && itemIndex) { printFullItemName(itemIndex); @@ -860,6 +924,11 @@ void EoBCoreEngine::setHandItem(Item itemIndex) { int mouseOffs = itemIndex ? 8 : 0; _screen->setMouseCursor(mouseOffs, mouseOffs, shp, ovl); + + if (_flags.useHiColorMode) { + _screen->setFadeTable(_greyFadingTable); + _screen->setShapeFadingLevel(0); + } } int EoBCoreEngine::getDexterityArmorClassModifier(int dexterity) { @@ -1247,7 +1316,9 @@ int EoBCoreEngine::prepareForNewPartyMember(int16 itemType, int16 itemValue) { deletePartyItems(itemType, itemValue); } else { gui_drawDialogueBox(); + _screen->set16bitShadingLevel(4); _txt->printDialogueText(_npcMaxStrings[0]); + _screen->set16bitShadingLevel(0); int r = runDialogue(-1, 7, _characters[0].name, _characters[1].name, _characters[2].name, _characters[3].name, _characters[4].name, _characters[5].name, _abortStrings[0]) - 1; @@ -1376,6 +1447,8 @@ void EoBCoreEngine::setupDialogueButtons(int presetfirst, int numStr, va_list &a _dialogueNumButtons = numStr; _dialogueHighlightedButton = 0; + Screen::FontId of = _screen->setFont((_flags.gameID == GI_EOB2 && _flags.platform == Common::kPlatformFMTowns) ? Screen::FID_8_FNT : _screen->_currentFont); + for (int i = 0; i < numStr; i++) { const char *s = va_arg(args, const char *); if (s) @@ -1396,6 +1469,8 @@ void EoBCoreEngine::setupDialogueButtons(int presetfirst, int numStr, va_list &a drawDialogueButtons(); + _screen->setFont(of); + if (!shouldQuit()) removeInputTop(); } @@ -1448,6 +1523,7 @@ void EoBCoreEngine::drawSequenceBitmap(const char *file, int destRect, int x1, i int page = ((flags & 2) || destRect) ? 0 : 6; if (scumm_stricmp(_dialogueLastBitmap, file)) { + _screen->clearPage(2); if (!destRect) { if (!(flags & 1)) { _screen->loadEoBBitmap("BORDER", 0, 3, 3, 2); @@ -1622,7 +1698,9 @@ void EoBCoreEngine::displayParchment(int id) { // display text Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT"); _screen->loadFileDataToPage(s, 5, 32000); + _screen->set16bitShadingLevel(4); gui_drawBox(0, 0, 176, 175, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); _txt->setupField(12, 1); if (_flags.gameID == GI_EOB2) id++; @@ -1792,6 +1870,30 @@ bool EoBCoreEngine::checkPassword() { return true; } +Common::String EoBCoreEngine::convertAsciiToSjis(Common::String str) { + if (_flags.platform != Common::kPlatformFMTowns) + return str; + + Common::String n; + const char *src = str.c_str(); + int pos = 0; + for (uint32 i = 0; i < str.size(); ++i) { + if (src[i] & 0x80) { + n.insertChar(src[i++], pos++); + n.insertChar(src[i], pos++); + } else if (src[i] >= 32 && src[i] <= 64) { + n.insertChar(_ascii2SjisTables[1][(src[i] - 32) * 2], pos++); + n.insertChar(_ascii2SjisTables[1][(src[i] - 32) * 2 + 1], pos++); + } else if ((src[i] >= 97 && src[i] <= 122) || (src[i] >= 65 && src[i] <= 90)) { + char c = (src[i] >= 97) ? src[i] - 97 : src[i] - 65; + n.insertChar(_ascii2SjisTables2[0][c * 2], pos++); + n.insertChar(_ascii2SjisTables2[0][c * 2 + 1], pos++); + } + } + + return n; +} + void EoBCoreEngine::useSlotWeapon(int charIndex, int slotIndex, Item item) { EoBCharacter *c = &_characters[charIndex]; int tp = item ? _items[item].type : 0; diff --git a/engines/kyra/eobcommon.h b/engines/kyra/eobcommon.h index 8d740f1f4d..e7b0f0d028 100644 --- a/engines/kyra/eobcommon.h +++ b/engines/kyra/eobcommon.h @@ -77,7 +77,7 @@ struct EoBGuiButtonDef { struct EoBCharacter { uint8 id; uint8 flags; - char name[11]; + char name[21]; int8 strengthCur; int8 strengthMax; int8 strengthExtCur; @@ -476,11 +476,15 @@ protected: const uint8 *_expObjectAnimTbl3; int _expObjectAnimTbl3Size; + const char *const *_ascii2SjisTables; + const char *const *_ascii2SjisTables2; + // Monsters void loadMonsterShapes(const char *filename, int monsterIndex, bool hasDecorations, int encodeTableIndex); void releaseMonsterShapes(int first, int num); + uint8 *loadTownsShape(Common::SeekableReadStream *stream); virtual void generateMonsterPalettes(const char *file, int16 monsterIndex) {} - virtual void loadMonsterDecoration(const char *file, int16 monsterIndex) {} + virtual void loadMonsterDecoration(Common::SeekableReadStream *stream, int16 monsterIndex) {} const uint8 *loadMonsterProperties(const uint8 *data); const uint8 *loadActiveMonsterData(const uint8 *data, int level); void initMonster(int index, int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int i, int randItem, int fixedItem); @@ -632,7 +636,6 @@ protected: const uint8 *_dscItemTileIndex; const uint8 *_dscItemShapeMap; - const uint8 *_dscDoorScaleOffs; const uint8 *_dscDoorScaleMult1; const uint8 *_dscDoorScaleMult2; const uint8 *_dscDoorScaleMult3; @@ -745,7 +748,7 @@ protected: static const uint8 _buttonList8[]; int _buttonList8Size; - const EoBGuiButtonDef *_buttonDefs; + EoBGuiButtonDef *_buttonDefs; const char *const *_characterGuiStringsHp; const char *const *_characterGuiStringsWp; @@ -832,6 +835,8 @@ protected: void seq_portal(); bool checkPassword(); + Common::String convertAsciiToSjis(Common::String str); + virtual int resurrectionSelectDialogue() = 0; virtual void useHorn(int charIndex, int weaponSlot) {} virtual bool checkPartyStatusExtra() = 0; @@ -1120,6 +1125,7 @@ protected: const EoBMenuButtonDef *_menuButtonDefs; bool _configMouse; + bool _config2431; const char *const *_menuStringsMain; const char *const *_menuStringsSaveLoad; @@ -1142,12 +1148,15 @@ protected: const char *_errorSlotEmptyString; const char *_errorSlotNoNameString; const char *_menuOkString; - + const char *const *_2431Strings; + const char *const *_katakanaLines; + const char *const *_katakanaSelectStrings; const char *const *_menuStringsTransfer; const char *const *_transferStringsScummVM; const char *const *_menuStringsSpec; const char *const *_menuStringsSpellNo; const char *const *_menuYesNoStrings; + const char *const *_saveNamePatterns; const uint8 *_spellLevelsMage; int _spellLevelsMageSize; diff --git a/engines/kyra/gui_eob.cpp b/engines/kyra/gui_eob.cpp index eaefa50c1e..1e4fc4388e 100644 --- a/engines/kyra/gui_eob.cpp +++ b/engines/kyra/gui_eob.cpp @@ -103,7 +103,7 @@ void EoBCoreEngine::gui_drawCharPortraitWithStats(int index) { if (index == _exchangeCharacterId) _screen->printText(_characterGuiStringsSt[0], x2 + 2, y2 + 2, 8, guiSettings()->colors.fill); else - _screen->printText(c->name, x2 + 2, y2 + 2, txtCol1, guiSettings()->colors.fill); + _screen->printText(c->name, x2 + 2, y2 + (_flags.platform == Common::kPlatformFMTowns ? 1 : 2), txtCol1, guiSettings()->colors.fill); gui_drawFaceShape(index); gui_drawWeaponSlot(index, 0); @@ -256,8 +256,10 @@ void EoBCoreEngine::gui_drawFaceShape(int index) { if (c->hitPointsCur < 1) _screen->drawShape(_screen->_curPage, _disabledCharGrid, x, y, 0); - _screen->setFadeTable(_greyFadingTable); - _screen->setShapeFadingLevel(0); + if (c->flags & 8 || c->flags & 2 || c->effectFlags & 0x140) { + _screen->setFadeTable(_greyFadingTable); + _screen->setShapeFadingLevel(0); + } } void EoBCoreEngine::gui_drawWeaponSlot(int charIndex, int slot) { @@ -527,8 +529,10 @@ void EoBCoreEngine::gui_drawCompass(bool force) { } void EoBCoreEngine::gui_drawDialogueBox() { + _screen->set16bitShadingLevel(4); gui_drawBox(0, 121, 320, 79, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); txt()->clearCurDim(); + _screen->set16bitShadingLevel(0); } void EoBCoreEngine::gui_drawSpellbook() { @@ -563,7 +567,9 @@ void EoBCoreEngine::gui_drawSpellbook() { gui_drawBox(i * 21 + 71, 122, 21, 9, col1, col2, col3); _screen->printText(_magicStrings7[i], i * 21 + 73, 123, 12, 0); } else { + _screen->set16bitShadingLevel(4); gui_drawBox(i * 18 + 68, 121, 18, 9, col1, col2, col3); + _screen->set16bitShadingLevel(0); _screen->printText(Common::String::format("%d", i + 1).c_str(), i * 18 + 75, 123, 12, 0); } } @@ -571,7 +577,9 @@ void EoBCoreEngine::gui_drawSpellbook() { if (_flags.gameID == GI_EOB1) gui_drawBox(71, 131, 105, 44, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); else { + _screen->set16bitShadingLevel(4); gui_drawBox(68, 130, 108, 47, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); gui_drawBox(68, 168, 78, 9, guiSettings()->colors.extraFrame1, guiSettings()->colors.extraFrame2, guiSettings()->colors.extraFill); gui_drawBox(146, 168, 14, 9, guiSettings()->colors.extraFrame1, guiSettings()->colors.extraFrame2, guiSettings()->colors.extraFill); gui_drawBox(160, 168, 16, 9, guiSettings()->colors.extraFrame1, guiSettings()->colors.extraFrame2, guiSettings()->colors.extraFill); @@ -600,6 +608,7 @@ void EoBCoreEngine::gui_drawSpellbook() { int d = _openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + i]; if (_openBookSpellSelectedItem == i) { if (d >= 0 && i < 6 && (i + _openBookSpellListOffset) < 9) { + _screen->fillRect(textXs, 132 + 6 * i, textXs + _screen->getTextWidth(_openBookSpellList[d]) - 1, 137 + 6 * i, textCol2); _screen->printText(_openBookSpellList[d], textXs, 132 + 6 * i, textCol1, textCol2); } else if (i == 6) { if (_flags.gameID == GI_EOB2) @@ -1073,6 +1082,7 @@ int EoBCoreEngine::clickedInventoryNextPage(Button *button) { int EoBCoreEngine::clickedPortraitRestore(Button *button) { _currentControlMode = 0; _screen->_curPage = 2; + _screen->fillRect(0, 0, 143, 167, 0); _screen->copyRegion(0, 0, 0, 0, 144, 168, 5, _screen->_curPage, Screen::CR_NO_P_CHECK); gui_drawAllCharPortraitsWithStats(); _screen->_curPage = 0; @@ -1178,6 +1188,8 @@ int EoBCoreEngine::clickedSceneSpecial(Button *button) { int EoBCoreEngine::clickedSpellbookAbort(Button *button) { _updateFlags = 0; + _screen->fillRect(64, 121, 175, 176, 0, 0); + _screen->fillRect(64, 121, 175, 176, 0, 2); _screen->copyRegion(0, 0, 64, 121, 112, 56, 10, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); gui_drawCompass(true); @@ -1372,8 +1384,8 @@ GUI_EoB::GUI_EoB(EoBCoreEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) { _saveSlotStringsTemp = new char*[6]; for (int i = 0; i < 6; i++) { - _saveSlotStringsTemp[i] = new char[20]; - memset(_saveSlotStringsTemp[i], 0, 20); + _saveSlotStringsTemp[i] = new char[26]; + memset(_saveSlotStringsTemp[i], 0, 26); } _saveSlotIdTemp = new int16[6]; _savegameOffset = 0; @@ -2030,6 +2042,7 @@ void GUI_EoB::runCampMenu() { int newMenu = 0; int lastMenu = -1; bool redrawPortraits = false; + bool keepButtons = false; _charSelectRedraw = false; _needRest = false; @@ -2040,23 +2053,26 @@ void GUI_EoB::runCampMenu() { updateOptionsStrings(); if (newMenu != -1) { - releaseButtons(buttonList); + if (!keepButtons) { + releaseButtons(buttonList); - _vm->_menuDefs[0].titleStrId = newMenu ? 1 : 56; - if (newMenu == 2) - _vm->_menuDefs[2].titleStrId = 57; - else if (newMenu == 1) - _vm->_menuDefs[1].titleStrId = 58; + _vm->_menuDefs[0].titleStrId = newMenu ? 1 : 56; + if (newMenu == 2) + _vm->_menuDefs[2].titleStrId = 57; + else if (newMenu == 1) + _vm->_menuDefs[1].titleStrId = 58; - buttonList = initMenu(newMenu); + buttonList = initMenu(newMenu); - if (newMenu != lastMenu) { - highlightButton = buttonList; - prevHighlightButton = 0; + if (newMenu != lastMenu) { + highlightButton = buttonList; + prevHighlightButton = 0; + } } lastMenu = newMenu; newMenu = -1; + keepButtons = false; } int inputFlag = _vm->checkInput(buttonList, false, 0) & 0x80FF; @@ -2089,6 +2105,8 @@ void GUI_EoB::runCampMenu() { if (prevHighlightButton) { int dir = (inputFlag == _vm->_keyMap[Common::KEYCODE_UP]) ? -1 : 1; int s = prevHighlightButton->index + dir; + if (lastMenu == 2 && _vm->gameFlags().platform == Common::kPlatformFMTowns) + s += 32; int a = _vm->_menuDefs[lastMenu].firstButtonStrId + 1; int b = a + _vm->_menuDefs[lastMenu].numButtons - 1; @@ -2102,10 +2120,12 @@ void GUI_EoB::runCampMenu() { s += dir; } while (!_vm->shouldQuit()); + if (lastMenu == 2 && _vm->gameFlags().platform == Common::kPlatformFMTowns) + s -= 32; highlightButton = _vm->gui_getButton(buttonList, s); } - } else if (inputFlag > 0x8000 && inputFlag < 0x8010) { + } else if (inputFlag > 0x8000 && inputFlag < 0x8011) { int i = 0; int cnt = 0; @@ -2148,7 +2168,7 @@ void GUI_EoB::runCampMenu() { // fall through case 0x800C: - case 0x800F: + case 0x8010: if (lastMenu == 1 || lastMenu == 2) newMenu = 0; else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) @@ -2199,13 +2219,24 @@ void GUI_EoB::runCampMenu() { case 0x800D: _vm->_configSounds ^= true; _vm->_configMusic = _vm->_configSounds ? 1 : 0; + keepButtons = true; newMenu = 2; break; case 0x800E: _vm->_configHpBarGraphs ^= true; newMenu = 2; - redrawPortraits = true; + redrawPortraits = keepButtons = true; + break; + + case 0x800F: + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + _vm->_config2431 ^= true; + newMenu = 2; + redrawPortraits = keepButtons = true; + } else { + newMenu = 0; + } break; default: @@ -2233,7 +2264,7 @@ void GUI_EoB::runCampMenu() { if (prevHighlightButton != highlightButton && newMenu == -1 && runLoop) { drawMenuButton(prevHighlightButton, false, false, true); - drawMenuButton(highlightButton, false, true, true); + drawMenuButton(highlightButton, false, true, false); _screen->updateScreen(); prevHighlightButton = highlightButton; } @@ -2322,7 +2353,7 @@ bool GUI_EoB::confirmDialogue2(int dim, int id, int deflt) { if (newHighlight != lastHighlight) { for (int i = 0; i < 2; i++) - _screen->printShadedText(_vm->_menuYesNoStrings[i], x[i] + 16 - (strlen(_vm->_menuYesNoStrings[i]) << 2) + 1, y + 3, i == newHighlight ? 6 : 15, 0); + _screen->printShadedText(_vm->_menuYesNoStrings[i], x[i] + 16 - (_screen->getTextWidth(_vm->_menuYesNoStrings[i]) / 2) + 1, y + 3, i == newHighlight ? 6 : 15, 0); _screen->updateScreen(); lastHighlight = newHighlight; } @@ -2349,9 +2380,9 @@ void GUI_EoB::messageDialogue(int dim, int id, int buttonTextCol) { drawTextBox(dim, id); const ScreenDim *dm = _screen->getScreenDim(dim); - int bx = ((dm->sx + dm->w) << 3) - ((strlen(_vm->_menuOkString) << 3) + 16); + int bx = ((dm->sx + dm->w) << 3) - (_screen->getTextWidth(_vm->_menuOkString) + 16); int by = dm->sy + dm->h - 19; - int bw = (strlen(_vm->_menuOkString) << 3) + 7; + int bw = _screen->getTextWidth(_vm->_menuOkString) + 7; drawMenuButtonBox(bx, by, bw, 14, false, false); _screen->printShadedText(_vm->_menuOkString, bx + 4, by + 3, buttonTextCol, 0); @@ -2382,8 +2413,6 @@ void GUI_EoB::messageDialogue(int dim, int id, int buttonTextCol) { } void GUI_EoB::messageDialogue2(int dim, int id, int buttonTextCol) { - drawMenuButtonBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, false, false); - _screen->_curPage = 2; _screen->setClearScreenDim(dim); drawMenuButtonBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, false, false); @@ -2391,9 +2420,9 @@ void GUI_EoB::messageDialogue2(int dim, int id, int buttonTextCol) { _screen->_curPage = 0; _screen->copyRegion(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, 2, 0, Screen::CR_NO_P_CHECK); - int x = (_screen->_curDim->sx << 3) + (_screen->_curDim->w << 2) - (strlen(_vm->_menuOkString) << 2); + int x = (_screen->_curDim->sx << 3) + (_screen->_curDim->w << 2) - (_screen->getTextWidth(_vm->_menuOkString) / 2); int y = _screen->_curDim->sy + _screen->_curDim->h - 21; - int w = (strlen(_vm->_menuOkString) << 3) + 8; + int w = _screen->getTextWidth(_vm->_menuOkString) + 8; drawMenuButtonBox(x, y, w, 14, false, false); _screen->printShadedText(_vm->_menuOkString, x + 4, y + 3, buttonTextCol, 0); _screen->updateScreen(); @@ -2410,7 +2439,9 @@ void GUI_EoB::messageDialogue2(int dim, int id, int buttonTextCol) { } } + _screen->set16bitShadingLevel(4); _vm->gui_drawBox(x, y, w, 14, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill, -1); + _screen->set16bitShadingLevel(0); _screen->updateScreen(); _vm->_system->delayMillis(80); drawMenuButtonBox(x, y, w, 14, false, false); @@ -2456,7 +2487,7 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo #endif uint8 cursorState = 1; - char sufx[] = " "; + char sufx[3] = " \0"; int len = strlen(dest); if (len > destMaxLen) { @@ -2469,12 +2500,17 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo pos--; _screen->copyRegion((x - 1) << 3, y, 0, 191, (destMaxLen + 2) << 3, 9, 0, 2, Screen::CR_NO_P_CHECK); + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) + _screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK); _screen->printShadedText(dest, x << 3, y, textColor1, textColor2); uint32 next = _vm->_system->getMillis() + 2 * _vm->_tickLength; sufx[0] = (pos < len) ? dest[pos] : 32; _screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor); + _menuCur = -1; + printKatakanaOptions(0); + int in = 0; do { @@ -2487,33 +2523,58 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo _screen->copyRegion((pos + 1) << 3, 191, (x + pos) << 3, y, 8, 9, 2, 0, Screen::CR_NO_P_CHECK); _screen->printShadedText(sufx, (x + pos) << 3, y, textColor1, textColor2); } else { + _screen->fillRect((x + pos) << 3, y, ((x + pos) << 3) + 7, y + 7, cursorColor); _screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor); } _screen->updateScreen(); cursorState ^= 1; - next = _vm->_system->getMillis() + 2 * _vm->_tickLength; + next = _vm->_system->getMillis() + 4 * _vm->_tickLength; } _vm->updateInput(); + in = checkKatakanaSelection(); + for (Common::List::const_iterator evt = _vm->_eventList.begin(); evt != _vm->_eventList.end(); ++evt) { if (evt->event.type == Common::EVENT_KEYDOWN) { _keyPressed = evt->event.kbd; in = _keyPressed.ascii; + + if (_vm->_flags.platform == Common::kPlatformFMTowns && _keyPressed.ascii > 31 && _keyPressed.ascii < 123) { + Common::String s; + s.insertChar(in & 0xff, 0); + s = _vm->convertAsciiToSjis(s); + if (s.empty()) { + in = 0; + } else { + _csjis[0] = s[0]; + _csjis[1] = s[1]; + _csjis[2] = 0; + in = 0x89; + } + } } } _vm->removeInputTop(); } if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE) { - if (pos >= len && len > 0) { - dest[--len] = 0; - pos--; + if (pos > 0 && pos < len ) { + for (int i = pos; i < len; i++) { + if (dest[i * 2] & 0x80) { + dest[(i - 1) * 2] = dest[i * 2]; + dest[(i - 1) * 2 + 1] = dest[i * 2 + 1]; + } else { + dest[i - 1] = dest[i]; + } + } + } - } else if (pos > 0) { - for (int i = pos; i < destMaxLen; i++) - dest[i - 1] = dest[i]; - dest[--len] = 0; + if (pos > 0) { + if (dest[(len - 1) * 2] & 0x80) + dest[--len * 2] = 0; + else + dest[--len] = 0; pos--; } @@ -2525,28 +2586,45 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo if (pos < len && pos < (destMaxLen - 1)) pos++; - } else if (in > 31 && in < 126) { + } else if ((in > 31 && in < 126) || (in == 0x89)) { if (!(in == 32 && pos == 0)) { if (in >= 97 && in <= 122) in -= 32; if (pos < len) { - for (int i = destMaxLen - 1; i >= pos; i--) - dest[i + 1] = dest[i]; - - dest[pos++] = in; - - if (len == destMaxLen) - dest[len] = 0; + for (int i = destMaxLen - 2; i >= pos; i--) { + if (in == 0x89) { + dest[(i + 1) * 2] = dest[i * 2]; + dest[(i + 1) * 2 + 1] = dest[i * 2 + 1]; + } else { + dest[i + 1] = dest[i]; + } + } + if (in == 0x89) { + dest[pos * 2] = _csjis[0]; + dest[pos++ * 2 + 1] = _csjis[1]; + if (len == destMaxLen) + dest[len * 2] = 0; + } else { + dest[pos++] = in; + if (len == destMaxLen) + dest[len] = 0; + } } else { if (pos == destMaxLen) { pos--; len--; } - dest[pos++] = in; - dest[pos] = 0; + if (in == 0x89) { + dest[pos * 2] = _csjis[0]; + dest[pos * 2 + 1] = _csjis[1]; + dest[++pos * 2] = 0; + } else { + dest[pos++] = in; + dest[pos] = 0; + } } if (++len > destMaxLen) @@ -2559,7 +2637,18 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo _screen->copyRegion(0, 191, (x - 1) << 3, y, (destMaxLen + 2) << 3, 9, 2, 0, Screen::CR_NO_P_CHECK); _screen->printShadedText(dest, x << 3, y, textColor1, textColor2); - sufx[0] = (pos < len) ? dest[pos] : 32; + + if (_vm->_flags.platform == Common::kPlatformFMTowns) { + if (pos < len) { + sufx[0] = dest[pos * 2]; + sufx[1] = dest[pos * 2 + 1]; + } else { + sufx[0] = 32; + sufx[1] = 0; + } + } else { + sufx[0] = (pos < len) ? dest[pos] : 32; + } if (cursorState) _screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor); @@ -2576,6 +2665,108 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo return _keyPressed.keycode == Common::KEYCODE_ESCAPE ? -1 : len; } +int GUI_EoB::checkKatakanaSelection() { + if (_vm->_flags.platform != Common::kPlatformFMTowns) + return 0; + + static uint16 kanaSelXCrds[] = { 224, 272, 186 }; + Common::Point mousePos = _vm->getMousePos(); + int highlight = -1; + _csjis[0] = _csjis[2] = 0; + + for (int y = 112; y < 168; y += 16) { + for (int x = 152; x < 288; x += 8) { + if (!_vm->posWithinRect(mousePos.x, mousePos.y, x, y, x + 9, y + 9)) + continue; + + int lineOffs = (y - 112) >> 4; + int column = (x - 152) >> 2; + + _csjis[0] = _vm->_katakanaLines[_currentKanaPage * 4 + lineOffs][column]; + _csjis[1] = _vm->_katakanaLines[_currentKanaPage * 4 + lineOffs][column + 1]; + + if (_csjis[0] != '\x81' || _csjis[1] != '\x40') { + highlight = lineOffs << 8 | column; + _screen->printShadedText(_csjis, x & ~7, y & ~15, 6, 0); + } + + x = 288; y = 168; + } + } + + if (highlight == -1) { + for (int i = 0; i < 3; i++) { + if (!_vm->posWithinRect(mousePos.x, mousePos.y, kanaSelXCrds[i], 176, kanaSelXCrds[i] + _screen->getTextWidth(_vm->_katakanaSelectStrings[i]), 184)) + continue; + + highlight = 0x400 | i; + _screen->printShadedText(_vm->_katakanaSelectStrings[i], kanaSelXCrds[i], 176, 6, 0); + i = 3; + } + } + + int in = 0; + for (Common::List::const_iterator evt = _vm->_eventList.begin(); evt != _vm->_eventList.end(); ++evt) { + if (evt->event.type == Common::EVENT_LBUTTONDOWN) + in = 1; + } + + if ((highlight == -1 || highlight == _menuCur) && !in) + return 0; + + if (_menuCur != -1) { + if (_menuCur & 0x400) { + _screen->printShadedText(_vm->_katakanaSelectStrings[_menuCur & 3], kanaSelXCrds[_menuCur & 3], 176, 15, 0); + } else { + char osjis[3]; + osjis[0] = _vm->_katakanaLines[_currentKanaPage * 4 + (_menuCur >> 8)][_menuCur & 0xFF]; + osjis[1] = _vm->_katakanaLines[_currentKanaPage * 4 + (_menuCur >> 8)][(_menuCur & 0xFF) + 1]; + osjis[2] = 0; + _screen->printShadedText(osjis, 152 + ((_menuCur & 0xFF) << 2), 112 + ((_menuCur >> 4) & ~0x0F), 15, 0); + } + } + + _menuCur = highlight; + + if (in && highlight != -1) { + if (highlight & 0x400) { + switch (highlight & 3) { + case 0: + printKatakanaOptions((_currentKanaPage + 1) % 3); + break; + case 1: + _keyPressed.keycode = Common::KEYCODE_RETURN; + break; + case 2: + _keyPressed.keycode = Common::KEYCODE_BACKSPACE; + break; + default: + break; + } + } else if (_csjis[0]) { + if (_csjis[0] == '\x81' && _csjis[1] == '\x51') + _csjis[1] = '\x40'; + return 0x89; + } + } + + return in; +} + +void GUI_EoB::printKatakanaOptions(int page) { + if (_vm->_flags.platform != Common::kPlatformFMTowns) + return; + + _currentKanaPage = page; + _screen->copyRegion(160, 44, 144, 108, 160, 84, 2, 0, Screen::CR_NO_P_CHECK); + for (int i = 0; i < 4; i++) + _screen->printShadedText(_vm->_katakanaLines[page * 4 + i], 152, (i << 4) + 112, 15, 0); + + static uint16 kanaSelCrds[] = { 224, 272, 186 }; + for (int i = 0; i < 3; i++) + _screen->printShadedText(_vm->_katakanaSelectStrings[i], kanaSelCrds[i], 176, 15, 0); +} + void GUI_EoB::transferWaitBox() { const ScreenDim *dm = _screen->getScreenDim(11); int xo = dm->sx; @@ -2698,10 +2889,21 @@ bool GUI_EoB::runSaveMenu(int x, int y) { int fx = (x + 1) << 3; int fy = y + slot * 17 + 23; + Screen::FontId of = _screen->_currentFont; + _screen->set16bitShadingLevel(4); for (int in = -1; in == -1 && !_vm->shouldQuit();) { _screen->fillRect(fx - 2, fy, fx + 160, fy + 8, _vm->guiSettings()->colors.fill); - in = getTextInput(_saveSlotStringsTemp[slot], x + 1, fy, 19, 2, 0, 8); + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + TimeDate td; + _vm->_system->getTimeAndDate(td); + Common::strlcpy(_saveSlotStringsTemp[slot], Common::String::format(_vm->_saveNamePatterns[_vm->_currentLevel * 2 + _vm->_currentSub], td.tm_mon + 1, td.tm_mday, td.tm_hour, td.tm_min).c_str(), 25); + in = strlen(_saveSlotStringsTemp[slot]); + of = _vm->screen()->setFont(Screen::FID_6_FNT); + y++; + } else { + in = getTextInput(_saveSlotStringsTemp[slot], x + 1, fy, 19, 2, 0, 8); + } if (in == -1) { useSlot = false; break; @@ -2719,6 +2921,9 @@ bool GUI_EoB::runSaveMenu(int x, int y) { _screen->fillRect(fx - 2, fy, fx + 160, fy + 8, _vm->guiSettings()->colors.fill); _screen->printShadedText(_saveSlotStringsTemp[slot], (x + 1) << 3, fy, 15, 0); + _screen->set16bitShadingLevel(0); + _screen->setFont(of); + _screen->updateScreen(); Graphics::Surface thumb; createScreenThumbnail(thumb); @@ -2831,7 +3036,9 @@ int GUI_EoB::selectSaveSlotDialogue(int x, int y, int id) { // Display highlighted slot index in the bottom left corner to avoid people getting lost with the 990 save slots _screen->setFont(Screen::FID_6_FNT); int sli = (newHighlight == 6) ? _savegameOffset : (_savegameOffset + newHighlight); + _screen->set16bitShadingLevel(4); _screen->printText(Common::String::format("%03d/989", sli).c_str(), _saveSlotX + 5, _saveSlotY + 135, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); _screen->setFont(Screen::FID_8_FNT); _screen->updateScreen(); @@ -2990,7 +3197,9 @@ void GUI_EoB::runMemorizePrayMenu(int charIndex, int spellType) { if (updateDesc) { updateDesc = false; + _screen->set16bitShadingLevel(4); _screen->printShadedText(Common::String::format(_vm->_menuStringsMgc[1], np[lastHighLightButton] - numAssignedSpellsPerBookPage[lastHighLightButton], np[lastHighLightButton]).c_str(), 8, 38, 9, _vm->guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); } if (newHighLightText < 0) @@ -3664,6 +3873,13 @@ int GUI_EoB::selectCharacterDialogue(int id) { result = -2; int hlCur = -1; + for (int i = 0; i < 6; ++i) { + if (found[i] != -1) { + hlCur = i; + break; + } + } + Screen::FontId of = _screen->setFont(Screen::FID_6_FNT); while (result == -2 && !_vm->shouldQuit()) { @@ -3788,6 +4004,8 @@ Button *GUI_EoB::initMenu(int id) { b->index = m->firstButtonStrId + i + 1; if (id == 4 && _vm->game() == GI_EOB1) b->index -= 14; + else if (id == 2 && _vm->gameFlags().platform == Common::kPlatformFMTowns) + b->index -= 32; b->data0Val2 = 12; b->data1Val2 = b->data2Val2 = 15; @@ -3830,7 +4048,7 @@ void GUI_EoB::drawMenuButton(Button *b, bool clicked, bool highlight, bool noFil int yOffs = 3; if (d->flags & 4) { - xOffs = ((b->width - (strlen(s) << 3)) >> 1) + 1; + xOffs = ((b->width - _screen->getTextWidth(s)) >> 1) + 1; yOffs = (b->height - 7) >> 1; } @@ -3850,8 +4068,10 @@ void GUI_EoB::drawMenuButtonBox(int x, int y, int w, int h, bool clicked, bool n if (clicked) col1 = col2 = _vm->guiSettings()->colors.fill; + _screen->set16bitShadingLevel(4); _vm->gui_drawBox(x, y, w, h, col1, col2, -1); _vm->gui_drawBox(x + 1, y + 1, w - 2, h - 2, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, noFill ? -1 : _vm->guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); } void GUI_EoB::drawTextBox(int dim, int id) { @@ -3893,7 +4113,14 @@ void GUI_EoB::drawSaveSlotButton(int slot, int redrawBox, int textCol) { if (redrawBox) drawMenuButtonBox(x, y, w, 14, (redrawBox - 1) ? true : false, false); + Screen::FontId fnt = _screen->_currentFont; + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + fnt = _vm->screen()->setFont(Screen::FID_6_FNT); + y++; + } + _screen->printShadedText(s, x + 4, y + 3, textCol, 0); + _vm->screen()->setFont(fnt); } void GUI_EoB::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int spellType, bool noFill, bool highLight) { @@ -3902,17 +4129,28 @@ void GUI_EoB::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int sp int y = bookPageIndex * 9 + 50; int col1 = (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : 15; + _screen->set16bitShadingLevel(4); if (spellId) { - Common::String s(Common::String::format(_vm->_menuStringsMgc[0], spellType ? _vm->_clericSpellList[spellId] : _vm->_mageSpellList[spellId], _numAssignedSpellsOfType[spellId * 2 - 2])); + Common::String s; + if (_vm->_flags.platform == Common::kPlatformFMTowns) { + s = spellType ? _vm->_clericSpellList[spellId] : _vm->_mageSpellList[spellId]; + for (int i = s.size() >> 1; i < 17; ++i) + s.insertChar(' ', s.size()); + s.insertChar((char)(_numAssignedSpellsOfType[spellId * 2 - 2] + 48), s.size()); + } else { + s = Common::String::format(_vm->_menuStringsMgc[0], spellType ? _vm->_clericSpellList[spellId] : _vm->_mageSpellList[spellId], _numAssignedSpellsOfType[spellId * 2 - 2]); + } + if (noFill) _screen->printText(s.c_str(), 8, y, highLight ? 6 : col1, 0); else _screen->printShadedText(s.c_str(), 8, y, highLight ? 6 : col1, _vm->guiSettings()->colors.fill); - } else { _screen->fillRect(6, y, 168, y + 8, _vm->guiSettings()->colors.fill); } + + _screen->set16bitShadingLevel(0); } void GUI_EoB::updateOptionsStrings() { @@ -3924,7 +4162,7 @@ void GUI_EoB::updateOptionsStrings() { Common::strlcpy(_menuStringsPrefsTemp[0], Common::String::format(_vm->_menuStringsPrefs[0], _vm->_menuStringsOnOff[_vm->_configMusic ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[0]) + 8); Common::strlcpy(_menuStringsPrefsTemp[1], Common::String::format(_vm->_menuStringsPrefs[1], _vm->_menuStringsOnOff[_vm->_configSounds ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[1]) + 8); Common::strlcpy(_menuStringsPrefsTemp[2], Common::String::format(_vm->_menuStringsPrefs[2], _vm->_menuStringsOnOff[_vm->_configHpBarGraphs ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[2]) + 8); - Common::strlcpy(_menuStringsPrefsTemp[3], Common::String::format(_vm->_menuStringsPrefs[3], _vm->_menuStringsOnOff[_vm->_configMouse ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[3]) + 8); + Common::strlcpy(_menuStringsPrefsTemp[3], Common::String::format(_vm->_menuStringsPrefs[3], _vm->gameFlags().platform == Common::kPlatformFMTowns ? _vm->_2431Strings[_vm->_config2431 ? 0 : 1] : _vm->_menuStringsOnOff[_vm->_configMouse ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[3]) + 8); } const char *GUI_EoB::getMenuString(int id) { @@ -4010,12 +4248,12 @@ void GUI_EoB::setupSaveMenuSlots() { for (int i = 0; i < 6; ++i) { if (_savegameOffset + i < _savegameListSize) { if (_savegameList[i + _savegameOffset]) { - Common::strlcpy(_saveSlotStringsTemp[i], _savegameList[i + _savegameOffset], 20); + Common::strlcpy(_saveSlotStringsTemp[i], _savegameList[i + _savegameOffset], 25); _saveSlotIdTemp[i] = i + _savegameOffset; continue; } } - Common::strlcpy(_saveSlotStringsTemp[i], _vm->_saveLoadStrings[1], 20); + Common::strlcpy(_saveSlotStringsTemp[i], _vm->_saveLoadStrings[1], 25); _saveSlotIdTemp[i] = -1; } } @@ -4055,14 +4293,13 @@ void GUI_EoB::restParty_updateRestTime(int hours, bool init) { _screen->printShadedText(getMenuString(42), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 5, 9, 0); } - _screen->setCurPage(2); - _screen->printShadedText(Common::String::format(_vm->_menuStringsRest2[3], hours).c_str(), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 20, 15, _vm->guiSettings()->colors.fill); _screen->setCurPage(0); - _screen->copyRegion(((_screen->_curDim->sx + 1) << 3) - 1, _screen->_curDim->sy + 20, ((_screen->_curDim->sx + 1) << 3) - 1, _screen->_curDim->sy + 20, 144, 8, 2, 0, Screen::CR_NO_P_CHECK); + _screen->set16bitShadingLevel(4); + _screen->fillRect((_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 20, ((_screen->_curDim->sx + 19) << 3) + 1, _screen->_curDim->sy + 29, _vm->guiSettings()->colors.fill); + _screen->printShadedText(Common::String::format(_vm->_menuStringsRest2[3], hours).c_str(), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 20, 15, _vm->guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); _screen->updateScreen(); - _vm->delay(160); - _screen->setScreenDim(od); _screen->setFont(of); } diff --git a/engines/kyra/gui_eob.h b/engines/kyra/gui_eob.h index e4daff6ada..5d2fed4dbc 100644 --- a/engines/kyra/gui_eob.h +++ b/engines/kyra/gui_eob.h @@ -154,6 +154,13 @@ private: static const EoBRect16 _highlightFrames[]; static const uint8 _highlightColorTableVGA[]; static const uint8 _highlightColorTableEGA[]; + + // FM-Towns specific + int checkKatakanaSelection(); + void printKatakanaOptions(int page); + + int _currentKanaPage; + char _csjis[3]; }; } // End of namespace Kyra diff --git a/engines/kyra/items_eob.cpp b/engines/kyra/items_eob.cpp index 6ec9b331a3..036ee818f8 100644 --- a/engines/kyra/items_eob.cpp +++ b/engines/kyra/items_eob.cpp @@ -444,7 +444,7 @@ void EoBCoreEngine::printFullItemName(Item item) { tmpString = (itm->flags & 0x40) ? nameId : nameUnid; } - _txt->printMessage(tmpString.c_str()); + _txt->printMessage(convertAsciiToSjis(tmpString).c_str()); } void EoBCoreEngine::identifyQueuedItems(Item itemQueue) { diff --git a/engines/kyra/kyra_rpg.cpp b/engines/kyra/kyra_rpg.cpp index 635559dcfd..75cb6f5945 100644 --- a/engines/kyra/kyra_rpg.cpp +++ b/engines/kyra/kyra_rpg.cpp @@ -46,6 +46,7 @@ KyraRpgEngine::KyraRpgEngine(OSystem *system, const GameFlags &flags) : KyraEngi _vcnTransitionMask = 0; _vcnShift = 0; _vcnColTable = 0; + _vcnBpp = flags.useHiColorMode ? 2 : 1; _vmpPtr = 0; _blockBrightness = _wllVcnOffset = 0; _blockDrawingBuffer = 0; @@ -84,7 +85,7 @@ KyraRpgEngine::KyraRpgEngine(OSystem *system, const GameFlags &flags) : KyraEngi _dscShapeX = 0; _dscTileIndex = 0; - _dscUnk2 = 0; + _dscDoorScaleOffs = 0; _dscDim1 = 0; _dscDim2 = 0; _dscBlockMap = 0; @@ -168,8 +169,9 @@ Common::Error KyraRpgEngine::init() { _blockDrawingBuffer = new uint16[1320]; memset(_blockDrawingBuffer, 0, 1320 * sizeof(uint16)); - _sceneWindowBuffer = new uint8[21120]; - memset(_sceneWindowBuffer, 0, 21120); + int windowBufferSize = _flags.useHiColorMode ? 42240 : 21120; + _sceneWindowBuffer = new uint8[windowBufferSize]; + memset(_sceneWindowBuffer, 0, windowBufferSize); _lvlShapeTop = new int16[18]; memset(_lvlShapeTop, 0, 18 * sizeof(int16)); @@ -187,7 +189,7 @@ Common::Error KyraRpgEngine::init() { initStaticResource(); - _envSfxDistThreshold = (_sound->getSfxType() == Sound::kAdLib || _sound->getSfxType() == Sound::kPCSpkr) ? 15 : 3; + _envSfxDistThreshold = (_flags.gameID == GI_EOB2 || _sound->getSfxType() == Sound::kAdLib || _sound->getSfxType() == Sound::kPCSpkr) ? 15 : 3; _dialogueButtonLabelColor1 = guiSettings()->buttons.labelColor1; _dialogueButtonLabelColor2 = guiSettings()->buttons.labelColor2; @@ -204,7 +206,7 @@ bool KyraRpgEngine::posWithinRect(int posX, int posY, int x1, int y1, int x2, in void KyraRpgEngine::drawDialogueButtons() { int cp = screen()->setCurPage(0); - Screen::FontId of = screen()->setFont(_flags.lang == Common::JA_JPN && _flags.use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT); + Screen::FontId of = screen()->setFont((_flags.lang == Common::JA_JPN && _flags.use16ColorMode) ? Screen::FID_SJIS_FNT : ((_flags.gameID == GI_EOB2 && _flags.platform == Common::kPlatformFMTowns) ? Screen::FID_8_FNT : Screen::FID_6_FNT)); for (int i = 0; i < _dialogueNumButtons; i++) { int x = _dialogueButtonPosX[i]; @@ -213,8 +215,10 @@ void KyraRpgEngine::drawDialogueButtons() { screen()->printText(_dialogueButtonString[i], (x + 37 - (screen()->getTextWidth(_dialogueButtonString[i])) / 2) & ~3, ((_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2) & ~7, _dialogueHighlightedButton == i ? 0xC1 : 0xE1, 0); } else { - int sjisYOffset = (_flags.lang == Common::JA_JPN && (_dialogueButtonString[i][0] & 0x80)) ? 2 : 0; + int sjisYOffset = (_flags.gameID == GI_EOB2 && _flags.platform == Common::kPlatformFMTowns) ? 1 : ((_flags.lang == Common::JA_JPN && (_dialogueButtonString[i][0] & 0x80)) ? 2 : 0); + screen()->set16bitShadingLevel(4); gui_drawBox(x, (_dialogueButtonYoffs + _dialogueButtonPosY[i]), _dialogueButtonWidth, guiSettings()->buttons.height, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill); + screen()->set16bitShadingLevel(0); screen()->printText(_dialogueButtonString[i], x + (_dialogueButtonWidth >> 1) - (screen()->getTextWidth(_dialogueButtonString[i])) / 2, (_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2 - sjisYOffset, _dialogueHighlightedButton == i ? _dialogueButtonLabelColor1 : _dialogueButtonLabelColor2, 0); } @@ -348,7 +352,7 @@ bool KyraRpgEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) } _environmentSfx = soundId; - _environmentSfxVol = (15 - ((block || (_flags.gameID == GI_LOL && dist < 2)) ? dist : 0)) << 4; + _environmentSfxVol = (_flags.gameID == GI_EOB2 && _flags.platform == Common::kPlatformFMTowns) ? (dist ? (16 - dist) * 8 - 1 : 127) : ((15 - ((block || (_flags.gameID == GI_LOL && dist < 2)) ? dist : 0)) << 4); return true; } diff --git a/engines/kyra/kyra_rpg.h b/engines/kyra/kyra_rpg.h index 69fc705ff2..3d673824f9 100644 --- a/engines/kyra/kyra_rpg.h +++ b/engines/kyra/kyra_rpg.h @@ -227,6 +227,7 @@ protected: uint8 *_vcnTransitionMask; uint8 *_vcnShift; uint8 *_vcnColTable; + uint8 _vcnBpp; uint16 *_blockDrawingBuffer; uint8 *_sceneWindowBuffer; uint8 _blockBrightness; @@ -263,7 +264,7 @@ protected: const int8 *_dscDim1; const int8 *_dscDim2; const int16 *_dscShapeX; - const uint8 *_dscUnk2; + const uint8 *_dscDoorScaleOffs; const uint8 *_dscBlockMap; const int8 *_dscBlockIndex; const uint8 *_dscTileIndex; diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index c8993fea47..83fe5192aa 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -378,21 +378,21 @@ void KyraEngine_v1::setupKeyMap() { { KC(KP1), 93, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, { KC(PAGEDOWN), 103, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, { KC(KP3), 103, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(F1), 112, 99, UNKNOWN_KEYCODE }, - { KC(F2), 113, 100, UNKNOWN_KEYCODE }, - { KC(F3), 114, 101, UNKNOWN_KEYCODE }, - { KC(F4), 115, 102, UNKNOWN_KEYCODE }, - { KC(F5), 116, 103, UNKNOWN_KEYCODE }, - { KC(F6), 117, 104, UNKNOWN_KEYCODE }, + { KC(F1), 112, 99, 93 }, + { KC(F2), 113, 100, 94 }, + { KC(F3), 114, 101, 95 }, + { KC(F4), 115, 102, 96 }, + { KC(F5), 116, 103, 97 }, + { KC(F6), 117, 104, 98 }, { KC(a), 31, 31, UNKNOWN_KEYCODE }, - { KC(b), 50, 50, UNKNOWN_KEYCODE }, + { KC(b), 50, 50, 66 }, { KC(c), 48, 48, 67 }, - { KC(d), 33, 33, UNKNOWN_KEYCODE }, + { KC(d), 33, 33, 68 }, { KC(e), 19, 19, UNKNOWN_KEYCODE }, - { KC(f), 34, 34, UNKNOWN_KEYCODE }, - { KC(i), 24, 24, UNKNOWN_KEYCODE }, - { KC(k), 38, 38, UNKNOWN_KEYCODE }, - { KC(m), 52, 52, UNKNOWN_KEYCODE }, + { KC(f), 34, 34, 70 }, + { KC(i), 24, 24, 24 }, + { KC(k), 38, 38, 75 }, + { KC(m), 52, 52, 77 }, { KC(n), 51, 51, UNKNOWN_KEYCODE }, { KC(o), 25, 25, 79 }, { KC(p), 26, 26, 80 }, @@ -411,22 +411,22 @@ void KyraEngine_v1::setupKeyMap() { { KC(7), 8, UNKNOWN_KEYCODE, 55 }, { KC(SLASH), 55, 55, 47 }, { KC(ESCAPE), 110, 1, 27 }, - { KC(MINUS), 12, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(KP_MINUS), 105, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(PLUS), 13, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(KP_PLUS), 106, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, + { KC(MINUS), 12, UNKNOWN_KEYCODE, 45 }, + { KC(KP_MINUS), 105, UNKNOWN_KEYCODE, 45 }, + { KC(PLUS), 13, UNKNOWN_KEYCODE, 43 }, + { KC(KP_PLUS), 106, UNKNOWN_KEYCODE, 43 }, // Multiple mappings for the keys to the right of the 'M' key, // since these are different for QWERTZ, QWERTY and AZERTY keyboards. // QWERTZ - { KC(COMMA), 53, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(PERIOD), 54, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, + { KC(COMMA), 53, UNKNOWN_KEYCODE, 60 }, + { KC(PERIOD), 54, UNKNOWN_KEYCODE, 62 }, // AZERTY - { KC(SEMICOLON), 53, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(COLON), 54, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, + { KC(SEMICOLON), 53, UNKNOWN_KEYCODE, 60 }, + { KC(COLON), 54, UNKNOWN_KEYCODE, 62 }, // QWERTY - { KC(LESS), 53, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE }, - { KC(GREATER), 54, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE } + { KC(LESS), 53, UNKNOWN_KEYCODE, 60 }, + { KC(GREATER), 54, UNKNOWN_KEYCODE, 62 } }; #undef KC #undef UNKNOWN_KEYCODE diff --git a/engines/kyra/magic_eob.cpp b/engines/kyra/magic_eob.cpp index 52bca46a24..91d50c6279 100644 --- a/engines/kyra/magic_eob.cpp +++ b/engines/kyra/magic_eob.cpp @@ -420,14 +420,14 @@ void EoBCoreEngine::sparkEffectDefensive(int charIndex) { void EoBCoreEngine::sparkEffectOffensive() { disableSysTimer(2); _screen->copyRegion(0, 0, 0, 0, 176, 120, 0, 2, Screen::CR_NO_P_CHECK); + int sh = _flags.useHiColorMode ? 9 : 8; for (int i = 0; i < 16; i++) - _screen->copyRegionToBuffer(0, _sparkEffectOfX[i], _sparkEffectOfY[i], 16, 16, &_spellAnimBuffer[i << 8]); - _screen->updateScreen(); + _screen->copyRegionToBuffer(0, _sparkEffectOfX[i], _sparkEffectOfY[i], 16, 16, &_spellAnimBuffer[i << sh]); for (int i = 0; i < 11; i++) { for (int ii = 0; ii < 16; ii++) - _screen->copyBlockToPage(2, _sparkEffectOfX[ii], _sparkEffectOfY[ii], 16, 16, &_spellAnimBuffer[ii << 8]); + _screen->copyBlockToPage(2, _sparkEffectOfX[ii], _sparkEffectOfY[ii], 16, 16, &_spellAnimBuffer[ii << sh]); for (int ii = 0; ii < 16; ii++) { int shpIndex = (_sparkEffectOfFlags1[i] & _sparkEffectOfFlags2[ii]) >> _sparkEffectOfShift[ii]; @@ -440,7 +440,7 @@ void EoBCoreEngine::sparkEffectOffensive() { } for (int i = 0; i < 16; i++) - _screen->copyBlockToPage(0, _sparkEffectOfX[i], _sparkEffectOfY[i], 16, 16, &_spellAnimBuffer[i << 8]); + _screen->copyBlockToPage(0, _sparkEffectOfX[i], _sparkEffectOfY[i], 16, 16, &_spellAnimBuffer[i << sh]); _screen->updateScreen(); enableSysTimer(2); diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index 21e3ba3dff..098c6da248 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -120,6 +120,7 @@ MODULE_OBJS += \ script_eob.o \ sequences_eob.o \ sequences_darkmoon.o \ + sound_towns_darkmoon.o \ sprites_eob.o \ staticres_eob.o \ timer_eob.o diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index c3ebf6e5fe..9d496baac5 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -255,7 +255,6 @@ enum KyraResources { kRpgCommonDscShapeIndex, kRpgCommonDscX, kRpgCommonDscTileIndex, - kRpgCommonDscUnk2, kRpgCommonDscDoorShapeIndex, kRpgCommonDscDimData1, kRpgCommonDscDimData2, @@ -266,6 +265,7 @@ enum KyraResources { kRpgCommonDscDoorFrameY2, kRpgCommonDscDoorFrameIndex1, kRpgCommonDscDoorFrameIndex2, + kRpgCommonDscDoorScaleOffs, kRpgCommonDscBlockIndex, kEoBBaseChargenStrings1, @@ -400,7 +400,6 @@ enum KyraResources { kEoBBaseWllFlagPreset, kEoBBaseDscShapeCoords, - kEoBBaseDscDoorScaleOffs, kEoBBaseDscDoorScaleMult1, kEoBBaseDscDoorScaleMult2, kEoBBaseDscDoorScaleMult3, @@ -554,6 +553,7 @@ enum KyraResources { kEoB1Npc7Strings, kEoB2MainMenuStrings, + kEoB2MainMenuUtilStrings, kEoB2TransferPortraitFrames, kEoB2TransferConvertTable, @@ -609,6 +609,7 @@ enum KyraResources { kEoB2IntroAnimData41, kEoB2IntroAnimData42, kEoB2IntroAnimData43, + kEoB2IntroShapes00, kEoB2IntroShapes01, kEoB2IntroShapes04, @@ -660,6 +661,257 @@ enum KyraResources { kEoB2WallOfForceNumH, kEoB2WallOfForceShpId, + kEoB2IntroCpsDataStreet1, + kEoB2IntroCpsDataStreet2, + kEoB2IntroCpsDataDoorway1, + kEoB2IntroCpsDataDoorway2, + kEoB2IntroCpsDataWestwood, + kEoB2IntroCpsDataWinding, + kEoB2IntroCpsDataKhelban2, + kEoB2IntroCpsDataKhelban1, + kEoB2IntroCpsDataKhelban3, + kEoB2IntroCpsDataKhelban4, + kEoB2IntroCpsDataCoin, + kEoB2IntroCpsDataKhelban5, + kEoB2IntroCpsDataKhelban6, + + kEoB2FinaleCpsDataDragon1, + kEoB2FinaleCpsDataDragon2, + kEoB2FinaleCpsDataHurry1, + kEoB2FinaleCpsDataHurry2, + kEoB2FinaleCpsDataDestroy0, + kEoB2FinaleCpsDataDestroy1, + kEoB2FinaleCpsDataDestroy2, + kEoB2FinaleCpsDataMagic, + kEoB2FinaleCpsDataDestroy3, + kEoB2FinaleCpsDataCredits2, + kEoB2FinaleCpsDataCredits3, + kEoB2FinaleCpsDataHeroes, + kEoB2FinaleCpsDataThanks, + + kEoB2ItemIconShapeData00, + kEoB2ItemIconShapeData01, + kEoB2ItemIconShapeData02, + kEoB2ItemIconShapeData03, + kEoB2ItemIconShapeData04, + kEoB2ItemIconShapeData05, + kEoB2ItemIconShapeData06, + kEoB2ItemIconShapeData07, + kEoB2ItemIconShapeData08, + kEoB2ItemIconShapeData09, + kEoB2ItemIconShapeData10, + kEoB2ItemIconShapeData11, + kEoB2ItemIconShapeData12, + kEoB2ItemIconShapeData13, + kEoB2ItemIconShapeData14, + kEoB2ItemIconShapeData15, + kEoB2ItemIconShapeData16, + kEoB2ItemIconShapeData17, + kEoB2ItemIconShapeData18, + kEoB2ItemIconShapeData19, + kEoB2ItemIconShapeData20, + kEoB2ItemIconShapeData21, + kEoB2ItemIconShapeData22, + kEoB2ItemIconShapeData23, + kEoB2ItemIconShapeData24, + kEoB2ItemIconShapeData25, + kEoB2ItemIconShapeData26, + kEoB2ItemIconShapeData27, + kEoB2ItemIconShapeData28, + kEoB2ItemIconShapeData29, + kEoB2ItemIconShapeData30, + kEoB2ItemIconShapeData31, + kEoB2ItemIconShapeData32, + kEoB2ItemIconShapeData33, + kEoB2ItemIconShapeData34, + kEoB2ItemIconShapeData35, + kEoB2ItemIconShapeData36, + kEoB2ItemIconShapeData37, + kEoB2ItemIconShapeData38, + kEoB2ItemIconShapeData39, + kEoB2ItemIconShapeData40, + kEoB2ItemIconShapeData41, + kEoB2ItemIconShapeData42, + kEoB2ItemIconShapeData43, + kEoB2ItemIconShapeData44, + kEoB2ItemIconShapeData45, + kEoB2ItemIconShapeData46, + kEoB2ItemIconShapeData47, + kEoB2ItemIconShapeData48, + kEoB2ItemIconShapeData49, + kEoB2ItemIconShapeData50, + kEoB2ItemIconShapeData51, + kEoB2ItemIconShapeData52, + kEoB2ItemIconShapeData53, + kEoB2ItemIconShapeData54, + kEoB2ItemIconShapeData55, + kEoB2ItemIconShapeData56, + kEoB2ItemIconShapeData57, + kEoB2ItemIconShapeData58, + kEoB2ItemIconShapeData59, + kEoB2ItemIconShapeData60, + kEoB2ItemIconShapeData61, + kEoB2ItemIconShapeData62, + kEoB2ItemIconShapeData63, + kEoB2ItemIconShapeData64, + kEoB2ItemIconShapeData65, + kEoB2ItemIconShapeData66, + kEoB2ItemIconShapeData67, + kEoB2ItemIconShapeData68, + kEoB2ItemIconShapeData69, + kEoB2ItemIconShapeData70, + kEoB2ItemIconShapeData71, + kEoB2ItemIconShapeData72, + kEoB2ItemIconShapeData73, + kEoB2ItemIconShapeData74, + kEoB2ItemIconShapeData75, + kEoB2ItemIconShapeData76, + kEoB2ItemIconShapeData77, + kEoB2ItemIconShapeData78, + kEoB2ItemIconShapeData79, + kEoB2ItemIconShapeData80, + kEoB2ItemIconShapeData81, + kEoB2ItemIconShapeData82, + kEoB2ItemIconShapeData83, + kEoB2ItemIconShapeData84, + kEoB2ItemIconShapeData85, + kEoB2ItemIconShapeData86, + kEoB2ItemIconShapeData87, + kEoB2ItemIconShapeData88, + kEoB2ItemIconShapeData89, + kEoB2ItemIconShapeData90, + kEoB2ItemIconShapeData91, + kEoB2ItemIconShapeData92, + kEoB2ItemIconShapeData93, + kEoB2ItemIconShapeData94, + kEoB2ItemIconShapeData95, + kEoB2ItemIconShapeData96, + kEoB2ItemIconShapeData97, + kEoB2ItemIconShapeData98, + kEoB2ItemIconShapeData99, + kEoB2ItemIconShapeData100, + kEoB2ItemIconShapeData101, + kEoB2ItemIconShapeData102, + kEoB2ItemIconShapeData103, + kEoB2ItemIconShapeData104, + kEoB2ItemIconShapeData105, + kEoB2ItemIconShapeData106, + kEoB2ItemIconShapeData107, + kEoB2ItemIconShapeData108, + kEoB2ItemIconShapeData109, + kEoB2ItemIconShapeData110, + kEoB2ItemIconShapeData111, + + kEoB2LargeItemsShapeData00, + kEoB2LargeItemsShapeData01, + kEoB2LargeItemsShapeData02, + kEoB2LargeItemsShapeData03, + kEoB2LargeItemsShapeData04, + kEoB2LargeItemsShapeData05, + kEoB2LargeItemsShapeData06, + kEoB2LargeItemsShapeData07, + kEoB2LargeItemsShapeData08, + kEoB2LargeItemsShapeData09, + kEoB2LargeItemsShapeData10, + + kEoB2SmallItemsShapeData00, + kEoB2SmallItemsShapeData01, + kEoB2SmallItemsShapeData02, + kEoB2SmallItemsShapeData03, + kEoB2SmallItemsShapeData04, + kEoB2SmallItemsShapeData05, + kEoB2SmallItemsShapeData06, + kEoB2SmallItemsShapeData07, + kEoB2SmallItemsShapeData08, + kEoB2SmallItemsShapeData09, + kEoB2SmallItemsShapeData10, + kEoB2SmallItemsShapeData11, + kEoB2SmallItemsShapeData12, + kEoB2SmallItemsShapeData13, + kEoB2SmallItemsShapeData14, + kEoB2SmallItemsShapeData15, + kEoB2SmallItemsShapeData16, + kEoB2SmallItemsShapeData17, + kEoB2SmallItemsShapeData18, + kEoB2SmallItemsShapeData19, + kEoB2SmallItemsShapeData20, + kEoB2SmallItemsShapeData21, + kEoB2SmallItemsShapeData22, + kEoB2SmallItemsShapeData23, + kEoB2SmallItemsShapeData24, + kEoB2SmallItemsShapeData25, + + kEoB2ThrownShapeData00, + kEoB2ThrownShapeData01, + kEoB2ThrownShapeData02, + kEoB2ThrownShapeData03, + kEoB2ThrownShapeData04, + kEoB2ThrownShapeData05, + kEoB2ThrownShapeData06, + kEoB2ThrownShapeData07, + kEoB2ThrownShapeData08, + + kEoB2SpellShapeData00, + kEoB2SpellShapeData01, + kEoB2SpellShapeData02, + kEoB2SpellShapeData03, + + kEoB2TeleporterShapeData00, + kEoB2TeleporterShapeData01, + kEoB2TeleporterShapeData02, + kEoB2TeleporterShapeData03, + kEoB2TeleporterShapeData04, + kEoB2TeleporterShapeData05, + + kEoB2LightningColumnShapeData, + kEoB2DeadCharShapeData, + kEoB2DisabledCharGridShapeData, + kEoB2WeaponSlotGridShapeData, + kEoB2SmallGridShapeData, + kEoB2WideGridShapeData, + kEoB2RedSplatShapeData, + kEoB2GreenSplatShapeData, + + kEoB2FirebeamShapeData00, + kEoB2FirebeamShapeData01, + kEoB2FirebeamShapeData02, + + kEoB2SparkShapeData00, + kEoB2SparkShapeData01, + kEoB2SparkShapeData02, + + kEoB2CompassShapeData00, + kEoB2CompassShapeData01, + kEoB2CompassShapeData02, + kEoB2CompassShapeData03, + kEoB2CompassShapeData04, + kEoB2CompassShapeData05, + kEoB2CompassShapeData06, + kEoB2CompassShapeData07, + kEoB2CompassShapeData08, + kEoB2CompassShapeData09, + kEoB2CompassShapeData10, + kEoB2CompassShapeData11, + + kEoB2WallOfForceShapeData00, + kEoB2WallOfForceShapeData01, + kEoB2WallOfForceShapeData02, + kEoB2WallOfForceShapeData03, + kEoB2WallOfForceShapeData04, + kEoB2WallOfForceShapeData05, + + kEoB2UtilMenuStrings, + kEoB2Config2431Strings, + kEoB2KatakanaLines, + kEoB2KanaSelectStrings, + kEoB2FontDmpSearchTbl, + kEoB2Ascii2SjisTables, + kEoB2Ascii2SjisTables2, + kEoB2SaveNamePatterns, + kEoB2PcmSoundEffectsIngame, + kEoB2PcmSoundEffectsIntro, + kEoB2PcmSoundEffectsFinale, + kLoLIngamePakFiles, kLoLCharacterDefs, kLoLIngameSfxFiles, diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 365941b1c8..e59eb5d77b 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -29,7 +29,7 @@ #include "graphics/thumbnail.h" #include "graphics/surface.h" -#define CURRENT_SAVE_VERSION 17 +#define CURRENT_SAVE_VERSION 18 #define GF_FLOPPY (1 << 0) #define GF_TALKIE (1 << 1) diff --git a/engines/kyra/saveload_eob.cpp b/engines/kyra/saveload_eob.cpp index dca4aaa0f1..0b24ba552d 100644 --- a/engines/kyra/saveload_eob.cpp +++ b/engines/kyra/saveload_eob.cpp @@ -38,6 +38,7 @@ namespace Kyra { Common::Error EoBCoreEngine::loadGameState(int slot) { // Special slot id -1 for EOB1 party transfer const char *fileName = (slot == -1) ? _savegameFilename.c_str() : getSavegameFilename(slot); + setHandItem(-1); SaveHeader header; Common::InSaveFile *saveFile = openSaveForReading(fileName, header, (slot != -1)); @@ -54,7 +55,7 @@ Common::Error EoBCoreEngine::loadGameState(int slot) { EoBCharacter *c = &_characters[i]; c->id = in.readByte(); c->flags = in.readByte(); - in.read(c->name, 11); + in.read(c->name, (header.version < 18) ? 11 : 21); c->strengthCur = in.readSByte(); c->strengthMax = in.readSByte(); c->strengthExtCur = in.readSByte(); @@ -273,6 +274,9 @@ Common::Error EoBCoreEngine::loadGameState(int slot) { } loadLevel(_currentLevel, _currentSub); + if (_flags.platform == Common::kPlatformFMTowns && _gameToLoad != -1) + _screen->setScreenPalette(_screen->getPalette(0)); + _sceneUpdateRequired = true; _screen->setFont(Screen::FID_6_FNT); @@ -283,6 +287,9 @@ Common::Error EoBCoreEngine::loadGameState(int slot) { } } + if (!_updateFlags) + _screen->fillRect(64, 121, 175, 176, 0, 2); + _screen->setCurPage(0); gui_drawPlayField(false); @@ -316,6 +323,7 @@ Common::Error EoBCoreEngine::loadGameState(int slot) { Common::Error EoBCoreEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) { Common::String saveNameTmp; const char *fileName = 0; + setHandItem(-1); // Special slot id -1 to create final save for party transfer if (slot == -1) { @@ -345,7 +353,7 @@ Common::Error EoBCoreEngine::saveGameStateIntern(int slot, const char *saveName, out->writeByte(c->id); out->writeByte(c->flags); - out->write(c->name, 11); + out->write(c->name, 21); out->writeSByte(c->strengthCur); out->writeSByte(c->strengthMax); out->writeSByte(c->strengthExtCur); @@ -525,6 +533,8 @@ Common::Error EoBCoreEngine::saveGameStateIntern(int slot, const char *saveName, _gui->notifyUpdateSaveSlotsList(); + setHandItem(_itemInHand); + return Common::kNoError; } @@ -636,13 +646,27 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { Common::SeekableSubReadStreamEndian in(fs, 0, fs->size(), _flags.platform == Common::kPlatformAmiga, DisposeAfterUse::YES); + // detect source platform + Common::Platform sourcePlatform = Common::kPlatformDOS; + in.seek(32); + uint16 testSJIS = in.readByte(); + in.seek(53); + int8 testStr = in.readSByte(); + in.seek(66); + int8 testChr = in.readSByte(); + in.seek(0); + if (testStr >= 0 && testStr <= 25 && testChr >= 0 && testChr <= 25) { + if (testSJIS >= 0xE0 || (testSJIS > 0x80 && testSJIS < 0xA0)) + sourcePlatform = Common::kPlatformFMTowns; + } + if (_flags.gameID == GI_EOB1) { // Nothing to read here for EOB 1. Original EOB 1 has // only one save slot without save file description. desc = ""; } else { - char tempStr[20]; - in.read(tempStr, 20); + char tempStr[30]; + in.read(tempStr, sourcePlatform == Common::kPlatformFMTowns ? 30 : 20); desc = tempStr; } @@ -650,7 +674,9 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { EoBCharacter *c = &_characters[i]; c->id = in.readByte(); c->flags = in.readByte(); - in.read(c->name, 11); + in.read(c->name, sourcePlatform == Common::kPlatformFMTowns ? 21 : 11); + if (_flags.platform != sourcePlatform) + c->name[10] = '\0'; c->strengthCur = in.readSByte(); c->strengthMax = in.readSByte(); c->strengthExtCur = in.readSByte(); @@ -696,7 +722,7 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { c->effectFlags = in.readUint32(); if (c->effectFlags && _flags.gameID == GI_EOB1) { // Spell effect flags are completely different in EOB I. We only use EOB II style flags in ScummVM. - // Doesn't matter much, since these are the temporary spell effects only anyway. + // Doesn't matter much, since these are only temporary spell effects. warning("EoBCoreEngine::readOriginalSaveFile(): Unhandled character effect flags encountered in original EOB1 save file '%s' ('%s')", file.c_str(), desc.c_str()); c->effectFlags = 0; } @@ -716,13 +742,13 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { _partyEffectFlags = (_flags.gameID == GI_EOB1) ? in.readUint16() : in.readUint32(); if (_partyEffectFlags && _flags.gameID == GI_EOB1) { // Spell effect flags are completely different in EOB I. We only use EOB II style flags in ScummVM. - // Doesn't matter much, since these are the temporary spell effects only anyway. + // Doesn't matter much, since these are only temporary spell effects. warning("EoBCoreEngine::readOriginalSaveFile(): Unhandled party effect flags encountered in original EOB1 save file '%s' ('%s')", file.c_str(), desc.c_str()); _partyEffectFlags = 0; } if (_flags.gameID == GI_EOB2) in.skip(1); - + _inf->loadState(in, true); int numItems = (_flags.gameID == GI_EOB1) ? 500 : 600; @@ -742,7 +768,7 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { } int numParts = (_flags.gameID == GI_EOB1) ? 12 : 17; - int partSize = (_flags.gameID == GI_EOB1) ? 2040 : 2130; + int partSize = (sourcePlatform == Common::kPlatformFMTowns) ? 5030 : (_flags.gameID == GI_EOB1 ? 2040 : 2130); uint32 nextPart = in.pos(); uint8 *cmpData = new uint8[1200]; @@ -777,8 +803,12 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { memset(lw, 0, 5 * sizeof(WallOfForce)); l->wallsOfForce = lw; - in.read(cmpData, 1200); - _screen->decodeFrame4(cmpData, l->wallsXorData, 4096); + if (sourcePlatform == Common::kPlatformFMTowns) { + in.read(l->wallsXorData, 4096); + } else { + in.read(cmpData, 1200); + _screen->decodeFrame4(cmpData, l->wallsXorData, 4096); + } _curBlockFile = getBlockFileName(i + 1, 0); const uint8 *p = getBlockFileData(); uint16 len = READ_LE_UINT16(p + 4); @@ -790,6 +820,9 @@ Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { *d++ ^= p[ii * len + iii]; } + if (sourcePlatform == Common::kPlatformFMTowns) + in.skip(4); + for (int ii = 0; ii < 30; ii++) { EoBMonsterInPlay *m = &lm[ii]; m->type = in.readByte(); @@ -998,8 +1031,8 @@ bool EoBCoreEngine::saveAsOriginalSaveFile(int slot) { Common::OutSaveFile *out = new Common::OutSaveFile(nf.createWriteStream()); if (_flags.gameID == GI_EOB2) { - static const char tempStr[20] = "SCUMMVM EXPORT "; - out->write(tempStr, 20); + static const char tempStr[31] = "SCUMMVM EXPORT "; + out->write(tempStr, (_flags.platform == Common::kPlatformFMTowns) ? 30 : 20); } completeDoorOperations(); @@ -1014,7 +1047,7 @@ bool EoBCoreEngine::saveAsOriginalSaveFile(int slot) { EoBCharacter *c = &_characters[i]; out->writeByte(c->id); out->writeByte(c->flags); - out->write(c->name, 11); + out->write(c->name, (_flags.platform == Common::kPlatformFMTowns) ? 21 : 11); out->writeSByte(c->strengthCur); out->writeSByte(c->strengthMax); out->writeSByte(c->strengthExtCur); @@ -1110,13 +1143,14 @@ bool EoBCoreEngine::saveAsOriginalSaveFile(int slot) { } int numParts = (_flags.gameID == GI_EOB1) ? 12 : 17; - int partSize = (_flags.gameID == GI_EOB1) ? 2040 : 2130; - uint8 *tempData = new uint8[4096]; + int partSize = (_flags.platform == Common::kPlatformFMTowns) ? 5030 :(_flags.gameID == GI_EOB1) ? 2040 : 2130; + + uint8 *tempData = new uint8[5030]; uint8 *cmpData = new uint8[1200]; for (int i = 0; i < numParts; i++) { LevelTempData *l = _lvlTempData[i]; - memset(tempData, 0, 4096); + memset(tempData, 0, 5030); memset(cmpData, 0, 1200); if (!l || !(_hasTempDataFlags & (1 << i))) { @@ -1135,11 +1169,18 @@ bool EoBCoreEngine::saveAsOriginalSaveFile(int slot) { *d++ = l->wallsXorData[ii * len + iii] ^ p[ii * len + iii]; } - uint32 outsize = encodeFrame4(tempData, cmpData, 4096); - if (outsize > 1200) - error("Map compression failure: size of map = %d", outsize); + if (_flags.platform == Common::kPlatformFMTowns) { + out->write(tempData, 4096); + } else { + uint32 outsize = encodeFrame4(tempData, cmpData, 4096); + if (outsize > 1200) + error("Map compression failure: size of map = %d", outsize); + + out->write(cmpData, 1200); + } - out->write(cmpData, 1200); + if (_flags.platform == Common::kPlatformFMTowns) + out->writeUint32BE(0); for (int ii = 0; ii < 30; ii++) { EoBMonsterInPlay *m = &((EoBMonsterInPlay*)l->monsters)[ii]; diff --git a/engines/kyra/scene_eob.cpp b/engines/kyra/scene_eob.cpp index 6fac56f12c..c19f102e03 100644 --- a/engines/kyra/scene_eob.cpp +++ b/engines/kyra/scene_eob.cpp @@ -36,6 +36,8 @@ namespace Kyra { void EoBCoreEngine::loadLevel(int level, int sub) { _currentLevel = level; _currentSub = sub; + if (!_loading) + setHandItem(-1); uint32 end = _system->getMillis() + 500; readLevelFileData(level); @@ -99,12 +101,13 @@ void EoBCoreEngine::loadLevel(int level, int sub) { _sceneDrawPage1 = 2; _sceneDrawPage2 = 1; _screen->setCurPage(0); + setHandItem(_itemInHand); } void EoBCoreEngine::readLevelFileData(int level) { Common::String file; Common::SeekableReadStream *s = 0; - static const char *const suffix[] = { "INF", "DRO", "ELO", 0 }; + static const char *const suffix[] = { "INF", "DRO", "ELO", "JOT", 0 }; for (const char *const *sf = suffix; *sf && !s; sf++) { file = Common::String::format("LEVEL%d.%s", level, *sf); @@ -112,7 +115,7 @@ void EoBCoreEngine::readLevelFileData(int level) { } if (!s) - error("Failed to load level file LEVEL%d.INF/DRO/ELO", level); + error("Failed to load level file LEVEL%d.INF/DRO/ELO/JOT", level); if (s->readUint16LE() + 2 == s->size()) { if (s->readUint16LE() == 4) { @@ -148,7 +151,7 @@ Common::String EoBCoreEngine::initLevelData(int sub) { const char *vmpPattern = (_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.EMP" : "%s.VMP"; Common::SeekableReadStream *s = _res->createReadStream(Common::String::format(vmpPattern, (const char *)pos)); - uint16 size = s->readUint16LE(); + uint16 size = (_flags.platform == Common::kPlatformFMTowns) ? 2916 : s->readUint16LE(); delete[] _vmpPtr; _vmpPtr = new uint16[size]; for (int i = 0; i < size; i++) @@ -175,7 +178,15 @@ Common::String EoBCoreEngine::initLevelData(int sub) { if (_flags.gameID == GI_EOB2 || _configRenderMode != Common::kRenderEGA) _screen->loadPalette(tmpStr.c_str(), _screen->getPalette(0)); - if (_configRenderMode != Common::kRenderCGA) { + if (_flags.platform == Common::kPlatformFMTowns) { + uint16 *src = (uint16*)_screen->getPalette(0).getData(); + _screen->createFadeTable16bit(src, (uint16*)_greenFadingTable, 4, 75); + _screen->createFadeTable16bit(src, (uint16*)_blackFadingTable, 12, 200); + _screen->createFadeTable16bit(src, (uint16*)_blueFadingTable, 10, 85); + _screen->createFadeTable16bit(src, (uint16*)_lightBlueFadingTable, 11, 125); + _screen->createFadeTable16bit(src, (uint16*)_greyFadingTable, 0, 85); + _screen->setScreenPalette(_screen->getPalette(0)); + } else if (_configRenderMode != Common::kRenderCGA) { Palette backupPal(256); backupPal.copy(_screen->getPalette(0), 224, 32, 224); _screen->getPalette(0).fill(224, 32, 0x3F); @@ -283,7 +294,14 @@ void EoBCoreEngine::loadVcnData(const char *file, const uint8 *cgaMapping) { if (file) strcpy(_lastBlockDataFile, file); - const char *filePattern = (_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.ECN" : "%s.VCN"; + if (_flags.platform == Common::kPlatformFMTowns) { + uint32 size; + delete[] _vcnBlocks; + _vcnBlocks = _res->fileData(Common::String::format("%s.VCC", _lastBlockDataFile).c_str(), &size); + return; + } + + const char *filePattern = ((_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.ECN" : "%s.VCN"); _screen->loadBitmap(Common::String::format(filePattern, _lastBlockDataFile).c_str(), 3, 3, 0); const uint8 *pos = _screen->getCPagePtr(3); diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp index a746080190..c1579c3501 100644 --- a/engines/kyra/scene_lol.cpp +++ b/engines/kyra/scene_lol.cpp @@ -1425,7 +1425,7 @@ void LoLEngine::drawSceneShapes(int) { if (!(w & 8)) continue; - uint16 v = 20 * (s - (s < 23 ? _dscUnk2[s] : 0)); + uint16 v = 20 * (s - (s < 23 ? _dscDoorScaleOffs[s] : 0)); if (v > 80) v = 80; diff --git a/engines/kyra/scene_rpg.cpp b/engines/kyra/scene_rpg.cpp index dabc368a27..756f694a36 100644 --- a/engines/kyra/scene_rpg.cpp +++ b/engines/kyra/scene_rpg.cpp @@ -348,6 +348,7 @@ bool KyraRpgEngine::checkSceneUpdateNeed(int block) { void KyraRpgEngine::drawVcnBlocks() { uint8 *d = _sceneWindowBuffer; uint16 *bdb = _blockDrawingBuffer; + uint16 *hiColorPal = screen()->get16bitPalette(); for (int y = 0; y < 15; y++) { for (int x = 0; x < 22; x++) { @@ -369,9 +370,9 @@ void KyraRpgEngine::drawVcnBlocks() { vcnOffset &= 0x3FFF; } - uint8 *src = 0; + const uint8 *src = 0; if (vcnOffset) { - src = &_vcnBlocks[vcnOffset << 5]; + src = &_vcnBlocks[vcnOffset << (4 + _vcnBpp)]; wllVcnOffset = _wllVcnOffset; } else { // floor/ceiling blocks @@ -381,36 +382,46 @@ void KyraRpgEngine::drawVcnBlocks() { vcnOffset &= 0x3FFF; } - src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset << 5); + src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset << (4 + _vcnBpp)); } uint8 shift = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness; if (horizontalFlip) { for (int blockY = 0; blockY < 8; blockY++) { - src += 3; - for (int blockX = 0; blockX < 4; blockX++) { - uint8 bl = *src--; - *d++ = _vcnColTable[((bl & 0x0F) + wllVcnOffset) | shift]; - *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; + src += ((_vcnBpp << 2) - 1); + for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { + if (_vcnBpp == 2) { + *(uint16*)d = hiColorPal[*src--]; + d += 2; + } else { + uint8 bl = *src--; + *d++ = _vcnColTable[((bl & 0x0F) + wllVcnOffset) | shift]; + *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; + } } - src += 5; - d += 168; + src += ((_vcnBpp << 2) + 1); + d += 168 * _vcnBpp; } } else { for (int blockY = 0; blockY < 8; blockY++) { - for (int blockX = 0; blockX < 4; blockX++) { - uint8 bl = *src++; - *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; - *d++ = _vcnColTable[((bl & 0x0F) + wllVcnOffset) | shift]; + for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { + if (_vcnBpp == 2) { + *(uint16*)d = hiColorPal[*src++]; + d += 2; + } else { + uint8 bl = *src++; + *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift]; + *d++ = _vcnColTable[((bl & 0x0F) + wllVcnOffset) | shift]; + } } - d += 168; + d += 168 * _vcnBpp; } } - d -= 1400; + d -= 1400 * _vcnBpp; if (vcnExtraOffsetWll) { - d -= 8; + d -= 8 * _vcnBpp; horizontalFlip = false; if (vcnExtraOffsetWll & 0x4000) { @@ -419,62 +430,76 @@ void KyraRpgEngine::drawVcnBlocks() { } shift = _vcnShift ? _vcnShift[vcnExtraOffsetWll] : _blockBrightness; - src = &_vcnBlocks[vcnExtraOffsetWll << 5]; + src = &_vcnBlocks[vcnExtraOffsetWll << (4 + _vcnBpp)]; uint8 *maskTable = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll << 5] : 0; if (horizontalFlip) { for (int blockY = 0; blockY < 8; blockY++) { - src += 3; + src += ((_vcnBpp << 2) - 1); maskTable += 3; - for (int blockX = 0; blockX < 4; blockX++) { - uint8 bl = *src--; - uint8 mask = _vcnTransitionMask ? *maskTable-- : 0; - uint8 h = _vcnColTable[((bl & 0x0F) + wllVcnRmdOffset) | shift]; - uint8 l = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; - - if (_vcnTransitionMask) - *d = (*d & (mask & 0x0F)) | h; - else if (h) - *d = h; - d++; - - if (_vcnTransitionMask) - *d = (*d & (mask >> 4)) | l; - else if (l) - *d = l; - d++; + for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { + if (_vcnBpp == 2) { + uint8 bl = *src--; + if (bl) + *(uint16*)d = hiColorPal[bl]; + d += 2; + } else { + uint8 bl = *src--; + uint8 mask = _vcnTransitionMask ? *maskTable-- : 0; + uint8 h = _vcnColTable[((bl & 0x0F) + wllVcnRmdOffset) | shift]; + uint8 l = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; + + if (_vcnTransitionMask) + *d = (*d & (mask & 0x0F)) | h; + else if (h) + *d = h; + d++; + + if (_vcnTransitionMask) + *d = (*d & (mask >> 4)) | l; + else if (l) + *d = l; + d++; + } } - src += 5; + src += ((_vcnBpp << 2) + 1); maskTable += 5; - d += 168; + d += 168 * _vcnBpp; } } else { for (int blockY = 0; blockY < 8; blockY++) { - for (int blockX = 0; blockX < 4; blockX++) { - uint8 bl = *src++; - uint8 mask = _vcnTransitionMask ? *maskTable++ : 0; - uint8 h = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; - uint8 l = _vcnColTable[((bl & 0x0F) + wllVcnRmdOffset) | shift]; - - if (_vcnTransitionMask) - *d = (*d & (mask >> 4)) | h; - else if (h) - *d = h; - d++; - - if (_vcnTransitionMask) - *d = (*d & (mask & 0x0F)) | l; - else if (l) - *d = l; - d++; + for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) { + if (_vcnBpp == 2) { + uint8 bl = *src++; + if (bl) + *(uint16*)d = hiColorPal[bl]; + d += 2; + } else { + uint8 bl = *src++; + uint8 mask = _vcnTransitionMask ? *maskTable++ : 0; + uint8 h = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift]; + uint8 l = _vcnColTable[((bl & 0x0F) + wllVcnRmdOffset) | shift]; + + if (_vcnTransitionMask) + *d = (*d & (mask >> 4)) | h; + else if (h) + *d = h; + d++; + + if (_vcnTransitionMask) + *d = (*d & (mask & 0x0F)) | l; + else if (l) + *d = l; + d++; + } } - d += 168; + d += 168 * _vcnBpp; } } - d -= 1400; + d -= 1400 * _vcnBpp; } } - d += 1232; + d += 1232 * _vcnBpp; } screen()->copyBlockToPage(_sceneDrawPage1, _sceneXoffset, 0, 176, 120, _sceneWindowBuffer); diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index a0cab913b9..eb9ba016bd 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -739,10 +739,13 @@ void Screen::copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, } } -uint8 Screen::getPagePixel(int pageNum, int x, int y) { +int Screen::getPagePixel(int pageNum, int x, int y) { assert(pageNum < SCREEN_PAGE_NUM); assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H); - return _pagePtrs[pageNum][y * SCREEN_W + x]; + if (_bytesPerPixel == 1) + return _pagePtrs[pageNum][y * SCREEN_W + x]; + else + return ((uint16*)_pagePtrs[pageNum])[y * SCREEN_W + x]; } void Screen::setPagePixel(int pageNum, int x, int y, uint8 color) { @@ -762,7 +765,7 @@ void Screen::setPagePixel(int pageNum, int x, int y, uint8 color) { } if (_bytesPerPixel == 2) { - *(uint16*)(&_pagePtrs[pageNum][y * SCREEN_W * 2 + x * 2]) = _16bitPalette[color]; + ((uint16*)_pagePtrs[pageNum])[y * SCREEN_W + x] = _16bitPalette[color]; } else { _pagePtrs[pageNum][y * SCREEN_W + x] = color; } @@ -781,12 +784,12 @@ void Screen::fadeToBlack(int delay, const UpdateFunctor *upFunc) { } void Screen::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc) { - if (_renderMode == Common::kRenderEGA) + if (_renderMode == Common::kRenderEGA || _bytesPerPixel == 2) setScreenPalette(pal); updateScreen(); - if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) + if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA || _bytesPerPixel == 2) return; int diff = 0, delayInc = 0; @@ -1056,7 +1059,7 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *dest) { if (y < 0) { - dest += (-y) * w; + dest += (-y) * w * _bytesPerPixel; h += y; y = 0; } else if (y + h > SCREEN_H) { @@ -1064,7 +1067,7 @@ void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 * } if (x < 0) { - dest += -x; + dest += -x * _bytesPerPixel; w += x; x = 0; } else if (x + w > SCREEN_W) { @@ -1093,7 +1096,7 @@ void Screen::copyPage(uint8 srcPage, uint8 dstPage) { void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint8 *src) { if (y < 0) { - src += (-y) * w; + src += (-y) * w * _bytesPerPixel; h += y; y = 0; } else if (y + h > SCREEN_H) { @@ -1101,7 +1104,7 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint } if (x < 0) { - src += -x; + src += -x * _bytesPerPixel; w += x; x = 0; } else if (x + w > SCREEN_W) { @@ -1398,7 +1401,7 @@ int Screen::getFontWidth() const { int Screen::getCharWidth(uint16 c) const { const int width = _fonts[_currentFont]->getCharWidth(c); - return width + ((_currentFont != FID_SJIS_FNT) ? _charWidth : 0); + return width + ((_currentFont != FID_SJIS_FNT && _currentFont != FID_SJIS_LARGE_FNT && _currentFont != FID_SJIS_SMALL_FNT) ? _charWidth : 0); } int Screen::getTextWidth(const char *str) { @@ -1408,8 +1411,8 @@ int Screen::getTextWidth(const char *str) { FontId curFont = _currentFont; while (1) { - if (_sjisMixedFontMode) - setFont((*str & 0x80) ? FID_SJIS_FNT : curFont); + if (_sjisMixedFontMode && curFont != FID_SJIS_FNT && curFont != FID_SJIS_LARGE_FNT && curFont != FID_SJIS_SMALL_FNT) + setFont((*str & 0x80) ? ((_vm->game() == GI_EOB2 && curFont == FID_6_FNT) ? FID_SJIS_SMALL_FNT : FID_SJIS_FNT) : curFont); uint c = fetchChar(str); @@ -1455,8 +1458,8 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 return; while (1) { - if (_sjisMixedFontMode) - setFont((*str & 0x80) ? FID_SJIS_FNT : curFont); + if (_sjisMixedFontMode && curFont != FID_SJIS_FNT && curFont != FID_SJIS_LARGE_FNT && curFont != FID_SJIS_SMALL_FNT) + setFont((*str & 0x80) ? ((_vm->game() == GI_EOB2 && curFont == FID_6_FNT) ? FID_SJIS_SMALL_FNT : FID_SJIS_FNT) : curFont); uint8 charHeightFnt = getFontHeight(); @@ -1483,7 +1486,7 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 } uint16 Screen::fetchChar(const char *&s) const { - if (_currentFont != FID_SJIS_FNT) + if (_currentFont != FID_SJIS_FNT && _currentFont != FID_SJIS_LARGE_FNT && _currentFont != FID_SJIS_SMALL_FNT) return (uint8)*s++; uint16 ch = (uint8)*s++; @@ -1515,7 +1518,7 @@ void Screen::drawChar(uint16 c, int x, int y) { return; } - int bpp = (_currentFont == Screen::FID_SJIS_FNT) ? 1 : 2; + int bpp = (_currentFont == Screen::FID_SJIS_FNT || _currentFont == Screen::FID_SJIS_SMALL_FNT) ? 1 : 2; destPage += (y * 2) * 640 * bpp + (x * 2 * bpp); fnt->drawChar(c, destPage, 640, bpp); @@ -3472,7 +3475,7 @@ void Screen::copyOverlayRegion(int x, int y, int x2, int y2, int w, int h, int s while (h--) { for (x = 0; x < w; ++x) - memcpy(dst, src, w); + memmove(dst, src, w); dst += 640; src += 640; } @@ -3486,7 +3489,7 @@ void Screen::crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int s hideMouse(); uint16 *wB = (uint16 *)_pagePtrs[14]; - uint8 *hB = _pagePtrs[14] + 640; + uint8 *hB = _pagePtrs[14] + 640 * _bytesPerPixel; for (int i = 0; i < w; i++) wB[i] = i; @@ -3515,7 +3518,10 @@ void Screen::crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int s if (++iH >= h) iH = 0; - d[dY * 320 + dX] = s[sY * 320 + sX]; + if (_bytesPerPixel == 2) + ((uint16*)d)[dY * 320 + dX] = ((uint16*)s)[sY * 320 + sX]; + else + d[dY * 320 + dX] = s[sY * 320 + sX]; addDirtyRect(dX, dY, 1, 1); } @@ -3815,16 +3821,6 @@ void SJISFont::drawChar(uint16 c, byte *dst, int pitch, int) const { _font->drawChar(dst, c, 640, 1, color1, color2, 640, 400); } -SJISFontLarge::SJISFontLarge(Graphics::FontSJIS *font) : SJISFont(font, 0, false, false, false, 0) { - _sjisWidth = _font->getMaxFontWidth(); - _fontHeight = _font->getFontHeight(); - _asciiWidth = _font->getCharWidth('a'); -} - -void SJISFontLarge::drawChar(uint16 c, byte *dst, int pitch) const { - _font->drawChar(dst, c, 320, 1, _colorMap[1], _colorMap[0], 320, 200); -} - #pragma mark - Palette::Palette(const int numColors) : _palData(0), _numColors(numColors) { diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index bac93ae49c..44113e4372 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -145,10 +145,10 @@ private: #ifdef ENABLE_EOB /** - * Implementation of the Font interface for old DOS fonts used - * in EOB and EOB II. - * - */ +* Implementation of the Font interface for old DOS fonts used +* in EOB and EOB II. +* +*/ class OldDOSFont : public Font { public: OldDOSFont(Common::RenderMode mode); @@ -249,18 +249,6 @@ private: const int _sjisWidthOffset; }; -/** -* SJISFont variant used in the intro and outro of EOB II FM-Towns. It appears twice as large, since it is not rendered on the hires overlay pages -*/ -class SJISFontLarge : public SJISFont { -public: - SJISFontLarge(Graphics::FontSJIS *font); - virtual ~SJISFontLarge() { unload(); } - - virtual bool usesOverlay() const { return false; } - virtual void drawChar(uint16 c, byte *dst, int pitch) const; -}; - /** * A class that manages KYRA palettes. * @@ -426,6 +414,7 @@ public: FID_INTRO_FNT, FID_SJIS_FNT, FID_SJIS_LARGE_FNT, + FID_SJIS_SMALL_FNT, FID_NUM }; @@ -466,7 +455,7 @@ public: void clearPage(int pageNum); - uint8 getPagePixel(int pageNum, int x, int y); + int getPagePixel(int pageNum, int x, int y); void setPagePixel(int pageNum, int x, int y, uint8 color); const uint8 *getCPagePtr(int pageNum) const; @@ -499,7 +488,7 @@ public: void drawBox(int x1, int y1, int x2, int y2, int color); // font/text handling - bool loadFont(FontId fontId, const char *filename); + virtual bool loadFont(FontId fontId, const char *filename); FontId setFont(FontId fontId); int getFontHeight() const; @@ -584,6 +573,7 @@ public: // RPG specific, this does not belong here void crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage); + uint16 *get16bitPalette() { return _16bitPalette; } void set16bitShadingLevel(int lvl) { _16bitShadingLevel = lvl; } protected: diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp index 88c53fdb7b..e24f6219a9 100644 --- a/engines/kyra/screen_eob.cpp +++ b/engines/kyra/screen_eob.cpp @@ -34,6 +34,7 @@ #include "graphics/cursorman.h" #include "graphics/palette.h" +#include "graphics/sjis.h" namespace Kyra { @@ -46,7 +47,7 @@ Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _gfxX = _gfxY = 0; _gfxCol = 0; _dsTempPage = 0; - _convertHiColorBuffer = 0; + _shpBuffer = _convertHiColorBuffer = 0; _dsDiv = 0; _dsRem = 0; _dsScaleTrans = 0; @@ -61,6 +62,7 @@ Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, Screen_EoB::~Screen_EoB() { delete[] _dsTempPage; + delete[] _shpBuffer; delete[] _convertHiColorBuffer; delete[] _cgaScaleTable; delete[] _egaDitheringTable; @@ -73,12 +75,21 @@ bool Screen_EoB::init() { if (Screen::init()) { int temp; _gfxMaxY = _vm->staticres()->loadRawData(kEoBBaseExpObjectY, temp); - _dsTempPage = new uint8[12000]; if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + _shpBuffer = new uint8[SCREEN_H * SCREEN_W]; _convertHiColorBuffer = new uint8[SCREEN_H * SCREEN_W]; + enableHiColorMode(true); + + Graphics::FontSJIS *font = Graphics::FontSJIS::createFont(Common::kPlatformFMTowns); + if (!font) + error("Could not load any SJIS font, neither the original nor ScummVM's 'SJIS.FNT'"); + _fonts[FID_SJIS_LARGE_FNT] = new SJISFontLarge(font); + + loadFont(FID_SJIS_SMALL_FNT, "FONT.DMP"); } + if (_vm->gameFlags().useHiRes && _renderMode == Common::kRenderEGA) { _useHiResEGADithering = true; _egaDitheringTable = new uint8[256]; @@ -124,19 +135,28 @@ void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ov int mouseH = (shape[3]); int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : _cursorColorKey; - int scaleFactor = _useHiResEGADithering ? 2 : 1; + int scaleFactor = _vm->gameFlags().useHiRes ? 2 : 1; int bpp = _useHiColorScreen ? 2 : 1; uint8 *cursor = new uint8[mouseW * scaleFactor * bpp * mouseH * scaleFactor]; - // We use memset and copyBlockToPage instead of fillRect to make sure that the - // color key 0xFF doesn't get converted into EGA color - memset(cursor, colorKey, mouseW * scaleFactor * bpp * mouseH * scaleFactor); + + if (_bytesPerPixel == 2) { + colorKey = _16bitPalette[colorKey]; + for (int s = mouseW * scaleFactor * bpp * mouseH * scaleFactor; s; s -= 2) + *(uint16*)(cursor + s - 2) = colorKey; + } else { + // We don't use fillRect here to make sure that the color key 0xFF doesn't get converted into EGA color + memset(cursor, colorKey, mouseW * scaleFactor * bpp * mouseH * scaleFactor); + } + copyBlockToPage(6, 0, 0, mouseW * scaleFactor, mouseH * scaleFactor, cursor); drawShape(6, shape, 0, 0, 0, 2, ovl); CursorMan.showMouse(false); if (_useHiResEGADithering) ditherRect(getCPagePtr(6), cursor, mouseW * scaleFactor, mouseW, mouseH, colorKey); + else if (_vm->gameFlags().useHiRes) + scale2x(cursor, mouseW * scaleFactor, getCPagePtr(6), SCREEN_W, mouseW, mouseH); else copyRegionToBuffer(6, 0, 0, mouseW, mouseH, cursor); @@ -185,9 +205,13 @@ void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, } void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2) { - printText(string, x - 1, y, 12, col2); - printText(string, x, y + 1, 12, 0); - printText(string, x - 1, y + 1, 12, 0); + if (_vm->gameFlags().platform != Common::kPlatformFMTowns) { + printText(string, x - 1, y, 12, col2); + printText(string, x, y + 1, 12, 0); + printText(string, x - 1, y + 1, 12, 0); + } else if (col2) { + fillRect(x, y, x + getTextWidth(string) - 1, y + getFontHeight() - 1, col2); + } printText(string, x, y, col1, 0); } @@ -197,22 +221,28 @@ void Screen_EoB::loadShapeSetBitmap(const char *file, int tempPage, int destPage } void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage) { - const char *filePattern = (_vm->game() == GI_EOB1 && (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA)) ? "%s.EGA" : "%s.CPS"; + const char *filePattern = _vm->gameFlags().platform == Common::kPlatformFMTowns ? "%s.SHP" : ((_vm->game() == GI_EOB1 && (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA)) ? "%s.EGA" : "%s.CPS"); Common::String tmp = Common::String::format(filePattern, file); Common::SeekableReadStream *s = _vm->resource()->createReadStream(tmp); bool loadAlternative = false; - if (s) { + + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + if (!s) + error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file); + s->read(_shpBuffer, s->size()); + decodeSHP(_shpBuffer, destPage); + } else if (s) { // This additional check is necessary since some localized versions of EOB II seem to contain invalid (size zero) cps files if (s->size()) loadBitmap(tmp.c_str(), tempPage, destPage, 0); else loadAlternative = true; - - delete s; } else { loadAlternative = true; } + delete s; + if (loadAlternative) { if (_vm->game() == GI_EOB1) { tmp.insertChar('1', tmp.size() - 4); @@ -279,7 +309,7 @@ void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) void Screen_EoB::setScreenPalette(const Palette &pal) { if (_bytesPerPixel == 2) { for (int i = 0; i < 4; i++) - createFadeTable16bit((const uint16*)(pal.getData()), &_16bitPalette[i * 256], 0, i * 53); + createFadeTable16bit((const uint16*)(pal.getData()), &_16bitPalette[i * 256], 0, i * 85); }else if (_useHiResEGADithering && pal.getNumColors() != 16) { generateEGADitheringTable(pal); } else if (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16) { @@ -315,7 +345,7 @@ uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool enco if (_renderMode == Common::kRenderEGA && !_useHiResEGADithering) encode8bit = false; - if (_bytesPerPixel == 2) { + if (_bytesPerPixel == 2 && encode8bit) { shapesize = h * (w << 3) + 4; shp = new uint8[shapesize]; memset(shp, 0, shapesize); @@ -890,6 +920,12 @@ const uint8 *Screen_EoB::generateShapeOverlay(const uint8 *shp, const uint8 *fad if (*shp != 2) return 0; + if (_bytesPerPixel == 2) { + setFadeTable(fadingTable); + setShapeFadingLevel(1); + return 0; + } + shp += 4; for (int i = 0; i < 16; i++) _shapeOverlay[i] = fadingTable[shp[i]]; @@ -963,8 +999,12 @@ void Screen_EoB::drawExplosion(int scale, int radius, int numElements, int stepS int16 py = ((ptr3[i] >> 6) >> scale) + gy2; if (py > ymax) py = ymax; - if (posWithinRect(px, py, rX1, rY1, rX2, rY2)) - setPagePixel(0, px, py, ptr6[i]); + if (posWithinRect(px, py, rX1, rY1, rX2, rY2)) { + if (_bytesPerPixel == 2) + setPagePixel16bit(0, px, py, ptr6[i]); + else + setPagePixel(0, px, py, ptr6[i]); + } } } @@ -1094,7 +1134,10 @@ void Screen_EoB::drawVortex(int numElements, int radius, int stepSize, int, int for (int ii = numElements - 1; ii >= 0; ii--) { int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1); int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1); - setPagePixel(0, px, py, pixBackup[ii]); + if (_bytesPerPixel == 2) + setPagePixel16bit(0, px, py, pixBackup[ii]); + else + setPagePixel(0, px, py, pixBackup[ii]); } } @@ -1219,6 +1262,8 @@ int Screen_EoB::getRectSize(int w, int h) { void Screen_EoB::setFadeTable(const uint8 *table) { _dsShapeFadingTable = table; + if (_bytesPerPixel == 2) + memcpy(&_16bitPalette[0x100], table, 512); } void Screen_EoB::createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) { @@ -1265,6 +1310,7 @@ void Screen_EoB::createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootCol } void Screen_EoB::createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 rootColor, uint8 weight) { + rootColor = palData[rootColor]; uint8 r8 = (rootColor & 0x1f); uint8 g8 = (rootColor & 0x3E0) >> 5; uint8 b8 = (rootColor & 0x7C00) >> 10; @@ -1320,7 +1366,6 @@ void Screen_EoB::createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 *dst++ = (b8 << 10) | (g8 << 5) | r8; } - } const uint16 *Screen_EoB::getCGADitheringTable(int index) { @@ -1331,10 +1376,69 @@ const uint8 *Screen_EoB::getEGADitheringTable() { return _egaDitheringTable; } +bool Screen_EoB::loadFont(FontId fontId, const char *filename) { + if (scumm_stricmp(filename, "FONT.DMP")) + return Screen::loadFont(fontId, filename); + + Font *&fnt = _fonts[fontId]; + int temp; + + const uint16 *tbl = _vm->staticres()->loadRawDataBe16(kEoB2FontDmpSearchTbl, temp); + assert(tbl); + + if (!fnt) { + fnt = new SJISFont12x12(tbl); + assert(fnt); + } + + Common::SeekableReadStream *file = _vm->resource()->createReadStream(filename); + if (!file) + error("Font file '%s' is missing", filename); + + bool ret = fnt->load(*file); + fnt->setColorMap(_textColorsMap); + delete file; + return ret; +} + +void Screen_EoB::decodeSHP(const uint8 *data, int dstPage) { + int32 bytesLeft = READ_LE_UINT32(data); + const uint8 *src = data + 4; + uint8 *dst = getPagePtr(dstPage); + + if (bytesLeft < 0) { + memcpy(dst, data, 64000); + return; + } + + while (bytesLeft > 0) { + uint8 code = *src++; + bytesLeft--; + + for (int i = 8; i; i--) { + if (code & 0x80) { + uint16 copyOffs = (src[0] << 4) | (src[1] >> 4); + uint8 count = (src[1] & 0x0F) + 3; + src += 2; + bytesLeft -= 2; + const uint8 *copySrc = dst - 1 - copyOffs; + while (count--) + *dst++ = *copySrc++; + } else if (bytesLeft) { + *dst++ = *src++; + bytesLeft--; + } else { + break; + } + code <<= 1; + } + } +} + void Screen_EoB::convertToHiColor(int page) { if (!_16bitPalette) return; - uint16 *dst = (uint16 *)getCPagePtr(page); + uint16 *dst = (uint16 *)getPagePtr(page); memcpy(_convertHiColorBuffer, dst, SCREEN_H * SCREEN_W); uint8 *src = _convertHiColorBuffer; for (int s = SCREEN_H * SCREEN_W; s; --s) @@ -1483,6 +1587,17 @@ bool Screen_EoB::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y return true; } +void Screen_EoB::setPagePixel16bit(int pageNum, int x, int y, uint16 color) { + assert(pageNum < SCREEN_PAGE_NUM); + assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H); + assert(_bytesPerPixel == 2); + + if (pageNum == 0 || pageNum == 1) + addDirtyRect(x, y, 1, 1); + + ((uint16*)_pagePtrs[pageNum])[y * SCREEN_W + x] = color; +} + void Screen_EoB::generateEGADitheringTable(const Palette &pal) { assert(_egaDitheringTable); const uint8 *src = pal.getData(); @@ -1795,6 +1910,66 @@ void OldDOSFont::unload() { _bitmapOffsets = 0; } +SJISFontLarge::SJISFontLarge(Graphics::FontSJIS *font) : SJISFont(font, 0, false, false, false, 0) { + _sjisWidth = _font->getMaxFontWidth(); + _fontHeight = _font->getFontHeight(); + _asciiWidth = _font->getCharWidth('a'); +} + +void SJISFontLarge::drawChar(uint16 c, byte *dst, int pitch, int) const { + _font->drawChar(dst, c, 320, 1, _colorMap[1], _colorMap[0], 320, 200); +} + +SJISFont12x12::SJISFont12x12(const uint16 *searchTable) : _height(6), _width(6), _data(0) { + assert(searchTable); + for (int i = 0; i < 148; i++) + _searchTable[searchTable[i]] = i + 1; +} + +bool SJISFont12x12::load(Common::SeekableReadStream &file) { + delete[] _data; + int size = 148 * 24; + if (file.size() < size) + return false; + + _data = new uint8[size]; + file.read(_data, size); + + return true; +} + +void SJISFont12x12::unload() { + delete[] _data; + _data = 0; + _searchTable.clear(); +} + +void SJISFont12x12::drawChar(uint16 c, byte *dst, int pitch, int) const { + int offs = _searchTable[c]; + if (!offs) + return; + + const uint8 *src = _data + (offs - 1) * 24; + uint8 color1 = _colorMap[1]; + + int bt = 0; + uint16 chr = 0; + + for (int i = 0; i < 192; ++i) { + if (!bt) { + chr = *src++; + bt = 8; + } + if (chr & 0x80) + *dst = color1; + dst++; + if (--bt) + chr <<= 1; + else if (i & 8) + dst += (pitch - 16); + } +} + } // End of namespace Kyra #endif // ENABLE_EOB diff --git a/engines/kyra/screen_eob.h b/engines/kyra/screen_eob.h index 7c2a31e9d3..f213fc985e 100644 --- a/engines/kyra/screen_eob.h +++ b/engines/kyra/screen_eob.h @@ -82,8 +82,13 @@ public: const uint16 *getCGADitheringTable(int index); const uint8 *getEGADitheringTable(); + bool loadFont(FontId fontId, const char *filename); + + // FM-Towns specific + void decodeSHP(const uint8 *data, int dstPage); void convertToHiColor(int page); void shadeRect(int x1, int y1, int x2, int y2, int shadingLevel); + private: void updateDirtyRects(); void ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey = -1); @@ -93,13 +98,15 @@ private: void scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src); bool posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2); + void setPagePixel16bit(int pageNum, int x, int y, uint16 color); + void generateEGADitheringTable(const Palette &pal); void generateCGADitheringTables(const uint8 *mappingData); int _dsDiv, _dsRem, _dsScaleTrans; uint8 *_cgaScaleTable; int16 _gfxX, _gfxY; - uint8 _gfxCol; + uint16 _gfxCol; const uint8 *_gfxMaxY; int16 _dsX1, _dsX2, _dsY1, _dsY2; @@ -109,6 +116,7 @@ private: uint8 _shapeOverlay[16]; uint8 *_dsTempPage; + uint8 *_shpBuffer; uint8 *_convertHiColorBuffer; uint16 *_cgaDitheringTables[2]; @@ -122,6 +130,44 @@ private: static const int _screenDimTableCount; }; +/** +* SJIS Font variant used in the intro and outro of EOB II FM-Towns. It appears twice as large, since it is not rendered on the hires overlay pages +*/ +class SJISFontLarge : public SJISFont { +public: + SJISFontLarge(Graphics::FontSJIS *font); + virtual ~SJISFontLarge() { unload(); } + + virtual bool usesOverlay() const { return false; } + virtual void drawChar(uint16 c, byte *dst, int pitch, int) const; +}; + +/** +* 12 x 12 SJIS font for EOB II FM-Towns. The data for this font comes from a file, not from the font rom. +*/ +class SJISFont12x12 : public Font { +public: + SJISFont12x12(const uint16 *searchTable); + virtual ~SJISFont12x12() { unload(); } + + virtual bool load(Common::SeekableReadStream &file); + virtual bool usesOverlay() const { return true; } + virtual int getHeight() const { return _height; } + virtual int getWidth() const { return _width; } + virtual int getCharWidth(uint16 c) const { return _width; } + virtual void setColorMap(const uint8 *src) { _colorMap = src; } + virtual void drawChar(uint16 c, byte *dst, int pitch, int) const; + +private: + void unload(); + + uint8 *_data; + Common::HashMap _searchTable; + + const uint8 *_colorMap; + const int _height, _width; +}; + } // End of namespace Kyra #endif // ENABLE_EOB diff --git a/engines/kyra/script_eob.cpp b/engines/kyra/script_eob.cpp index 455180b5e1..eb1eb7d39c 100644 --- a/engines/kyra/script_eob.cpp +++ b/engines/kyra/script_eob.cpp @@ -1495,7 +1495,8 @@ int EoBInfProcessor::oeob_sequence(int8 *data) { break; case -1: - _vm->_runFlag = _vm->checkPassword(); + if (_vm->gameFlags().platform == Common::kPlatformDOS) + _vm->_runFlag = _vm->checkPassword(); break; default: diff --git a/engines/kyra/sequences_darkmoon.cpp b/engines/kyra/sequences_darkmoon.cpp index befa8aa6a6..2f99ffe41d 100644 --- a/engines/kyra/sequences_darkmoon.cpp +++ b/engines/kyra/sequences_darkmoon.cpp @@ -41,18 +41,7 @@ public: kFinale }; - struct Config { - Config(Mode m, const char *const *str, const char *const *cps, const char *const *pal, const DarkMoonShapeDef **shp, const DarkMoonAnimCommand **anim, bool paletteFading) : mode(m), strings(str), cpsFiles(cps), palFiles(pal), shapeDefs(shp), animData(anim), palFading(paletteFading) {} - Mode mode; - const char *const *strings; - const char *const *cpsFiles; - const char *const *palFiles; - const DarkMoonShapeDef **shapeDefs; - const DarkMoonAnimCommand **animData; - bool palFading; - }; - - DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, const Config *config); + DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, Mode mode); ~DarkmoonSequenceHelper(); void loadScene(int index, int pageNum); @@ -79,9 +68,28 @@ private: OSystem *_system; DarkMoonEngine *_vm; Screen_EoB *_screen; + + struct Config { + Config(const char *const *str, const char *const *cpsfiles, const uint8 **cpsdata, const char *const *pal, const DarkMoonShapeDef **shp, const DarkMoonAnimCommand **anim, bool loadScenePalette, bool paletteFading, bool animCmdRestorePalette, bool shapeBackgroundFading, int animPalOffset, int animType1ShapeDim, bool animCmd5SetPalette, int animCmd5ExtraPage) : strings(str), cpsFiles(cpsfiles), cpsData(cpsdata), palFiles(pal), shapeDefs(shp), animData(anim), loadScenePal(loadScenePalette), palFading(paletteFading), animCmdRestorePal(animCmdRestorePalette), shpBackgroundFading(shapeBackgroundFading), animPalOffs(animPalOffset), animCmd1ShapeFrame(animType1ShapeDim), animCmd5SetPal(animCmd5SetPalette), animCmd5AltPage(animCmd5ExtraPage) {} + const char *const *strings; + const char *const *cpsFiles; + const uint8 **cpsData; + const char *const *palFiles; + const DarkMoonShapeDef **shapeDefs; + const DarkMoonAnimCommand **animData; + bool loadScenePal; + bool palFading; + bool animCmdRestorePal; + bool shpBackgroundFading; + int animPalOffs; + int animCmd1ShapeFrame; + bool animCmd5SetPal; + int animCmd5AltPage; + }; + const Config *_config; - Palette *_palettes[12]; + Palette *_palettes[13]; uint8 *_fadingTables[7]; const uint8 **_shapes; @@ -89,13 +97,22 @@ private: uint32 _fadePalTimer; int _fadePalRate; int _fadePalIndex; + + Screen::FontId _prevFont; + + static const char *const _palFilesIntroVGA[]; + static const char *const _palFilesIntroEGA[]; + static const char *const _palFilesFinaleVGA[]; + static const char *const _palFilesFinaleEGA[]; }; int DarkMoonEngine::mainMenu() { int menuChoice = _menuChoiceInit; _menuChoiceInit = 0; + _sound->selectAudioResourceSet(kMusicIntro); _sound->loadSoundFile("INTRO"); + Screen::FontId of = _screen->_currentFont; int op = 0; Common::SeekableReadStream *s = 0; @@ -103,17 +120,23 @@ int DarkMoonEngine::mainMenu() { while (menuChoice >= 0 && !shouldQuit()) { switch (menuChoice) { case 0: { - s = _res->createReadStream("XENU.CPS"); - if (s) { - s->read(_screen->getPalette(0).getData(), 768); - _screen->loadFileDataToPage(s, 3, 64000); - delete s; + if (_flags.platform == Common::kPlatformFMTowns) { + _screen->loadPalette("MENU.PAL", _screen->getPalette(0)); + _screen->setScreenPalette(_screen->getPalette(0)); + _screen->loadEoBBitmap("MENU", 0, 3, 3, 2); } else { - _screen->loadBitmap("MENU.CPS", 3, 3, &_screen->getPalette(0)); - } + s = _res->createReadStream("XENU.CPS"); + if (s) { + s->read(_screen->getPalette(0).getData(), 768); + _screen->loadFileDataToPage(s, 3, 64000); + delete s; + } else { + _screen->loadBitmap("MENU.CPS", 3, 3, &_screen->getPalette(0)); + } - if (_configRenderMode == Common::kRenderEGA) - _screen->loadPalette("MENU.EGA", _screen->getPalette(0)); + if (_configRenderMode == Common::kRenderEGA) + _screen->loadPalette("MENU.EGA", _screen->getPalette(0)); + } _screen->setScreenPalette(_screen->getPalette(0)); _screen->convertPage(3, 2, 0); @@ -121,10 +144,11 @@ int DarkMoonEngine::mainMenu() { of = _screen->setFont(Screen::FID_6_FNT); op = _screen->setCurPage(2); Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion)); - _screen->printText(versionString.c_str(), 267 - versionString.size() * 6, 160, 13, 0); + _screen->printText(versionString.c_str(), 267 - versionString.size() * 6, _flags.platform == Common::kPlatformFMTowns ? 152 : 160, 13, 0); _screen->setFont(of); _screen->_curPage = op; _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); + _screen->shadeRect(78, 99, 249, 141, 4); _screen->updateScreen(); _allowImport = true; menuChoice = mainMenuLoop(); @@ -172,12 +196,30 @@ int DarkMoonEngine::mainMenuLoop() { sel = _gui->simpleMenu_process(6, _mainMenuStrings, 0, -1, 0); } while ((sel < 0 || sel > 5) && !shouldQuit()); + if (_flags.platform == Common::kPlatformFMTowns && sel == 2) { + townsUtilitiesMenu(); + sel = -1; + } + return sel + 1; } +void DarkMoonEngine::townsUtilitiesMenu() { + _screen->copyRegion(78, 99, 78, 99, 172, 43, 2, 0, Screen::CR_NO_P_CHECK); + int sel = -1; + do { + _gui->simpleMenu_setup(8, 0, _utilMenuStrings, -1, 0, 0); + while (sel == -1 && !shouldQuit()) + sel = _gui->simpleMenu_process(8, _utilMenuStrings, 0, -1, 0); + if (sel == 0) { + _config2431 ^= true; + sel = -1; + } + } while ((sel < 0 || sel > 1) && !shouldQuit()); +} + void DarkMoonEngine::seq_playIntro() { - DarkmoonSequenceHelper::Config config(DarkmoonSequenceHelper::kIntro, _introStrings, _cpsFilesIntro, _configRenderMode == Common::kRenderEGA ? _palFilesIntroEGA : _palFilesIntroVGA, _shapesIntro, _animIntro, false); - DarkmoonSequenceHelper sq(_system, this, _screen, &config); + DarkmoonSequenceHelper sq(_system, this, _screen, DarkmoonSequenceHelper::kIntro); _screen->setCurPage(0); _screen->clearCurPage(); @@ -206,13 +248,13 @@ void DarkMoonEngine::seq_playIntro() { sq.animCommand(6, 18); sq.animCommand(0); - sq.waitForSongNotifier(1); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 229 : 1); sq.animCommand(_configRenderMode == Common::kRenderEGA ? 12 : 11); sq.animCommand(7, 6); sq.animCommand(2, 6); - sq.waitForSongNotifier(2); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 447 : 2); sq.animCommand(_configRenderMode == Common::kRenderEGA ? 39 : 38); sq.animCommand(3); @@ -221,7 +263,7 @@ void DarkMoonEngine::seq_playIntro() { sq.animCommand(0, 6); sq.animCommand(2); - sq.waitForSongNotifier(3); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 670 : 3); _screen->setClearScreenDim(17); _screen->setCurPage(2); @@ -249,7 +291,7 @@ void DarkMoonEngine::seq_playIntro() { sq.printText(3, 16); // The message was urgent. sq.loadScene(1, 2); - sq.waitForSongNotifier(4); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 1380 : 4); // intro scroll if (!skipFlag() && !shouldQuit()) { @@ -310,7 +352,7 @@ void DarkMoonEngine::seq_playIntro() { sq.animCommand(14); sq.loadScene(5, 2); - sq.waitForSongNotifier(5); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2037 : 5); sq.fadeText(); _screen->clearCurPage(); @@ -365,7 +407,7 @@ void DarkMoonEngine::seq_playIntro() { sq.loadScene(9, 2); sq.fadeText(); - sq.waitForSongNotifier(6); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 3000 : 6); sq.update(2); sq.animCommand(34); @@ -470,12 +512,12 @@ void DarkMoonEngine::seq_playIntro() { sq.fadeText(); sq.animCommand(29); - sq.waitForSongNotifier(7); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 4475 : 7); sq.animCommand(30); sq.animCommand(31); - sq.waitForSongNotifier(8, true); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 4825 : 8, true); if (skipFlag() || shouldQuit()) { snd_fadeOut(); @@ -496,17 +538,16 @@ void DarkMoonEngine::seq_playIntro() { } void DarkMoonEngine::seq_playFinale() { - DarkmoonSequenceHelper::Config config(DarkmoonSequenceHelper::kFinale, _finaleStrings, _cpsFilesFinale, _configRenderMode == Common::kRenderEGA ? _palFilesFinaleEGA : _palFilesFinaleVGA, _shapesFinale, _animFinale, true); - DarkmoonSequenceHelper sq(_system, this, _screen, &config); + DarkmoonSequenceHelper sq(_system, this, _screen, DarkmoonSequenceHelper::kFinale); _screen->setCurPage(0); - _screen->setFont(Screen::FID_8_FNT); - _sound->loadSoundFile("FINALE1"); + _sound->loadSoundFile(_flags.platform == Common::kPlatformFMTowns ? "FINALE" : "FINALE1"); snd_stopSound(); sq.delay(3); _screen->clearCurPage(); + _screen->clearPage(2); _screen->updateScreen(); sq.loadScene(0, 2); @@ -532,7 +573,7 @@ void DarkMoonEngine::seq_playFinale() { sq.fadeText(); sq.animCommand(2); - sq.waitForSongNotifier(1); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 475 : 1); sq.printText(1, 10); // Suddenly, your friend Khelben appears sq.animCommand(4); @@ -624,7 +665,7 @@ void DarkMoonEngine::seq_playFinale() { sq.loadScene(4, 2); - sq.waitForSongNotifier(2); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2030 : 2); _screen->clearCurPage(); sq.update(2); @@ -637,7 +678,7 @@ void DarkMoonEngine::seq_playFinale() { sq.delay(90); sq.fadeText(); - sq.waitForSongNotifier(3); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2200 : 3); if (!skipFlag() && !shouldQuit()) snd_playSoundEffect(7); @@ -669,7 +710,7 @@ void DarkMoonEngine::seq_playFinale() { sq.delay(72); sq.fadeText(); - sq.waitForSongNotifier(4); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2752 : 4); if (!skipFlag() && !shouldQuit()) snd_playSoundEffect(7); @@ -703,7 +744,7 @@ void DarkMoonEngine::seq_playFinale() { sq.fadeText(); sq.loadScene(12, 2); - sq.waitForSongNotifier(5); + sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 3475 : 5); if (!skipFlag() && !shouldQuit()) snd_playSoundEffect(6); @@ -782,16 +823,24 @@ void DarkMoonEngine::seq_playFinale() { sq.loadScene(10, 2); sq.loadScene(9, 2); + snd_stopSound(); sq.delay(3); - _sound->loadSoundFile("FINALE2"); + if (_flags.platform != Common::kPlatformFMTowns) + _sound->loadSoundFile("FINALE2"); sq.delay(18); if (!skipFlag() && !shouldQuit()) - snd_playSong(1); + snd_playSong(_flags.platform == Common::kPlatformFMTowns ? 16 : 1); - seq_playCredits(&sq, _creditsData, 18, 2, 6, 2); + int temp = 0; + const uint8 *creditsData = (_flags.platform == Common::kPlatformFMTowns) ? _res->fileData("CREDITS.TXT", 0) : _staticres->loadRawData(kEoB2CreditsData, temp); + + seq_playCredits(&sq, creditsData, 18, 2, 6, 2); + + if (_flags.platform == Common::kPlatformFMTowns) + delete[] creditsData; sq.delay(90); @@ -817,6 +866,9 @@ void DarkMoonEngine::seq_playFinale() { _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); + if (_flags.platform == Common::kPlatformFMTowns) + sq.copyPalette(12, 0); + sq.setPalette(9); sq.fadePalette(0, 18); @@ -831,7 +883,9 @@ void DarkMoonEngine::seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *da if (!data) return; + _screen->setFont(Screen::FID_8_FNT); _screen->setScreenDim(sd); + const ScreenDim *dm = _screen->_curDim; _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 0, backupPage, Screen::CR_NO_P_CHECK); @@ -955,8 +1009,74 @@ void DarkMoonEngine::seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *da delete[] items[i].str; } -DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, const Config *config) : - _system(system), _vm(vm), _screen(screen), _config(config) { +DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, Mode mode) : + _system(system), _vm(vm), _screen(screen) { + + int size = 0; + + if (mode == kIntro) { + _config = new Config( + _vm->staticres()->loadStrings(kEoB2IntroStrings, size), + _vm->staticres()->loadStrings(kEoB2IntroCPSFiles, size), + new const uint8*[13], + _vm->_configRenderMode == Common::kRenderEGA ? _palFilesIntroEGA : _palFilesIntroVGA, + new const DarkMoonShapeDef*[13], + new const DarkMoonAnimCommand *[44], + false, + false, + true, + true, + 0, + 0, + false, + 2 + ); + + for (int i = 0; i < 44; i++) + _config->animData[i] = _vm->staticres()->loadEoB2SeqData(kEoB2IntroAnimData00 + i, size); + + for (int i = 0; i < 13; i++) + _config->cpsData[i] = _vm->staticres()->loadRawData(kEoB2IntroCpsDataStreet1 + i, size); + + memset(_config->shapeDefs, 0, 13 * sizeof(DarkMoonShapeDef*)); + _config->shapeDefs[0] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes00, size); + _config->shapeDefs[1] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes01, size); + _config->shapeDefs[4] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes04, size); + _config->shapeDefs[7] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes07, size); + + } else { + _config = new Config( + _vm->staticres()->loadStrings(kEoB2FinaleStrings, size), + _vm->staticres()->loadStrings(kEoB2FinaleCPSFiles, size), + new const uint8*[13], + _vm->_configRenderMode == Common::kRenderEGA ? _palFilesFinaleEGA : _palFilesFinaleVGA, + new const DarkMoonShapeDef*[13], + new const DarkMoonAnimCommand *[21], + true, + true, + false, + false, + 1, + 18, + true, + 6 + ); + + for (int i = 0; i < 21; i++) + _config->animData[i] = _vm->staticres()->loadEoB2SeqData(kEoB2FinaleAnimData00 + i, size); + + for (int i = 0; i < 13; i++) + _config->cpsData[i] = _vm->staticres()->loadRawData(kEoB2FinaleCpsDataDragon1 + i, size); + + memset(_config->shapeDefs, 0, 13 * sizeof(DarkMoonShapeDef*)); + _config->shapeDefs[0] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes00, size); + _config->shapeDefs[3] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes03, size); + _config->shapeDefs[7] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes07, size); + _config->shapeDefs[9] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes09, size); + _config->shapeDefs[10] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes10, size); + } + + _screen->enableHiColorMode(false); for (int i = 0; _config->palFiles[i]; i++) { if (i < 4) @@ -966,13 +1086,16 @@ DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine * _screen->loadPalette(_config->palFiles[i], *_palettes[i]); } - _palettes[9] = new Palette(256); + for (int i = 9; i < 13; ++i) + _palettes[i] = new Palette(256); + _palettes[9]->fill(0, 256, 0); - _palettes[10] = new Palette(256); _palettes[10]->fill(0, 256, 63); - _palettes[11] = new Palette(256); _palettes[11]->fill(0, 256, 0); + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) + _screen->loadPalette("PALETTE.COL", *_palettes[12]); + for (int i = 0; i < 7; i++) _fadingTables[i] = 0; @@ -1001,7 +1124,7 @@ DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine * _fadePalRate = 0; _screen->setScreenPalette(*_palettes[0]); - _screen->setFont(Screen::FID_8_FNT); + _prevFont = _screen->setFont(_vm->gameFlags().platform == Common::kPlatformFMTowns ? Screen::FID_SJIS_LARGE_FNT : Screen::FID_8_FNT); _screen->hideMouse(); _vm->delay(150); @@ -1012,9 +1135,8 @@ DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine * DarkmoonSequenceHelper::~DarkmoonSequenceHelper() { for (int i = 4; _config->palFiles[i]; i++) delete _palettes[i]; - delete _palettes[9]; - delete _palettes[10]; - delete _palettes[11]; + for (int i = 9; i < 13; ++i) + delete _palettes[i]; for (int i = 0; i < 7; i++) delete[] _fadingTables[i]; @@ -1023,7 +1145,14 @@ DarkmoonSequenceHelper::~DarkmoonSequenceHelper() { delete[] _shapes[i]; delete[] _shapes; + delete[] _config->animData; + delete[] _config->shapeDefs; + delete[] _config->cpsData; + delete _config; + + _screen->enableHiColorMode(true); _screen->clearCurPage(); + _screen->setFont(_prevFont); _screen->showMouse(); _screen->updateScreen(); @@ -1033,17 +1162,23 @@ DarkmoonSequenceHelper::~DarkmoonSequenceHelper() { } void DarkmoonSequenceHelper::loadScene(int index, int pageNum) { - char file[13]; - strcpy(file, _config->cpsFiles[index]); - - Common::SeekableReadStream *s = _vm->resource()->createReadStream(file); + char file[13] = ""; + Common::SeekableReadStream *s = 0; uint32 chunkID = 0; + + if (_config->cpsFiles) { + strcpy(file, _config->cpsFiles[index]); + s = _vm->resource()->createReadStream(file); + } + if (s) { chunkID = s->readUint32LE(); s->seek(0); } - if (s && chunkID == MKTAG('F', 'O', 'R', 'M')) { + if (_config->cpsData[index]) { + _screen->decodeSHP(_config->cpsData[index], pageNum); + } else if (s && chunkID == MKTAG('F', 'O', 'R', 'M')) { // The original code also handles files with FORM chunks and ILBM and PBM sub chunks. This will probably be necessary for Amiga versions. // The DOS versions do not need this, but still have the code for it. We error out for now. error("DarkmoonSequenceHelper::loadScene(): CPS file loading failure in scene %d - unhandled FORM chunk encountered", index); @@ -1059,7 +1194,7 @@ void DarkmoonSequenceHelper::loadScene(int index, int pageNum) { if (!s) error("DarkmoonSequenceHelper::loadScene(): CPS file loading failure in scene %d", index); - if (_config->mode == kFinale) + if (_config->loadScenePal) s->read(_palettes[0]->getData(), 768); else s->seek(768); @@ -1096,8 +1231,10 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { uint32 end = 0; for (const DarkMoonAnimCommand *s = _config->animData[index]; s->command != 0xFF && !_vm->skipFlag() && !_vm->shouldQuit(); s++) { - int palIndex = _config->mode == kFinale ? (s->pal + 1) : s->pal; + int palIndex = s->pal + _config->animPalOffs; int x = s->x1; + if (x >= Screen::SCREEN_W) + x >>= 1; int y = s->y1; int x2 = 0; uint16 shapeW = 0; @@ -1109,7 +1246,7 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { if (_vm->_configRenderMode != Common::kRenderEGA && s->pal) setPaletteWithoutTextColor(palIndex); delay(s->delay); - if (_vm->_configRenderMode != Common::kRenderEGA && _config->mode == kIntro && s->pal) + if (_vm->_configRenderMode != Common::kRenderEGA && _config->animCmdRestorePal && s->pal) setPaletteWithoutTextColor(0); break; @@ -1118,7 +1255,7 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { shapeW = _shapes[s->obj][2]; shapeH = _shapes[s->obj][3]; - if (_config->mode == kFinale) { + if (_config->animCmd1ShapeFrame == 18) { _screen->setScreenDim(18); x -= (_screen->_curDim->sx << 3); y -= _screen->_curDim->sy; @@ -1128,7 +1265,7 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { x2 = x; } - _screen->drawShape(0, _shapes[s->obj], x, y, _config->mode == kIntro ? 0 : 18); + _screen->drawShape(0, _shapes[s->obj], x, y, _config->animCmd1ShapeFrame); if (_vm->_configRenderMode != Common::kRenderEGA && s->pal) setPaletteWithoutTextColor(palIndex); @@ -1137,7 +1274,7 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { delay(s->delay); - if (_config->mode == kIntro) { + if (_config->animCmd1ShapeFrame == 0) { if (_vm->_configRenderMode != Common::kRenderEGA && s->pal) setPaletteWithoutTextColor(0); _screen->copyRegion(x - 8, y - 8, x, y, (shapeW + 1) << 3, shapeH, 2, 0, Screen::CR_NO_P_CHECK); @@ -1159,14 +1296,14 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { delay(s->delay); - if (_vm->_configRenderMode != Common::kRenderEGA && _config->mode == kIntro && s->pal) + if (_vm->_configRenderMode != Common::kRenderEGA && _config->animCmdRestorePal && s->pal) setPaletteWithoutTextColor(0); break; case 3: case 4: // fade shape in or out or restore background - if (_config->mode == kFinale) + if (!_config->shpBackgroundFading) break; if (_vm->_configRenderMode == Common::kRenderEGA) { @@ -1201,10 +1338,10 @@ void DarkmoonSequenceHelper::animCommand(int index, int del) { case 5: // copy region - if (_config->mode == kFinale && s->pal) + if (_config->animCmd5SetPal && s->pal) setPaletteWithoutTextColor(palIndex); - _screen->copyRegion(s->x2 << 3, s->y2, s->x1, s->y1, s->w << 3, s->h, (s->obj && _config->mode == kFinale) ? 6 : 2, 0, Screen::CR_NO_P_CHECK); + _screen->copyRegion(s->x2 << 3, s->y2, s->x1, s->y1, s->w << 3, s->h, s->obj ? _config->animCmd5AltPage : 2, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); delay(s->delay); break; @@ -1250,8 +1387,9 @@ void DarkmoonSequenceHelper::printText(int index, int color) { strcpy(str, _config->strings[index]); const ScreenDim *dm = _screen->_curDim; + int fontHeight = _screen->getFontHeight() + 1; - for (int yOffs = 0; *str; yOffs += 9) { + for (int yOffs = 0; *str; yOffs += fontHeight) { char *cr = strchr(str, 13); if (cr) @@ -1383,8 +1521,52 @@ void DarkmoonSequenceHelper::waitForSongNotifier(int index, bool introUpdateAnim } } +const char *const DarkmoonSequenceHelper::_palFilesIntroVGA[] = { + "PALETTE1.PAL", + "PALETTE3.PAL", + "PALETTE2.PAL", + "PALETTE4.PAL", + 0 +}; + +const char *const DarkmoonSequenceHelper::_palFilesIntroEGA[] = { + "PALETTE0.PAL", + "PALETTE3.PAL", + "PALETTE2.PAL", + "PALETTE4.PAL", + 0 +}; + +const char *const DarkmoonSequenceHelper::_palFilesFinaleVGA[] = { + "FINALE_0.PAL", + "FINALE_0.PAL", + "FINALE_1.PAL", + "FINALE_2.PAL", + "FINALE_3.PAL", + "FINALE_4.PAL", + "FINALE_5.PAL", + "FINALE_6.PAL", + "FINALE_7.PAL", + 0 +}; + +const char *const DarkmoonSequenceHelper::_palFilesFinaleEGA[] = { + "FINALE_0.PAL", + "FINALE_0.PAL", + "FINALE_1.PAL", + "FINALE_2.PAL", + "FINALE_3.PAL", + "FINALE_4.PAL", + "FINALE_5.PAL", + "FINALE_0.PAL", + "FINALE_0.PAL", + 0 +}; + void DarkMoonEngine::seq_nightmare() { Screen::FontId of = _screen->setFont(Screen::FID_6_FNT); + if (_flags.lang == Common::JA_JPN) + _screen->clearCurDim(); _screen->copyRegion(0, 0, 0, 120, 176, 24, 12, 2, Screen::CR_NO_P_CHECK); initDialogueSequence(); @@ -1416,6 +1598,7 @@ void DarkMoonEngine::seq_kheldran() { gui_drawDialogueBox(); static const char file[] = "KHELDRAN"; + _screen->set16bitShadingLevel(4); _txt->printDialogueText(_kheldranStrings[0]); drawSequenceBitmap(file, 0, 0, 0, 0); _txt->printDialogueText(20, _moreStrings[0]); diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 2f5a0b6121..3f4216c5fb 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -66,6 +66,13 @@ struct SoundResourceInfo_TownsPC98V2 { uint cdaTableSize; }; +struct SoundResourceInfo_TownsEoB { + SoundResourceInfo_TownsEoB(const uint8 *pcmdata, uint dataSize, int pcmvolume) : pcmData(pcmdata), pcmDataSize(dataSize), pcmVolume(pcmvolume) {} + const uint8 *pcmData; + uint pcmDataSize; + int pcmVolume; +}; + /** * Analog audio output device API for Kyrandia games. * It contains functionality to play music tracks, diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h index 3559133cb1..dd043790a2 100644 --- a/engines/kyra/sound_intern.h +++ b/engines/kyra/sound_intern.h @@ -349,6 +349,59 @@ protected: int _tableSfxGame_Size; }; +class SoundTowns_Darkmoon : public Sound, public TownsAudioInterfacePluginDriver { +public: + SoundTowns_Darkmoon(KyraEngine_v1 *vm, Audio::Mixer *mixer); + virtual ~SoundTowns_Darkmoon(); + + virtual kType getMusicType() const { return kTowns; } + + virtual bool init(); + + void timerCallback(int timerId); + + virtual void initAudioResourceInfo(int set, void *info); + virtual void selectAudioResourceSet(int set); + virtual bool hasSoundFile(uint file) const; + virtual void loadSoundFile(uint file) {} + virtual void loadSoundFile(Common::String name); + + virtual void playTrack(uint8 track); + virtual void haltTrack(); + virtual bool isPlaying() const; + + virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF); + virtual void stopAllSoundEffects(); + + virtual void beginFadeOut(); + + virtual void updateVolumeSettings(); + + virtual int checkTrigger(); + + virtual void resetTrigger(); + +private: + struct SoundTableEntry { + int8 type; + int32 para1; + int16 para2; + } _soundTable[120]; + + uint8 _lastSfxChan; + uint8 _lastEnvChan; + uint8 *_pcmData; + uint32 _pcmDataSize; + uint8 _pcmVol; + + int _timer; + int _timerSwitch; + + SoundResourceInfo_TownsEoB *_pcmResource[3]; + + TownsAudioInterface *_intf; +}; + } // End of namespace Kyra #endif diff --git a/engines/kyra/sound_towns_darkmoon.cpp b/engines/kyra/sound_towns_darkmoon.cpp new file mode 100644 index 0000000000..b1fcb57e30 --- /dev/null +++ b/engines/kyra/sound_towns_darkmoon.cpp @@ -0,0 +1,276 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kyra/sound_intern.h" +#include "kyra/resource.h" + +#include "common/config-manager.h" +#include "common/system.h" + +#include "backends/audiocd/audiocd.h" + +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" + +namespace Kyra { + +SoundTowns_Darkmoon::SoundTowns_Darkmoon(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer) { + _intf = new TownsAudioInterface(mixer, this, false); + _pcmData = 0; + _pcmVol = 0; + _timer = 0; + _timerSwitch = 0; + memset(_pcmResource, 0, sizeof(_pcmResource)); +} + +SoundTowns_Darkmoon::~SoundTowns_Darkmoon() { + for (int i = 0; i < 3; i++) + initAudioResourceInfo(i, 0); + delete _intf; + delete[] _pcmData; +} + +bool SoundTowns_Darkmoon::init() { + if (!_intf->init()) + return false; + + _intf->callback(21, 255, 1); + _intf->callback(21, 0, 1); + _intf->callback(22, 255, 221); + + _intf->callback(70, 0x31); + _intf->callback(33, 1); + _intf->callback(8, 0x47, 127); + _intf->callback(67, 1, 127, 127); + + _lastSfxChan = 0x46; + _lastEnvChan = 0x40; + + updateVolumeSettings(); + + return true; +} + +void SoundTowns_Darkmoon::timerCallback(int timerId) { + switch (timerId) { + case 1: + _timerSwitch = (_timerSwitch + 1) % 4; + if (!_timerSwitch) + _timer++; + break; + default: + break; + } +} + +void SoundTowns_Darkmoon::initAudioResourceInfo(int set, void *info) { + delete _pcmResource[set]; + _pcmResource[set] = info ? new SoundResourceInfo_TownsEoB(*(SoundResourceInfo_TownsEoB*)info) : 0; +} + +void SoundTowns_Darkmoon::selectAudioResourceSet(int set) { + delete[] _pcmData; + + if (!_pcmResource[set] || !_pcmResource[kMusicIngame]) + return; + + _pcmDataSize = _pcmResource[kMusicIngame]->pcmDataSize; + _pcmData = new uint8[_pcmDataSize]; + _pcmVol = _pcmResource[set]->pcmVolume; + memcpy(_pcmData, _pcmResource[kMusicIngame]->pcmData, _pcmDataSize); + + if (set == kMusicIngame) + return; + + memcpy(_pcmData, _pcmResource[set]->pcmData, _pcmResource[set]->pcmDataSize); +} + +bool SoundTowns_Darkmoon::hasSoundFile(uint file) const { + return true; +} + +void SoundTowns_Darkmoon::loadSoundFile(Common::String name) { + Common::SeekableReadStream *s = _vm->resource()->createReadStream(Common::String::format("%s.SDT", name.c_str())); + if (!s) + error("Failed to load sound file '%s.SDT'", name.c_str()); + + for (int i = 0; i < 120; i++) { + _soundTable[i].type = s->readSByte(); + _soundTable[i].para1 = s->readSint32LE(); + _soundTable[i].para2 = s->readSint16LE(); + } + + delete s; + + uint32 bytesLeft; + uint8 *pmb = _vm->resource()->fileData(Common::String::format("%s.PMB", name.c_str()).c_str(), &bytesLeft); + + _vm->delay(300); + + if (pmb) { + uint8 *src = pmb + 8; + for (int i = 0; i < 32; i++) + _intf->callback(5, 0x40, i, &src[i << 7]); + + _intf->callback(35, -1); + src += 0x1000; + bytesLeft -= 0x1008; + + while (bytesLeft) { + _intf->callback(34, src); + uint32 len = READ_LE_UINT16(&src[12]) + 32; + src = src + len; + bytesLeft -= len; + } + + delete[] pmb; + } else { + warning("Sound file '%s.PMB' not found.", name.c_str()); + // TODO + } +} + +void SoundTowns_Darkmoon::playTrack(uint8 track) { + if (track >= 120 || !_sfxEnabled) + return; + + uint8 *pcm = 0; + + switch (_soundTable[track].type) { + case -1: + if (track == 0) + haltTrack(); + else if (track == 2) + beginFadeOut(); + break; + + case 0: + if (_soundTable[track].para1 == -1 || (uint32)_soundTable[track].para1 > _pcmDataSize) + return; + + pcm = _pcmData + _soundTable[track].para1; + WRITE_LE_UINT16(&pcm[24], _soundTable[track].para2 * 98 / 1000); + + _intf->callback(39, 0x47); + _intf->callback(37, 0x47, 60, track == 11 ? 127 : _pcmVol, pcm); + break; + + case 2: + resetTrigger(); + g_system->getAudioCDManager()->play(_soundTable[track].para1 - 1, 1, 0, 0); + break; + + case 3: + _lastSfxChan ^= 3; + _intf->callback(39, _lastSfxChan); + _intf->callback(4, _lastSfxChan, _soundTable[track].para1); + _intf->callback(1, _lastSfxChan, _soundTable[track].para2, 127); + break; + + default: + break; + } +} + +void SoundTowns_Darkmoon::haltTrack() { + _intf->callback(39, 0x47); + _intf->callback(39, 0x46); + _intf->callback(39, 0x45); + + g_system->getAudioCDManager()->stop(); +} + +bool SoundTowns_Darkmoon::isPlaying() const { + return g_system->getAudioCDManager()->isPlaying(); +} + +void SoundTowns_Darkmoon::playSoundEffect(uint8 track, uint8 volume) { + if (!_sfxEnabled) + return; + + if (volume == 255) + return playTrack(track); + + uint8 *pcm = 0; + + switch (_soundTable[track].type) { + case 0: + if (_soundTable[track].para1 == -1 || (uint32)_soundTable[track].para1 > _pcmDataSize) + return; + + pcm = _pcmData + _soundTable[track].para1; + WRITE_LE_UINT16(&pcm[24], _soundTable[track].para2 * 98 / 1000); + + _intf->callback(39, 0x47); + _intf->callback(37, 0x47, 60, volume, pcm); + break; + + case 3: + _intf->callback(2, _lastEnvChan); + _intf->callback(4, _lastEnvChan, _soundTable[track].para1); + _intf->callback(1, _lastEnvChan, _soundTable[track].para2, volume); + break; + + default: + break; + } + + if (++_lastEnvChan == 0x43) + _lastEnvChan = 0x40; +} + +void SoundTowns_Darkmoon::stopAllSoundEffects() { + _intf->callback(39, 0x42); + _intf->callback(39, 0x41); + _intf->callback(39, 0x40); +} + +void SoundTowns_Darkmoon::beginFadeOut() { + for (int vol = 127; vol >= 0; vol -= 2) { + _intf->callback(67, 1, vol, vol); + _vm->delay(16); + } + + _intf->callback(67, 1, 0, 0); + _intf->callback(70, 1); + + g_system->getAudioCDManager()->stop(); + + _intf->callback(70, 0x31); + _intf->callback(67, 1, 127, 127); +} + +void SoundTowns_Darkmoon::updateVolumeSettings() { + bool mute = (ConfMan.hasKey("mute")) ? ConfMan.getBool("mute") : false; + _intf->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume"))); +} + +int SoundTowns_Darkmoon::checkTrigger() { + return _timer; +} + +void SoundTowns_Darkmoon::resetTrigger() { + _timer = 0; + _timerSwitch = 0; +} + +} // End of namespace Kyra diff --git a/engines/kyra/sprites_eob.cpp b/engines/kyra/sprites_eob.cpp index c93bf0edb7..077eafa97b 100644 --- a/engines/kyra/sprites_eob.cpp +++ b/engines/kyra/sprites_eob.cpp @@ -33,17 +33,40 @@ namespace Kyra { void EoBCoreEngine::loadMonsterShapes(const char *filename, int monsterIndex, bool hasDecorations, int encodeTableIndex) { - _screen->loadShapeSetBitmap(filename, 3, 3); - const uint16 *enc = &_encodeMonsterShpTable[encodeTableIndex << 2]; + if (_flags.platform == Common::kPlatformFMTowns) { + Common::String tmp = Common::String::format("%s.MNT", filename); + Common::SeekableReadStream *s = _res->createReadStream(tmp); + if (!s) + error("Screen_EoB::loadMonsterShapes(): Failed to load file '%s'", tmp.c_str()); + + for (int i = 0; i < 6; i++) + _monsterShapes[monsterIndex + i] = loadTownsShape(s); + + for (int i = 0; i < 6; i++) { + for (int ii = 0; ii < 2; ii++) + s->read(_monsterPalettes[(monsterIndex >= 18 ? i + 6 : i) * 2 + ii], 16); + } + + if (hasDecorations) + loadMonsterDecoration(s, monsterIndex); - for (int i = 0; i < 6; i++, enc += 4) - _monsterShapes[monsterIndex + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3], false, _cgaMappingDefault); + delete s; + } else { + _screen->loadShapeSetBitmap(filename, 3, 3); + const uint16 *enc = &_encodeMonsterShpTable[encodeTableIndex << 2]; - generateMonsterPalettes(filename, monsterIndex); + for (int i = 0; i < 6; i++, enc += 4) + _monsterShapes[monsterIndex + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3], false, _cgaMappingDefault); - if (hasDecorations) - loadMonsterDecoration(filename, monsterIndex); + generateMonsterPalettes(filename, monsterIndex); + if (hasDecorations) { + Common::SeekableReadStream *s = _res->createReadStream(Common::String::format("%s.DCR", filename)); + if (s) + loadMonsterDecoration(s, monsterIndex); + delete s; + } + } _screen->_curPage = 0; } @@ -56,6 +79,15 @@ void EoBCoreEngine::releaseMonsterShapes(int first, int num) { } } +uint8 *EoBCoreEngine::loadTownsShape(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32LE(); + uint8 *shape= new uint8[size]; + stream->read(shape, size); + if (shape[0] == 1) + shape[0]++; + return shape; +} + const uint8 *EoBCoreEngine::loadMonsterProperties(const uint8 *data) { uint8 cmd = *data++; while (cmd != 0xFF) { diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 7cb102b0c4..3a83bd193d 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -39,7 +39,7 @@ namespace Kyra { -#define RESFILE_VERSION 90 +#define RESFILE_VERSION 91 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { diff --git a/engines/kyra/staticres_eob.cpp b/engines/kyra/staticres_eob.cpp index f4897b5256..933b120370 100644 --- a/engines/kyra/staticres_eob.cpp +++ b/engines/kyra/staticres_eob.cpp @@ -22,6 +22,7 @@ #include "kyra/eob.h" #include "kyra/resource.h" +#include "kyra/sound_intern.h" namespace Kyra { @@ -164,7 +165,7 @@ const ScreenDim Screen_EoB::_screenDimTable[] = { { 0x01, 0x14, 0x14, 0x58, 0x0F, 0x02, 0x00, 0x00 }, { 0x02, 0x06, 0x23, 0x78, 0x0F, 0x02, 0x00, 0x00 }, { 0x09, 0x14, 0x16, 0x38, 0x0F, 0x02, 0x00, 0x00 }, - { 0x01, 0x96, 0x26, 0x31, 0x0F, 0x00, 0x00, 0x00 }, + { 0x01, 0x96, 0x26, 0x32, 0x0F, 0x00, 0x00, 0x00 }, { 0x01, 0x08, 0x26, 0x80, 0x0C, 0x0F, 0x00, 0x00 }, { 0x01, 0x10, 0x26, 0x14, 0x00, 0x0F, 0x06, 0x00 }, { 0x00, 0x10, 0x10, 0x0C, 0x00, 0x0F, 0x06, 0x00 }, @@ -407,7 +408,6 @@ void EoBCoreEngine::initStaticResource() { _wllFlagPreset = _staticres->loadRawData(kEoBBaseWllFlagPreset, _wllFlagPresetSize); _dscShapeCoords = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscShapeCoords, temp); - _dscDoorScaleOffs = _staticres->loadRawData(kEoBBaseDscDoorScaleOffs, temp); _dscDoorScaleMult1 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult1, temp); _dscDoorScaleMult2 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult2, temp); _dscDoorScaleMult3 = _staticres->loadRawData(kEoBBaseDscDoorScaleMult3, temp); @@ -471,10 +471,11 @@ void EoBCoreEngine::initStaticResource() { { 0, 0, 0, 0 } }; - static const char *const errorSlotEmptyString[4] = { + static const char *const errorSlotEmptyString[5] = { "There is no game\rsaved in that slot!", "Hier ist noch kein\rSpiel gespeichert!", "Non c'\x0E alcun gioco\rsalvato in quella\rposizione!", + "\r ""\x82\xBB\x82\xCC\x83""X""\x83\x8D\x83""b""\x83""g""\x82\xC9\x82\xCD\x83""Q""\x81""[""\x83\x80\x82\xAA\x83""Z""\x81""[""\x83""u\r ""\x82\xB3\x82\xEA\x82\xC4\x82\xA2\x82\xDC\x82\xB9\x82\xF1\x81""B", 0 }; @@ -487,10 +488,15 @@ void EoBCoreEngine::initStaticResource() { } else if (_flags.lang == Common::IT_ITA) { _saveLoadStrings = saveLoadStrings[2]; _errorSlotEmptyString = errorSlotEmptyString[2]; - } else { - _saveLoadStrings = saveLoadStrings[3]; + } else if (_flags.lang == Common::JA_JPN) { + // EOB II FM-Towns uses English here. + // Only the empty slot warning is in Japanese. + _saveLoadStrings = saveLoadStrings[0]; _errorSlotEmptyString = errorSlotEmptyString[3]; - } + } else { + _saveLoadStrings = saveLoadStrings[4]; + _errorSlotEmptyString = errorSlotEmptyString[4]; + } _menuOkString = "OK"; } @@ -602,7 +608,24 @@ void EoBCoreEngine::initButtonData() { { 110, 0, 0x1100, 75, 168, 97, 6, 0 } }; - _buttonDefs = buttonDefs; + _buttonDefs = new EoBGuiButtonDef[ARRAYSIZE(buttonDefs)]; + memcpy(_buttonDefs, buttonDefs, sizeof(buttonDefs)); + + if (_flags.platform == Common::kPlatformFMTowns) { + static const uint16 keyCodesFMTowns[] = { + 93, 94, 95, 96, 67, 27, 24, 349, 350, 351, 352, 80, 27, 24, 30, 0, 31, 0, 29, 0, 28, 0, 127, 18, 27, 93, 94, 95, 96, + 49, 50, 51, 52, 53, 93, 94, 95, 96, 60, 62, 32, 353, 354, 97, 98, 27, 27, 97, 98, 97, 98, 54, 49, 50, 51, 52, 53, 27 + }; + + const uint16 *c = keyCodesFMTowns; + for (int i = 0; i < ARRAYSIZE(buttonDefs); ++i) { + if (_buttonDefs[i].keyCode) + _buttonDefs[i].keyCode = *c++; + if (_buttonDefs[i].keyCode2) + _buttonDefs[i].keyCode2 = *c++; + } + } + _buttonCallbacks.clear(); _buttonCallbacks.reserve(ARRAYSIZE(buttonDefs)); @@ -696,7 +719,12 @@ void EoBCoreEngine::initMenus() { { 32, 40, 16, 24, 20, 3, 5 }, { 33, 72, 16, 24, 20, 4, 5 }, { 34, 104, 16, 24, 20, 5, 5 }, - { 35, 136, 16, 24, 20, 6, 5 } + { 35, 136, 16, 24, 20, 6, 5 }, + // FM-Towns options menu + { 18, 12, 20, 158, 14, 32, 3 }, + { 19, 12, 37, 158, 14, 50, 3 }, + { 20, 12, 54, 158, 14, 21, 3 }, + { 8, 128, 122, 40, 14, 19, 7 } }; _menuButtonDefs = buttonDefs; @@ -720,6 +748,12 @@ void EoBCoreEngine::initMenus() { _menuDefs[4].numButtons = 8; _menuDefs[4].firstButtonStrId = 36; } + + if (_flags.platform == Common::kPlatformFMTowns) { + // assign FM-Towns style options menu + _menuDefs[2].numButtons = 4; + _menuDefs[2].firstButtonStrId = 44; + } } @@ -1226,35 +1260,6 @@ const uint8 EoBEngine::_monsterAcHitChanceTbl2[] = { void DarkMoonEngine::initStaticResource() { int temp; _mainMenuStrings = _staticres->loadStrings(kEoB2MainMenuStrings, temp); - _introStrings = _staticres->loadStrings(kEoB2IntroStrings, temp); - _cpsFilesIntro = _staticres->loadStrings(kEoB2IntroCPSFiles, temp); - - _animIntro = new const DarkMoonAnimCommand*[44]; - for (int i = 0; i < 44; i++) - _animIntro[i] = _staticres->loadEoB2SeqData(kEoB2IntroAnimData00 + i, temp); - - _shapesIntro = new const DarkMoonShapeDef*[13]; - memset(_shapesIntro, 0, sizeof(DarkMoonShapeDef *) * 13); - _shapesIntro[0] = _staticres->loadEoB2ShapeData(kEoB2IntroShapes00, temp); - _shapesIntro[1] = _staticres->loadEoB2ShapeData(kEoB2IntroShapes01, temp); - _shapesIntro[4] = _staticres->loadEoB2ShapeData(kEoB2IntroShapes04, temp); - _shapesIntro[7] = _staticres->loadEoB2ShapeData(kEoB2IntroShapes07, temp); - - _finaleStrings = _staticres->loadStrings(kEoB2FinaleStrings, temp); - _creditsData = _staticres->loadRawData(kEoB2CreditsData, temp); - _cpsFilesFinale = _staticres->loadStrings(kEoB2FinaleCPSFiles, temp); - - _animFinale = new const DarkMoonAnimCommand*[21]; - for (int i = 0; i < 21; i++) - _animFinale[i] = _staticres->loadEoB2SeqData(kEoB2FinaleAnimData00 + i, temp); - - _shapesFinale = new const DarkMoonShapeDef*[13]; - memset(_shapesFinale, 0, sizeof(DarkMoonShapeDef *) * 13); - _shapesFinale[0] = _staticres->loadEoB2ShapeData(kEoB2FinaleShapes00, temp); - _shapesFinale[3] = _staticres->loadEoB2ShapeData(kEoB2FinaleShapes03, temp); - _shapesFinale[7] = _staticres->loadEoB2ShapeData(kEoB2FinaleShapes07, temp); - _shapesFinale[9] = _staticres->loadEoB2ShapeData(kEoB2FinaleShapes09, temp); - _shapesFinale[10] = _staticres->loadEoB2ShapeData(kEoB2FinaleShapes10, temp); _dscDoorType5Offs = _staticres->loadRawData(kEoBBaseDscDoorType5Offs, temp); @@ -1273,6 +1278,26 @@ void DarkMoonEngine::initStaticResource() { _wallOfForceDsNumH = _staticres->loadRawData(kEoB2WallOfForceNumH, temp); _wallOfForceShpId = _staticres->loadRawData(kEoB2WallOfForceShpId, temp); + _utilMenuStrings = _staticres->loadStrings(kEoB2UtilMenuStrings, temp); + _2431Strings = _staticres->loadStrings(kEoB2Config2431Strings, temp); + _katakanaLines = _staticres->loadStrings(kEoB2KatakanaLines, temp); + _katakanaSelectStrings = _staticres->loadStrings(kEoB2KanaSelectStrings, temp); + + _ascii2SjisTables = _staticres->loadStrings(kEoB2Ascii2SjisTables, temp); + _ascii2SjisTables2 = _staticres->loadStrings(kEoB2Ascii2SjisTables2, temp); + _saveNamePatterns = _staticres->loadStrings(kEoB2SaveNamePatterns, temp); + + const uint8 *data = _staticres->loadRawData(kEoB2PcmSoundEffectsIngame, temp); + SoundResourceInfo_TownsEoB ingame(data, temp, 127); + data = _staticres->loadRawData(kEoB2PcmSoundEffectsIntro, temp); + SoundResourceInfo_TownsEoB intro(data, temp, 40); + data = _staticres->loadRawData(kEoB2PcmSoundEffectsFinale, temp); + SoundResourceInfo_TownsEoB finale(data, temp, 40); + + _sound->initAudioResourceInfo(kMusicIngame, &ingame); + _sound->initAudioResourceInfo(kMusicIntro, &intro); + _sound->initAudioResourceInfo(kMusicFinale, &finale); + _monsterAcHitChanceTable1 = _monsterAcHitChanceTbl1; _monsterAcHitChanceTable2 = _monsterAcHitChanceTbl2; @@ -1327,49 +1352,12 @@ void DarkMoonEngine::initSpells() { } } -const char *const DarkMoonEngine::_palFilesIntroVGA[] = { - "PALETTE1.PAL", - "PALETTE3.PAL", - "PALETTE2.PAL", - "PALETTE4.PAL", - 0 -}; - -const char *const DarkMoonEngine::_palFilesIntroEGA[] = { - "PALETTE0.PAL", - "PALETTE3.PAL", - "PALETTE2.PAL", - "PALETTE4.PAL", - 0 -}; - -const char *const DarkMoonEngine::_palFilesFinaleVGA[] = { - "FINALE_0.PAL", - "FINALE_0.PAL", - "FINALE_1.PAL", - "FINALE_2.PAL", - "FINALE_3.PAL", - "FINALE_4.PAL", - "FINALE_5.PAL", - "FINALE_6.PAL", - "FINALE_7.PAL", - 0 -}; - -const char *const DarkMoonEngine::_palFilesFinaleEGA[] = { - "FINALE_0.PAL", - "FINALE_0.PAL", - "FINALE_1.PAL", - "FINALE_2.PAL", - "FINALE_3.PAL", - "FINALE_4.PAL", - "FINALE_5.PAL", - "FINALE_0.PAL", - "FINALE_0.PAL", - 0 +const KyraRpgGUISettings DarkMoonEngine::_guiSettingsFMTowns = { + { 9, 15, 95, 11, 7, { 221, 76 }, { 187, 162 }, { 95, 95 } }, + { 186, 181, 183, 133, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180 } }; -const KyraRpgGUISettings DarkMoonEngine::_guiSettings = { +const KyraRpgGUISettings DarkMoonEngine::_guiSettingsDOS = { { 9, 15, 95, 9, 7, { 221, 76 }, { 189, 162 }, { 95, 95 } }, { 186, 181, 183, 133, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180 } }; diff --git a/engines/kyra/staticres_rpg.cpp b/engines/kyra/staticres_rpg.cpp index 671d3dfd1d..55d14698fd 100644 --- a/engines/kyra/staticres_rpg.cpp +++ b/engines/kyra/staticres_rpg.cpp @@ -81,7 +81,7 @@ void KyraRpgEngine::initStaticResource() { _dscTileIndex = _staticres->loadRawData(kRpgCommonDscTileIndex, temp); _dscDim1 = (const int8 *)_staticres->loadRawData(kRpgCommonDscDimData1, temp); _dscDim2 = (const int8 *)_staticres->loadRawData(kRpgCommonDscDimData2, temp); - _dscUnk2 = _staticres->loadRawData(kRpgCommonDscUnk2, temp); + _dscDoorScaleOffs = _staticres->loadRawData(kRpgCommonDscDoorScaleOffs, temp); _dscBlockMap = _staticres->loadRawData(kRpgCommonDscBlockMap, temp); _dscBlockIndex = (const int8 *)_staticres->loadRawData(kRpgCommonDscBlockIndex, temp); _dscDimMap = _staticres->loadRawData(kRpgCommonDscDimMap, temp); diff --git a/engines/kyra/text_rpg.cpp b/engines/kyra/text_rpg.cpp index 6dea66c14d..cc7ab068a7 100644 --- a/engines/kyra/text_rpg.cpp +++ b/engines/kyra/text_rpg.cpp @@ -75,10 +75,13 @@ void TextDisplayer_rpg::setupField(int dim, bool mode) { _textDimData[dim].color2 = _vm->guiSettings()->colors.fill; _screen->setScreenDim(dim); - if (mode) + if (mode) { + _screen->set16bitShadingLevel(4); clearCurDim(); - else + _screen->set16bitShadingLevel(0); + } else { resetDimTextPositions(dim); + } } void TextDisplayer_rpg::resetDimTextPositions(int dim) { @@ -123,7 +126,8 @@ void TextDisplayer_rpg::displayText(char *str, ...) { int sdx = _screen->curDimIndex(); bool sjisTextMode = (_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false; - int sjisOffs = sjisTextMode ? 8 : 9; + int sjisOffs = (sjisTextMode || _vm->game() == GI_EOB2) ? 8 : 9; + Screen::FontId of = (_vm->game() == GI_EOB2 && _vm->gameFlags().platform == Common::kPlatformFMTowns) ? _screen->setFont(Screen::FID_8_FNT) : _screen->_currentFont; uint16 charsPerLine = (sd->w << 3) / (_screen->getFontWidth() + _screen->_charWidth); @@ -225,6 +229,8 @@ void TextDisplayer_rpg::displayText(char *str, ...) { if (_numCharsLeft) printLine(_currentLine); + + _screen->setFont(of); } char TextDisplayer_rpg::parseCommand() { @@ -283,7 +289,7 @@ void TextDisplayer_rpg::readNextPara() { void TextDisplayer_rpg::printLine(char *str) { const ScreenDim *sd = _screen->_curDim; int sdx = _screen->curDimIndex(); - bool sjisTextMode = (_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false; + bool sjisTextMode = _vm->gameFlags().lang == Common::JA_JPN && (_vm->gameFlags().use16ColorMode && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false; int fh = (_screen->_currentFont == Screen::FID_SJIS_FNT) ? 9 : (_screen->getFontHeight() + _screen->_charOffset); int lines = (sd->h - _screen->_charOffset) / fh; @@ -301,7 +307,10 @@ void TextDisplayer_rpg::printLine(char *str) { if (h2) _screen->copyRegion(sd->sx << 3, sd->sy + fh, sd->sx << 3, sd->sy, sd->w << 3, h2, _screen->_curPage, _screen->_curPage, Screen::CR_NO_P_CHECK); + _screen->set16bitShadingLevel(4); _screen->fillRect(sd->sx << 3, sd->sy + h1, ((sd->sx + sd->w) << 3) - 1, sd->sy + sd->h - 1, _textDimData[sdx].color2); + _screen->set16bitShadingLevel(0); + if (_textDimData[sdx].line) _textDimData[sdx].line--; } @@ -482,7 +491,7 @@ void TextDisplayer_rpg::printLine(char *str) { str[len] = 0; _numCharsLeft = strlen(str); - _lineWidth = sjisTextMode ? (_numCharsLeft << 2) : (_screen->_currentFont == Screen::FID_SJIS_FNT ? _numCharsLeft * 9: _screen->getTextWidth(str)); + _lineWidth = sjisTextMode ? (_numCharsLeft << 2) : (_screen->_currentFont == Screen::FID_SJIS_FNT ? _numCharsLeft * 9 : _screen->getTextWidth(str)); if (!_numCharsLeft && (_textDimData[sdx].column + twoByteCharOffs) <= (sd->w << 3)) return; @@ -499,7 +508,9 @@ void TextDisplayer_rpg::printDialogueText(int stringId, const char *pageBreakStr assert(strlen(str) < kEoBTextBufferSize); Common::strlcpy(_dialogueBuffer, str, kEoBTextBufferSize); + _screen->set16bitShadingLevel(4); displayText(_dialogueBuffer); + _screen->set16bitShadingLevel(0); if (pageBreakString) { if (pageBreakString[0]) { @@ -566,7 +577,7 @@ void TextDisplayer_rpg::textPageBreak() { SWAP(_vm->_dialogueButtonLabelColor1, _vm->_dialogueButtonLabelColor2); int cp = _screen->setCurPage(0); - Screen::FontId cf = _screen->setFont((_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT); + Screen::FontId cf = _screen->setFont((_vm->gameFlags().lang == Common::JA_JPN && _vm->gameFlags().use16ColorMode) ? Screen::FID_SJIS_FNT : ((_vm->game() == GI_EOB2 && _vm->gameFlags().platform == Common::kPlatformFMTowns) ? Screen::FID_8_FNT : Screen::FID_6_FNT)); if (_vm->game() == GI_LOL) _vm->_timer->pauseSingleTimer(11, true); @@ -614,8 +625,11 @@ void TextDisplayer_rpg::textPageBreak() { _vm->gui_drawBox(x + 8, (y & ~7) - 1, 66, 10, 0xEE, 0xCC, -1); _screen->printText(_pageBreakString, (x + 37 - (strlen(_pageBreakString) << 1) + 4) & ~3, (y + 2) & ~7, 0xC1, 0); } else { + int yOffs = (_vm->game() == GI_EOB2 && _vm->gameFlags().platform == Common::kPlatformFMTowns) ? 1 : 2; + _screen->set16bitShadingLevel(4); _vm->gui_drawBox(x, y, w, _vm->guiSettings()->buttons.height, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill); - _screen->printText(_pageBreakString, x + (w >> 1) - (_vm->screen()->getTextWidth(_pageBreakString) >> 1), y + 2, _vm->_dialogueButtonLabelColor1, 0); + _screen->set16bitShadingLevel(0); + _screen->printText(_pageBreakString, x + (w >> 1) - (_vm->screen()->getTextWidth(_pageBreakString) >> 1), y + yOffs, _vm->_dialogueButtonLabelColor1, 0); } _vm->removeInputTop(); @@ -659,12 +673,14 @@ void TextDisplayer_rpg::textPageBreak() { } } while (loop && !_vm->shouldQuit()); + _screen->set16bitShadingLevel(4); if (_vm->gameFlags().use16ColorMode) _screen->fillRect(x + 8, y, x + 57, y + 9, _textDimData[_screen->curDimIndex()].color2); else - _screen->fillRect(x, y, x + w - 1, y + 8, _textDimData[_screen->curDimIndex()].color2); + _screen->fillRect(x, y, x + w - 1, y + _vm->guiSettings()->buttons.height - 1, _textDimData[_screen->curDimIndex()].color2); clearCurDim(); + _screen->set16bitShadingLevel(0); _screen->updateScreen(); if (_vm->game() == GI_LOL) @@ -709,7 +725,9 @@ void TextDisplayer_rpg::displayWaitButton() { while (!_vm->processDialogue() && !_vm->shouldQuit()) {} + _screen->set16bitShadingLevel(4); _screen->fillRect(_vm->_dialogueButtonPosX[0], _vm->_dialogueButtonPosY[0], _vm->_dialogueButtonPosX[0] + _vm->_dialogueButtonWidth - 1, _vm->_dialogueButtonPosY[0] + _vm->guiSettings()->buttons.height - 1, _vm->guiSettings()->colors.fill); + _screen->set16bitShadingLevel(0); _screen->updateScreen(); _vm->_dialogueButtonWidth = 95; SWAP(_vm->_dialogueButtonLabelColor1, _vm->_dialogueButtonLabelColor2); -- cgit v1.2.3