/* 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. * */ #ifdef ENABLE_LOL #include "kyra/gui_lol.h" #include "kyra/lol.h" #include "kyra/screen_lol.h" #include "kyra/resource.h" #include "kyra/util.h" #include "kyra/sound.h" #include "common/savefile.h" #include "common/system.h" #include "common/config-manager.h" #include "graphics/scaler.h" #include "backends/keymapper/keymapper.h" #include "base/version.h" namespace Kyra { void LoLEngine::gui_drawPlayField() { _screen->loadBitmap("PLAYFLD.CPS", 3, 3, 0); if (_flagsTable[31] & 0x40) { // copy compass shape static const int cx[] = { 112, 152, 224 }; _screen->copyRegion(cx[_flags.isTalkie ? _lang : 0], 32, 288, 0, 32, 32, 2, 2, Screen::CR_NO_P_CHECK); _compassDirection = -1; } if (_flagsTable[31] & 0x10) // draw automap book _screen->drawShape(2, _gameShapes[_flags.isTalkie ? 78 : 76], 290, 32, 0, 0); int cp = _screen->setCurPage(2); if (_flagsTable[31] & 0x20) { gui_drawScroll(); } else { _selectedSpell = 0; } if (_flagsTable[31] & 0x08) resetLampStatus(); updateDrawPage2(); gui_drawScene(2); gui_drawAllCharPortraitsWithStats(); gui_drawInventory(); gui_drawMoneyBox(_screen->_curPage); _screen->setCurPage(cp); _screen->copyPage(2, 0); updateDrawPage2(); } void LoLEngine::gui_drawScene(int pageNum) { if (!(_updateFlags & 1) && _weaponsDisabled == false && _partyAwake && _vcnBlocks) drawScene(pageNum); } void LoLEngine::gui_drawInventory() { if (!_currentControlMode || !_needSceneRestore) { for (int i = 0; i < 9; i++) gui_drawInventoryItem(i); } } void LoLEngine::gui_drawInventoryItem(int index) { static const uint16 inventoryXpos[] = { 0x6A, 0x7F, 0x94, 0xA9, 0xBE, 0xD3, 0xE8, 0xFD, 0x112 }; int x = inventoryXpos[index]; int item = _inventoryCurItem + index; if (item > 47) item -= 48; int flag = item & 1 ? 0 : 1; _screen->drawShape(_screen->_curPage, _gameShapes[4], x, 179, 0, flag); if (_inventory[item]) _screen->drawShape(_screen->_curPage, getItemIconShapePtr(_inventory[item]), x + 1, 180, 0, 0); } void LoLEngine::gui_drawScroll() { _screen->copyRegion(112, 0, 12, 0, 87, 15, 2, 2, Screen::CR_NO_P_CHECK); Screen::FontId of = _screen->setFont(Screen::FID_9_FNT); int h = 0; for (int i = 0; i < 7; i++) { if (_availableSpells[i] != -1) h += 9; } if (h == 18) h = 27; if (h) { _screen->copyRegion(201, 1, 17, 15, 6, h, 2, 2, Screen::CR_NO_P_CHECK); _screen->copyRegion(208, 1, 89, 15, 6, h, 2, 2, Screen::CR_NO_P_CHECK); _screen->fillRect(21, 15, 89, h + 15, _flags.use16ColorMode ? 0xBB : 206); } _screen->copyRegion(112, 16, 12, h + 15, 87, 14, 2, 2, Screen::CR_NO_P_CHECK); int y = 15; for (int i = 0; i < 7; i++) { if (_availableSpells[i] == -1) continue; uint8 col = (i == _selectedSpell) ? (_flags.use16ColorMode ? 0x88 : 132) : (_flags.use16ColorMode ? 0x44 : 1); _screen->fprintString("%s", 24, y, col, 0, 0, getLangString(_spellProperties[_availableSpells[i]].spellNameCode)); y += 9; } _screen->setFont(of); } void LoLEngine::gui_highlightSelectedSpell(bool mode) { int y = 15; Screen::FontId of = _screen->setFont(Screen::FID_9_FNT); for (int i = 0; i < 7; i++) { if (_availableSpells[i] == -1) continue; uint8 col = (mode && (i == _selectedSpell)) ? (_flags.use16ColorMode ? 0x88 : 132) : (_flags.use16ColorMode ? 0x44 : 1); _screen->fprintString("%s", 24, y, col, 0, 0, getLangString(_spellProperties[_availableSpells[i]].spellNameCode)); y += 9; } _screen->setFont(of); } void LoLEngine::gui_displayCharInventory(int charNum) { static const uint8 inventoryTypes[] = { 0, 1, 2, 6, 3, 1, 1, 3, 5, 4 }; int cp = _screen->setCurPage(2); LoLCharacter *l = &_characters[charNum]; int id = l->id; if (id < 0) id = -id; if (id != _lastCharInventory) { char file[13]; sprintf(file, "invent%d.cps", inventoryTypes[id]); _screen->loadBitmap(file, 3, 3, 0); _screen->copyRegion(0, 0, 112, 0, 208, 120, 2, 6); } else { _screen->copyRegion(112, 0, 0, 0, 208, 120, 6, 2); } _screen->copyRegion(80, 143, 80, 143, 232, 35, 0, 2); gui_drawAllCharPortraitsWithStats(); if (_flags.use16ColorMode) _screen->fprintString("%s", 156, 8, 0xE1, 0, 1, l->name); else _screen->fprintString("%s", 157, 9, 254, 0, 5, l->name); gui_printCharInventoryStats(charNum); for (int i = 0; i < 11; i++) gui_drawCharInventoryItem(i); Screen::FontId of = _screen->setFont(Screen::FID_9_FNT); _screen->fprintString("%s", 182, 103, _flags.use16ColorMode ? 0xBB : 172, 0, 5, getLangString(0x4033)); _screen->setFont(of); static const uint16 statusFlags[] = { 0x0080, 0x0000, 0x1000, 0x0002, 0x100, 0x0001, 0x0000, 0x0000 }; memset(_charStatusFlags, 0xFF, sizeof(_charStatusFlags)); int x = 0; int32 c = 0; for (int i = 0; i < 3; i++) { if (!(l->flags & statusFlags[i << 1])) continue; uint8 *shp = _gameShapes[statusFlags[(i << 1) + 1]]; _screen->drawShape(_screen->_curPage, shp, 108 + x, 98, 0, 0); x += (shp[3] + 2); _charStatusFlags[c] = statusFlags[(i << 1) + 1]; c++; } for (int i = 0; i < 3; i++) { int32 b = l->experiencePts[i] - _expRequirements[l->skillLevels[i] - 1]; int32 e = _expRequirements[l->skillLevels[i]] - _expRequirements[l->skillLevels[i] - 1]; while (e & 0xFFFF8000) { e >>= 1; c = b; b >>= 1; if (c && !b) b = 1; } if (_flags.use16ColorMode) gui_drawHorizontalBarGraph(154, 66 + i * 8, 34, 5, b, e, 0x88, 0); else gui_drawHorizontalBarGraph(154, 64 + i * 10, 34, 5, b, e, 132, 0); } _screen->drawClippedLine(14, 120, 194, 120, 1); _screen->copyRegion(0, 0, 112, 0, 208, 121, 2, 0); _screen->copyRegion(80, 143, 80, 143, 232, 35, 2, 0); _screen->setCurPage(cp); } void LoLEngine::gui_printCharInventoryStats(int charNum) { for (int i = 0; i < 5; i++) gui_printCharacterStats(i, 1, calculateCharacterStats(charNum, i)); _charInventoryUnk |= (1 << charNum); } void LoLEngine::gui_printCharacterStats(int index, int redraw, int value) { uint32 offs = _screen->_curPage ? 0 : 112; int y = 0; int col = 0; if (index < 2) { // might // protection if (_flags.use16ColorMode) { y = (index + 2) << 3; col = 0xA1; if (redraw) _screen->fprintString("%s", offs + 108, y, col, 0, 0, getLangString(0x4014 + index)); } else { y = index * 10 + 22; col = 158; if (redraw) _screen->fprintString("%s", offs + 108, y, col, 0, 4, getLangString(0x4014 + index)); } } else { //skills int s = index - 2; y = s * 10 + 62; if (_flags.use16ColorMode) { y = (s + 8) << 3; col = _characters[_selectedCharacter].flags & (0x200 << s) ? 0xE1 : 0x81; if (redraw) _screen->fprintString("%s", offs + 108, y, col, 0, 0, getLangString(0x4014 + index)); } else { y = s * 10 + 62; col = _characters[_selectedCharacter].flags & (0x200 << s) ? 254 : 180; if (redraw) _screen->fprintString("%s", offs + 108, y, col, 0, 4, getLangString(0x4014 + index)); } } if (offs) _screen->copyRegion(294, y, 182 + offs, y, 18, 8, 6, _screen->_curPage, Screen::CR_NO_P_CHECK); Screen::FontId of = (_flags.lang == Common::JA_JPN && _flags.use16ColorMode) ? _screen->setFont(Screen::FID_SJIS_FNT) : _screen->_currentFont; _screen->fprintString("%d", 200 + offs, y, col, 0, _flags.use16ColorMode ? 2 : 6, value); _screen->setFont(of); } void LoLEngine::gui_changeCharacterStats(int charNum) { int tmp[5]; int inc[5]; bool prc = false; for (int i = 0; i < 5; i++) { tmp[i] = calculateCharacterStats(charNum, i); int diff = tmp[i] - _charStatsTemp[i]; inc[i] = diff / 15; if (diff) { prc = true; if (!inc[i]) inc[i] = (diff < 0) ? -1 : 1; } } if (!prc) return; do { prc = false; for (int i = 0; i < 5; i++) { if (tmp[i] == _charStatsTemp[i]) continue; _charStatsTemp[i] += inc[i]; if ((inc[i] > 0 && tmp[i] < _charStatsTemp[i]) || (inc[i] < 0 && tmp[i] > _charStatsTemp[i])) _charStatsTemp[i] = tmp[i]; gui_printCharacterStats(i, 0, _charStatsTemp[i]); prc = true; } delay(_tickLength, true); } while (prc); } void LoLEngine::gui_drawCharInventoryItem(int itemIndex) { static const uint8 slotShapes[] = { 0x30, 0x34, 0x30, 0x34, 0x2E, 0x2F, 0x32, 0x33, 0x31, 0x35, 0x35 }; //2Eh, 32h, 2Eh, 32h, 2Ch, 2Dh, 30h, 31h, 2Fh, 33h, 33h const uint8 *coords = &_charInvDefs[_charInvIndex[_characters[_selectedCharacter].raceClassSex] * 22 + itemIndex * 2]; uint8 x = *coords++; uint8 y = *coords; if (y == 0xFF) return; if (!_screen->_curPage) x += 112; int i = _characters[_selectedCharacter].items[itemIndex]; int shapeNum = i ? ((itemIndex < 9) ? 4 : 5) : (_flags.isTalkie ? slotShapes[itemIndex] : slotShapes[itemIndex] - 2); _screen->drawShape(_screen->_curPage, _gameShapes[shapeNum], x, y, 0, 0); if (itemIndex > 8) { x -= 5; y -= 5; } if (i) _screen->drawShape(_screen->_curPage, getItemIconShapePtr(i), x + 1, y + 1, 0, 0); } void LoLEngine::gui_drawAllCharPortraitsWithStats() { int numChars = countActiveCharacters(); if (!numChars) return; for (int i = 0; i < numChars; i++) gui_drawCharPortraitWithStats(i); } void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { if (!(_characters[charNum].flags & 1) || _updateFlags & 2) return; Screen::FontId tmpFid = _screen->setFont(Screen::FID_6_FNT); int cp = _screen->setCurPage(6); gui_drawBox(0, 0, 66, 34, 1, 1, -1); gui_drawCharFaceShape(charNum, 0, 1, _screen->_curPage); if (_flags.use16ColorMode) { gui_drawLiveMagicBar(33, 32, _characters[charNum].magicPointsCur, 0, _characters[charNum].magicPointsMax, 5, 32, 0xAA, 0x44, 0); gui_drawLiveMagicBar(39, 32, _characters[charNum].hitPointsCur, 0, _characters[charNum].hitPointsMax, 5, 32, 0x66, 0x44, 1); _screen->printText(getLangString(0x4253), 33, 1, 0x99, 0); _screen->printText(getLangString(0x4254), 39, 1, 0x55, 0); } else { gui_drawLiveMagicBar(33, 32, _characters[charNum].magicPointsCur, 0, _characters[charNum].magicPointsMax, 5, 32, 162, 1, 0); gui_drawLiveMagicBar(39, 32, _characters[charNum].hitPointsCur, 0, _characters[charNum].hitPointsMax, 5, 32, 154, 1, 1); _screen->printText((_flags.platform == Common::kPlatformDOS && !_flags.isTalkie) ? "M" : getLangString(0x4253), 33, 1, 160, 0); _screen->printText((_flags.platform == Common::kPlatformDOS && !_flags.isTalkie) ? "H" : getLangString(0x4254), 39, 1, 152, 0); } int spellLevels = 0; if (_availableSpells[_selectedSpell] != -1) { for (int i = 0; i < 4; i++) { if (_spellProperties[_availableSpells[_selectedSpell]].mpRequired[i] <= _characters[charNum].magicPointsCur && _spellProperties[_availableSpells[_selectedSpell]].hpRequired[i] <= _characters[charNum].hitPointsCur) spellLevels++; } } if (_characters[charNum].flags & 0x10) { // magic submenu open _screen->drawShape(_screen->_curPage, _gameShapes[_flags.isTalkie ? 73 : 71], 44, 0, 0, 0); if (spellLevels < 4) _screen->drawGridBox(44, (spellLevels << 3) + 1, 22, 32 - (spellLevels << 3), 1); } else { // magic submenu closed int handIndex = 0; if (_characters[charNum].items[0]) { if (_itemProperties[_itemsInPlay[_characters[charNum].items[0]].itemPropertyIndex].might != -1) handIndex = _itemsInPlay[_characters[charNum].items[0]].itemPropertyIndex; } handIndex = _gameShapeMap[(_itemProperties[handIndex].shpIndex << 1) + 1]; if (handIndex == _gameShapeMap[1]) { // draw raceClassSex specific hand shape handIndex = _characters[charNum].raceClassSex - 1; if (handIndex < 0) handIndex = 0; handIndex += (_flags.isTalkie ? 68 : 66); } // draw hand/weapon _screen->drawShape(_screen->_curPage, _gameShapes[handIndex], 44, 0, 0, 0); // draw magic symbol _screen->drawShape(_screen->_curPage, _gameShapes[(_flags.isTalkie ? 72 : 70) + _characters[charNum].field_41], 44, 17, 0, 0); if (spellLevels == 0) _screen->drawGridBox(44, 17, 22, 16, 1); } uint16 f = _characters[charNum].flags & 0x314C; if ((f == 0 && _weaponsDisabled) || (f && (f != 4 || _characters[charNum].weaponHit == 0 || (_characters[charNum].weaponHit && _weaponsDisabled)))) _screen->drawGridBox(44, 0, 22, 34, 1); if (_characters[charNum].weaponHit) { _screen->drawShape(_screen->_curPage, _gameShapes[_flags.isTalkie ? 34 : 32], 44, 0, 0, 0); _screen->fprintString("%d", 57, 7, _flags.use16ColorMode ? 0x33 : 254, 0, 1, _characters[charNum].weaponHit); } if (_characters[charNum].damageSuffered) _screen->fprintString("%d", 17, 28, _flags.use16ColorMode ? 0x33 : 254, 0, 1, _characters[charNum].damageSuffered); uint8 col = (charNum != _selectedCharacter || countActiveCharacters() == 1) ? 1 : 212; if (_flags.use16ColorMode) col = (charNum != _selectedCharacter || countActiveCharacters() == 1) ? 0x44 : 0x22; _screen->drawBox(0, 0, 65, 33, col); _screen->copyRegion(0, 0, _activeCharsXpos[charNum], 143, 66, 34, _screen->_curPage, cp, Screen::CR_NO_P_CHECK); _screen->setCurPage(cp); _screen->setFont(tmpFid); } void LoLEngine::gui_drawCharFaceShape(int charNum, int x, int y, int pageNum) { if (_characters[charNum].curFaceFrame < 7 && _characters[charNum].tempFaceFrame) _characters[charNum].curFaceFrame = _characters[charNum].tempFaceFrame; if (_characters[charNum].tempFaceFrame == 0 && _characters[charNum].curFaceFrame > 1 && _characters[charNum].curFaceFrame < 7) _characters[charNum].curFaceFrame = _characters[charNum].tempFaceFrame; int frm = (_characters[charNum].flags & 0x1108 && _characters[charNum].curFaceFrame < 7) ? 1 : _characters[charNum].curFaceFrame; if (_characters[charNum].hitPointsCur <= (_characters[charNum].hitPointsMax >> 1)) frm += 14; if (!pageNum) _screen->hideMouse(); _screen->drawShape(pageNum, _characterFaceShapes[frm][charNum], x, y, 0, 0x100, _screen->_paletteOverlay2, (_characters[charNum].flags & 0x80 ? 1 : 0)); if (_characters[charNum].flags & 0x40) // draw spider web _screen->drawShape(pageNum, _gameShapes[21], x, y, 0, 0); if (!pageNum) _screen->showMouse(); } void LoLEngine::gui_highlightPortraitFrame(int charNum) { if (charNum != _selectedCharacter) { int o = _selectedCharacter; _selectedCharacter = charNum; gui_drawCharPortraitWithStats(o); } gui_drawCharPortraitWithStats(charNum); } void LoLEngine::gui_drawLiveMagicBar(int x, int y, int curPoints, int unk, int maxPoints, int w, int h, int col1, int col2, int flag) { w--; h--; if (maxPoints < 1) return; int t = (curPoints < 1) ? 0 : curPoints; curPoints = (maxPoints < t) ? maxPoints : t; int barHeight = (curPoints * h) / maxPoints; if (barHeight < 1 && curPoints > 0) barHeight = 1; _screen->drawClippedLine(x - 1, y - h, x - 1, y, _flags.use16ColorMode ? 0x44 : 1); if (flag) { t = maxPoints >> 1; if (t > curPoints) col1 = _flags.use16ColorMode ? 0xBB : 144; t = maxPoints >> 2; if (t > curPoints) col1 = _flags.use16ColorMode ? 0x88 : 132; } if (barHeight > 0) _screen->fillRect(x, y - barHeight, x + w, y, col1); if (barHeight < h) _screen->fillRect(x, y - h, x + w, y - barHeight, col2); if (unk > 0 && unk < maxPoints) _screen->drawBox(x, y - barHeight, x + w, y, col1 - 2); } void LoLEngine::calcCharPortraitXpos() { int nc = countActiveCharacters(); if (_currentControlMode && !textEnabled()) { int t = (280 - (nc * 33)) / (nc + 1); for (int i = 0; i < nc; i++) _activeCharsXpos[i] = i * 33 + t * (i + 1) + 10; } else { int t = (235 - (nc * 66)) / (nc + 1); for (int i = 0; i < nc; i++) _activeCharsXpos[i] = i * 66 + t * (i + 1) + 83; } } void LoLEngine::gui_drawMoneyBox(int pageNum) { static const uint16 moneyX256[] = { 0x128, 0x134, 0x12B, 0x131, 0x12E}; static const uint16 moneyY256[] = { 0x73, 0x73, 0x74, 0x74, 0x75}; static const uint16 moneyX16[] = { 0x127, 0x133, 0x12A, 0x130, 0x12D}; static const uint16 moneyY16[] = { 0x74, 0x74, 0x75, 0x75, 0x76}; int backupPage = _screen->_curPage; _screen->_curPage = pageNum; const uint16 *moneyX; const uint16 *moneyY; if (_flags.use16ColorMode) { moneyX = moneyX16; moneyY = moneyY16; _screen->fillRect(291, 98, 315, 118, 0x11, pageNum); } else { moneyX = moneyX256; moneyY = moneyY256; _screen->fillRect(292, 97, 316, 118, 252, pageNum); } for (int i = 0; i < 5; i++) { if (!_moneyColumnHeight[i]) continue; uint8 h = _moneyColumnHeight[i] - 1; _screen->drawClippedLine(moneyX[i], moneyY[i], moneyX[i], moneyY[i] - h, _flags.use16ColorMode ? 1 : 0xD2); _screen->drawClippedLine(moneyX[i] + 1, moneyY[i], moneyX[i] + 1, moneyY[i] - h, _flags.use16ColorMode ? 2 : 0xD1); _screen->drawClippedLine(moneyX[i] + 2, moneyY[i], moneyX[i] + 2, moneyY[i] - h, _flags.use16ColorMode ? 3 : 0xD0); _screen->drawClippedLine(moneyX[i] + 3, moneyY[i], moneyX[i] + 3, moneyY[i] - h, _flags.use16ColorMode ? 2 : 0xD1); _screen->drawClippedLine(moneyX[i] + 4, moneyY[i], moneyX[i] + 4, moneyY[i] - h, _flags.use16ColorMode ? 1 : 0xD2); } Screen::FontId backupFont = _screen->setFont(Screen::FID_6_FNT); if (_flags.use16ColorMode) _screen->fprintString("%d", 304, 99, 0x33, 0, 1, _credits); else _screen->fprintString("%d", 305, 98, 254, 0, 1, _credits); _screen->setFont(backupFont); _screen->_curPage = backupPage; if (pageNum == 6) { if (_flags.use16ColorMode) _screen->copyRegion(291, 98, 291, 98, 24, 20, 6, 0); else _screen->copyRegion(292, 97, 292, 97, 25, 22, 6, 0); } } void LoLEngine::gui_drawCompass() { if (!(_flagsTable[31] & 0x40)) return; if (_compassDirection == -1) { _compassDirectionIndex = -1; _compassDirection = _currentDirection << 6; } int t = ((_compassDirection + 4) >> 3) & 0x1F; if (t == _compassDirectionIndex) return; _compassDirectionIndex = t; if (!_screen->_curPage) _screen->hideMouse(); const CompassDef *c = &_compassDefs[t]; int compassShp = 22; int compassPtr = 23; if (_flags.isTalkie) { compassShp += _lang; compassPtr = 25; } _screen->drawShape(_screen->_curPage, _gameShapes[compassShp], 294, 3, 0, 0); _screen->drawShape(_screen->_curPage, _gameShapes[compassPtr + c->shapeIndex], 298 + c->x, c->y + 9, 0, c->flags | 0x300, _screen->_paletteOverlay1, 1); _screen->drawShape(_screen->_curPage, _gameShapes[compassPtr + c->shapeIndex], 299 + c->x, c->y + 8, 0, c->flags); if (!_screen->_curPage) _screen->showMouse(); } int LoLEngine::gui_enableControls() { _floatingCursorControl = 0; int start = 74; int end = 83; if (_flags.isTalkie) { start = 76; end = 85; } if (!_currentControlMode) { for (int i = start; i < end; i++) gui_toggleButtonDisplayMode(i, 2); } gui_toggleFightButtons(false); return 1; } int LoLEngine::gui_disableControls(int controlMode) { if (_currentControlMode) return 0; _floatingCursorControl = (controlMode & 2) ? 2 : 1; gui_toggleFightButtons(true); int start = 74; int end = 83; int swtch = 76; if (_flags.isTalkie) { start = 76; end = 85; swtch = 78; } for (int i = start; i < end; i++) gui_toggleButtonDisplayMode(i, ((controlMode & 2) && (i > swtch)) ? 2 : 3); return 1; } void LoLEngine::gui_toggleButtonDisplayMode(int shapeIndex, int mode) { static const int16 buttonX[] = { 0x0056, 0x0128, 0x000C, 0x0021, 0x0122, 0x000C, 0x0021, 0x0036, 0x000C, 0x0021, 0x0036 }; static const int16 buttonY[] = { 0x00B4, 0x00B4, 0x00B4, 0x00B4, 0x0020, 0x0084, 0x0084, 0x0084, 0x0096, 0x0096, 0x0096 }; int swtch = 76; int subst = 72; if (_flags.isTalkie) { swtch = 78; subst = 74; } if (shapeIndex == swtch && !(_flagsTable[31] & 0x10)) return; if (_currentControlMode && _needSceneRestore) return; if (mode == 0) shapeIndex = _lastButtonShape; int pageNum = 0; int16 x1 = buttonX[shapeIndex - subst]; int16 y1 = buttonY[shapeIndex - subst]; int16 x2 = 0; int16 y2 = 0; uint32 t = 0; switch (mode) { case 1: mode = 0x100; _lastButtonShape = shapeIndex; break; case 0: if (!_lastButtonShape) return; t = _system->getMillis(); if (_buttonPressTimer > t) delay(_buttonPressTimer - t); // fall through case 2: mode = 0; _lastButtonShape = 0; break; case 3: mode = 0; _lastButtonShape = 0; pageNum = 6; x2 = x1; y2 = y1; x1 = 0; y1 = 0; break; default: break; } _screen->drawShape(pageNum, _gameShapes[shapeIndex], x1, y1, 0, mode, _screen->_paletteOverlay1, 1); if (!pageNum) _screen->updateScreen(); if (pageNum == 6) { int cp = _screen->setCurPage(6); _screen->drawGridBox(x1, y1, _gameShapes[shapeIndex][3], _gameShapes[shapeIndex][2], 1); _screen->copyRegion(x1, y1, x2, y2, _gameShapes[shapeIndex][3], _gameShapes[shapeIndex][2], pageNum, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); _screen->setCurPage(cp); } _buttonPressTimer = _system->getMillis() + 6 * _tickLength; } void LoLEngine::gui_toggleFightButtons(bool disable) { for (int i = 0; i < 3; i++) { if (!(_characters[i].flags & 1)) continue; if (disable) _characters[i].flags |= 0x2000; else _characters[i].flags &= 0xDFFF; if (disable && !textEnabled()) { int u = _selectedCharacter; _selectedCharacter = 99; int f = _updateFlags; _updateFlags &= 0xFFFD; gui_drawCharPortraitWithStats(i); _updateFlags = f; _selectedCharacter = u; } else { gui_drawCharPortraitWithStats(i); } } } void LoLEngine::gui_updateInput() { // TODO: We need to catch all cases where loading is not possible and // set the "mainLoop" parameter to false for them. int inputFlag = checkInput(_activeButtons, !((_updateFlags & 3) || _weaponsDisabled), 0); if (_preserveEvents) _preserveEvents = false; else removeInputTop(); if (inputFlag && _activeMagicMenu != -1 && !(inputFlag & 0x8800)) { gui_enableDefaultPlayfieldButtons(); _characters[_activeMagicMenu].flags &= 0xFFEF; gui_drawCharPortraitWithStats(_activeMagicMenu); gui_triggerEvent(inputFlag); _preserveEvents = false; _activeMagicMenu = -1; inputFlag = 0; } if (inputFlag == _keyMap[Common::KEYCODE_SPACE] || inputFlag == _keyMap[Common::KEYCODE_RETURN]) { snd_stopSpeech(true); } else if (inputFlag == _keyMap[Common::KEYCODE_SLASH]) { if (_weaponsDisabled || _availableSpells[1] == -1) return; gui_highlightSelectedSpell(false); if (_availableSpells[++_selectedSpell] == -1) _selectedSpell = 0; gui_highlightSelectedSpell(true); gui_drawAllCharPortraitsWithStats(); } } void LoLEngine::gui_triggerEvent(int eventType) { Common::Event evt; memset(&evt, 0, sizeof(Common::Event)); evt.mouse.x = _mouseX; evt.mouse.y = _mouseY; if (eventType == 65 || eventType == 199) { evt.type = Common::EVENT_LBUTTONDOWN; } else if (eventType == 66 || eventType == 201) { evt.type = Common::EVENT_RBUTTONDOWN; } else { evt.type = Common::EVENT_KEYDOWN; for (KeyMap::const_iterator c = _keyMap.begin(); c != _keyMap.end(); ++c) { if (c->_value == eventType) evt.kbd.keycode = (Common::KeyCode)c->_key; } } removeInputTop(); _eventList.push_back(Event(evt, true)); _preserveEvents = true; } void LoLEngine::gui_enableDefaultPlayfieldButtons() { gui_resetButtonList(); gui_initButtonsFromList(_buttonList1); gui_setFaceFramesControlButtons(7, 44); gui_setFaceFramesControlButtons(11, 44); gui_setFaceFramesControlButtons(17, 0); gui_setFaceFramesControlButtons(29, 0); gui_setFaceFramesControlButtons(25, 33); if (_flagsTable[31] & 0x20) gui_initMagicScrollButtons(); } void LoLEngine::gui_enableSequenceButtons(int x, int y, int w, int h, int enableFlags) { gui_resetButtonList(); _sceneWindowButton.x = x; _sceneWindowButton.y = y; _sceneWindowButton.w = w; _sceneWindowButton.h = h; gui_initButtonsFromList(_buttonList3); if (enableFlags & 1) gui_initButtonsFromList(_buttonList4); if (enableFlags & 2) gui_initButtonsFromList(_buttonList5); } void LoLEngine::gui_specialSceneRestoreButtons() { if (!_spsWindowW && !_spsWindowH) return; gui_enableDefaultPlayfieldButtons(); _spsWindowX = _spsWindowY = _spsWindowW = _spsWindowH = _seqTrigger = 0; } void LoLEngine::gui_enableCharInventoryButtons(int charNum) { gui_resetButtonList(); gui_initButtonsFromList(_buttonList2); gui_initCharInventorySpecialButtons(charNum); gui_setFaceFramesControlButtons(21, 0); } void LoLEngine::gui_setFaceFramesControlButtons(int index, int xOffs) { int c = countActiveCharacters(); for (int i = 0; i < c; i++) gui_initButton(index + i, _activeCharsXpos[i] + xOffs); } void LoLEngine::gui_initCharInventorySpecialButtons(int charNum) { const uint8 *s = &_charInvDefs[_charInvIndex[_characters[charNum].raceClassSex] * 22]; for (int i = 0; i < 11; i++) { if (*s != 0xFF) gui_initButton(33 + i, s[0], s[1], i); s += 2; } } void LoLEngine::gui_initMagicScrollButtons() { for (int i = 0; i < 7; i++) { if (_availableSpells[i] == -1) continue; gui_initButton(71 + i, -1, -1, i); } } void LoLEngine::gui_initMagicSubmenu(int charNum) { gui_resetButtonList(); _subMenuIndex = charNum; gui_initButtonsFromList(_buttonList7); } void LoLEngine::gui_initButton(int index, int x, int y, int val) { Button *b = 0; int cnt = 1; if (_activeButtons) { Button *n = _activeButtons; while (n->nextButton) { ++cnt; n = n->nextButton; } ++cnt; b = n->nextButton = &_activeButtonData[cnt]; } else { b = &_activeButtonData[0]; _activeButtons = b; } *b = Button(); b->nextButton = 0; b->data0Val2 = b->data1Val2 = b->data2Val2 = 0xFE; b->data0Val3 = b->data1Val3 = b->data2Val3 = 0x01; b->index = cnt; b->keyCode = _buttonData[index].keyCode; b->keyCode2 = _buttonData[index].keyCode2; b->dimTableIndex = _buttonData[index].screenDim; b->flags = _buttonData[index].buttonflags; b->arg = (val != -1) ? (uint8)(val & 0xFF) : _buttonData[index].index; if (index == 15) { // magic sub menu b->x = _activeCharsXpos[_subMenuIndex] + 44; b->arg = _subMenuIndex; b->y = _buttonData[index].y; b->width = _buttonData[index].w - 1; b->height = _buttonData[index].h - 1; } else if (index == 64) { // scene window button b->x = _sceneWindowButton.x; b->y = _sceneWindowButton.y; b->width = _sceneWindowButton.w - 1; b->height = _sceneWindowButton.h - 1; } else { b->x = x != -1 ? x : _buttonData[index].x; b->y = y != -1 ? y : _buttonData[index].y; b->width = _buttonData[index].w - 1; b->height = _buttonData[index].h - 1; } b->buttonCallback = _buttonCallbacks[index]; } int LoLEngine::clickedUpArrow(Button *button) { if (button->arg && !_floatingCursorsEnabled) return 0; moveParty(_currentDirection, ((button->flags2 & 0x1080) == 0x1080) ? 1 : 0, 0, _flags.isTalkie ? 80 : 78); return 1; } int LoLEngine::clickedDownArrow(Button *button) { if (button->arg && !_floatingCursorsEnabled) return 0; moveParty(_currentDirection ^ 2, 0, 1, _flags.isTalkie ? 83 : 81); return 1; } int LoLEngine::clickedLeftArrow(Button *button) { if (button->arg && !_floatingCursorsEnabled) return 0; moveParty((_currentDirection - 1) & 3, ((button->flags2 & 0x1080) == 0x1080) ? 1 : 0, 2, _flags.isTalkie ? 82 : 80); return 1; } int LoLEngine::clickedRightArrow(Button *button) { if (button->arg && !_floatingCursorsEnabled) return 0; moveParty((_currentDirection + 1) & 3, ((button->flags2 & 0x1080) == 0x1080) ? 1 : 0, 3, _flags.isTalkie ? 84 : 82); return 1; } int LoLEngine::clickedTurnLeftArrow(Button *button) { if (button->arg && !_floatingCursorsEnabled) return 0; gui_toggleButtonDisplayMode(_flags.isTalkie ? 79 : 77, 1); _currentDirection = (_currentDirection - 1) & 3; _sceneDefaultUpdate = 1; runLevelScript(_currentBlock, 0x4000); initTextFading(2, 0); if (!_sceneDefaultUpdate) gui_drawScene(0); else movePartySmoothScrollTurnLeft(1); gui_toggleButtonDisplayMode(_flags.isTalkie ? 79 : 77, 0); runLevelScript(_currentBlock, 0x10); return 1; } int LoLEngine::clickedTurnRightArrow(Button *button) { if (button->arg && !_floatingCursorsEnabled) return 0; gui_toggleButtonDisplayMode(_flags.isTalkie ? 81 : 79, 1); _currentDirection = (_currentDirection + 1) & 3; _sceneDefaultUpdate = 1; runLevelScript(_currentBlock, 0x4000); initTextFading(2, 0); if (!_sceneDefaultUpdate) gui_drawScene(0); else movePartySmoothScrollTurnRight(1); gui_toggleButtonDisplayMode(_flags.isTalkie ? 81 : 79, 0); runLevelScript(_currentBlock, 0x10); return 1; } int LoLEngine::clickedAttackButton(Button *button) { int c = button->arg; if (_characters[c].flags & 0x314C) return 1; int bl = calcNewBlockPosition(_currentBlock, _currentDirection); if (_levelBlockProperties[bl].flags & 0x10) { breakIceWall(0, 0); return 1; } uint16 target = getNearestMonsterFromCharacter(c); int s = 0; for (int i = 0; i < 4; i++) { if (!_characters[c].items[i]) continue; runItemScript(c, _characters[c].items[i], 0x400, target, s); runLevelScriptCustom(_currentBlock, 0x400, c, _characters[c].items[i], target, s); s -= 10; } if (!s) { runItemScript(c, 0, 0x400, target, s); runLevelScriptCustom(_currentBlock, 0x400, c, 0, target, s); } s = _characters[c].weaponHit ? 4 : calcMonsterSkillLevel(c, 8) + 4; // check for Zephyr ring if (itemEquipped(c, 230)) s >>= 1; _characters[c].flags |= 4; gui_highlightPortraitFrame(c); setCharacterUpdateEvent(c, 1, s, 1); return 1; } int LoLEngine::clickedMagicButton(Button *button) { int c = button->arg; if (_characters[c].flags & 0x314C) return 1; if (checkMagic(c, _availableSpells[_selectedSpell], 0)) return 1; _characters[c].flags ^= 0x10; gui_drawCharPortraitWithStats(c); gui_initMagicSubmenu(c); _activeMagicMenu = c; return 1; } int LoLEngine::clickedMagicSubmenu(Button *button) { int spellLevel = (_mouseY - 144) >> 3; int c = button->arg; gui_enableDefaultPlayfieldButtons(); if (checkMagic(c, _availableSpells[_selectedSpell], spellLevel)) { _characters[c].flags &= 0xFFEF; gui_drawCharPortraitWithStats(c); } else { _characters[c].flags |= 4; _characters[c].flags &= 0xFFEF; if (castSpell(c, _availableSpells[_selectedSpell], spellLevel)) { setCharacterUpdateEvent(c, 1, 8, 1); increaseExperience(c, 2, spellLevel * spellLevel); } else { _characters[c].flags &= 0xFFFB; gui_drawCharPortraitWithStats(c); } } _activeMagicMenu = -1; return 1; } int LoLEngine::clickedScreen(Button *button) { _characters[_activeMagicMenu].flags &= 0xFFEF; gui_drawCharPortraitWithStats(_activeMagicMenu); _activeMagicMenu = -1; if (!(button->flags2 & 0x80)) { if (button->flags2 & 0x100) gui_triggerEvent(65); else gui_triggerEvent(66); } gui_enableDefaultPlayfieldButtons(); return 1; } int LoLEngine::clickedPortraitLeft(Button *button) { disableSysTimer(2); if (!_weaponsDisabled) { _screen->copyRegionToBuffer(2, 0, 0, 320, 200, _pageBuffer2); _screen->copyPage(0, 2); _screen->copyRegionToBuffer(2, 0, 0, 320, 200, _pageBuffer1); _updateFlags |= 0x0C; gui_disableControls(1); } _selectedCharacter = button->arg; _weaponsDisabled = true; if (_flags.use16ColorMode) _screen->fillRect(112, 0, 288, 120, 0, 2); gui_displayCharInventory(_selectedCharacter); gui_enableCharInventoryButtons(_selectedCharacter); return 1; } int LoLEngine::clickedLiveMagicBarsLeft(Button *button) { gui_highlightPortraitFrame(button->arg); _txt->printMessage(0, getLangString(0x4047), _characters[button->arg].name, _characters[button->arg].hitPointsCur, _characters[button->arg].hitPointsMax, _characters[button->arg].magicPointsCur, _characters[button->arg].magicPointsMax); return 1; } int LoLEngine::clickedPortraitEtcRight(Button *button) { if (!_itemInHand) return 1; int flg = _itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].flags; int c = button->arg; if (flg & 1) { if (!(_characters[c].flags & 8) || (flg & 0x20)) { runItemScript(c, _itemInHand, 0x400, 0, 0); runLevelScriptCustom(_currentBlock, 0x400, c, _itemInHand, 0, 0); } else { _txt->printMessage(2, getLangString(0x402C), _characters[c].name); } return 1; } _txt->printMessage(2, "%s", getLangString((flg & 8) ? 0x4029 : ((flg & 0x10) ? 0x402A : 0x402B))); return 1; } int LoLEngine::clickedCharInventorySlot(Button *button) { if (_itemInHand) { uint16 sl = 1 << button->arg; int type = _itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].type; if (!(sl & type)) { bool f = false; for (int i = 0; i < 11; i++) { if (!(type & (1 << i))) continue; _txt->printMessage(0, getLangString(i > 3 ? 0x418A : 0x418B), getLangString(_itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].nameStringId), getLangString(_inventorySlotDesc[i])); f = true; } if (!f) _txt->printMessage(_itemsInPlay[_itemInHand].itemPropertyIndex == 231 ? 2 : 0, "%s", getLangString(0x418C)); return 1; } } else { if (!_characters[_selectedCharacter].items[button->arg]) { _txt->printMessage(0, "%s", getLangString(_inventorySlotDesc[button->arg] + 8)); return 1; } } int ih = _itemInHand; setHandItem(_characters[_selectedCharacter].items[button->arg]); _characters[_selectedCharacter].items[button->arg] = ih; gui_drawCharInventoryItem(button->arg); recalcCharacterStats(_selectedCharacter); if (_itemInHand) runItemScript(_selectedCharacter, _itemInHand, 0x100, 0, 0); if (ih) runItemScript(_selectedCharacter, ih, 0x80, 0, 0); gui_drawCharInventoryItem(button->arg); gui_drawCharPortraitWithStats(_selectedCharacter); gui_changeCharacterStats(_selectedCharacter); return 1; } int LoLEngine::clickedExitCharInventory(Button *button) { _updateFlags &= 0xFFF3; gui_enableDefaultPlayfieldButtons(); _weaponsDisabled = false; for (int i = 0; i < 4; i++) { if (_charInventoryUnk & (1 << i)) _characters[i].flags &= 0xF1FF; } _screen->copyBlockToPage(2, 0, 0, 320, 200, _pageBuffer1); int cp = _screen->setCurPage(2); gui_drawAllCharPortraitsWithStats(); gui_drawInventory(); _screen->setCurPage(cp); _screen->copyPage(2, 0); _screen->updateScreen(); gui_enableControls(); _screen->copyBlockToPage(2, 0, 0, 320, 200, _pageBuffer2); _lastCharInventory = -1; updateDrawPage2(); enableSysTimer(2); return 1; } int LoLEngine::clickedSceneDropItem(Button *button) { static const uint8 offsX[] = { 0x40, 0xC0, 0x40, 0xC0 }; static const uint8 offsY[] = { 0x40, 0x40, 0xC0, 0xC0 }; if ((_updateFlags & 1) || !_itemInHand) return 0; uint16 block = _currentBlock; if (button->arg > 1) { block = calcNewBlockPosition(_currentBlock, _currentDirection); int f = _wllWallFlags[_levelBlockProperties[block].walls[_currentDirection ^ 2]]; if (!(f & 0x80) || (f & 2)) return 1; } uint16 x = 0; uint16 y = 0; int i = _dropItemDirIndex[(_currentDirection << 2) + button->arg]; calcCoordinates(x, y, block, offsX[i], offsY[i]); setItemPosition(_itemInHand, x, y, 0, 1); setHandItem(0); return 1; } int LoLEngine::clickedScenePickupItem(Button *button) { static const int8 checkX[] = { 0, 0, 1, 0, -1, -1, 1, 1, -1, 0, 2, 0, -2, -1, 1, 2, 2, 1, -1, -2, -2 }; static const int8 checkY[] = { 0, -1, 0, 1, 0, -1, -1, 1, 1, -2, 0, 2, 0, -2, -2, -1, 1, 2, 2, 1, -1 }; static const int len = ARRAYSIZE(checkX); if ((_updateFlags & 1) || _itemInHand) return 0; int cp = _screen->setCurPage(_sceneDrawPage1); redrawSceneItem(); int p = 0; for (int i = 0; i < len; i++) { p = _screen->getPagePixel(_screen->_curPage, CLIP(_mouseX + checkX[i], 0, 320), CLIP(_mouseY + checkY[i], 0, 200)); if (p) break; } _screen->setCurPage(cp); if (!p) return 0; uint16 block = (p <= 128) ? calcNewBlockPosition(_currentBlock, _currentDirection) : _currentBlock; int found = checkSceneForItems(&_levelBlockProperties[block].drawObjects, p & 0x7F); if (found != -1) { removeLevelItem(found, block); setHandItem(found); } _sceneUpdateRequired = true; return 1; } int LoLEngine::clickedInventorySlot(Button *button) { int slot = _inventoryCurItem + button->arg; if (slot > 47) slot -= 48; uint16 slotItem = _inventory[slot]; int hItem = _itemInHand; if ((_itemsInPlay[hItem].itemPropertyIndex == 281 || _itemsInPlay[slotItem].itemPropertyIndex == 281) && (_itemsInPlay[hItem].itemPropertyIndex == 220 || _itemsInPlay[slotItem].itemPropertyIndex == 220)) { // merge ruby of truth WSAMovie_v2 *wsa = new WSAMovie_v2(this); wsa->open("truth.wsa", 0, 0); _screen->hideMouse(); _inventory[slot] = 0; gui_drawInventoryItem(button->arg); _screen->copyRegion(button->x, button->y - 3, button->x, button->y - 3, 25, 27, 0, 2); KyraEngine_v1::snd_playSoundEffect(99); for (int i = 0; i < 25; i++) { uint32 delayTimer = _system->getMillis() + 7 * _tickLength; _screen->copyRegion(button->x, button->y - 3, 0, 0, 25, 27, 2, 2); wsa->displayFrame(i, 2, 0, 0, 0x4000, 0, 0); _screen->copyRegion(0, 0, button->x, button->y - 3, 25, 27, 2, 0); _screen->updateScreen(); delayUntil(delayTimer); } _screen->showMouse(); wsa->close(); delete wsa; deleteItem(slotItem); deleteItem(hItem); setHandItem(0); _inventory[slot] = makeItem(280, 0, 0); } else { setHandItem(slotItem); _inventory[slot] = hItem; } gui_drawInventoryItem(button->arg); return 1; } int LoLEngine::clickedInventoryScroll(Button *button) { int8 inc = (int8)button->arg; int shp = (inc == 1) ? 75 : 74; if (!_flags.isTalkie) shp -= 2; if (button->flags2 & 0x1000) inc *= 9; _inventoryCurItem += inc; gui_toggleButtonDisplayMode(shp, 1); if (_inventoryCurItem < 0) _inventoryCurItem += 48; if (_inventoryCurItem > 47) _inventoryCurItem -= 48; gui_drawInventory(); gui_toggleButtonDisplayMode(shp, 0); return 1; } int LoLEngine::clickedWall(Button *button) { int block = calcNewBlockPosition(_currentBlock, _currentDirection); int dir = _currentDirection ^ 2; uint8 type = _specialWallTypes[_levelBlockProperties[block].walls[dir]]; int res = 0; switch (type) { case 1: res = clickedWallShape(block, dir); break; case 2: res = clickedLeverOn(block, dir); break; case 3: res = clickedLeverOff(block, dir); break; case 4: res = clickedWallOnlyScript(block); break; case 5: res = clickedDoorSwitch(block, dir); break; case 6: res = clickedNiche(block, dir); break; default: break; } return res; } int LoLEngine::clickedSequenceWindow(Button *button) { runLevelScript(calcNewBlockPosition(_currentBlock, _currentDirection), 0x40); if (!_seqTrigger || !posWithinRect(_mouseX, _mouseY, _seqWindowX1, _seqWindowY1, _seqWindowX2, _seqWindowY2)) { _seqTrigger = 0; removeInputTop(); } return 1; } int LoLEngine::clickedScroll(Button *button) { if (_selectedSpell == button->arg) return 1; gui_highlightSelectedSpell(false); _selectedSpell = button->arg; gui_highlightSelectedSpell(true); gui_drawAllCharPortraitsWithStats(); return 1; } int LoLEngine::clickedSpellTargetCharacter(Button *button) { int t = button->arg; _txt->printMessage(0, "%s.\r", _characters[t].name); if ((_spellProperties[_activeSpell.spell].flags & 0xFF) == 1) { _activeSpell.target = t; castHealOnSingleCharacter(&_activeSpell); } gui_enableDefaultPlayfieldButtons(); return 1; } int LoLEngine::clickedSpellTargetScene(Button *button) { LoLCharacter *c = &_characters[_activeSpell.charNum]; _txt->printMessage(0, "%s", getLangString(0x4041)); c->magicPointsCur += _activeSpell.p->mpRequired[_activeSpell.level]; if (c->magicPointsCur > c->magicPointsMax) c->magicPointsCur = c->magicPointsMax; c->hitPointsCur += _activeSpell.p->hpRequired[_activeSpell.level]; if (c->hitPointsCur > c->hitPointsMax) c->hitPointsCur = c->hitPointsMax; gui_drawCharPortraitWithStats(_activeSpell.charNum); gui_enableDefaultPlayfieldButtons(); return 1; } int LoLEngine::clickedSceneThrowItem(Button *button) { if (_updateFlags & 1) return 0; uint16 block = calcNewBlockPosition(_currentBlock, _currentDirection); if ((_wllWallFlags[_levelBlockProperties[block].walls[_currentDirection ^ 2]] & 2) || !_itemInHand) return 0; uint16 x = 0; uint16 y = 0; calcCoordinates(x, y, _currentBlock, 0x80, 0x80); if (launchObject(0, _itemInHand, x, y, 12, _currentDirection << 1, 6, _selectedCharacter, 0x3F)) { snd_playSoundEffect(18, -1); setHandItem(0); } _sceneUpdateRequired = true; return 1; } int LoLEngine::clickedOptions(Button *button) { removeInputTop(); gui_toggleButtonDisplayMode(_flags.isTalkie ? 76 : 74, 1); _updateFlags |= 4; Button b; b.data0Val2 = b.data1Val2 = b.data2Val2 = 0xFE; b.data0Val3 = b.data1Val3 = b.data2Val3 = 0x01; if (_weaponsDisabled) clickedExitCharInventory(&b); initTextFading(0, 1); stopPortraitSpeechAnim(); setLampMode(true); setMouseCursorToIcon(0); disableSysTimer(2); gui_toggleButtonDisplayMode(_flags.isTalkie ? 76 : 74, 0); bool speechWasEnabled = speechEnabled(); if (_flags.isTalkie && getVolume(kVolumeSpeech) == 2) _configVoice |= (textEnabled() ? 2 : 1); _gui->runMenu(_gui->_mainMenu); _updateFlags &= 0xFFFB; setMouseCursorToItemInHand(); resetLampStatus(); gui_enableDefaultPlayfieldButtons(); enableSysTimer(2); updateDrawPage2(); gui_drawPlayField(); if (getVolume(kVolumeSpeech) == 2) _configVoice &= (textEnabled() ? ~2 : ~1); if (speechWasEnabled && !textEnabled() && !speechEnabled()) _configVoice = 0; writeSettings(); return 1; } int LoLEngine::clickedRestParty(Button *button) { gui_toggleButtonDisplayMode(_flags.isTalkie ? 77 : 75, 1); Button b; b.data0Val2 = b.data1Val2 = b.data2Val2 = 0xFE; b.data0Val3 = b.data1Val3 = b.data2Val3 = 0x01; if (_weaponsDisabled) clickedExitCharInventory(&b); int tHp = -1; int tMp = -1; int tHa = -1; int needPoisoningFlags = 0; int needHealingFlags = 0; int needMagicGainFlags = 0; for (int i = 0; i < 4; i++) { LoLCharacter *c = &_characters[i]; if (!(c->flags & 1) || (c->flags & 8)) continue; if (c->hitPointsMax > tHp) tHp = c->hitPointsMax; if (c->magicPointsMax > tMp) tMp = c->magicPointsMax; if (c->flags & 0x80) { needPoisoningFlags |= (1 << i); if (c->hitPointsCur > tHa) tHa = c->hitPointsCur; } else { if (c->hitPointsCur < c->hitPointsMax) needHealingFlags |= (1 << i); } if (c->magicPointsCur < c->magicPointsMax) needMagicGainFlags |= (1 << i); c->flags |= 0x1000; } removeInputTop(); if (needHealingFlags || needMagicGainFlags) { _screen->fillRect(112, 0, 288, 120, _flags.use16ColorMode ? 0x44 : 1); gui_drawAllCharPortraitsWithStats(); _txt->printMessage(0x8000, "%s", getLangString(0x4057)); gui_toggleButtonDisplayMode(_flags.isTalkie ? 77 : 75, 0); int h = 600 / tHp; if (h > 30) h = 30; int m = 600 / tMp; if (m > 30) m = 30; int a = 600 / tHa; if (a > 15) a = 15; uint32 delay1 = _system->getMillis() + h * _tickLength; uint32 delay2 = _system->getMillis() + m * _tickLength; uint32 delay3 = _system->getMillis() + a * _tickLength; _partyAwake = false; _updateFlags |= 1; for (int i = 0, im = _smoothScrollModeNormal ? 32 : 16; i < im; i++) { timerProcessMonsters(0); timerProcessMonsters(1); timerProcessDoors(0); timerProcessFlyingObjects(0); if (_partyAwake) break; } resetBlockProperties(); do { for (int i = 0, im = _smoothScrollModeNormal ? 8 : 4; i < im; i++) { timerProcessMonsters(0); timerProcessMonsters(1); timerProcessDoors(0); timerProcessFlyingObjects(0); if (_partyAwake) break; } int f = checkInput(0); removeInputTop(); if (f & 0x800) { gui_notifyButtonListChanged(); } else if (f) { gui_triggerEvent(f); break; } if (!_partyAwake) { if (_system->getMillis() > delay3) { for (int i = 0; i < 4; i++) { if (!(needPoisoningFlags & (1 << i))) continue; inflictDamage(i, 1, 0x8000, 1, 0x80); if (_characters[i].flags & 8) needPoisoningFlags &= ~(1 << i); } delay3 = _system->getMillis() + a * _tickLength; } if (_system->getMillis() > delay1) { for (int i = 0; i < 4; i++) { if (!(needHealingFlags & (1 << i))) continue; increaseCharacterHitpoints(i, 1, false); gui_drawCharPortraitWithStats(i); if (_characters[i].hitPointsCur == _characters[i].hitPointsMax) needHealingFlags &= ~(1 << i); } delay1 = _system->getMillis() + h * _tickLength; } if (_system->getMillis() > delay2) { for (int i = 0; i < 4; i++) { if (!(needMagicGainFlags & (1 << i))) continue; _characters[i].magicPointsCur++; gui_drawCharPortraitWithStats(i); if (_characters[i].magicPointsCur == _characters[i].magicPointsMax) needMagicGainFlags &= ~(1 << i); } delay2 = _system->getMillis() + m * _tickLength; } _screen->updateScreen(); } } while (!_partyAwake && (needHealingFlags || needMagicGainFlags)); for (int i = 0; i < 4; i++) { int frm = 0; int upd = 0; bool setframe = true; if (_characters[i].flags & 0x1000) { _characters[i].flags &= 0xEFFF; if (_partyAwake) { if (_characters[i].damageSuffered) { frm = 5; snd_playSoundEffect(_characters[i].screamSfx, -1); } else { frm = 4; } upd = 6; } } else { if (_characters[i].damageSuffered) setframe = false; else frm = 4; } if (setframe) setTemporaryFaceFrame(i, frm, upd, 1); } _updateFlags &= 0xFFFE; _partyAwake = true; updateDrawPage2(); gui_drawScene(0); _txt->printMessage(0x8000, "%s", getLangString(0x4059)); _screen->fadeToPalette1(40); } else { for (int i = 0; i < 4; i++) _characters[i].flags &= 0xEFFF; if (needPoisoningFlags) { setTemporaryFaceFrameForAllCharacters(0, 0, 0); for (int i = 0; i < 4; i++) { if (needPoisoningFlags & (1 << i)) setTemporaryFaceFrame(i, 3, 8, 0); } _txt->printMessage(0x8000, "%s", getLangString(0x405A)); gui_drawAllCharPortraitsWithStats(); } else { setTemporaryFaceFrameForAllCharacters(2, 4, 1); _txt->printMessage(0x8000, "%s", getLangString(0x4058)); } gui_toggleButtonDisplayMode(_flags.isTalkie ? 77 : 75, 0); } return 1; } int LoLEngine::clickedMoneyBox(Button *button) { _txt->printMessage(0, getLangString(_credits == 1 ? 0x402D : 0x402E), _credits); return 1; } int LoLEngine::clickedCompass(Button *button) { if (!(_flagsTable[31] & 0x40)) return 0; if (_compassBroken) { if (characterSays(0x425B, -1, true)) _txt->printMessage(4, "%s", getLangString(0x425B)); } else { _txt->printMessage(0, "%s", getLangString(0x402F + _currentDirection)); } return 1; } int LoLEngine::clickedAutomap(Button *button) { if (!(_flagsTable[31] & 0x10)) return 0; removeInputTop(); displayAutomap(); gui_drawPlayField(); setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); return 1; } int LoLEngine::clickedLamp(Button *button) { if (!(_flagsTable[31] & 0x08)) return 0; if (_itemsInPlay[_itemInHand].itemPropertyIndex == 248) { if (_lampOilStatus >= 100) { _txt->printMessage(0, "%s", getLangString(0x4061)); return 1; } _txt->printMessage(0, "%s", getLangString(0x4062)); deleteItem(_itemInHand); snd_playSoundEffect(181, -1); setHandItem(0); _lampOilStatus += 100; } else { uint16 s = (_lampOilStatus >= 100) ? 0x4060 : ((!_lampOilStatus) ? 0x405C : (_lampOilStatus / 33) + 0x405D); _txt->printMessage(0, getLangString(0x405B), getLangString(s)); } if (_brightness) setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); return 1; } int LoLEngine::clickedStatusIcon(Button *button) { int t = _mouseX - 220; if (t < 0) t = 0; t /= 14; if (t > 2) t = 2; uint16 str = _charStatusFlags[t] + 1; if (str == 0 || str > 3) return 1; _txt->printMessage(0x8002, "%s", getLangString(str == 1 ? 0x424C : (str == 2 ? 0x424E : 0x424D))); return 1; } GUI_LoL::GUI_LoL(LoLEngine *vm) : GUI_v1(vm), _vm(vm), _screen(vm->_screen) { _scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollUp); _scrollDownFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollDown); _redrawButtonFunctor = BUTTON_FUNCTOR(GUI_v1, this, &GUI_v1::redrawButtonCallback); _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI_v1, this, &GUI_v1::redrawShadedButtonCallback); _specialProcessButton = _backUpButtonList = 0; _flagsModifier = 0; _sliderSfx = 11; } void GUI_LoL::processButton(Button *button) { if (!button) return; if (button->flags & 8) { if (button->flags & 0x10) { // XXX } return; } int entry = button->flags2 & 5; byte val1 = 0, val2 = 0, val3 = 0; const uint8 *dataPtr = 0; Button::Callback callback; if (entry == 1) { val1 = button->data1Val1; dataPtr = button->data1ShapePtr; callback = button->data1Callback; val2 = button->data1Val2; val3 = button->data1Val3; } else if (entry == 4 || entry == 5) { val1 = button->data2Val1; dataPtr = button->data2ShapePtr; callback = button->data2Callback; val2 = button->arg; val3 = button->data2Val3; } else { val1 = button->data0Val1; dataPtr = button->data0ShapePtr; callback = button->data0Callback; val2 = button->data0Val2; val3 = button->data0Val3; } int x = 0, y = 0, x2 = 0, y2 = 0; x = button->x; if (x < 0) x += _screen->getScreenDim(button->dimTableIndex)->w << 3; x += _screen->getScreenDim(button->dimTableIndex)->sx << 3; x2 = x + button->width - 1; y = button->y; if (y < 0) y += _screen->getScreenDim(button->dimTableIndex)->h << 3; y += _screen->getScreenDim(button->dimTableIndex)->sy << 3; y2 = y + button->height - 1; switch (val1 - 1) { case 0: _screen->hideMouse(); _screen->drawShape(_screen->_curPage, dataPtr, x, y, button->dimTableIndex, 0x10); _screen->showMouse(); break; case 1: _screen->hideMouse(); _screen->printText((const char *)dataPtr, x, y, val2, val3); _screen->showMouse(); break; case 3: if (callback) (*callback)(button); break; case 4: _screen->hideMouse(); _screen->drawBox(x, y, x2, y2, val2); _screen->showMouse(); break; case 5: _screen->hideMouse(); _screen->fillRect(x, y, x2, y2, val2, -1, true); _screen->showMouse(); break; default: break; } _screen->updateScreen(); } int GUI_LoL::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseWheel) { if (!buttonList) return inputFlag & 0x7FFF; if (_backUpButtonList != buttonList || _vm->_buttonListChanged) { _specialProcessButton = 0; _flagsModifier = 0; if (_vm->_mouseClick == 1) _flagsModifier |= 0x200; if (_vm->_mouseClick == 2) _flagsModifier |= 0x2000; _vm->_mouseClick = 0; _backUpButtonList = buttonList; _vm->_buttonListChanged = false; while (buttonList) { processButton(buttonList); buttonList = buttonList->nextButton; } } int mouseX = _vm->_mouseX; int mouseY = _vm->_mouseY; uint16 flags = 0; if (1/*!_screen_cursorDisable*/) { uint16 inFlags = inputFlag & 0xFF; uint16 temp = 0; // HACK: inFlags == 200 is our left button (up) if (inFlags == 199 || inFlags == 200) temp = 0x100; if (inFlags == 201 || inFlags == 202) temp = 0x1000; if (inputFlag & 0x800) temp <<= 2; flags |= temp; _flagsModifier &= ~((temp & 0x4400) >> 1); _flagsModifier |= (temp & 0x1100) * 2; flags |= _flagsModifier; flags |= (_flagsModifier << 2) ^ 0x8800; } buttonList = _backUpButtonList; if (_specialProcessButton) { buttonList = _specialProcessButton; if (_specialProcessButton->flags & 8) _specialProcessButton = 0; } int returnValue = 0; while (buttonList) { if (buttonList->flags & 8) { buttonList = buttonList->nextButton; continue; } buttonList->flags2 &= ~0x18; buttonList->flags2 |= (buttonList->flags2 & 3) << 3; int x = buttonList->x; if (x < 0) x += _screen->getScreenDim(buttonList->dimTableIndex)->w << 3; x += _screen->getScreenDim(buttonList->dimTableIndex)->sx << 3; int y = buttonList->y; if (y < 0) y += _screen->getScreenDim(buttonList->dimTableIndex)->h; y += _screen->getScreenDim(buttonList->dimTableIndex)->sy; bool progress = false; if (mouseX >= x && mouseY >= y && mouseX <= x + buttonList->width && mouseY <= y + buttonList->height) progress = true; buttonList->flags2 &= ~0x80; uint16 inFlags = inputFlag & 0x7FFF; if (inFlags) { if (buttonList->keyCode == inFlags) { progress = true; flags = buttonList->flags & 0x0F00; buttonList->flags2 |= 0x80; inputFlag = 0; _specialProcessButton = buttonList; } else if (buttonList->keyCode2 == inFlags) { flags = buttonList->flags & 0xF000; if (!flags) flags = buttonList->flags & 0x0F00; progress = true; buttonList->flags2 |= 0x80; inputFlag = 0; _specialProcessButton = buttonList; } } bool unk1 = false; if (mouseWheel && buttonList->mouseWheel == mouseWheel) { progress = true; unk1 = true; } if (!progress) buttonList->flags2 &= ~6; if ((flags & 0x3300) && (buttonList->flags & 4) && progress && (buttonList == _specialProcessButton || !_specialProcessButton)) { buttonList->flags |= 6; if (!_specialProcessButton) _specialProcessButton = buttonList; } else if ((flags & 0x8800) && !(buttonList->flags & 4) && progress) { buttonList->flags2 |= 6; } else { buttonList->flags2 &= ~6; } bool progressSwitch = false; if (!_specialProcessButton) { progressSwitch = progress; } else { if (_specialProcessButton->flags & 0x40) progressSwitch = (_specialProcessButton == buttonList); else progressSwitch = progress; } if (progressSwitch) { if ((flags & 0x1100) && progress && !_specialProcessButton) { inputFlag = 0; _specialProcessButton = buttonList; } if ((buttonList->flags & flags) && (progress || !(buttonList->flags & 1))) { uint16 combinedFlags = (buttonList->flags & flags); combinedFlags = ((combinedFlags & 0xF000) >> 4) | (combinedFlags & 0x0F00); combinedFlags >>= 8; static const uint16 flagTable[] = { 0x000, 0x100, 0x200, 0x100, 0x400, 0x100, 0x400, 0x100, 0x800, 0x100, 0x200, 0x100, 0x400, 0x100, 0x400, 0x100 }; assert(combinedFlags < ARRAYSIZE(flagTable)); switch (flagTable[combinedFlags]) { case 0x400: if (!(buttonList->flags & 1) || ((buttonList->flags & 1) && _specialProcessButton == buttonList)) { buttonList->flags2 ^= 1; returnValue = buttonList->index | 0x8000; unk1 = true; } if (!(buttonList->flags & 4)) { buttonList->flags2 &= ~4; buttonList->flags2 &= ~2; } break; case 0x800: if (!(buttonList->flags & 4)) { buttonList->flags2 |= 4; buttonList->flags2 |= 2; } if (!(buttonList->flags & 1)) unk1 = true; break; case 0x200: if (buttonList->flags & 4) { buttonList->flags2 |= 4; buttonList->flags2 |= 2; } if (!(buttonList->flags & 1)) unk1 = true; break; case 0x100: default: buttonList->flags2 ^= 1; returnValue = buttonList->index | 0x8000; unk1 = true; if (buttonList->flags & 4) { buttonList->flags2 |= 4; buttonList->flags2 |= 2; } _specialProcessButton = buttonList; } } } bool unk2 = false; if ((flags & 0x2200) && progress) { buttonList->flags2 |= 6; if (!(buttonList->flags & 4) && !(buttonList->flags2 & 1)) { unk2 = true; buttonList->flags2 |= 1; } } if ((flags & 0x8800) == 0x8800) { _specialProcessButton = 0; if (!progress || (buttonList->flags & 4)) buttonList->flags2 &= ~6; } if (!progress && buttonList == _specialProcessButton && !(buttonList->flags & 0x40)) _specialProcessButton = 0; if ((buttonList->flags2 & 0x18) != ((buttonList->flags2 & 3) << 3)) processButton(buttonList); if (unk2) buttonList->flags2 &= ~1; if (unk1) { buttonList->flags2 &= 0xFF; buttonList->flags2 |= flags; if (buttonList->buttonCallback) { //_vm->removeInputTop(); if ((*buttonList->buttonCallback)(buttonList)) break; } if (buttonList->flags & 0x20) break; } if (_specialProcessButton == buttonList && (buttonList->flags & 0x40)) break; buttonList = buttonList->nextButton; } if (!returnValue) returnValue = inputFlag & 0x7FFF; return returnValue; } int GUI_LoL::redrawButtonCallback(Button *button) { if (!_displayMenu || _vm->gameFlags().use16ColorMode) return 0; _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 225); return 0; } int GUI_LoL::redrawShadedButtonCallback(Button *button) { if (!_displayMenu || _vm->gameFlags().use16ColorMode) return 0; _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 223, 227); return 0; } int GUI_LoL::runMenu(Menu &menu) { _currentMenu = &menu; _lastMenu = _currentMenu; _newMenu = 0; _displayMenu = true; _menuResult = 1; _savegameOffset = 0; backupPage0(); const ScreenDim *d = _screen->getScreenDim(8); uint32 textCursorTimer = 0; uint8 textCursorStatus = 1; Screen::FontId of = _screen->setFont(Screen::FID_9_FNT); int wW = _screen->getCharWidth('W'); _screen->setFont(of); int fW = (d->w << 3) - wW; int fC = 0; // LoL doesnt't have default higlighted items. No item should be // highlighted when entering a new menu. // Instead, the respevtive struct entry is used to determine whether // a menu has scroll buttons or slider bars. uint8 hasSpecialButtons = 0; _saveSlotsListUpdateNeeded = true; while (_displayMenu) { _vm->_mouseX = _vm->_mouseY = 0; if (_currentMenu == &_loadMenu || _currentMenu == &_saveMenu || _currentMenu == &_deleteMenu) { updateSaveSlotsList(_vm->_targetName); setupSaveMenuSlots(*_currentMenu, 4); } hasSpecialButtons = _currentMenu->highlightedItem; _currentMenu->highlightedItem = 255; if (_currentMenu == &_gameOptions) { char *s = (char *)_vm->_tempBuffer5120; Common::strlcpy(s, _vm->getLangString(0x406F + _vm->_monsterDifficulty), 30); _currentMenu->item[_vm->gameFlags().isTalkie ? 0 : 2].itemString = s; s += (strlen(s) + 1); Common::strlcpy(s, _vm->getLangString(_vm->_smoothScrollingEnabled ? 0x4068 : 0x4069), 30); _currentMenu->item[_vm->gameFlags().isTalkie ? 1 : 3].itemString = s; s += (strlen(s) + 1); Common::strlcpy(s, _vm->getLangString(_vm->_floatingCursorsEnabled ? 0x4068 : 0x4069), 30); _currentMenu->item[_vm->gameFlags().isTalkie ? 2 : 4].itemString = s; s += (strlen(s) + 1); if (_vm->gameFlags().isTalkie) { Common::strlcpy(s, _vm->getLangString(0x42D6 + _vm->_lang), 30); _currentMenu->item[3].itemString = s; s += (strlen(s) + 1); Common::strlcpy(s, _vm->getLangString(_vm->textEnabled() ? 0x4068 : 0x4069), 30); _currentMenu->item[4].itemString = s; s += (strlen(s) + 1); } else { Common::strlcpy(s, _vm->getLangString(_vm->_configMusic ? 0x4068 : 0x4069), 30); _currentMenu->item[0].itemString = s; s += (strlen(s) + 1); Common::strlcpy(s, _vm->getLangString(_vm->_configSounds ? 0x4068 : 0x4069), 30); _currentMenu->item[1].itemString = s; s += (strlen(s) + 1); } } if (hasSpecialButtons == 1) { if (_savegameOffset == 0) { _scrollUpButton.data0ShapePtr = _scrollUpButton.data1ShapePtr = _scrollUpButton.data2ShapePtr = 0; } else { _scrollUpButton.data0ShapePtr = _vm->_gameShapes[17]; _scrollUpButton.data1ShapePtr = _scrollUpButton.data2ShapePtr = _vm->_gameShapes[19]; } int slotOffs = (_currentMenu == &_saveMenu) ? 1 : 0; if (((uint)_savegameOffset == _saveSlots.size() - (4 - slotOffs)) || _saveSlots.size() < (uint)(5 - slotOffs)) { _scrollDownButton.data0ShapePtr = _scrollDownButton.data1ShapePtr = _scrollDownButton.data2ShapePtr = 0; } else { _scrollDownButton.data0ShapePtr = _vm->_gameShapes[18]; _scrollDownButton.data1ShapePtr = _scrollDownButton.data2ShapePtr = _vm->_gameShapes[20]; } } for (uint i = 0; i < _currentMenu->numberOfItems; ++i) { _menuButtons[i].data0Val1 = _menuButtons[i].data1Val1 = _menuButtons[i].data2Val1 = 4; _menuButtons[i].data0Callback = _redrawShadedButtonFunctor; _menuButtons[i].data1Callback = _menuButtons[i].data2Callback = _redrawButtonFunctor; _menuButtons[i].flags = 0x4487; _menuButtons[i].flags2 = 0; } initMenu(*_currentMenu); if (_currentMenu == &_loadMenu || _currentMenu == &_deleteMenu) { if (_saveSlots.begin() == _saveSlots.end()) // "no savegames to load" message _screen->fprintString("%s", _currentMenu->x + _currentMenu->width / 2, _currentMenu->y + 42, 204, 0, 9, _vm->getLangString(0x4009)); } if (hasSpecialButtons == 2) { static const uint8 oX[] = { 0, 10, 124 }; static const uint8 oW[] = { 10, 114, 10 }; for (int i = 1; i < 4; ++i) { int tX = _currentMenu->x + _currentMenu->item[i].x; int tY = _currentMenu->y + _currentMenu->item[i].y; for (int ii = 0; ii < 3; ++ii) { Button *b = getButtonListData() + 1 + (i - 1) * 3 + ii; b->nextButton = 0; b->data0Val2 = b->data1Val2 = b->data2Val2 = 0xFE; b->data0Val3 = b->data1Val3 = b->data2Val3 = 0x01; b->index = ii; b->keyCode = b->keyCode2 = 0; b->x = tX + oX[ii]; b->y = tY; b->width = oW[ii]; b->height = _currentMenu->item[i].height; b->data0Val1 = b->data1Val1 = b->data2Val1 = 0; b->flags = (ii == 1) ? 0x6606 : 0x4406; b->dimTableIndex = 0; b->buttonCallback = _currentMenu->item[i].callback; b->arg = _currentMenu->item[i].itemId; _menuButtonList = addButtonToList(_menuButtonList, b); processButton(b); updateButton(b); } _currentMenu->item[i].labelX = _currentMenu->item[i].x - 5; _currentMenu->item[i].labelY = _currentMenu->item[i].y + 3; printMenuText(getMenuItemLabel(_currentMenu->item[i]), _currentMenu->x + _currentMenu->item[i].labelX, _currentMenu->y + _currentMenu->item[i].labelY, _currentMenu->item[i].textColor, 0, 10); int volume = _vm->getVolume((KyraEngine_v1::kVolumeEntry)(i - 1)); _screen->drawShape(_screen->_curPage, _vm->_gameShapes[85], tX , tY, 0, 0x10); _screen->drawShape(_screen->_curPage, _vm->_gameShapes[87], tX + 2 + oX[1], tY, 0, 0x10); _screen->drawShape(_screen->_curPage, _vm->_gameShapes[86], tX + oX[1] + volume, tY, 0, 0x10); } _screen->updateScreen(); } if (_currentMenu == &_mainMenu && !_vm->gameFlags().use16ColorMode) { Screen::FontId f = _screen->setFont(Screen::FID_6_FNT); _screen->fprintString("%s", menu.x + 8, menu.y + menu.height - 12, 204, 0, 8, gScummVMVersion); _screen->setFont(f); _screen->updateScreen(); } if (_currentMenu == &_savenameMenu) { int mx = (d->sx << 3) - 1; int my = d->sy - 1; int mw = (d->w << 3) + 1; int mh = d->h + 1; if (_vm->gameFlags().use16ColorMode) { _screen->drawShadedBox(mx, my, mx + mw + 1, my + mh + 1, 0xDD, 0xFF); _screen->drawLine(true, mx + mw + 1, my, mh + 1, 0xCC); _screen->drawLine(false, mx, my + mh + 1, mw + 2, 0xCC); } else { _screen->drawShadedBox(mx, my, mx + mw, my + mh, 227, 223); } int pg = _screen->setCurPage(0); _vm->_txt->clearDim(8); textCursorTimer = 0; textCursorStatus = 0; Screen::FontId f = _screen->setFont(Screen::FID_9_FNT); fC = _screen->getTextWidth(_saveDescription); while (fC >= fW) { _saveDescription[strlen(_saveDescription) - 1] = 0; fC = _screen->getTextWidth(_saveDescription); } _screen->fprintString("%s", (d->sx << 3), d->sy + 2, d->unk8, d->unkA, 0, _saveDescription); f = _screen->setFont(f); _screen->fillRect((d->sx << 3) + fC, d->sy, (d->sx << 3) + fC + wW, d->sy + d->h - (_vm->gameFlags().use16ColorMode ? 2 : 1), d->unk8, 0); _screen->setCurPage(pg); } while (!_newMenu && _displayMenu) { processHighlights(*_currentMenu); if (_currentMenu == &_savenameMenu) { if (textCursorTimer <= _vm->_system->getMillis()) { Screen::FontId f = _screen->setFont(Screen::FID_9_FNT); fC = _screen->getTextWidth(_saveDescription); textCursorStatus ^= 1; textCursorTimer = _vm->_system->getMillis() + 20 * _vm->_tickLength; _screen->fillRect((d->sx << 3) + fC, d->sy, (d->sx << 3) + fC + wW, d->sy + d->h - (_vm->gameFlags().use16ColorMode ? 2 : 1), textCursorStatus ? d->unk8 : d->unkA, 0); _screen->updateScreen(); f = _screen->setFont(f); } } if (getInput()) { if (!_newMenu) { if (_currentMenu == &_savenameMenu) { Screen::FontId f = _screen->setFont(Screen::FID_9_FNT); _screen->fillRect((d->sx << 3) + fC, d->sy, (d->sx << 3) + fC + wW, d->sy + d->h - (_vm->gameFlags().use16ColorMode ? 2 : 1), d->unkA, 0); fC = _screen->getTextWidth(_saveDescription); while (fC >= fW) { _saveDescription[strlen(_saveDescription) - 1] = 0; fC = _screen->getTextWidth(_saveDescription); } _screen->fprintString("%s", (d->sx << 3), d->sy + 2, d->unk8, d->unkA, 0, _saveDescription); _screen->fillRect((d->sx << 3) + fC, d->sy, (d->sx << 3) + fC + wW, d->sy + d->h - (_vm->gameFlags().use16ColorMode ? 2 : 1), textCursorStatus ? d->unk8 : d->unkA, 0); f = _screen->setFont(f); textCursorTimer = 0; textCursorStatus = 0; } else { _newMenu = (_currentMenu != &_audioOptions) ? _currentMenu : 0; } } else { _lastMenu = _menuResult == -1 ? _lastMenu : _currentMenu; } } if (!_menuResult) _displayMenu = false; } if (_newMenu != _currentMenu || !_displayMenu) restorePage0(); _currentMenu->highlightedItem = hasSpecialButtons; if (_newMenu) _currentMenu = _newMenu; _newMenu = 0; } if (_savegameList) { for (int i = 0; i < _savegameListSize; i++) delete[] _savegameList[i]; delete[] _savegameList; _savegameList = 0; } return _menuResult; } void GUI_LoL::createScreenThumbnail(Graphics::Surface &dst) { uint8 *screenPal = new uint8[768]; _screen->getRealPalette(1, screenPal); if (_vm->gameFlags().platform == Common::kPlatformPC98) { uint8 *screen = new uint8[Screen::SCREEN_W * Screen::SCREEN_H]; assert(screen); _screen->copyRegionToBuffer(7, 0, 0, 320, 200, screen); Screen_LoL::convertPC98Gfx(screen, Screen::SCREEN_W, Screen::SCREEN_H, Screen::SCREEN_W); ::createThumbnail(&dst, screen, Screen::SCREEN_W, Screen::SCREEN_H, screenPal); delete[] screen; } else { ::createThumbnail(&dst, _screen->getCPagePtr(7), Screen::SCREEN_W, Screen::SCREEN_H, screenPal); } delete[] screenPal; } void GUI_LoL::backupPage0() { _screen->copyPage(0, 7); } void GUI_LoL::restorePage0() { _screen->copyPage(7, 0); _screen->updateScreen(); } void GUI_LoL::setupSaveMenuSlots(Menu &menu, int num) { char *s = (char *)_vm->_tempBuffer5120; for (int i = 0; i < num; ++i) { menu.item[i].saveSlot = -1; menu.item[i].enabled = false; } int startSlot = 0; int slotOffs = 0; if (&menu == &_saveMenu) { if (_savegameOffset == 0) startSlot = 1; slotOffs = 1; } int saveSlotMaxLen = ((_screen->getScreenDim(8))->w << 3) - _screen->getCharWidth('W'); for (int i = startSlot; i < num && _savegameOffset + i - slotOffs < _savegameListSize; ++i) { if (_savegameList[i + _savegameOffset - slotOffs]) { Common::strlcpy(s, _savegameList[i + _savegameOffset - slotOffs], 80); // Trim long GMM save descriptions to fit our save slots int fC = _screen->getTextWidth(s); while (s[0] && fC >= saveSlotMaxLen) { s[strlen(s) - 1] = 0; fC = _screen->getTextWidth(s); } menu.item[i].itemString = s; s += (strlen(s) + 1); menu.item[i].saveSlot = _saveSlots[i + _savegameOffset - slotOffs]; menu.item[i].enabled = true; } } if (_savegameOffset == 0) { if (&menu == &_saveMenu) { strcpy(s, _vm->getLangString(0x4010)); menu.item[0].itemString = s; menu.item[0].saveSlot = -3; menu.item[0].enabled = true; } } } void GUI_LoL::sortSaveSlots() { Common::sort(_saveSlots.begin(), _saveSlots.end(), Common::Greater()); } void GUI_LoL::printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 flags) { _screen->fprintString("%s", x, y, c0, c1, _vm->gameFlags().use16ColorMode ? (flags & 3) : flags , str); } int GUI_LoL::getMenuCenterStringX(const char *str, int x1, int x2) { if (!str) return 0; int strWidth = _screen->getTextWidth(str); int w = x2 - x1 + 1; return x1 + (w - strWidth) / 2; } int GUI_LoL::getInput() { if (!_displayMenu) return 0; #ifdef ENABLE_KEYMAPPER Common::Keymapper *const keymapper = _vm->getEventManager()->getKeymapper(); keymapper->pushKeymap(Common::kGlobalKeymapName); #endif Common::Point p = _vm->getMousePos(); _vm->_mouseX = p.x; _vm->_mouseY = p.y; if (_currentMenu == &_savenameMenu) { _vm->updateInput(); 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; } } int inputFlag = _vm->checkInput(_menuButtonList); if (_currentMenu == &_savenameMenu && _keyPressed.ascii) { char inputKey = _keyPressed.ascii; Util::convertISOToDOS(inputKey); if ((uint8)inputKey > 31 && (uint8)inputKey < (_vm->gameFlags().lang == Common::JA_JPN ? 128 : 226)) { _saveDescription[strlen(_saveDescription) + 1] = 0; _saveDescription[strlen(_saveDescription)] = inputKey; inputFlag |= 0x8000; } else if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE && strlen(_saveDescription)) { _saveDescription[strlen(_saveDescription) - 1] = 0; inputFlag |= 0x8000; } } _vm->removeInputTop(); _keyPressed.reset(); if (_vm->shouldQuit()) _displayMenu = false; _vm->delay(8); #ifdef ENABLE_KEYMAPPER keymapper->popKeymap(Common::kGlobalKeymapName); #endif return inputFlag & 0x8000 ? 1 : 0; } int GUI_LoL::clickedMainMenu(Button *button) { updateMenuButton(button); switch (button->arg) { case 0x4001: _savegameOffset = 0; _newMenu = &_loadMenu; break; case 0x4002: _savegameOffset = 0; _newMenu = &_saveMenu; break; case 0x4003: _savegameOffset = 0; _newMenu = &_deleteMenu; break; case 0x4004: _newMenu = &_gameOptions; break; case 0x42D9: _newMenu = &_audioOptions; break; case 0x4006: _choiceMenu.menuNameId = 0x400A; _newMenu = &_choiceMenu; break; case 0x4005: _displayMenu = false; break; } return 1; } int GUI_LoL::clickedLoadMenu(Button *button) { updateMenuButton(button); if (button->arg == 0x4011) { if (_currentMenu != _lastMenu) _newMenu = _lastMenu; else _menuResult = 0; return 1; } int16 s = (int16)button->arg; _vm->_gameToLoad = _loadMenu.item[-s - 2].saveSlot; _displayMenu = false; return 1; } int GUI_LoL::clickedSaveMenu(Button *button) { updateMenuButton(button); if (button->arg == 0x4011) { _newMenu = &_mainMenu; return 1; } _newMenu = &_savenameMenu; int16 s = (int16)button->arg; _menuResult = _saveMenu.item[-s - 2].saveSlot + 1; _saveDescription = (char *)_vm->_tempBuffer5120 + 1000; _saveDescription[0] = 0; if (_saveMenu.item[-s - 2].saveSlot != -3) strcpy(_saveDescription, _saveMenu.item[-s - 2].itemString); return 1; } int GUI_LoL::clickedDeleteMenu(Button *button) { updateMenuButton(button); if (button->arg == 0x4011) { _newMenu = &_mainMenu; return 1; } _choiceMenu.menuNameId = 0x400B; _newMenu = &_choiceMenu; int16 s = (int16)button->arg; _menuResult = _deleteMenu.item[-s - 2].saveSlot + 1; return 1; } int GUI_LoL::clickedOptionsMenu(Button *button) { updateMenuButton(button); switch (button->arg) { case 0xFFF9: _vm->_configMusic ^= 1; _vm->sound()->enableMusic(_vm->_configMusic); if (_vm->_configMusic) _vm->snd_playTrack(_vm->_curMusicTheme); else _vm->_sound->beginFadeOut(); break; case 0xFFF8: _vm->_configSounds ^= true; _vm->sound()->enableSFX(_vm->_configSounds); break; case 0xFFF7: _vm->_monsterDifficulty = (_vm->_monsterDifficulty + 1) % 3; break; case 0xFFF6: _vm->_smoothScrollingEnabled ^= true; break; case 0xFFF5: _vm->_floatingCursorsEnabled ^= true; break; case 0xFFF4: _vm->_lang = (_vm->_lang + 1) % 3; break; case 0xFFF3: _vm->_configVoice ^= 3; break; case 0x4072: { Common::String filename; filename = Common::String::format("LEVEL%02d.%s", _vm->_currentLevel, _vm->_languageExt[_vm->_lang]); delete[] _vm->_levelLangFile; _vm->_levelLangFile = _vm->resource()->fileData(filename.c_str(), 0); filename = Common::String::format("LANDS.%s", _vm->_languageExt[_vm->_lang]); delete[] _vm->_landsFile; _vm->_landsFile = _vm->resource()->fileData(filename.c_str(), 0); _newMenu = _lastMenu; } break; default: // TODO: Is there anything we should do if we hit this case? break; } return 1; } int GUI_LoL::clickedAudioMenu(Button *button) { updateMenuButton(button); if (button->arg == 0x4072) { _newMenu = _lastMenu; return 1; } int tX = button->x; const int oldVolume = _vm->getVolume((KyraEngine_v1::kVolumeEntry)(button->arg - 3)); int newVolume = oldVolume; if (button->index == 0) { newVolume -= 10; tX += 10; } else if (button->index == 1) { newVolume = _vm->_mouseX - (tX + 7); } else if (button->index == 2) { newVolume += 10; tX -= 114; } newVolume = CLIP(newVolume, 2, 102); if (newVolume == oldVolume) { _screen->updateScreen(); return 0; } _screen->drawShape(0, _vm->_gameShapes[87], tX + oldVolume, button->y, 0, 0x10); // Temporary HACK const int volumeDrawX = _vm->convertVolumeFromMixer(_vm->convertVolumeToMixer(newVolume)); _screen->drawShape(0, _vm->_gameShapes[86], tX + volumeDrawX, button->y, 0, 0x10); _screen->updateScreen(); _vm->snd_stopSpeech(0); _vm->setVolume((KyraEngine_v1::kVolumeEntry)(button->arg - 3), newVolume); if (newVolume) { if (button->arg == 4) { _vm->snd_playSoundEffect(_sliderSfx, -1); int16 vocIndex = (int16)READ_LE_UINT16(&_vm->_ingameSoundIndex[_sliderSfx * 2]); do { ++_sliderSfx; if (_sliderSfx < 47) _sliderSfx++; if (vocIndex == 199) _sliderSfx = 11; vocIndex = (int16)READ_LE_UINT16(&_vm->_ingameSoundIndex[_sliderSfx * 2]); if (vocIndex == -1) continue; if (!scumm_stricmp(_vm->_ingameSoundList[vocIndex], "EMPTY")) continue; break; } while (1); } else if (button->arg == 5) { _vm->_lastSpeechId = -1; _vm->snd_playCharacterSpeech(0x42E0, 0, 0); } } return 1; } int GUI_LoL::clickedDeathMenu(Button *button) { updateMenuButton(button); if (button->arg == _deathMenu.item[0].itemId) { _vm->quitGame(); } else if (button->arg == _deathMenu.item[1].itemId) { _newMenu = &_loadMenu; } return 1; } int GUI_LoL::clickedSavenameMenu(Button *button) { updateMenuButton(button); if (button->arg == _savenameMenu.item[0].itemId) { Util::convertDOSToISO(_saveDescription); int slot = _menuResult == -2 ? getNextSavegameSlot() : _menuResult - 1; Graphics::Surface thumb; createScreenThumbnail(thumb); _vm->saveGameStateIntern(slot, _saveDescription, &thumb); thumb.free(); _displayMenu = false; } else if (button->arg == _savenameMenu.item[1].itemId) { _newMenu = &_saveMenu; } return 1; } int GUI_LoL::clickedChoiceMenu(Button *button) { updateMenuButton(button); if (button->arg == _choiceMenu.item[0].itemId) { if (_lastMenu == &_mainMenu) { _vm->quitGame(); } else if (_lastMenu == &_deleteMenu) { _vm->_saveFileMan->removeSavefile(_vm->getSavegameFilename(_menuResult - 1)); Common::Array::iterator i = Common::find(_saveSlots.begin(), _saveSlots.end(), _menuResult - 1); while (i != _saveSlots.begin()) { --i; // not rename quicksave slot filenames if (*i >= 990) break; Common::String oldName = _vm->getSavegameFilename(*i); Common::String newName = _vm->getSavegameFilename(*i - 1); _vm->_saveFileMan->renameSavefile(oldName, newName); } _newMenu = &_mainMenu; _saveSlotsListUpdateNeeded = true; } } else if (button->arg == _choiceMenu.item[1].itemId) { _newMenu = &_mainMenu; } return 1; } int GUI_LoL::scrollUp(Button *button) { if (!_scrollUpButton.data0ShapePtr) return 0; updateButton(button); if (_savegameOffset > 0) { _savegameOffset--; _newMenu = _currentMenu; _menuResult = -1; } return 1; } int GUI_LoL::scrollDown(Button *button) { if (!_scrollDownButton.data0ShapePtr) return 0; updateButton(button); if ((uint)_savegameOffset < _saveSlots.size() - (_currentMenu == &_saveMenu ? 3 : 4)) { _savegameOffset++; _newMenu = _currentMenu; _menuResult = -1; } return 1; } const char *GUI_LoL::getMenuTitle(const Menu &menu) { if (!menu.menuNameId) return 0; return _vm->getLangString(menu.menuNameId); } const char *GUI_LoL::getMenuItemTitle(const MenuItem &menuItem) { if (menuItem.itemId & 0x8000 && menuItem.itemString) return menuItem.itemString; else if (menuItem.itemId & 0x8000 || !menuItem.itemId) return 0; return _vm->getLangString(menuItem.itemId); } const char *GUI_LoL::getMenuItemLabel(const MenuItem &menuItem) { if (menuItem.labelId & 0x8000 && menuItem.labelString) return menuItem.labelString; else if (menuItem.labelId & 0x8000 || !menuItem.labelId) return 0; return _vm->getLangString(menuItem.labelId); } } // End of namespace Kyra #endif // ENABLE_LOL