diff options
-rw-r--r-- | engines/mads/dialogs.h | 3 | ||||
-rw-r--r-- | engines/mads/events.cpp | 7 | ||||
-rw-r--r-- | engines/mads/events.h | 12 | ||||
-rw-r--r-- | engines/mads/nebular/dialogs_nebular.cpp | 83 | ||||
-rw-r--r-- | engines/mads/nebular/dialogs_nebular.h | 2 | ||||
-rw-r--r-- | engines/mads/nebular/game_nebular.cpp | 8 | ||||
-rw-r--r-- | engines/mads/nebular/menu_nebular.cpp | 738 | ||||
-rw-r--r-- | engines/mads/nebular/menu_nebular.h | 175 | ||||
-rw-r--r-- | engines/scumm/input.cpp | 5 | ||||
-rw-r--r-- | engines/scumm/sound.cpp | 9 |
10 files changed, 829 insertions, 213 deletions
diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h index c2d5bba8ed..c586a6f1fe 100644 --- a/engines/mads/dialogs.h +++ b/engines/mads/dialogs.h @@ -202,7 +202,8 @@ public: enum DialogId { DIALOG_NONE = 0, DIALOG_GAME_MENU = 1, DIALOG_SAVE = 2, DIALOG_RESTORE = 3, DIALOG_OPTIONS = 4, DIALOG_DIFFICULTY = 5, DIALOG_ERROR = 6, - DIALOG_MAIN_MENU = 7 + DIALOG_MAIN_MENU = 7, DIALOG_TEXTVIEW = 8, DIALOG_ANIMVIEW = 9, + DIALOG_ADVERT = 10 }; class Dialogs { diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp index 41c8255ce8..de4dc3c070 100644 --- a/engines/mads/events.cpp +++ b/engines/mads/events.cpp @@ -46,6 +46,7 @@ EventsManager::EventsManager(MADSEngine *vm) { _mouseMoved = false; _vD8 = 0; _rightMousePressed = false; + _eventTarget = nullptr; } EventsManager::~EventsManager() { @@ -138,6 +139,12 @@ void EventsManager::pollEvents() { Common::Event event; while (g_system->getEventManager()->pollEvent(event)) { + // If an event target is specified, pass the event to it + if (_eventTarget) { + _eventTarget->onEvent(event); + continue; + } + // Handle keypress switch (event.type) { case Common::EVENT_QUIT: diff --git a/engines/mads/events.h b/engines/mads/events.h index f491556e9e..54df337efd 100644 --- a/engines/mads/events.h +++ b/engines/mads/events.h @@ -39,6 +39,12 @@ enum CursorType { CURSOR_NONE = 0, CURSOR_ARROW = 1, CURSOR_WAIT = 2, CURSOR_GO_ class MADSEngine; +class EventTarget { +public: + virtual ~EventTarget() {} + virtual bool onEvent(Common::Event &event) { return false; } +}; + class EventsManager { private: MADSEngine *_vm; @@ -46,6 +52,7 @@ private: uint32 _priorFrameTime; Common::Point _mousePos; Common::Point _currentPos; + EventTarget *_eventTarget; /** * Updates the cursor image when the current cursor changes @@ -122,6 +129,11 @@ public: void pollEvents(); /** + * Sets an event handler other than the events manager + */ + void setEventTarget(EventTarget *target) { _eventTarget = target; } + + /** * Return the current mouse position */ Common::Point mousePos() const { return _mousePos; } diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index 63b16d87e2..d4b277d856 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -270,41 +270,52 @@ bool DialogsNebular::commandCheck(const char *idStr, Common::String &valStr, } void DialogsNebular::showDialog() { - switch (_pendingDialog) { - case DIALOG_MAIN_MENU: { - MainMenu *menu = new MainMenu(_vm); - menu->show(); - delete menu; - break; - } - case DIALOG_DIFFICULTY: { - DifficultyDialog *dlg = new DifficultyDialog(_vm); - dlg->show(); - delete dlg; - break; - } - case DIALOG_GAME_MENU: { - GameMenuDialog *dlg = new GameMenuDialog(_vm); - dlg->show(); - delete dlg; - break; - } - case DIALOG_SAVE: { - showScummVMSaveDialog(); - break; - } - case DIALOG_RESTORE: { - showScummVMRestoreDialog(); - break; - } - case DIALOG_OPTIONS: { - OptionsDialog *dlg = new OptionsDialog(_vm); - dlg->show(); - delete dlg; - break; - } - default: - break; + while (_pendingDialog != DIALOG_NONE && !_vm->shouldQuit()) { + DialogId dialogId = _pendingDialog; + _pendingDialog = DIALOG_NONE; + + switch (dialogId) { + case DIALOG_MAIN_MENU: { + MainMenu *menu = new MainMenu(_vm); + menu->show(); + delete menu; + break; + } + case DIALOG_DIFFICULTY: { + DifficultyDialog *dlg = new DifficultyDialog(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_GAME_MENU: { + GameMenuDialog *dlg = new GameMenuDialog(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_SAVE: { + showScummVMSaveDialog(); + break; + } + case DIALOG_RESTORE: { + showScummVMRestoreDialog(); + break; + } + case DIALOG_OPTIONS: { + OptionsDialog *dlg = new OptionsDialog(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_ADVERT: { + AdvertView *dlg = new AdvertView(_vm); + dlg->show(); + delete dlg; + break; + } + default: + break; + } } } @@ -537,13 +548,13 @@ FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) { } FullScreenDialog::~FullScreenDialog() { + _vm->_screen._offset.y = 0; } void FullScreenDialog::display() { Game &game = *_vm->_game; Scene &scene = game._scene; - bool palFlag = false; int nextSceneId = scene._nextSceneId; int currentSceneId = scene._currentSceneId; int priorSceneId = scene._priorSceneId; diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index fe7e656b0d..1468db38c8 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -107,7 +107,7 @@ enum DialogTextAlign { ALIGN_NONE = 0, ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, enum DialogState { DLGSTATE_UNSELECTED = 0, DLGSTATE_SELECTED = 1, DLGSTATE_FOCUSED = 2 }; -class FullScreenDialog { +class FullScreenDialog: public EventTarget { protected: /** * Engine reference diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp index 8fddf8b9c4..902f42507a 100644 --- a/engines/mads/nebular/game_nebular.cpp +++ b/engines/mads/nebular/game_nebular.cpp @@ -60,9 +60,7 @@ ProtectionResult GameNebular::checkCopyProtection() { } void GameNebular::startGame() { - // Show the main menu - // TODO: Show the main menu here - + /* // Check copy protection ProtectionResult protectionResult = checkCopyProtection(); switch (protectionResult) { @@ -80,11 +78,13 @@ void GameNebular::startGame() { // Copy protection check succeeded break; } + */ initSection(_sectionNumber); _statusFlag = true; - _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY; + // Show the main menu + _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU; _vm->_dialogs->showDialog(); _vm->_dialogs->_pendingDialog = DIALOG_NONE; diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp index f6ca990952..cb8f56bd05 100644 --- a/engines/mads/nebular/menu_nebular.cpp +++ b/engines/mads/nebular/menu_nebular.cpp @@ -46,13 +46,14 @@ void MenuView::show() { EventsManager &events = *_vm->_events; display(); + events.setEventTarget(this); events.hideCursor(); while (!_breakFlag && !_vm->shouldQuit()) { - handleEvents(); - if (_redrawFlag) { scene.drawElements(_vm->_game->_fx, _vm->_game->_fx); + + _vm->_screen.copyRectToScreen(Common::Rect(0, 0, 320, 200)); _redrawFlag = false; } @@ -60,6 +61,8 @@ void MenuView::show() { _vm->_game->_fx = kTransitionNone; doFrame(); } + + events.setEventTarget(nullptr); } void MenuView::display() { @@ -68,37 +71,132 @@ void MenuView::display() { FullScreenDialog::display(); } -void MenuView::handleEvents() { - Common::Event event; - - while (g_system->getEventManager()->pollEvent(event)) - onEvent(event); -} - /*------------------------------------------------------------------------*/ MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) { - _itemPosList[0] = Common::Point(12, 68); - _itemPosList[1] = Common::Point(12, 87); - _itemPosList[2] = Common::Point(12, 107); - _itemPosList[3] = Common::Point(184, 75); - _itemPosList[4] = Common::Point(245, 75); - _itemPosList[5] = Common::Point(184, 99); - + Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr); + Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1); _delayTimeout = 0; - _menuItem = NULL; - _menuItemIndex = 0; + _menuItemIndex = -1; _frameIndex = 0; - _highlightedIndex = -1; _skipFlag = false; + _highlightedIndex = -1; + _selectedIndex = -1; + _buttonDown = false; } MainMenu::~MainMenu() { - if (_menuItem) - delete _menuItem; +} + +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 + _vm->_screen._offset.y); + screenObjects.add( + Common::Rect(pt.x, pt.y, pt.x + frame0->w, pt.y + frame0->h), + LAYER_GUI, 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 != _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) { + // 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; + } + + _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) { @@ -129,23 +227,12 @@ bool MainMenu::onEvent(Common::Event &event) { 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(); - */ // Restart the animation - _menuItemIndex = 0; + _menuItemIndex = -1; + for (int i = 0; i < 6; ++i) + scene._spriteSlots.deleteTimer(i); + _skipFlag = false; - _menuItem = NULL; _vm->_events->hideCursor(); break; } @@ -159,21 +246,19 @@ bool MainMenu::onEvent(Common::Event &event) { return true; } - int menuIndex; - switch (event.type) { case Common::EVENT_LBUTTONDOWN: if (_vm->_events->isCursorVisible()) { - menuIndex = getHighlightedItem(event.mouse.x, event.mouse.y); + _buttonDown = true; + int menuIndex = getHighlightedItem(event.mouse); if (menuIndex != _highlightedIndex) { -// _bgSurface->copyTo(this, Common::Point(0, MADS_MENU_Y)); + scene._spriteSlots.deleteTimer(menuIndex); _highlightedIndex = menuIndex; if (_highlightedIndex != -1) { - MSprite *spr = _menuItem->getFrame(_highlightedIndex); - const Common::Point &pt = _itemPosList[_highlightedIndex]; - spr->copyTo(&_vm->_screen, Common::Point(pt.x, MADS_MENU_Y + pt.y)); + _frameIndex = _highlightedIndex; + addSpriteSlot(); } } } else { @@ -182,165 +267,508 @@ bool MainMenu::onEvent(Common::Event &event) { } 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: - if (_highlightedIndex != -1) - handleAction((MADSGameAction)_highlightedIndex); + _buttonDown = false; + if (_highlightedIndex != -1) { + _selectedIndex = _highlightedIndex; + unhighlightItem(); + _frameIndex = 0; + } + return true; default: break; } - + return false; } -void MainMenu::doFrame() { - int itemSize; +int MainMenu::getHighlightedItem(const Common::Point &pt) { + return _vm->_game->_screenObjects.scan(pt, LAYER_GUI) - 1; +} - // Delay between animation frames on the menu - uint32 currTime = g_system->getMillis(); - if (currTime < _delayTimeout) +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; - _delayTimeout = currTime + MADS_MENU_ANIM_DELAY; - // If we've alerady reached the end of the menuitem animation, exit immediately - if (_menuItemIndex == 7) + case SHOW_INTRO: + AnimationView::execute(_vm, "@rexopen"); + break; + + case CREDITS: + TextView::execute(_vm, "credits"); return; - // If the user has chosen to skip the animation, show the full menu immediately - if (_skipFlag && !_vm->_events->isCursorVisible()) { - // Clear any pending animation -// _savedSurface.copyTo(&_vm->_screen, Common::Point(0, MADS_MENU_Y)); - - // Quickly loop through all the menu items to display each's final frame - while (_menuItemIndex < 7) { - if (_menuItem) { - // Draw the final frame of the menuitem - MSprite *spr = _menuItem->getFrame(0); - itemSize = _menuItem->getFrame(0)->h; - spr->copyTo(&_vm->_screen, Common::Point(_itemPosList[_menuItemIndex - 1].x, - _itemPosList[_menuItemIndex - 1].y + MADS_MENU_Y + (itemSize / 2) - (spr->h / 2))); - - delete _menuItem; - //copyTo(_bgSurface, Common::Rect(0, row, width(), row + MADS_SCENE_HEIGHT), 0, 0); + 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()); + 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(); +} + +bool AdvertView::onEvent(Common::Event &event) { + if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) { + _breakFlag = true; + return true; + } + + return false; +} + +/*------------------------------------------------------------------------*/ + +char TextView::_resourceName[100]; +#define TEXTVIEW_LINE_SPACING 2 +#define TEXT_ANIMATION_DELAY 100 +#define TV_NUM_FADE_STEPS 40 +#define TV_FADE_DELAY_MILLI 50 + +void TextView::execute(MADSEngine *vm, const Common::String &resName) { + assert(resName.size() < 100); + strcpy(_resourceName, resName.c_str()); + vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW; +} + +TextView::TextView(MADSEngine *vm) : MenuView(vm), + _textSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT + _vm->_font->getHeight()) { + _animating = false; + _panSpeed = 0; + Common::fill(&_spareScreens[0], &_spareScreens[10], 0); + _spareScreen = nullptr; + _scrollCount = 0; + _lineY = -1; + _scrollTimeout = 0; + _panCountdown = 0; + _translationX = 0; +} + +TextView::~TextView() { + delete _spareScreen; +} + +void TextView::load() { + if (!_script.open(_resourceName)) + error("Could not open resource %s", _resourceName); + + processLines(); +} + +void TextView::processLines() { + if (_script.eos()) + error("Attempted to read past end of response file"); + + while (!_script.eos()) { + _script.readLine(_currentLine, 79); + + // Commented out line, so go loop for another + if (_currentLine[0] == '#') + continue; + + // Process the line + char *cStart = strchr(_currentLine, '['); + if (cStart) { + while (cStart) { + // Loop for possible multiple commands on one line + char *cEnd = strchr(_currentLine, ']'); + if (!cEnd) + error("Unterminated command '%s' in response file", _currentLine); + + *cEnd = '\0'; + processCommand(); + + // Copy rest of line (if any) to start of buffer + strcpy(_currentLine, cEnd + 1); + + cStart = strchr(_currentLine, '['); } - // Get the next sprite set - Common::String spritesName = Resources::formatName(NEBULAR_MENUSCREEN, - 'A', ++_menuItemIndex, EXT_SS, ""); - _menuItem = new SpriteAsset(_vm, spritesName, 0); - - // Slot it into available palette space -/* - RGBList *palData = _menuItem->getRgbList(); - _vm->_palette->addRange(palData); - _menuItem->translate(palData, true); - _itemPalData.push_back(palData); -*/ - } + if (_currentLine[0]) { + processText(); + break; + } - _vm->_events->showCursor(); - return; + } else { + processText(); + break; + } } +} - if ((_menuItemIndex == 0) || (_frameIndex == 0)) { - // Get the next menu item - if (_menuItem) { - delete _menuItem; +void TextView::processCommand() { + Scene &scene = _vm->_game->_scene; + Common::String scriptLine(_currentLine + 1); + scriptLine.toUppercase(); + const char *paramP; + const char *commandStr = scriptLine.c_str(); + + if (!strncmp(commandStr, "BACKGROUND", 10)) { + // Set the background + paramP = commandStr + 10; + int screenId = getParameter(¶mP); + + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->load(screenId, 0, Common::String(), 0, scene._depthSurface, + scene._backgroundSurface); + + } else if (!strncmp(commandStr, "GO", 2)) { + _animating = true; + + // Grab what the final palete will be + byte destPalette[PALETTE_SIZE]; + _vm->_palette->grabPalette(destPalette, 0, 256); + + // Copy the loaded background, if any, to the view surface + //int yp = 22; + //scene._backgroundSurface.copyTo(this, 0, 22); + + // Handle fade-in + //byte srcPalette[768]; + //Common::fill(&srcPalette[0], &srcPalette[PALETTE_SIZE], 0); + //_vm->_palette->fadeIn(srcPalette, destPalette, 0, PALETTE_COUNT, 0, 0, + // TV_FADE_DELAY_MILLI, TV_NUM_FADE_STEPS); + _vm->_game->_fx = kTransitionFadeIn; + + } else if (!strncmp(commandStr, "PAN", 3)) { + // Set panning values + paramP = commandStr + 3; + int panX = getParameter(¶mP); + int panY = getParameter(¶mP); + int panSpeed = getParameter(¶mP); + + if ((panX != 0) || (panY != 0)) { + _pan = Common::Point(panX, panY); + _panSpeed = panSpeed; + } - // 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_SCENE_HEIGHT), 0, 0); + } else if (!strncmp(commandStr, "DRIVER", 6)) { + // Set the driver to use + paramP = commandStr + 6; + int driverNum = getParameter(¶mP); + _vm->_sound->init(driverNum); + + } else if (!strncmp(commandStr, "SOUND", 5)) { + // Set sound number + paramP = commandStr + 5; + int soundId = getParameter(¶mP); + _vm->_sound->command(soundId); + + } else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') || + (commandStr[5] == '1'))) { + // Set the text colors + int index = commandStr[5] - '0'; + paramP = commandStr + 6; + + byte palEntry[3]; + palEntry[0] = getParameter(¶mP) << 2; + palEntry[1] = getParameter(¶mP) << 2; + palEntry[2] = getParameter(¶mP) << 2; + _vm->_palette->setPalette(&palEntry[0], 5 + index, 1); + + } else if (!strncmp(commandStr, "SPARE", 5)) { + // Sets a secondary background number that can be later switched in with a PAGE command + paramP = commandStr + 6; + int spareIndex = commandStr[5] - '0'; + if ((spareIndex >= 0) && (spareIndex <= 9)) { + int screenId = getParameter(¶mP); + + _spareScreens[spareIndex] = screenId; } - // Get the next menuitem resource - Common::String spritesName = Resources::formatName(NEBULAR_MENUSCREEN, - 'A', ++_menuItemIndex, EXT_SS, ""); - _menuItem = new SpriteAsset(_vm, spritesName, 0); - _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->_events->showCursor(); - return; + } else if (!strncmp(commandStr, "PAGE", 4)) { + // Signals to change to a previous specified secondary background + paramP = commandStr + 4; + int spareIndex = getParameter(¶mP); + + // Only allow background switches if one isn't currently in progress + if (!_spareScreen && (_spareScreens[spareIndex] != 0)) { + _spareScreen = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT); + //_spareScreen->loadBackground(_spareScreens[spareIndex], &_bgSpare); + + _translationX = 0; } + } else { - --_frameIndex; + error("Unknown response command: '%s'", commandStr); } +} - // Move to the next menuitem frame +int TextView::getParameter(const char **paramP) { + if ((**paramP != '=') && (**paramP != ',')) + return 0; - itemSize = _menuItem->getFrame(0)->h; + int result = 0; + ++*paramP; + while ((**paramP >= '0') && (**paramP <= '9')) { + result = result * 10 + (**paramP - '0'); + ++*paramP; + } - //_bgSurface->copyTo(this, 0, row); - MSprite *spr = _menuItem->getFrame(_frameIndex); - - spr->copyTo(&_vm->_screen, - Common::Point(_itemPosList[_menuItemIndex - 1].x, - _itemPosList[_menuItemIndex - 1].y + MADS_MENU_Y + - (itemSize / 2) - (spr->h / 2))); + return result; +} + +void TextView::processText() { + int lineWidth, xStart; + + if (!strcmp(_currentLine, "***")) { + // Special signifier for end of script + _scrollCount = _vm->_font->getHeight() * 13; + _lineY = -1; + return; + } + + _lineY = 0; + + // Lines are always centered, except if line contains a '@', in which case the + // '@' marks the position that must be horizontally centered + char *centerP = strchr(_currentLine, '@'); + if (centerP) { + *centerP = '\0'; + xStart = (MADS_SCREEN_WIDTH / 2) - _vm->_font->getWidth(_currentLine); + + // Delete the @ character and shift back the remainder of the string + char *p = centerP + 1; + if (*p == ' ') ++p; + strcpy(centerP, p); + + } else { + lineWidth = _vm->_font->getWidth(_currentLine); + xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2; + } + + // Copy the text line onto the bottom of the textSurface surface, which will allow it + // to gradually scroll onto the screen + int yp = _textSurface.h - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING; + _textSurface.fillRect(Common::Rect(0, yp, MADS_SCREEN_WIDTH, _textSurface.h), 0); + _vm->_font->writeString(&_textSurface, _currentLine, Common::Point(xStart, yp)); } -int MainMenu::getHighlightedItem(int x, int y) { - y -= MADS_MENU_Y; +/*------------------------------------------------------------------------*/ + +char AnimationView::_resourceName[100]; - for (int index = 0; index < 6; ++index) { - const Common::Point &pt = _itemPosList[index]; - MSprite *spr = _menuItem->getFrame(index); +void AnimationView::execute(MADSEngine *vm, const Common::String &resName) { + assert(resName.size() < 100); + strcpy(_resourceName, resName.c_str()); + vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW; +} + +AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) { + _soundDriverLoaded = false; +} - if ((x >= pt.x) && (y >= pt.y) && (x < (pt.x + spr->w)) && (y < (pt.y + spr->h))) - return index; +void AnimationView::load() { + Common::String resName(_resourceName); + if (!resName.hasSuffix(".")) + resName += ".res"; + + if (!_script.open(resName)) + error("Could not open resource %s", resName.c_str()); + + processLines(); +} + +bool AnimationView::onEvent(Common::Event &event) { + // Wait for the Escape key or a mouse press + if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) || + (event.type == Common::EVENT_RBUTTONUP)) { + scriptDone(); + return true; } - return -1; + return false; } -void MainMenu::handleAction(MADSGameAction action) { - _vm->_events->hideCursor(); - /* - 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); +void AnimationView::doFrame() { + Scene &scene = _vm->_game->_scene; + int bgNumber = 0; + + // Only update state if wait period has expired + if (_previousUpdate > 0) { + if (g_system->getMillis() - _previousUpdate < 3000) { + return; + } else { + // time for an update + _previousUpdate = g_system->getMillis(); + } + } else { + _previousUpdate = g_system->getMillis(); return; + } - case SHOW_INTRO: - _vm->_viewManager->showAnimView("@rexopen"); - break; + char bgFile[10]; + strncpy(bgFile, _currentFile, 5); + bgFile[0] = bgFile[2]; + bgFile[1] = bgFile[3]; + bgFile[2] = bgFile[4]; + bgFile[3] = '\0'; + bgNumber = atoi(bgFile); + sprintf(bgFile, "rm%i.art", bgNumber); + + // Not all scenes have a background. If there is one, refresh it + if (Common::File::exists(bgFile)) { + _vm->_palette->resetGamePalette(4, 8); + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->load(bgNumber, 0, Common::String(), 0, scene._depthSurface, + scene._backgroundSurface); + } - case CREDITS: - _vm->_viewManager->showTextView("credits"); - return; + // Read next line + processLines(); +} - case QUOTES: - _vm->_viewManager->showTextView("quotes"); +void AnimationView::scriptDone() { + _breakFlag = true; + _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU; +} + +void AnimationView::processLines() { + if (_script.eos()) { + // end of script, end animation + scriptDone(); return; + } - case EXIT: - { - // When the Exit action is done from the menu, show one of two possible advertisements + while (!_script.eos()) { + _script.readLine(_currentLine, 79); - // 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); + // Process the line + char *cStart = strchr(_currentLine, '-'); + if (cStart) { + while (cStart) { + // Loop for possible multiple commands on one line + char *cEnd = strchr(_currentLine, ' '); + if (!cEnd) + error("Unterminated command '%s' in response file", _currentLine); - _vm->_viewManager->refreshAll(); - _vm->delay(10000); + *cEnd = '\0'; + processCommand(); - _vm->_events->quitFlag = true; - return; + // Copy rest of line (if any) to start of buffer + // Don't use strcpy() here, because if the + // rest of the line is the longer of the two + // strings, the memory areas will overlap. + memmove(_currentLine, cEnd + 1, strlen(cEnd + 1) + 1); + + cStart = strchr(_currentLine, '-'); + } + + if (_currentLine[0]) { + sprintf(_currentFile, "%s", _currentLine); + //printf("File: %s\n", _currentLine); + break; + } + + } else { + sprintf(_currentFile, "%s", _currentLine); + warning("File: %s\n", _currentLine); + break; + } } - break; - default: - break; +} + +void AnimationView::processCommand() { + Common::String commandLine(_currentLine + 1); + commandLine.toUppercase(); + const char *commandStr = commandLine.c_str(); + const char *param = commandStr; + + if (!strncmp(commandStr, "X", 1)) { + //printf("X "); + } else if (!strncmp(commandStr, "W", 1)) { + //printf("W "); + } else if (!strncmp(commandStr, "R", 1)) { + param = param + 2; + //printf("R:%s ", param); + } else if (!strncmp(commandStr, "O", 1)) { + // Set the transition effect + param = param + 2; + _vm->_game->_fx = (ScreenTransition)atoi(param); + } else { + error("Unknown response command: '%s'", commandStr); } - */ } } // End of namespace Nebular diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h index e960da494d..6e877a8a24 100644 --- a/engines/mads/nebular/menu_nebular.h +++ b/engines/mads/nebular/menu_nebular.h @@ -37,16 +37,12 @@ namespace Nebular { enum MADSGameAction { START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT }; class MenuView: public FullScreenDialog { -private: - void handleEvents(); protected: bool _breakFlag; bool _redrawFlag; virtual void doFrame() = 0; - virtual bool onEvent(Common::Event &event) = 0; - virtual void display(); public: MenuView(MADSEngine *vm); @@ -58,27 +54,186 @@ public: class MainMenu: public MenuView { private: - Common::Point _itemPosList[6]; - int _usageIndex; + SpriteAsset *_menuItems[7]; + int _menuItemIndexes[7]; int _menuItemIndex; int _frameIndex; - bool _skipFlag; - SpriteAsset *_menuItem; - //Common::Array<RGBList *> _itemPalData; uint32 _delayTimeout; + bool _skipFlag; + + /** + * Currently highlighted menu item + */ int _highlightedIndex; - int getHighlightedItem(int x, int y); + /** + * Flag for mouse button being pressed + */ + bool _buttonDown; + + /** + * Stores menu item selection + */ + int _selectedIndex; + + /** + * Get the highlighted menu item under the cursor + */ + int getHighlightedItem(const Common::Point &pt); + + /** + * Un-highlight a currently highlighted item + */ + void unhighlightItem(); + + /** + * Execute a given menuitem + */ void handleAction(MADSGameAction action); + + /** + * Add a sprite slot for the current menuitem frame + */ + void addSpriteSlot(); protected: + /** + * Display the menu + */ + virtual void display(); + + /** + * Handle the menu item animations + */ virtual void doFrame(); + /** + * Event handler + */ virtual bool onEvent(Common::Event &event); public: MainMenu(MADSEngine *vm); + virtual ~MainMenu(); }; +class AdvertView : public EventTarget { +private: + /** + * Engine reference + */ + MADSEngine *_vm; + + /** + * Signals when to close the dialog + */ + bool _breakFlag; +protected: + /** + * Event handler + */ + virtual bool onEvent(Common::Event &event); +public: + AdvertView(MADSEngine *vm); + + virtual ~AdvertView() {} + + /** + * Show the dialog + */ + void show(); +}; + +/** + * Scrolling text view + */ +class TextView : public MenuView { +private: + static char _resourceName[100]; + + bool _animating; + Common::Point _pan; + int _panSpeed; + int _spareScreens[10]; + int _scrollCount; + int _lineY; + uint32 _scrollTimeout; + int _panCountdown; + int _translationX; + Common::File _script; + char _currentLine[80]; + MSurface _textSurface; + MSurface *_spareScreen; +private: + /** + * Load the text resource + */ + void load(); + + /** + * Process the lines + */ + void processLines(); + + /** + * Process a command from the script file + */ + void processCommand(); + + /** + * Process text from the script file + */ + void processText(); + + /** + * Get a parameter from line + */ + int getParameter(const char **paramP); +public: + /** + * Queue the given text resource for display + */ + static void execute(MADSEngine *vm, const Common::String &resName); + + TextView(MADSEngine *vm); + + virtual ~TextView(); +}; + +/** +* Animation cutscene view +*/ +class AnimationView : public MenuView { +private: + static char _resourceName[100]; + + Common::File _script; + uint32 _previousUpdate; + char _currentLine[80]; + char _currentFile[10]; + bool _soundDriverLoaded; +private: + void load(); + + void processLines(); + + void processCommand(); + + void scriptDone(); + + void doFrame(); +protected: + virtual bool onEvent(Common::Event &event); +public: + /** + * Queue the given text resource for display + */ + static void execute(MADSEngine *vm, const Common::String &resName); + + AnimationView(MADSEngine *vm); + + virtual ~AnimationView() {} +}; + } // End of namespace Nebular } // End of namespace MADS diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 5e2566dc32..824dfec144 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -435,8 +435,9 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) { break; } - if (VAR_VOICE_MODE != 0xFF) - VAR(VAR_VOICE_MODE) = _voiceMode; + // We need to sync the current sound settings here to make sure that + // we actually update the mute state of speech properly. + syncSoundSettings(); return; } diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 7f045517bc..cb428d1c15 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -658,7 +658,11 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle _vm->_imuseDigital->startVoice(kTalkSoundID, input); #endif } else { - _mixer->playStream(Audio::Mixer::kSpeechSoundType, handle, input, id); + if (mode == 1) { + _mixer->playStream(Audio::Mixer::kSFXSoundType, handle, input, id); + } else { + _mixer->playStream(Audio::Mixer::kSpeechSoundType, handle, input, id); + } } } } @@ -847,9 +851,6 @@ void Sound::soundKludge(int *list, int num) { } void Sound::talkSound(uint32 a, uint32 b, int mode, int channel) { - if (_vm->_game.version >= 5 && ConfMan.getBool("speech_mute")) - return; - if (mode == 1) { _talk_sound_a1 = a; _talk_sound_b1 = b; |