diff options
Diffstat (limited to 'engines/mohawk/myst_stacks/menu.cpp')
-rw-r--r-- | engines/mohawk/myst_stacks/menu.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/engines/mohawk/myst_stacks/menu.cpp b/engines/mohawk/myst_stacks/menu.cpp new file mode 100644 index 0000000000..ebcfb15a65 --- /dev/null +++ b/engines/mohawk/myst_stacks/menu.cpp @@ -0,0 +1,366 @@ +/* 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 "mohawk/myst.h" +#include "mohawk/myst_areas.h" +#include "mohawk/myst_card.h" +#include "mohawk/myst_graphics.h" +#include "mohawk/myst_state.h" +#include "mohawk/cursors.h" +#include "mohawk/sound.h" +#include "mohawk/video.h" +#include "mohawk/myst_stacks/menu.h" + +#include "common/translation.h" +#include "graphics/cursorman.h" +#include "gui/message.h" + +namespace Mohawk { +namespace MystStacks { + +Menu::Menu(MohawkEngine_Myst *vm) : + MystScriptParser(vm, kMenuStack), + _inGame(false), + _canSave(false), + _wasCursorVisible(true), + _introMoviesRunning(false) { + + for (uint i = 0; i < ARRAYSIZE(_menuItemHovered); i++) { + _menuItemHovered[i] = false; + } + + setupOpcodes(); +} + +Menu::~Menu() { +} + +void Menu::setupOpcodes() { + // "Stack-Specific" Opcodes + REGISTER_OPCODE(150, Menu, o_menuItemEnter); + REGISTER_OPCODE(151, Menu, o_menuItemLeave); + REGISTER_OPCODE(152, Menu, o_menuResume); + REGISTER_OPCODE(153, Menu, o_menuLoad); + REGISTER_OPCODE(154, Menu, o_menuSave); + REGISTER_OPCODE(155, Menu, o_menuNew); + REGISTER_OPCODE(156, Menu, o_menuOptions); + REGISTER_OPCODE(157, Menu, o_menuQuit); + + // "Init" Opcodes + REGISTER_OPCODE(200, Menu, o_playIntroMovies); + REGISTER_OPCODE(201, Menu, o_menuInit); + + // "Exit" Opcodes + REGISTER_OPCODE(300, Menu, NOP); + REGISTER_OPCODE(301, Menu, o_menuExit); +} + +void Menu::disablePersistentScripts() { + _introMoviesRunning = false; +} + +void Menu::runPersistentScripts() { + if (_introMoviesRunning) + introMovies_run(); +} + +uint16 Menu::getVar(uint16 var) { + switch (var) { + case 1000: // New game + case 1001: // Load + case 1004: // Quit + case 1005: // Options + return _menuItemHovered[var - 1000] ? 1 : 0; + case 1002: // Save + if (_canSave) { + return _menuItemHovered[var - 1000] ? 1 : 0; + } else { + return 2; + } + case 1003: // Resume + if (_inGame) { + return _menuItemHovered[var - 1000] ? 1 : 0; + } else { + return 2; + } + default: + return MystScriptParser::getVar(var); + } +} + +void Menu::o_menuInit(uint16 var, const ArgumentsArray &args) { + _vm->pauseEngine(true); + + if (_inGame) { + _wasCursorVisible = CursorMan.isVisible(); + } + + if (!_wasCursorVisible) { + CursorMan.showMouse(true); + } + + struct MenuButton { + uint16 highlightedIndex; + uint16 disabledIndex; + Graphics::TextAlign align; + }; + + static const MenuButton buttons[] = { + { 1, 0, Graphics::kTextAlignRight }, + { 1, 0, Graphics::kTextAlignRight }, + { 1, 2, Graphics::kTextAlignRight }, + { 1, 2, Graphics::kTextAlignRight }, + { 1, 0, Graphics::kTextAlignRight }, + { 1, 0, Graphics::kTextAlignLeft } + }; + + const char **buttonCaptions = getButtonCaptions(); + + for (uint i = 0; i < ARRAYSIZE(buttons); i++) { + MystAreaImageSwitch *image = _vm->getCard()->getResource<MystAreaImageSwitch>(2 * i + 0); + MystAreaHover *hover = _vm->getCard()->getResource<MystAreaHover> (2 * i + 1); + + drawButtonImages(buttonCaptions[i], image, buttons[i].align, buttons[i].highlightedIndex, buttons[i].disabledIndex); + hover->setRect(image->getRect()); + } +} + +const char **Menu::getButtonCaptions() const { + static const char *buttonCaptionsEnglish[] = { + "NEW GAME", + "LOAD GAME", + "SAVE GAME", + "RESUME", + "QUIT", + "OPTIONS" + }; + + static const char *buttonCaptionsFrench[] = { + "NOUVEAU", + "CHARGER", + "SAUVER", + "REPRENDRE", + "QUITTER", + "OPTIONS" + }; + + static const char *buttonCaptionsGerman[] = { + "NEUES SPIEL", + "SPIEL LADEN", + "SPIEL SPEICHERN", + "FORTSETZEN", + "BEENDEN", + "OPTIONEN" + }; + + switch (_vm->getLanguage()) { + case Common::FR_FRA: + return buttonCaptionsFrench; + case Common::DE_DEU: + return buttonCaptionsGerman; + case Common::EN_ANY: + default: + return buttonCaptionsEnglish; + } +} + +void Menu::drawButtonImages(const char *text, MystAreaImageSwitch *area, Graphics::TextAlign align, uint16 highlightedIndex, uint16 disabledIndex) const { + Common::Rect backgroundRect = area->getRect(); + Common::Rect textBoundingBox = _vm->_gfx->getTextBoundingBox(text, backgroundRect, align); + + // Restrict the rectangle to the portion were the text will be drawn + if (align == Graphics::kTextAlignLeft) { + backgroundRect.right = textBoundingBox.right; + } else if (align == Graphics::kTextAlignRight) { + backgroundRect.left = textBoundingBox.left; + } else { + error("Unexpected align: %d", align); + } + + // Update the area with the new background rect + area->setRect(backgroundRect); + + MystAreaImageSwitch::SubImage idle = area->getSubImage(0); + area->setSubImageRect(0, Common::Rect(backgroundRect.left, idle.rect.top, backgroundRect.right, idle.rect.bottom)); + + // Align the text to the top of the destination rectangles + int16 deltaY = backgroundRect.top - textBoundingBox.top; + + if (highlightedIndex) { + replaceButtonSubImageWithText(text, align, area, highlightedIndex, backgroundRect, deltaY, 215, 216, 219); + } + + if (disabledIndex) { + replaceButtonSubImageWithText(text, align, area, disabledIndex, backgroundRect, deltaY, 136, 140, 145); + } + + uint16 cardBackground = _vm->getCard()->getBackgroundImageId(); + _vm->_gfx->drawText(cardBackground, text, backgroundRect, 181, 184, 189, align, deltaY); +} + +void Menu::replaceButtonSubImageWithText(const char *text, const Graphics::TextAlign &align, MystAreaImageSwitch *area, + uint16 subimageIndex, const Common::Rect &backgroundRect, int16 deltaY, + uint8 r, uint8 g, uint8 b) const { + uint16 cardBackground = _vm->getCard()->getBackgroundImageId(); + + MystAreaImageSwitch::SubImage highlighted = area->getSubImage(subimageIndex); + Common::Rect subImageRect(0, 0, backgroundRect.width(), backgroundRect.height()); + + // Create an image exactly the size of the rendered text with the backdrop as a background + _vm->_gfx->replaceImageWithRect(highlighted.wdib, cardBackground, backgroundRect); + area->setSubImageRect(subimageIndex, subImageRect); + + // Draw the text in the subimage + _vm->_gfx->drawText(highlighted.wdib, text, subImageRect, r, g, b, align, deltaY); +} + +void Menu::o_menuItemEnter(uint16 var, const ArgumentsArray &args) { + _menuItemHovered[var - 1000] = true; + _vm->getCard()->redrawArea(var); +} + +void Menu::o_menuItemLeave(uint16 var, const ArgumentsArray &args) { + _menuItemHovered[var - 1000] = false; + _vm->getCard()->redrawArea(var); +} + +void Menu::o_menuResume(uint16 var, const ArgumentsArray &args) { + if (!_inGame) { + return; + } + + _vm->resumeFromMainMenu(); +} + +void Menu::o_menuLoad(uint16 var, const ArgumentsArray &args) { + if (!showConfirmationDialog(_("Are you sure you want to load a saved game? All unsaved progress will be lost."), + _("Load game"), _("Cancel"))) { + return; + } + + _vm->runLoadDialog(); +} + +void Menu::o_menuSave(uint16 var, const ArgumentsArray &args) { + if (!_canSave) { + return; + } + + _vm->runSaveDialog(); +} + +void Menu::o_menuNew(uint16 var, const ArgumentsArray &args) { + if (!showConfirmationDialog(_("Are you sure you want to start a new game? All unsaved progress will be lost."), + _("New game"), _("Cancel"))) { + return; + } + + _vm->_gameState->reset(); + _vm->setTotalPlayTime(0); + _vm->setMainCursor(kDefaultMystCursor); + _vm->changeToStack(kIntroStack, 1, 0, 0); +} + +void Menu::o_menuOptions(uint16 var, const ArgumentsArray &args) { + resetButtons(); + + _vm->runOptionsDialog(); +} + +void Menu::o_menuQuit(uint16 var, const ArgumentsArray &args) { + if (!showConfirmationDialog(_("Are you sure you want to quit? All unsaved progress will be lost."), _("Quit"), + _("Cancel"))) { + return; + } + + _vm->changeToStack(kCreditsStack, 10000, 0, 0); +} + +void Menu::o_menuExit(uint16 var, const ArgumentsArray &args) { + if (_inGame) { + _vm->_gfx->restoreStateForMainMenu(); + } + + CursorMan.showMouse(_wasCursorVisible); + + _vm->pauseEngine(false); +} + +void Menu::o_playIntroMovies(uint16 var, const ArgumentsArray &args) { + _introMoviesRunning = true; + _introStep = 0; +} + +void Menu::introMovies_run() { + // Play Intro Movies + // This is all quite messy... + + VideoEntryPtr video; + + switch (_introStep) { + case 0: + _introStep = 1; + video = _vm->playMovie("broder", kIntroStack); + video->center(); + break; + case 1: + if (!_vm->_video->isVideoPlaying()) + _introStep = 2; + break; + case 2: + _introStep = 3; + video = _vm->playMovie("cyanlogo", kIntroStack); + video->center(); + break; + case 3: + if (!_vm->_video->isVideoPlaying()) + _introStep = 4; + break; + default: + _vm->changeToCard(1000, kTransitionCopy); + } +} + +bool Menu::showConfirmationDialog(const char *message, const char *confirmButton, const char *cancelButton) { + if (!_inGame) { + return true; + } + + resetButtons(); + + GUI::MessageDialog dialog(message, confirmButton, cancelButton); + + return dialog.runModal() !=0; +} + +void Menu::resetButtons() { + for (uint i = 0; i < ARRAYSIZE(_menuItemHovered); i++) { + _menuItemHovered[i] = false; + _vm->getCard()->redrawArea(1000 + i); + } + + _vm->doFrame(); +} + + +} // End of namespace MystStacks +} // End of namespace Mohawk |