mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-02 15:38:59 +00:00
410 lines
10 KiB
C++
410 lines
10 KiB
C++
/* 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/scummsys.h"
|
|
#include "common/config-manager.h"
|
|
#include "mads/game.h"
|
|
#include "mads/mads.h"
|
|
#include "mads/menu_views.h"
|
|
#include "mads/resources.h"
|
|
#include "mads/scene.h"
|
|
#include "mads/screen.h"
|
|
#include "mads/nebular/menu_nebular.h"
|
|
|
|
namespace MADS {
|
|
|
|
namespace Nebular {
|
|
|
|
#define NEBULAR_MENUSCREEN 990
|
|
#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
|
|
#define MADS_MENU_ANIM_DELAY 70
|
|
|
|
MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
|
|
Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr);
|
|
Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1);
|
|
_delayTimeout = 0;
|
|
_menuItemIndex = -1;
|
|
_frameIndex = 0;
|
|
_skipFlag = false;
|
|
_highlightedIndex = -1;
|
|
_selectedIndex = -1;
|
|
_buttonDown = false;
|
|
|
|
for (int i = 0; i < 7; ++i)
|
|
_menuItems[i] = nullptr;
|
|
}
|
|
|
|
MainMenu::~MainMenu() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
for (int i = 0; i < 7; ++i) {
|
|
if (_menuItemIndexes[i] != -1)
|
|
scene._sprites.remove(_menuItemIndexes[i]);
|
|
}
|
|
|
|
scene._spriteSlots.reset();
|
|
}
|
|
|
|
bool MainMenu::shouldShowQuotes() {
|
|
return ConfMan.hasKey("ShowQuotes") && ConfMan.getBool("ShowQuotes");
|
|
}
|
|
|
|
void MainMenu::display() {
|
|
MenuView::display();
|
|
Scene &scene = _vm->_game->_scene;
|
|
ScreenObjects &screenObjects = _vm->_game->_screenObjects;
|
|
screenObjects.clear();
|
|
|
|
// Load each of the menu item assets and add to the scene sprites list
|
|
for (int i = 0; i < 7; ++i) {
|
|
Common::String spritesName = Resources::formatName(NEBULAR_MENUSCREEN,
|
|
'A', i + 1, EXT_SS, "");
|
|
_menuItems[i] = new SpriteAsset(_vm, spritesName, 0);
|
|
_menuItemIndexes[i] = scene._sprites.add(_menuItems[i]);
|
|
|
|
// Register the menu item area in the screen objects
|
|
MSprite *frame0 = _menuItems[i]->getFrame(0);
|
|
Common::Point pt(frame0->_offset.x - (frame0->w / 2),
|
|
frame0->_offset.y - frame0->h);
|
|
screenObjects.add(
|
|
Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w,
|
|
pt.y + frame0->h + DIALOG_TOP), SCREENMODE_VGA, CAT_COMMAND, i);
|
|
}
|
|
|
|
// Set the cursor for when it's shown
|
|
_vm->_events->setCursor(CURSOR_ARROW);
|
|
}
|
|
|
|
void MainMenu::doFrame() {
|
|
// Delay between animation frames on the menu
|
|
uint32 currTime = g_system->getMillis();
|
|
if (currTime < _delayTimeout)
|
|
return;
|
|
_delayTimeout = currTime + MADS_MENU_ANIM_DELAY;
|
|
|
|
// If an item has already been selected, handle rotating out the other menu items
|
|
if (_selectedIndex != -1) {
|
|
if (_frameIndex == _menuItems[0]->getCount()) {
|
|
handleAction((MADSGameAction)_selectedIndex);
|
|
} else {
|
|
for (_menuItemIndex = 0; _menuItemIndex < 6; ++_menuItemIndex) {
|
|
if (_menuItemIndex == 4 && !shouldShowQuotes())
|
|
continue;
|
|
|
|
if (_menuItemIndex != _selectedIndex) {
|
|
addSpriteSlot();
|
|
}
|
|
}
|
|
|
|
// Move the menu items to the next frame
|
|
++_frameIndex;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If we've alerady reached the end of the menuitem animation, exit immediately
|
|
if (_menuItemIndex == 6)
|
|
return;
|
|
|
|
// If the user has chosen to skip the animation, show the full menu immediately
|
|
if (_skipFlag && _menuItemIndex >= 0) {
|
|
// Quickly loop through all the menu items to display each's final frame
|
|
for (; _menuItemIndex < 6; ++_menuItemIndex) {
|
|
if (_menuItemIndex == 4 && !shouldShowQuotes())
|
|
continue;
|
|
|
|
// Draw the final frame of the menuitem
|
|
_frameIndex = 0;
|
|
addSpriteSlot();
|
|
}
|
|
|
|
_vm->_events->showCursor();
|
|
} else {
|
|
if ((_menuItemIndex == -1) || (_frameIndex == 0)) {
|
|
if (++_menuItemIndex == 6) {
|
|
|
|
// Reached end of display animation
|
|
_vm->_events->showCursor();
|
|
return;
|
|
} else if (_menuItemIndex == 4 && !shouldShowQuotes()) {
|
|
++_menuItemIndex;
|
|
}
|
|
|
|
_frameIndex = _menuItems[_menuItemIndex]->getCount() - 1;
|
|
} else {
|
|
--_frameIndex;
|
|
}
|
|
|
|
// Move to the next menuitem frame
|
|
addSpriteSlot();
|
|
}
|
|
}
|
|
|
|
void MainMenu::addSpriteSlot() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
SpriteSlots &spriteSlots = scene._spriteSlots;
|
|
|
|
int seqIndex = (_menuItemIndex < 6) ? _menuItemIndex : _frameIndex;
|
|
spriteSlots.deleteTimer(seqIndex);
|
|
|
|
SpriteAsset *menuItem = _menuItems[_menuItemIndex];
|
|
MSprite *spr = menuItem->getFrame(_frameIndex);
|
|
|
|
SpriteSlot &slot = spriteSlots[spriteSlots.add()];
|
|
slot._flags = IMG_UPDATE;
|
|
slot._seqIndex = seqIndex;
|
|
slot._spritesIndex = _menuItemIndexes[_menuItemIndex];
|
|
slot._frameNumber = _frameIndex + 1;
|
|
slot._position = spr->_offset;
|
|
slot._depth = 1;
|
|
slot._scale = 100;
|
|
|
|
_redrawFlag = true;
|
|
}
|
|
|
|
bool MainMenu::onEvent(Common::Event &event) {
|
|
Scene &scene = _vm->_game->_scene;
|
|
if (_selectedIndex != -1)
|
|
return false;
|
|
|
|
// Handle keypresses - these can be done at any time, even when the menu items are being drawn
|
|
if (event.type == Common::EVENT_KEYDOWN) {
|
|
switch (event.kbd.keycode) {
|
|
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
|
|
// Restart the animation
|
|
_menuItemIndex = -1;
|
|
for (int i = 0; i < 6; ++i)
|
|
scene._spriteSlots.deleteTimer(i);
|
|
|
|
_skipFlag = false;
|
|
_vm->_events->hideCursor();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Any other key skips the menu animation
|
|
_skipFlag = true;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
switch (event.type) {
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
if (_vm->_events->isCursorVisible()) {
|
|
_buttonDown = true;
|
|
int menuIndex = getHighlightedItem(event.mouse);
|
|
|
|
if (menuIndex != _highlightedIndex) {
|
|
scene._spriteSlots.deleteTimer(menuIndex);
|
|
|
|
_highlightedIndex = menuIndex;
|
|
if (_highlightedIndex != -1) {
|
|
_frameIndex = _highlightedIndex;
|
|
addSpriteSlot();
|
|
}
|
|
}
|
|
} else {
|
|
// Skip the menu animation
|
|
_skipFlag = true;
|
|
}
|
|
return true;
|
|
|
|
case Common::EVENT_MOUSEMOVE:
|
|
if (_buttonDown) {
|
|
int menuIndex = getHighlightedItem(event.mouse);
|
|
if (menuIndex != _highlightedIndex) {
|
|
if (_highlightedIndex != -1) {
|
|
// Revert to the unselected menu item
|
|
unhighlightItem();
|
|
}
|
|
|
|
if (menuIndex != -1) {
|
|
// Highlight new item
|
|
_highlightedIndex = menuIndex;
|
|
_frameIndex = _highlightedIndex;
|
|
addSpriteSlot();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONUP:
|
|
_buttonDown = false;
|
|
if (_highlightedIndex != -1) {
|
|
_selectedIndex = _highlightedIndex;
|
|
unhighlightItem();
|
|
_frameIndex = 0;
|
|
}
|
|
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int MainMenu::getHighlightedItem(const Common::Point &pt) {
|
|
return _vm->_game->_screenObjects.scan(pt, SCREENMODE_VGA) - 1;
|
|
}
|
|
|
|
void MainMenu::unhighlightItem() {
|
|
// Revert to the unselected menu item
|
|
_vm->_game->_scene._spriteSlots.deleteTimer(_highlightedIndex);
|
|
_menuItemIndex = _highlightedIndex;
|
|
_frameIndex = 0;
|
|
addSpriteSlot();
|
|
|
|
_menuItemIndex = 6;
|
|
_highlightedIndex = -1;
|
|
}
|
|
|
|
void MainMenu::handleAction(MADSGameAction action) {
|
|
_vm->_events->hideCursor();
|
|
_breakFlag = true;
|
|
|
|
switch (action) {
|
|
case START_GAME:
|
|
// Show the difficulty dialog
|
|
_vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY;
|
|
break;
|
|
|
|
case RESUME_GAME:
|
|
// The original resumed the most recently saved game. Instead,
|
|
// just show the load game scren
|
|
_vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
|
|
return;
|
|
|
|
case SHOW_INTRO:
|
|
AnimationView::execute(_vm, "rexopen");
|
|
break;
|
|
|
|
case CREDITS:
|
|
TextView::execute(_vm, "credits");
|
|
return;
|
|
|
|
case QUOTES:
|
|
TextView::execute(_vm, "quotes");
|
|
return;
|
|
|
|
case EXIT:
|
|
_vm->_dialogs->_pendingDialog = DIALOG_ADVERT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
AdvertView::AdvertView(MADSEngine *vm): EventTarget(), _vm(vm) {
|
|
_breakFlag = false;
|
|
}
|
|
|
|
void AdvertView::show() {
|
|
bool altAdvert = _vm->getRandomNumber(1000) >= 500;
|
|
int screenId = altAdvert ? 995 : 996;
|
|
uint32 expiryTime = g_system->getMillis() + 10 * 1000;
|
|
|
|
_vm->_palette->resetGamePalette(4, 8);
|
|
|
|
// Load the advert background onto the screen
|
|
SceneInfo *sceneInfo = SceneInfo::init(_vm);
|
|
sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface,
|
|
_vm->_screen);
|
|
_vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
|
|
_vm->_palette->setFullPalette(_vm->_palette->_mainPalette);
|
|
|
|
delete sceneInfo;
|
|
|
|
EventsManager &events = *_vm->_events;
|
|
events.setEventTarget(this);
|
|
events.hideCursor();
|
|
|
|
while (!_breakFlag && !_vm->shouldQuit()) {
|
|
_vm->_events->waitForNextFrame();
|
|
_vm->_game->_fx = kTransitionNone;
|
|
|
|
_breakFlag |= g_system->getMillis() >= expiryTime;
|
|
}
|
|
|
|
events.setEventTarget(nullptr);
|
|
_vm->quitGame();
|
|
events.pollEvents();
|
|
}
|
|
|
|
bool AdvertView::onEvent(Common::Event &event) {
|
|
if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
|
|
_breakFlag = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void RexAnimationView::scriptDone() {
|
|
AnimationView::scriptDone();
|
|
|
|
Common::String s = getResourceName();
|
|
if (s == "rexend1") {
|
|
TextView::execute(_vm, "ending1");
|
|
} else if (s == "rexend2") {
|
|
TextView::execute(_vm, "ending2");
|
|
} else if (s == "rexend3") {
|
|
TextView::execute(_vm, "credits");
|
|
}
|
|
}
|
|
|
|
} // End of namespace Nebular
|
|
|
|
} // End of namespace MADS
|