diff options
author | Matthew Hoops | 2011-12-12 15:25:28 -0500 |
---|---|---|
committer | Matthew Hoops | 2011-12-12 15:25:28 -0500 |
commit | 00279659b22cbd5db739d5351e83a9fc2a2ae408 (patch) | |
tree | 497f06f46820043cbdf1725652b8f0073223e24a /engines/toltecs/menu.cpp | |
parent | d932df79bed5aac97e17c0920a5e75cb5ce733ee (diff) | |
parent | d1628feb761acc9f4607f64de3eb620fea53bcc9 (diff) | |
download | scummvm-rg350-00279659b22cbd5db739d5351e83a9fc2a2ae408.tar.gz scummvm-rg350-00279659b22cbd5db739d5351e83a9fc2a2ae408.tar.bz2 scummvm-rg350-00279659b22cbd5db739d5351e83a9fc2a2ae408.zip |
Merge remote branch 'upstream/master' into pegasus
Conflicts:
video/qt_decoder.cpp
Diffstat (limited to 'engines/toltecs/menu.cpp')
-rw-r--r-- | engines/toltecs/menu.cpp | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp new file mode 100644 index 0000000000..00a0372e99 --- /dev/null +++ b/engines/toltecs/menu.cpp @@ -0,0 +1,613 @@ +/* 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 "common/savefile.h" + +#include "toltecs/toltecs.h" +#include "toltecs/menu.h" +#include "toltecs/palette.h" +#include "toltecs/render.h" +#include "toltecs/resource.h" + +namespace Toltecs { + +MenuSystem::MenuSystem(ToltecsEngine *vm) : _vm(vm) { +} + +MenuSystem::~MenuSystem() { +} + +int MenuSystem::run() { + + //debug("MenuSystem::run()"); + + _background = new Graphics::Surface(); + _background->create(640, 400, Graphics::PixelFormat::createFormatCLUT8()); + + // Save original background + Graphics::Surface backgroundOrig; + backgroundOrig.create(640, 400, Graphics::PixelFormat::createFormatCLUT8()); + memcpy(backgroundOrig.getBasePtr(0,0), _vm->_screen->_frontScreen, 640 * 400); + + _currMenuID = kMenuIdNone; + _newMenuID = kMenuIdMain; + _currItemID = kItemIdNone; + _editingDescription = false; + _cfgText = true; + _cfgVoices = true; + _cfgMasterVolume = 10; + _cfgVoicesVolume = 10; + _cfgMusicVolume = 10; + _cfgSoundFXVolume = 10; + _cfgBackgroundVolume = 10; + _running = true; + _top = 30 - _vm->_guiHeight / 2; + _needRedraw = false; + + // TODO: buildColorTransTable2 + _vm->_palette->buildColorTransTable(0, 16, 7); + + _vm->_screen->_renderQueue->clear(); + // Draw the menu background and frame + _vm->_screen->blastSprite(0x140 + _vm->_cameraX, 0x175 + _vm->_cameraY, 0, 1, 0x4000); + shadeRect(60, 39, 520, 246, 30, 94); + + memcpy(_background->pixels, _vm->_screen->_frontScreen, 640 * 400); + + while (_running) { + update(); + _vm->_system->updateScreen(); + } + + // Restore original background + memcpy(_vm->_screen->_frontScreen, backgroundOrig.getBasePtr(0,0), 640 * 400); + _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen, 640, 0, 0, 640, 400); + _vm->_system->updateScreen(); + + // Cleanup + backgroundOrig.free(); + _background->free(); + delete _background; + + return 0; +} + +void MenuSystem::update() { + + if (_currMenuID != _newMenuID) { + _currMenuID = _newMenuID; + //debug("_currMenuID = %d", _currMenuID); + initMenu(_currMenuID); + } + + handleEvents(); + + if (_needRedraw) { + //_vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen + 39 * 640 + 60, 640, 60, 39, 520, 247); + _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen, 640, 0, 0, 640, 400); + //debug("redraw"); + _needRedraw = false; + } + + _vm->_system->delayMillis(5); + +} + +void MenuSystem::handleEvents() { + + Common::Event event; + Common::EventManager *eventMan = _vm->_system->getEventManager(); + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + handleKeyDown(event.kbd); + break; + case Common::EVENT_QUIT: + _running = false; + break; + case Common::EVENT_MOUSEMOVE: + handleMouseMove(event.mouse.x, event.mouse.y); + break; + case Common::EVENT_LBUTTONDOWN: + handleMouseClick(event.mouse.x, event.mouse.y); + break; + default: + break; + } + } + +} + +void MenuSystem::addClickTextItem(ItemID id, int x, int y, int w, uint fontNum, const char *caption, byte defaultColor, byte activeColor) { + Item item; + item.id = id; + item.defaultColor = defaultColor; + item.activeColor = activeColor; + item.x = x; + item.y = y; + item.w = w; + item.fontNum = fontNum; + setItemCaption(&item, caption); + _items.push_back(item); +} + +void MenuSystem::drawItem(ItemID itemID, bool active) { + Item *item = getItem(itemID); + if (item) { + byte color = active ? item->activeColor : item->defaultColor; + drawString(item->rect.left, item->y, 0, item->fontNum, color, item->caption.c_str()); + } +} + +void MenuSystem::handleMouseMove(int x, int y) { + if (!_editingDescription) { + ItemID newItemID = findItemAt(x, y); + if (_currItemID != newItemID) { + leaveItem(_currItemID); + _currItemID = newItemID; + enterItem(newItemID); + } + } +} + +void MenuSystem::handleMouseClick(int x, int y) { + if (!_editingDescription) { + ItemID id = findItemAt(x, y); + clickItem(id); + } +} + +void MenuSystem::handleKeyDown(const Common::KeyState& kbd) { + if (_editingDescription) { + if (kbd.keycode >= Common::KEYCODE_SPACE && kbd.keycode <= Common::KEYCODE_z) { + _editingDescriptionItem->caption += kbd.ascii; + restoreRect(_editingDescriptionItem->rect.left, _editingDescriptionItem->rect.top, + _editingDescriptionItem->rect.width() + 1, _editingDescriptionItem->rect.height() - 2); + setItemCaption(_editingDescriptionItem, _editingDescriptionItem->caption.c_str()); + drawItem(_editingDescriptionID, true); + } else if (kbd.keycode == Common::KEYCODE_BACKSPACE) { + _editingDescriptionItem->caption.deleteLastChar(); + restoreRect(_editingDescriptionItem->rect.left, _editingDescriptionItem->rect.top, + _editingDescriptionItem->rect.width() + 1, _editingDescriptionItem->rect.height() - 2); + setItemCaption(_editingDescriptionItem, _editingDescriptionItem->caption.c_str()); + drawItem(_editingDescriptionID, true); + } else if (kbd.keycode == Common::KEYCODE_RETURN) { + SavegameItem *savegameItem = getSavegameItemByID(_editingDescriptionID); + _editingDescription = false; + _vm->requestSavegame(savegameItem->_slotNum, _editingDescriptionItem->caption); + _running = false; + } else if (kbd.keycode == Common::KEYCODE_ESCAPE) { + _editingDescription = false; + } + } +} + +ItemID MenuSystem::findItemAt(int x, int y) { + for (Common::Array<Item>::iterator iter = _items.begin(); iter != _items.end(); iter++) { + if ((*iter).rect.contains(x, y)) + return (*iter).id; + } + return kItemIdNone; +} + +MenuSystem::Item *MenuSystem::getItem(ItemID id) { + for (Common::Array<Item>::iterator iter = _items.begin(); iter != _items.end(); iter++) { + if ((*iter).id == id) + return &(*iter); + } + return NULL; +} + +void MenuSystem::setItemCaption(Item *item, const char *caption) { + Font font(_vm->_res->load(_vm->_screen->getFontResIndex(item->fontNum))->data); + int width = font.getTextWidth((const byte*)caption); + int height = font.getHeight(); + item->rect = Common::Rect(item->x, item->y - height, item->x + width, item->y); + if (item->w) { + item->rect.translate(item->w - width / 2, 0); + } + item->caption = caption; +} + +void MenuSystem::initMenu(MenuID menuID) { + int newSlotNum; + + _items.clear(); + + memcpy(_vm->_screen->_frontScreen, _background->pixels, 640 * 400); + + switch (menuID) { + case kMenuIdMain: + drawString(0, 74, 320, 1, 229, _vm->getSysString(kStrWhatCanIDoForYou)); + addClickTextItem(kItemIdLoad, 0, 115, 320, 0, _vm->getSysString(kStrLoad), 229, 255); + addClickTextItem(kItemIdSave, 0, 135, 320, 0, _vm->getSysString(kStrSave), 229, 255); + addClickTextItem(kItemIdToggleText, 0, 165, 320, 0, _vm->getSysString(kStrTextOn), 229, 255); + addClickTextItem(kItemIdToggleVoices, 0, 185, 320, 0, _vm->getSysString(kStrVoicesOn), 229, 255); + addClickTextItem(kItemIdVolumesMenu, 0, 215, 320, 0, _vm->getSysString(kStrVolume), 229, 255); + addClickTextItem(kItemIdPlay, 0, 245, 320, 0, _vm->getSysString(kStrPlay), 229, 255); + addClickTextItem(kItemIdQuit, 0, 275, 320, 0, _vm->getSysString(kStrQuit), 229, 255); + break; + case kMenuIdLoad: + drawString(0, 74, 320, 1, 229, _vm->getSysString(kStrLoadGame)); + addClickTextItem(kItemIdSavegameUp, 0, 155, 545, 1, "^", 255, 253); + addClickTextItem(kItemIdSavegameDown, 0, 195, 545, 1, "\\", 255, 253); + addClickTextItem(kItemIdCancel, 0, 275, 320, 0, _vm->getSysString(kStrCancel), 255, 253); + for (int i = 1; i <= 7; i++) { + Common::String saveDesc = Common::String::format("SAVEGAME %d", i); + addClickTextItem((ItemID)(kItemIdSavegame1 + i - 1), 0, 115 + 20 * (i - 1), 300, 0, saveDesc.c_str(), 231, 234); + } + loadSavegamesList(); + setSavegameCaptions(); + break; + case kMenuIdSave: + drawString(0, 74, 320, 1, 229, _vm->getSysString(kStrSaveGame)); + addClickTextItem(kItemIdSavegameUp, 0, 155, 545, 1, "^", 255, 253); + addClickTextItem(kItemIdSavegameDown, 0, 195, 545, 1, "\\", 255, 253); + addClickTextItem(kItemIdCancel, 0, 275, 320, 0, _vm->getSysString(kStrCancel), 255, 253); + for (int i = 1; i <= 7; i++) { + Common::String saveDesc = Common::String::format("SAVEGAME %d", i); + addClickTextItem((ItemID)(kItemIdSavegame1 + i - 1), 0, 115 + 20 * (i - 1), 300, 0, saveDesc.c_str(), 231, 234); + } + newSlotNum = loadSavegamesList() + 1; + _savegames.push_back(SavegameItem(newSlotNum, Common::String::format("GAME %03d", _savegames.size() + 1))); + setSavegameCaptions(); + break; + case kMenuIdVolumes: + drawString(0, 74, 320, 1, 229, _vm->getSysString(kStrAdjustVolume)); + drawString(0, 130, 200, 0, 246, _vm->getSysString(kStrMaster)); + drawString(0, 155, 200, 0, 244, _vm->getSysString(kStrVoices)); + drawString(0, 180, 200, 0, 244, _vm->getSysString(kStrMusic)); + drawString(0, 205, 200, 0, 244, _vm->getSysString(kStrSoundFx)); + drawString(0, 230, 200, 0, 244, _vm->getSysString(kStrBackground)); + addClickTextItem(kItemIdDone, 0, 275, 200, 0, _vm->getSysString(kStrDone), 229, 253); + addClickTextItem(kItemIdCancel, 0, 275, 440, 0, _vm->getSysString(kStrCancel), 229, 253); + addClickTextItem(kItemIdMasterDown, 0, 130 + 25 * 0, 348, 1, "[", 229, 253); + addClickTextItem(kItemIdVoicesDown, 0, 130 + 25 * 1, 348, 1, "[", 229, 253); + addClickTextItem(kItemIdMusicDown, 0, 130 + 25 * 2, 348, 1, "[", 229, 253); + addClickTextItem(kItemIdSoundFXDown, 0, 130 + 25 * 3, 348, 1, "[", 229, 253); + addClickTextItem(kItemIdBackgroundDown, 0, 130 + 25 * 4, 348, 1, "[", 229, 253); + addClickTextItem(kItemIdMasterUp, 0, 130 + 25 * 0, 372, 1, "]", 229, 253); + addClickTextItem(kItemIdVoicesUp, 0, 130 + 25 * 1, 372, 1, "]", 229, 253); + addClickTextItem(kItemIdMusicUp, 0, 130 + 25 * 2, 372, 1, "]", 229, 253); + addClickTextItem(kItemIdSoundFXUp, 0, 130 + 25 * 3, 372, 1, "]", 229, 253); + addClickTextItem(kItemIdBackgroundUp, 0, 130 + 25 * 4, 372, 1, "]", 229, 253); + drawVolumeBar(kItemIdMaster); + drawVolumeBar(kItemIdVoices); + drawVolumeBar(kItemIdMusic); + drawVolumeBar(kItemIdSoundFX); + drawVolumeBar(kItemIdBackground); + break; + default: + break; + } + + for (Common::Array<Item>::iterator iter = _items.begin(); iter != _items.end(); iter++) { + drawItem((*iter).id, false); + } + +} + +void MenuSystem::enterItem(ItemID id) { + drawItem(id, true); +} + +void MenuSystem::leaveItem(ItemID id) { + drawItem(id, false); +} + +void MenuSystem::clickItem(ItemID id) { + //Item *item = getItem(id); + switch (id) { + // Main menu + case kItemIdSave: + _newMenuID = kMenuIdSave; + break; + case kItemIdLoad: + _newMenuID = kMenuIdLoad; + break; + case kItemIdToggleText: + setCfgText(!_cfgText, true); + if (!_cfgVoices && !_cfgText) + setCfgVoices(true, false); + break; + case kItemIdToggleVoices: + setCfgVoices(!_cfgVoices, true); + if (!_cfgVoices && !_cfgText) + setCfgText(true, false); + break; + case kItemIdVolumesMenu: + //debug("kItemIdVolumesMenu"); + _newMenuID = kMenuIdVolumes; + break; + case kItemIdPlay: + //debug("kItemIdPlay"); + _running = false; + break; + case kItemIdQuit: + _running = false; + _vm->quitGame(); + break; + // Volumes menu + case kItemIdMasterUp: + changeVolumeBar(kItemIdMaster, +1); + break; + case kItemIdVoicesUp: + changeVolumeBar(kItemIdVoices, +1); + break; + case kItemIdMusicUp: + changeVolumeBar(kItemIdMusic, +1); + break; + case kItemIdSoundFXUp: + changeVolumeBar(kItemIdSoundFX, +1); + break; + case kItemIdBackgroundUp: + changeVolumeBar(kItemIdBackground, +1); + break; + case kItemIdMasterDown: + changeVolumeBar(kItemIdMaster, -1); + break; + case kItemIdVoicesDown: + changeVolumeBar(kItemIdVoices, -1); + break; + case kItemIdMusicDown: + changeVolumeBar(kItemIdMusic, -1); + break; + case kItemIdSoundFXDown: + changeVolumeBar(kItemIdSoundFX, -1); + break; + case kItemIdBackgroundDown: + changeVolumeBar(kItemIdBackground, -1); + break; + case kItemIdCancel: + _newMenuID = kMenuIdMain; + break; + // Save/Load menu + case kItemIdSavegame1: + case kItemIdSavegame2: + case kItemIdSavegame3: + case kItemIdSavegame4: + case kItemIdSavegame5: + case kItemIdSavegame6: + case kItemIdSavegame7: + clickSavegameItem(id); + break; + case kItemIdDone: + _newMenuID = kMenuIdMain; + break; + case kItemIdSavegameUp: + scrollSavegames(-6); + break; + case kItemIdSavegameDown: + scrollSavegames(+6); + break; + default: + break; + } +} + +void MenuSystem::restoreRect(int x, int y, int w, int h) { + byte *src = (byte*)_background->getBasePtr(x, y); + byte *dst = _vm->_screen->_frontScreen + x + y * 640; + while (h--) { + memcpy(dst, src, w); + src += 640; + dst += 640; + } +} + +void MenuSystem::shadeRect(int x, int y, int w, int h, byte color1, byte color2) { + byte *src = (byte*)_background->getBasePtr(x, y); + for (int xc = 0; xc < w; xc++) { + src[xc] = color2; + src[xc + h * 640] = color1; + } + src += 640; + w -= 1; + h -= 1; + while (h--) { + src[0] = color2; + src[w] = color1; + src += 640; + } +} + +void MenuSystem::drawString(int16 x, int16 y, int w, uint fontNum, byte color, const char *text) { + fontNum = _vm->_screen->getFontResIndex(fontNum); + Font font(_vm->_res->load(fontNum)->data); + if (w) { + x = x + w - font.getTextWidth((const byte*)text) / 2; + } + _vm->_screen->drawString(x, y - font.getHeight(), color, fontNum, (const byte*)text, -1, NULL, true); + _needRedraw = true; +} + +int MenuSystem::loadSavegamesList() { + + int maxSlotNum = -1; + + _savegameListTopIndex = 0; + _savegames.clear(); + + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Toltecs::ToltecsEngine::SaveHeader header; + Common::String pattern = _vm->getTargetName(); + pattern += ".???"; + + Common::StringArray filenames; + filenames = saveFileMan->listSavefiles(pattern.c_str()); + Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + if (slotNum > maxSlotNum) + maxSlotNum = slotNum; + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + if (Toltecs::ToltecsEngine::readSaveHeader(in, false, header) == Toltecs::ToltecsEngine::kRSHENoError) { + _savegames.push_back(SavegameItem(slotNum, header.description)); + //debug("%s -> %s", file->c_str(), header.description.c_str()); + } + delete in; + } + } + } + + return maxSlotNum; +} + +MenuSystem::SavegameItem *MenuSystem::getSavegameItemByID(ItemID id) { + if (id >= kItemIdSavegame1 && id <= kItemIdSavegame7) + return &_savegames[_savegameListTopIndex + id - kItemIdSavegame1]; + else + return NULL; +} + +void MenuSystem::setSavegameCaptions() { + uint index = _savegameListTopIndex; + for (int i = 1; i <= 7; i++) + setItemCaption(getItem((ItemID)(kItemIdSavegame1 + i - 1)), index < _savegames.size() ? _savegames[index++]._description.c_str() : ""); +} + +void MenuSystem::scrollSavegames(int delta) { + int newPos = CLIP<int>(_savegameListTopIndex + delta, 0, _savegames.size() - 1); + _savegameListTopIndex = newPos; + restoreRect(80, 92, 440, 140); + setSavegameCaptions(); + for (int i = 1; i <= 7; i++) + drawItem((ItemID)(kItemIdSavegame1 + i - 1), false); +} + +void MenuSystem::clickSavegameItem(ItemID id) { + if (_currMenuID == kMenuIdLoad) { + SavegameItem *savegameItem = getSavegameItemByID(id); + //debug("slotNum = [%d]; description = [%s]", savegameItem->_slotNum, savegameItem->_description.c_str()); + //_vm->loadgame(savegameItem->_filename.c_str()); + _vm->requestLoadgame(savegameItem->_slotNum); + _running = false; + } else { + _editingDescription = true; + _editingDescriptionItem = getItem(id); + _editingDescriptionID = id; + _editingDescriptionItem->activeColor = 249; + _editingDescriptionItem->defaultColor = 249; + drawItem(_editingDescriptionID, true); + } +} + +void MenuSystem::setCfgText(bool value, bool active) { + if (_cfgText != value) { + Item *item = getItem(kItemIdToggleText); + _cfgText = value; + restoreRect(item->rect.left, item->rect.top, item->rect.width() + 1, item->rect.height() - 2); + setItemCaption(item, _vm->getSysString(_cfgText ? kStrTextOn : kStrTextOff)); + drawItem(kItemIdToggleText, true); + } +} + +void MenuSystem::setCfgVoices(bool value, bool active) { + if (_cfgVoices != value) { + Item *item = getItem(kItemIdToggleVoices); + _cfgVoices = value; + restoreRect(item->rect.left, item->rect.top, item->rect.width() + 1, item->rect.height() - 2); + setItemCaption(item, _vm->getSysString(_cfgVoices ? kStrVoicesOn : kStrVoicesOff)); + drawItem(kItemIdToggleVoices, true); + } +} + +void MenuSystem::drawVolumeBar(ItemID itemID) { + int w = 440, y, volume; + char text[21]; + + switch (itemID) { + case kItemIdMaster: + y = 130 + 25 * 0; + volume = _cfgMasterVolume; + break; + case kItemIdVoices: + y = 130 + 25 * 1; + volume = _cfgVoicesVolume; + break; + case kItemIdMusic: + y = 130 + 25 * 2; + volume = _cfgMusicVolume; + break; + case kItemIdSoundFX: + y = 130 + 25 * 3; + volume = _cfgSoundFXVolume; + break; + case kItemIdBackground: + y = 130 + 25 * 4; + volume = _cfgBackgroundVolume; + break; + default: + return; + } + + Font font(_vm->_res->load(_vm->_screen->getFontResIndex(1))->data); + restoreRect(390, y - font.getHeight(), 100, 25); + + for (int i = 0; i < volume; i++) + text[i] = '|'; + text[volume] = 0; + + drawString(0, y, w, 0, 246, text); + +} + +void MenuSystem::changeVolumeBar(ItemID itemID, int delta) { + + int *volume, newVolume; + + switch (itemID) { + case kItemIdMaster: + volume = &_cfgMasterVolume; + break; + case kItemIdVoices: + volume = &_cfgVoicesVolume; + break; + case kItemIdMusic: + volume = &_cfgMusicVolume; + break; + case kItemIdSoundFX: + volume = &_cfgSoundFXVolume; + break; + case kItemIdBackground: + volume = &_cfgBackgroundVolume; + break; + default: + return; + } + + newVolume = CLIP(*volume + delta, 0, 20); + + if (newVolume != *volume) { + *volume = newVolume; + drawVolumeBar(itemID); + } + +} + +} // End of namespace Toltecs |