aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/dialogs.h3
-rw-r--r--engines/mads/events.cpp7
-rw-r--r--engines/mads/events.h12
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp83
-rw-r--r--engines/mads/nebular/dialogs_nebular.h2
-rw-r--r--engines/mads/nebular/game_nebular.cpp8
-rw-r--r--engines/mads/nebular/menu_nebular.cpp738
-rw-r--r--engines/mads/nebular/menu_nebular.h175
-rw-r--r--engines/scumm/input.cpp5
-rw-r--r--engines/scumm/sound.cpp9
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(&paramP);
+
+ 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(&paramP);
+ int panY = getParameter(&paramP);
+ int panSpeed = getParameter(&paramP);
+
+ 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(&paramP);
+ _vm->_sound->init(driverNum);
+
+ } else if (!strncmp(commandStr, "SOUND", 5)) {
+ // Set sound number
+ paramP = commandStr + 5;
+ int soundId = getParameter(&paramP);
+ _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(&paramP) << 2;
+ palEntry[1] = getParameter(&paramP) << 2;
+ palEntry[2] = getParameter(&paramP) << 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(&paramP);
+
+ _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(&paramP);
+
+ // 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;