diff options
Diffstat (limited to 'engines/m4/mads_menus.cpp')
-rw-r--r-- | engines/m4/mads_menus.cpp | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp new file mode 100644 index 0000000000..2857fc8080 --- /dev/null +++ b/engines/m4/mads_menus.cpp @@ -0,0 +1,586 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "m4/mads_menus.h" +#include "m4/m4.h" + +namespace M4 { + +#define REX_MENUSCREEN 990 +#define PHANTOM_MENUSCREEN 920 +#define DRAGON_MENUSCREEN 922 + +static Common::Point rexMenuItemPosList[6] = { + Common::Point(12, 68), Common::Point(12, 87), Common::Point(12, 107), + Common::Point(184, 75), Common::Point(245, 75), Common::Point(184, 99) +}; + +static Common::Point dragonMenuItemPosList[6] = { + Common::Point(46, 187), Common::Point(92, 187), Common::Point(138, 187), + Common::Point(184, 187), Common::Point(230, 187), Common::Point(276, 187) +}; + +#define DRAGON_MENU_BUTTON_W = 45 +#define DRAGON_MENU_BUTTON_H = 11 + +RexMainMenuView::RexMainMenuView(M4Engine *vm): + View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())) { + + _screenType = VIEWID_MAINMENU; + _screenFlags.get = SCREVENT_ALL; + + _delayTimeout = 0; + _menuItem = NULL; + _menuItemIndex = 0; + _frameIndex = 0; + _highlightedIndex = -1; + _skipFlag = false; + + // Load the background for the Rex Nebular game + _bgSurface = new M4Surface(width(), MADS_SURFACE_HEIGHT); + _bgSurface->loadBackground(REX_MENUSCREEN, &_bgPalData); + _vm->_palette->addRange(_bgPalData); + _bgSurface->translate(_bgPalData); + + int row = (height() - MADS_SURFACE_HEIGHT) / 2; + _bgSurface->copyTo(this, 0, row); + + // Add in the bounding lines for the background + setColor(2); + hLine(0, width() - 1, row - 1); + hLine(0, width() - 1, height() - row + 1); +} + +RexMainMenuView::~RexMainMenuView() { + if (_menuItem) + delete _menuItem; + + _vm->_palette->deleteRange(_bgPalData); + + delete _bgPalData; + delete _bgSurface; + + for (uint i = 0; i < _itemPalData.size(); ++i) { + _vm->_palette->deleteRange(_itemPalData[i]); + delete _itemPalData[i]; + } +} + +bool RexMainMenuView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) { + // Handle keypresses - these can be done at any time, even when the menu items are being drawn + if (eventType == KEVENT_KEY) { + switch (param) { + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_F6: + handleAction(EXIT); + break; + + case Common::KEYCODE_F1: + handleAction(START_GAME); + break; + + case Common::KEYCODE_F2: + handleAction(RESUME_GAME); + break; + + case Common::KEYCODE_F3: + handleAction(SHOW_INTRO); + break; + + case Common::KEYCODE_F4: + handleAction(CREDITS); + break; + + case Common::KEYCODE_F5: + handleAction(QUOTES); + break; + + case Common::KEYCODE_s: + // Goodness knows why, but Rex has a key to restart the menuitem animations + + // Delete the current menu items + if (_menuItem) + delete _menuItem; + + _vm->_palette->deleteRange(_bgPalData); + delete _bgPalData; + for (uint i = 0; i < _itemPalData.size(); ++i) { + _vm->_palette->deleteRange(_itemPalData[i]); + delete _itemPalData[i]; + } + _itemPalData.clear(); + + // Reload the background surface, and restart the animation + _bgSurface->loadBackground(REX_MENUSCREEN, &_bgPalData); + _vm->_palette->addRange(_bgPalData); + _bgSurface->translate(_bgPalData); + + _menuItemIndex = 0; + _skipFlag = false; + _menuItem = NULL; + _vm->_mouse->cursorOff(); + break; + + default: + // Any other key skips the menu animation + _skipFlag = true; + return false; + } + + return true; + } + + int row = (height() - MADS_SURFACE_HEIGHT) / 2; + int menuIndex; + + switch (eventType) { + case MEVENT_LEFT_CLICK: + case MEVENT_LEFT_DRAG: + if (_vm->_mouse->getCursorOn()) { + menuIndex = getHighlightedItem(x, y); + if (menuIndex != _highlightedIndex) { + _bgSurface->copyTo(this, 0, row); + + _highlightedIndex = menuIndex; + if (_highlightedIndex != -1) { + M4Sprite *spr = _menuItem->getFrame(_highlightedIndex); + const Common::Point &pt = rexMenuItemPosList[_highlightedIndex]; + spr->copyTo(this, pt.x, row + pt.y, 0); + } + } + } else { + // Skip the menu animation + _skipFlag = true; + } + return true; + + case MEVENT_LEFT_RELEASE: + if (_highlightedIndex != -1) + handleAction((MadsGameAction) _highlightedIndex); + return true; + + default: + break; + } + + return false; +} + +void RexMainMenuView::updateState() { + char resName[20]; + Common::SeekableReadStream *data; + int row = (height() - MADS_SURFACE_HEIGHT) / 2; + int itemSize; + + uint32 currTime = g_system->getMillis(); + if (currTime < _delayTimeout) + return; + _delayTimeout = currTime + MADS_MENU_ANIM_DELAY; + + // Rex Nebular handling to cycle through the animated display of the menu items + if (_menuItemIndex == 7) + return; + + // If the user has chosen to skip the menu animation, show the menu immediately + if (_skipFlag && !_vm->_mouse->getCursorOn()) { + // Clear any pending animation + _bgSurface->copyTo(this, 0, row); + // Quickly loop through all the menuitems to display each's final frame + while (_menuItemIndex < 7) { + + if (_menuItem) { + // Draw the final frame of the menuitem + M4Sprite *spr = _menuItem->getFrame(0); + itemSize = _menuItem->getFrame(0)->height(); + spr->copyTo(this, rexMenuItemPosList[_menuItemIndex - 1].x, + rexMenuItemPosList[_menuItemIndex - 1].y + row + (itemSize / 2) - (spr->height() / 2), 0); + + delete _menuItem; + copyTo(_bgSurface, Common::Rect(0, row, width(), row + MADS_SURFACE_HEIGHT), 0, 0); + } + + // Get the next sprite set + sprintf(resName, "RM%dA%d.SS", REX_MENUSCREEN, ++_menuItemIndex); + data = _vm->res()->get(resName); + _menuItem = new SpriteAsset(_vm, data, data->size(), resName); + _vm->res()->toss(resName); + + // Slot it into available palette space + RGBList *palData = _menuItem->getRgbList(); + _vm->_palette->addRange(palData); + _menuItem->translate(palData, true); + _itemPalData.push_back(palData); + } + + _vm->_mouse->cursorOn(); + return; + } + + if ((_menuItemIndex == 0) || (_frameIndex == 0)) { + // Get the next menu item + if (_menuItem) { + delete _menuItem; + + // Copy over the current display surface area to the background, so the final frame + // of the previous menuitem should be kept on the screen + copyTo(_bgSurface, Common::Rect(0, row, width(), row + MADS_SURFACE_HEIGHT), 0, 0); + } + + // Get the next menuitem resource + sprintf(resName, "RM%dA%d.SS", REX_MENUSCREEN, ++_menuItemIndex); + data = _vm->res()->get(resName); + _menuItem = new SpriteAsset(_vm, data, data->size(), resName); + _vm->res()->toss(resName); + + // Slot it into available palette space + RGBList *palData = _menuItem->getRgbList(); + _vm->_palette->addRange(palData); + _menuItem->translate(palData, true); + _itemPalData.push_back(palData); + + _frameIndex = _menuItem->getCount() - 1; + + // If the final resource is now loaded, which contains the highlighted versions of + // each menuitem, then the startup animation is complete + if (_menuItemIndex == 7) { + _vm->_mouse->cursorOn(); + return; + } + } else { + --_frameIndex; + } + + // Move to the next menuitem frame + + itemSize = _menuItem->getFrame(0)->height(); + + _bgSurface->copyTo(this, 0, row); + M4Sprite *spr = _menuItem->getFrame(_frameIndex); + spr->copyTo(this, rexMenuItemPosList[_menuItemIndex - 1].x, rexMenuItemPosList[_menuItemIndex - 1].y + + row + (itemSize / 2) - (spr->height() / 2), 0); +} + +int RexMainMenuView::getHighlightedItem(int x, int y) { + y -= (height() - MADS_SURFACE_HEIGHT) / 2; + + for (int index = 0; index < 6; ++index) { + const Common::Point &pt = rexMenuItemPosList[index]; + M4Sprite *spr = _menuItem->getFrame(index); + + if ((x >= pt.x) && (y >= pt.y) && (x < (pt.x + spr->width())) && (y < (pt.y + spr->height()))) + return index; + } + + return -1; +} + +void RexMainMenuView::handleAction(MadsGameAction action) { + M4Engine *vm = _vm; + vm->_mouse->cursorOff(); + vm->_viewManager->deleteView(this); + + switch (action) { + case START_GAME: + case RESUME_GAME: + // Load a sample starting scene - note that, currently, calling loadScene automatically + // removes this menu screen from being displayed + vm->_mouse->cursorOn(); + vm->_viewManager->addView(vm->_scene); + vm->_scene->loadScene(101); + return; + + case SHOW_INTRO: + vm->_viewManager->showAnimView("@rexopen"); + break; + + case CREDITS: + vm->_viewManager->showTextView("credits"); + return; + + case QUOTES: + vm->_viewManager->showTextView("quotes"); + return; + + case EXIT: + { + // When the Exit action is done from the menu, show one of two possible advertisements + + // Activate the scene display with the specified scene + bool altAdvert = vm->_random->getRandomNumber(1000) >= 500; + vm->_scene->loadScene(altAdvert ? 995 : 996); + vm->_viewManager->addView(vm->_scene); + + vm->_viewManager->refreshAll(); + vm->delay(10000); + + vm->_events->quitFlag = true; + return; + } + break; + default: + break; + } +} + +//-------------------------------------------------------------------------- + +MadsMainMenuView::MadsMainMenuView(M4Engine *vm): + View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())) { + +} + +bool MadsMainMenuView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) { + return false; +} + +void MadsMainMenuView::updateState() { + // TODO: Implement me +} + +//-------------------------------------------------------------------------- + +DragonMainMenuView::DragonMainMenuView(M4Engine *vm): + View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())) { + + _screenType = VIEWID_MAINMENU; + _screenFlags.get = SCREVENT_ALL; + + _delayTimeout = 0; + _menuItem = NULL; + _menuItemIndex = 0; + _frameIndex = 0; + _highlightedIndex = -1; + _skipFlag = false; + + // Load the background for the Dragonsphere game + this->loadBackground(942, &_bgPalData); + _vm->_palette->addRange(_bgPalData); + this->translate(_bgPalData); +} + +DragonMainMenuView::~DragonMainMenuView() { + //if (_menuItem) + // delete _menuItem; + + _vm->_palette->deleteRange(_bgPalData); + + delete _bgPalData; + + for (uint i = 0; i < _itemPalData.size(); ++i) { + _vm->_palette->deleteRange(_itemPalData[i]); + delete _itemPalData[i]; + } +} + +bool DragonMainMenuView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) { + char resName[20]; + Common::SeekableReadStream *data; + + // Handle keypresses - these can be done at any time, even when the menu items are being drawn + if (eventType == KEVENT_KEY) { + switch (param) { + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_F6: + handleAction(EXIT); + break; + + case Common::KEYCODE_F1: + handleAction(START_GAME); + break; + + case Common::KEYCODE_F2: + handleAction(RESUME_GAME); + break; + + case Common::KEYCODE_F3: + handleAction(SHOW_INTRO); + break; + + case Common::KEYCODE_F4: + handleAction(CREDITS); + break; + + default: + // Any other key skips the menu animation + _skipFlag = true; + return false; + } + + return true; + } + + int menuIndex; + + switch (eventType) { + case MEVENT_LEFT_CLICK: + case MEVENT_LEFT_DRAG: + if (_vm->_mouse->getCursorOn()) { + menuIndex = getHighlightedItem(x, y); + if (menuIndex != _highlightedIndex) { + + _highlightedIndex = menuIndex; + if (_highlightedIndex != -1) { + sprintf(resName, "MAIN%d.SS", menuIndex); + data = _vm->res()->get(resName); + _menuItem = new SpriteAsset(_vm, data, data->size(), resName); + _vm->res()->toss(resName); + + M4Sprite *spr = _menuItem->getFrame(1); + spr->copyTo(this, spr->xOffset - 25, spr->yOffset - spr->height()); + } + } + } else { + // Skip the menu animation + _skipFlag = true; + } + return true; + + case MEVENT_LEFT_RELEASE: + if (_highlightedIndex != -1) + handleAction((MadsGameAction) _highlightedIndex); + return true; + + default: + break; + } + + return false; +} + +void DragonMainMenuView::updateState() { + char resName[20]; + Common::SeekableReadStream *data; + RGBList *palData; + M4Sprite *spr; + + if (_menuItemIndex == 6) + return; + + while (_menuItemIndex < 6) { + sprintf(resName, "MAIN%d.SS", _menuItemIndex); + data = _vm->res()->get(resName); + _menuItem = new SpriteAsset(_vm, data, data->size(), resName); + _vm->res()->toss(resName); + + // Slot it into available palette space + palData = _menuItem->getRgbList(); + _vm->_palette->addRange(palData); + _menuItem->translate(palData, true); + _itemPalData.push_back(palData); + + spr = _menuItem->getFrame(0); + spr->copyTo(this, spr->xOffset - 25, spr->yOffset - spr->height()); + + if (_menuItemIndex != 5) + delete _menuItem; + _menuItemIndex++; + } + + // Sphere + sprintf(resName, "RM920X0.SS"); + data = _vm->res()->get(resName); + _menuItem = new SpriteAsset(_vm, data, data->size(), resName); + _vm->res()->toss(resName); + + // Slot it into available palette space + palData = _menuItem->getRgbList(); + _vm->_palette->addRange(palData); + _menuItem->translate(palData, true); + _itemPalData.push_back(palData); + + spr = _menuItem->getFrame(0); // empty sphere + spr->copyTo(this, spr->xOffset - 75, spr->yOffset - spr->height()); + spr = _menuItem->getFrame(1); // dragon inside sphere + spr->copyTo(this, spr->xOffset - 75, spr->yOffset - spr->height()); + + // Dragonsphere letters + sprintf(resName, "RM920X3.SS"); + data = _vm->res()->get(resName); + _menuItem = new SpriteAsset(_vm, data, data->size(), resName); + _vm->res()->toss(resName); + + // Slot it into available palette space + palData = _menuItem->getRgbList(); + _vm->_palette->addRange(palData); + _menuItem->translate(palData, true); + _itemPalData.push_back(palData); + + spr = _menuItem->getFrame(1); + // FIXME: We assume that the transparent color is the color of the top left pixel + byte *transparentColor = (byte *)spr->pixels; + spr->copyTo(this, spr->xOffset - 140, spr->yOffset - spr->height(), (int)*transparentColor); + + _vm->_mouse->cursorOn(); +} + +int DragonMainMenuView::getHighlightedItem(int x, int y) { + y -= (height() - MADS_SURFACE_HEIGHT) / 2; + + for (int index = 0; index < 6; ++index) { + const Common::Point &pt = dragonMenuItemPosList[index]; + M4Sprite *spr = _menuItem->getFrame(0); + + if ((x >= pt.x - 25) && (y >= pt.y - spr->height()) && (x < (pt.x - 25 + spr->width())) && (y < (pt.y))) { + printf("x = %d, y = %d, index = %d\n", x, y, index); + return index; + } + } + + return -1; +} + +void DragonMainMenuView::handleAction(MadsGameAction action) { + M4Engine *vm = _vm; + vm->_mouse->cursorOff(); + vm->_viewManager->deleteView(this); + + switch (action) { + case START_GAME: + case RESUME_GAME: + // Load a sample starting scene - note that, currently, calling loadScene automatically + // removes this menu screen from being displayed + vm->_mouse->cursorOn(); + vm->_viewManager->addView(vm->_scene); + vm->_scene->loadScene(101); + return; + + case SHOW_INTRO: + vm->_viewManager->showAnimView("@dragon"); + break; + + case CREDITS: + vm->_viewManager->showTextView("credits"); + return; + + case EXIT: + vm->_events->quitFlag = true; + return; + break; + default: + break; + } +} + +} |