aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/mads/debugger.cpp4
-rw-r--r--engines/mads/dialogs.cpp73
-rw-r--r--engines/mads/dialogs.h32
-rw-r--r--engines/mads/menu_views.cpp782
-rw-r--r--engines/mads/menu_views.h226
-rw-r--r--engines/mads/module.mk1
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp61
-rw-r--r--engines/mads/nebular/dialogs_nebular.h32
-rw-r--r--engines/mads/nebular/menu_nebular.cpp753
-rw-r--r--engines/mads/nebular/menu_nebular.h190
10 files changed, 1118 insertions, 1036 deletions
diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp
index 3b77d5332b..99251f9fbb 100644
--- a/engines/mads/debugger.cpp
+++ b/engines/mads/debugger.cpp
@@ -362,7 +362,7 @@ bool Debugger::Cmd_PlayAnim(int argc, const char **argv) {
Common::File f;
if (f.exists(resName) || f.exists(resName + ".res")) {
- Nebular::AnimationView::execute(_vm, resName);
+ AnimationView::execute(_vm, resName);
return false;
} else {
debugPrintf("Could not find resource file\n");
@@ -382,7 +382,7 @@ bool Debugger::Cmd_PlayText(int argc, const char **argv) {
Common::File f;
if (f.exists(resName) || f.exists(resName + ".txr")) {
- Nebular::TextView::execute(_vm, resName);
+ TextView::execute(_vm, resName);
return false;
} else {
debugPrintf("Could not find resource file\n");
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
index 7e6909d113..5ea8fb115c 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/dialogs.cpp
@@ -395,4 +395,77 @@ Dialogs::Dialogs(MADSEngine *vm)
_pendingDialog = DIALOG_NONE;
}
+/*------------------------------------------------------------------------*/
+
+FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
+ switch (_vm->getGameID()) {
+ case GType_RexNebular:
+ _screenId = 990;
+ break;
+ case GType_Phantom:
+ _screenId = 920;
+ break;
+ case GType_Dragonsphere:
+ _screenId = 922;
+ break;
+ default:
+ error("FullScreenDialog:Unknown game");
+ }
+ _palFlag = true;
+}
+
+FullScreenDialog::~FullScreenDialog() {
+ _vm->_screen.resetClipBounds();
+ _vm->_game->_scene.restrictScene();
+}
+
+void FullScreenDialog::display() {
+ Game &game = *_vm->_game;
+ Scene &scene = game._scene;
+
+ int nextSceneId = scene._nextSceneId;
+ int currentSceneId = scene._currentSceneId;
+ int priorSceneId = scene._priorSceneId;
+
+ if (_screenId > 0) {
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(_screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
+ }
+
+ scene._priorSceneId = priorSceneId;
+ scene._currentSceneId = currentSceneId;
+ scene._nextSceneId = nextSceneId;
+
+ _vm->_events->initVars();
+ game._kernelMode = KERNEL_ROOM_INIT;
+
+ byte pal[768];
+ if (_vm->_screenFade) {
+ Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
+ _vm->_palette->setFullPalette(pal);
+ } else {
+ _vm->_palette->getFullPalette(pal);
+ _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
+ }
+
+ // Set Fx state and palette entries
+ game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
+ game._trigger = 0;
+
+ // Clear the screen and draw the upper and lower horizontal lines
+ _vm->_screen.empty();
+ _vm->_palette->setLowRange();
+ _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+
+ // Restrict the screen to the area between the two lines
+ _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH,
+ DIALOG_TOP + MADS_SCENE_HEIGHT));
+ _vm->_game->_scene.restrictScene();
+
+ if (_screenId > 0)
+ scene._spriteSlots.fullRefresh();
+}
+
} // End of namespace MADS
diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h
index c586a6f1fe..317c7bd792 100644
--- a/engines/mads/dialogs.h
+++ b/engines/mads/dialogs.h
@@ -30,6 +30,8 @@
namespace MADS {
+#define DIALOG_TOP 22
+
class Dialog {
private:
void setDialogPalette();
@@ -226,6 +228,36 @@ public:
virtual bool show(int messageId, int objectId = -1) = 0;
};
+class FullScreenDialog: public EventTarget {
+protected:
+ /**
+ * Engine reference
+ */
+ MADSEngine *_vm;
+
+ /**
+ * Screen/scene to show background from
+ */
+ int _screenId;
+
+ /**
+ * Flag for palette initialization
+ */
+ bool _palFlag;
+
+ /**
+ * Handles displaying the screen background and dialog
+ */
+ virtual void display();
+public:
+ /**
+ * Constructor
+ */
+ FullScreenDialog(MADSEngine *vm);
+
+ virtual ~FullScreenDialog();
+};
+
} // End of namespace MADS
#endif /* MADS_DIALOGS_H */
diff --git a/engines/mads/menu_views.cpp b/engines/mads/menu_views.cpp
new file mode 100644
index 0000000000..6acf6cdf9f
--- /dev/null
+++ b/engines/mads/menu_views.cpp
@@ -0,0 +1,782 @@
+/* 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 "mads/game.h"
+#include "mads/mads.h"
+#include "mads/menu_views.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/screen.h"
+
+namespace MADS {
+
+MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
+ _breakFlag = false;
+ _redrawFlag = true;
+ _palFlag = false;
+}
+
+void MenuView::show() {
+ Scene &scene = _vm->_game->_scene;
+ EventsManager &events = *_vm->_events;
+ _vm->_screenFade = SCREEN_FADE_FAST;
+
+ scene._spriteSlots.reset(true);
+ display();
+
+ events.setEventTarget(this);
+ events.hideCursor();
+
+ while (!_breakFlag && !_vm->shouldQuit()) {
+ if (_redrawFlag) {
+ scene._kernelMessages.update();
+
+ _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
+ _redrawFlag = false;
+ }
+
+ _vm->_events->waitForNextFrame();
+ _vm->_game->_fx = kTransitionNone;
+ doFrame();
+ }
+
+ events.setEventTarget(nullptr);
+ _vm->_sound->stop();
+}
+
+void MenuView::display() {
+ _vm->_palette->resetGamePalette(4, 8);
+
+ FullScreenDialog::display();
+}
+
+bool MenuView::onEvent(Common::Event &event) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+ 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);
+ Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
+ vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
+}
+
+TextView::TextView(MADSEngine *vm) : MenuView(vm) {
+ _animating = false;
+ _panSpeed = 0;
+ _spareScreen = nullptr;
+ _scrollCount = 0;
+ _lineY = -1;
+ _scrollTimeout = 0;
+ _panCountdown = 0;
+ _translationX = 0;
+ _screenId = -1;
+
+ _font = _vm->_font->getFont(FONT_CONVERSATION);
+ _vm->_palette->resetGamePalette(4, 0);
+
+ load();
+}
+
+TextView::~TextView() {
+}
+
+void TextView::load() {
+ Common::String scriptName(_resourceName);
+ scriptName += ".txr";
+
+ if (!_script.open(scriptName))
+ 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()) {
+ // Read in the next line
+ _script.readLine(_currentLine, 79);
+ char *p = _currentLine + strlen(_currentLine) - 1;
+ if (*p == '\n')
+ *p = '\0';
+
+ // 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
+ Common::strlcpy(_currentLine, cEnd + 1, sizeof(_currentLine));
+
+ cStart = strchr(_currentLine, '[');
+ }
+
+ if (_currentLine[0]) {
+ processText();
+ break;
+ }
+
+ } else {
+ processText();
+ break;
+ }
+ }
+}
+
+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;
+ resetPalette();
+ int screenId = getParameter(&paramP);
+
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
+ scene._spriteSlots.fullRefresh();
+ _redrawFlag = true;
+
+ } else if (!strncmp(commandStr, "GO", 2)) {
+ _animating = true;
+
+ } 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;
+ }
+
+ } else if (!strncmp(commandStr, "DRIVER", 6)) {
+ // Set the driver to use
+ paramP = commandStr + 7;
+
+ if (!strncmp(paramP, "#SOUND.00", 9)) {
+ int driverNum = paramP[9] - '0';
+ _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 r = getParameter(&paramP);
+ byte g = getParameter(&paramP);
+ byte b = getParameter(&paramP);
+
+ _vm->_palette->setEntry(5 + index, r, g, b);
+
+ } 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';
+ assert(spareIndex < 4);
+ int screenId = getParameter(&paramP);
+
+ // Load the spare background
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->_width = MADS_SCREEN_WIDTH;
+ sceneInfo->_height = MADS_SCENE_HEIGHT;
+ _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
+ _spareScreens[spareIndex]);
+ delete sceneInfo;
+
+ } 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].getPixels() != nullptr) {
+ _spareScreen = &_spareScreens[spareIndex];
+ _translationX = 0;
+ }
+
+ } else {
+ error("Unknown response command: '%s'", commandStr);
+ }
+}
+
+int TextView::getParameter(const char **paramP) {
+ if ((**paramP != '=') && (**paramP != ','))
+ return 0;
+
+ int result = 0;
+ ++*paramP;
+ while ((**paramP >= '0') && (**paramP <= '9')) {
+ result = result * 10 + (**paramP - '0');
+ ++*paramP;
+ }
+
+ return result;
+}
+
+void TextView::processText() {
+ int xStart;
+
+ if (!strcmp(_currentLine, "***")) {
+ // Special signifier for end of script
+ _scrollCount = _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) - _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 {
+ int lineWidth = _font->getWidth(_currentLine);
+ xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
+ }
+
+ // Add the new line to the list of pending lines
+ TextLine tl;
+ tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT);
+ tl._line = _currentLine;
+ tl._textDisplayIndex = -1;
+ _textLines.push_back(tl);
+}
+
+void TextView::display() {
+ FullScreenDialog::display();
+}
+
+void TextView::resetPalette() {
+ _vm->_palette->resetGamePalette(8, 8);
+ _vm->_palette->setEntry(5, 0, 63, 63);
+ _vm->_palette->setEntry(6, 0, 45, 45);
+}
+
+void TextView::doFrame() {
+ Scene &scene = _vm->_game->_scene;
+ if (!_animating)
+ return;
+
+ // Only update state if wait period has expired
+ uint32 currTime = g_system->getMillis();
+
+ // If a screen transition is in progress and it's time for another column, handle it
+ if (_spareScreen) {
+ byte *srcP = _spareScreen->getBasePtr(_translationX, 0);
+ byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0);
+ byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0);
+
+ for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
+ bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
+ *bgP = *srcP;
+ *screenP = *srcP;
+ }
+
+ // Flag the column of the screen is modified
+ _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0,
+ _translationX + 1, MADS_SCENE_HEIGHT));
+
+ // Keep moving the column to copy to the right
+ if (++_translationX == MADS_SCREEN_WIDTH) {
+ // Surface transition is complete
+ _spareScreen = nullptr;
+ }
+ }
+
+ // Make sure it's time for an update
+ if (currTime < _scrollTimeout)
+ return;
+ _scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
+ _redrawFlag = true;
+
+ // If any panning values are set, pan the background surface
+ if ((_pan.x != 0) || (_pan.y != 0)) {
+ if (_panCountdown > 0) {
+ --_panCountdown;
+ return;
+ }
+
+ // Handle horizontal panning
+ if (_pan.x != 0) {
+ byte *lineTemp = new byte[_pan.x];
+ for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) {
+ byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
+
+ // Copy the first X pixels into temp buffer, move the rest of the line
+ // to the start of the line, and then move temp buffer pixels to end of line
+ Common::copy(pixelsP, pixelsP + _pan.x, lineTemp);
+ Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP);
+ Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x);
+ }
+
+ delete[] lineTemp;
+ }
+
+ // Handle vertical panning
+ if (_pan.y != 0) {
+ // Store the bottom Y lines into a temp buffer, move the rest of the lines down,
+ // and then copy the stored lines back to the top of the screen
+ byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH];
+ byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y);
+ Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp);
+
+ for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) {
+ byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
+ byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y);
+ Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP);
+ }
+
+ Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH,
+ (byte *)scene._backgroundSurface.getPixels());
+ delete[] linesTemp;
+ }
+
+ // Flag for a full screen refresh
+ scene._spriteSlots.fullRefresh();
+ }
+
+ // Scroll all active text lines up
+ for (int i = _textLines.size() - 1; i >= 0; --i) {
+ TextLine &tl = _textLines[i];
+ if (tl._textDisplayIndex != -1)
+ // Expire the text line that's already on-screen
+ scene._textDisplay.expire(tl._textDisplayIndex);
+
+ tl._pos.y--;
+ if (tl._pos.y < 0) {
+ _textLines.remove_at(i);
+ } else {
+ tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y,
+ 0x605, -1, tl._line, _font);
+ }
+ }
+
+ if (_scrollCount > 0) {
+ // Handling final scrolling of text off of screen
+ if (--_scrollCount == 0) {
+ scriptDone();
+ return;
+ }
+ } else {
+ // Handling a text row
+ if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING))
+ processLines();
+ }
+}
+
+void TextView::scriptDone() {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+}
+
+/*------------------------------------------------------------------------*/
+
+char AnimationView::_resourceName[100];
+
+void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
+ assert(resName.size() < 100);
+ Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
+ vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
+}
+
+AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
+ _redrawFlag = false;
+
+ _soundDriverLoaded = false;
+ _previousUpdate = 0;
+ _screenId = -1;
+ _resetPalette = false;
+ _resyncMode = NEVER;
+ _v1 = 0;
+ _v2 = -1;
+ _resourceIndex = -1;
+ _currentAnimation = nullptr;
+ _sfx = 0;
+ _soundFlag = _bgLoadFlag = true;
+ _showWhiteBars = true;
+ _manualFrameNumber = 0;
+ _manualSpriteSet = nullptr;
+ _manualStartFrame = _manualEndFrame = 0;
+ _manualFrame2 = 0;
+ _animFrameNumber = 0;
+ _nextCyclingActive = false;
+ _sceneInfo = SceneInfo::init(_vm);
+
+ load();
+}
+
+AnimationView::~AnimationView() {
+ delete _currentAnimation;
+ delete _sceneInfo;
+}
+
+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();
+}
+
+void AnimationView::display() {
+ Scene &scene = _vm->_game->_scene;
+ _vm->_palette->initPalette();
+ Common::fill(&_vm->_palette->_cyclingPalette[0], &_vm->_palette->_cyclingPalette[PALETTE_SIZE], 0);
+
+ _vm->_palette->resetGamePalette(1, 8);
+ scene._spriteSlots.reset();
+ scene._paletteCycles.clear();
+
+ MenuView::display();
+}
+
+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 false;
+}
+
+void AnimationView::doFrame() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_resourceIndex == -1 || _currentAnimation->freeFlag()) {
+ if (++_resourceIndex == (int)_resources.size()) {
+ scriptDone();
+ } else {
+ scene._frameStartTime = 0;
+ loadNextResource();
+ }
+ } else if (_currentAnimation->getCurrentFrame() == 1) {
+ scene._cyclingActive = _nextCyclingActive;
+ }
+
+ if (_currentAnimation) {
+ ++scene._frameStartTime;
+ _currentAnimation->update();
+ _redrawFlag = true;
+ }
+}
+
+void AnimationView::loadNextResource() {
+ Scene &scene = _vm->_game->_scene;
+ Palette &palette = *_vm->_palette;
+ ResourceEntry &resEntry = _resources[_resourceIndex];
+ Common::Array<PaletteCycle> paletteCycles;
+
+ if (resEntry._bgFlag)
+ palette.resetGamePalette(1, 8);
+
+ palette._mainPalette[253 * 3] = palette._mainPalette[253 * 3 + 1]
+ = palette._mainPalette[253 * 3 + 2] = 0xb4;
+ palette.setPalette(&palette._mainPalette[253 * 3], 253, 1);
+
+ // Free any previous messages
+ scene._kernelMessages.reset();
+
+ // Handle the bars at the top/bottom
+ if (resEntry._showWhiteBars) {
+ // For animations the screen has been clipped to the middle 156 rows.
+ // So although it's slightly messy, bypass our screen class entirely,
+ // and draw the horizontal lines directly on the physiacl screen surface
+ Graphics::Surface *s = g_system->lockScreen();
+ s->hLine(0, 20, MADS_SCREEN_WIDTH, 253);
+ s->hLine(0, 179, MADS_SCREEN_WIDTH, 253);
+ g_system->unlockScreen();
+ }
+
+ // Load the new animation
+ delete _currentAnimation;
+ _currentAnimation = Animation::init(_vm, &scene);
+ int flags = ANIMFLAG_ANIMVIEW | (resEntry._bgFlag ? ANIMFLAG_LOAD_BACKGROUND : 0);
+ _currentAnimation->load(scene._backgroundSurface, scene._depthSurface,
+ resEntry._resourceName, flags, &paletteCycles, _sceneInfo);
+
+ // Signal for a screen refresh
+ scene._spriteSlots.fullRefresh();
+
+ // If a sound driver has been specified, then load the correct one
+ if (!_currentAnimation->_header._soundName.empty()) {
+ const char *chP = strchr(_currentAnimation->_header._soundName.c_str(), '.');
+ assert(chP);
+
+ // Handle both Rex naming (xxx.009) and naming in later games (e.g. xxx.ph9)
+ int driverNum = atoi(chP + 3);
+ // HACK for Dragon
+ if (_currentAnimation->_header._soundName == "#SOUND.DRG")
+ driverNum = 9;
+ _vm->_sound->init(driverNum);
+ }
+
+ // Handle any manual setup
+ if (_currentAnimation->_header._manualFlag) {
+ _manualFrameNumber = _currentAnimation->_header._spritesIndex;
+ _manualSpriteSet = _currentAnimation->getSpriteSet(_manualFrameNumber);
+ }
+
+ // Set the sound data for the animation
+ _vm->_sound->setEnabled(resEntry._soundFlag);
+
+ Common::String dsrName = _currentAnimation->_header._dsrName;
+ if (!dsrName.empty())
+ _vm->_audio->setSoundGroup(dsrName);
+
+ // Start the new animation
+ _currentAnimation->startAnimation(0);
+
+ // Handle the palette and cycling palette
+ scene._cyclingActive = false;
+ Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE],
+ &palette._cyclingPalette[0]);
+
+ _vm->_game->_fx = (ScreenTransition)resEntry._fx;
+ _nextCyclingActive = paletteCycles.size() > 0;
+ if (!_vm->_game->_fx) {
+ palette.setFullPalette(palette._mainPalette);
+ }
+
+ scene.initPaletteAnimation(paletteCycles, _nextCyclingActive && !_vm->_game->_fx);
+}
+
+void AnimationView::scriptDone() {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+}
+
+void AnimationView::processLines() {
+ if (_script.eos()) {
+ // end of script, end animation
+ scriptDone();
+ return;
+ }
+
+ while (!_script.eos()) {
+ // Get in next line
+ _currentLine.clear();
+ char c;
+ while (!_script.eos() && (c = _script.readByte()) != '\n') {
+ if (c != '\r' && c != '\0')
+ _currentLine += c;
+ }
+
+ // Process the line
+ while (!_currentLine.empty()) {
+ if (_currentLine.hasPrefix("-")) {
+ _currentLine.deleteChar(0);
+
+ processCommand();
+ } else {
+ // Get resource name
+ Common::String resName;
+ while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') {
+ _currentLine.deleteChar(0);
+ resName += c;
+ }
+
+ // Add resource into list along with any set state information
+ _resources.push_back(ResourceEntry(resName, _sfx, _soundFlag,
+ _bgLoadFlag, _showWhiteBars));
+
+ // Fx resets between resource entries
+ _sfx = 0;
+ }
+
+ // Skip any spaces
+ while (_currentLine.hasPrefix(" "))
+ _currentLine.deleteChar(0);
+ }
+ }
+}
+
+void AnimationView::processCommand() {
+ // Get the command character
+ char commandChar = toupper(_currentLine[0]);
+ _currentLine.deleteChar(0);
+
+ // Handle the command
+ switch (commandChar) {
+ case 'B':
+ _soundFlag = !_soundFlag;
+ break;
+ case 'H':
+ // -h[:ex] Disable EMS / XMS high memory support
+ if (_currentLine.hasPrefix(":"))
+ _currentLine.deleteChar(0);
+ while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x"))
+ _currentLine.deleteChar(0);
+ break;
+ case 'O':
+ // -o:xxx Specify opening special effect
+ assert(_currentLine[0] == ':');
+ _currentLine.deleteChar(0);
+ _sfx = getParameter();
+ break;
+ case 'P':
+ // Switch to CONCAT mode, which is ignored anyway
+ break;
+ case 'R': {
+ // Resynch timer (always, beginning, never)
+ assert(_currentLine[0] == ':');
+ _currentLine.deleteChar(0);
+
+ char v = toupper(_currentLine[0]);
+ _currentLine.deleteChar(0);
+ if (v == 'N')
+ _resyncMode = NEVER;
+ else if (v == 'A')
+ _resyncMode = ALWAYS;
+ else if (v == 'B')
+ _resyncMode = BEGINNING;
+ else
+ error("Unknown parameter");
+ break;
+ }
+ case 'W':
+ // Switch white bars being visible
+ _showWhiteBars = !_showWhiteBars;
+ break;
+ case 'X':
+ // Exit after animation finishes. Ignore
+ break;
+ case 'D':
+ // Unimplemented and ignored in the original. Ignore as well
+ break;
+ case 'Y':
+ // Reset palette on startup
+ _resetPalette = true;
+ break;
+ default:
+ error("Unknown command char: '%c'", commandChar);
+ }
+}
+
+int AnimationView::getParameter() {
+ int result = 0;
+
+ while (!_currentLine.empty()) {
+ char c = _currentLine[0];
+
+ if (c >= '0' && c <= '9') {
+ _currentLine.deleteChar(0);
+ result = result * 10 + (c - '0');
+ } else {
+ break;
+ }
+ }
+
+ return result;
+}
+
+void AnimationView::checkResource(const Common::String &resourceName) {
+ //bool hasSuffix = false;
+
+}
+
+int AnimationView::scanResourceIndex(const Common::String &resourceName) {
+ int foundIndex = -1;
+
+ if (_v1) {
+ const char *chP = strchr(resourceName.c_str(), '\\');
+ if (!chP) {
+ chP = strchr(resourceName.c_str(), '*');
+ }
+
+ Common::String resName = chP ? Common::String(chP + 1) : resourceName;
+
+ if (_v2 != 3) {
+ assert(_resIndex.size() == 0);
+ }
+
+ // Scan for the resource name
+ for (uint resIndex = 0; resIndex < _resIndex.size(); ++resIndex) {
+ ResIndexEntry &resEntry = _resIndex[resIndex];
+ if (resEntry._resourceName.compareToIgnoreCase(resourceName)) {
+ foundIndex = resIndex;
+ break;
+ }
+ }
+ }
+
+ if (foundIndex >= 0) {
+ // TODO
+ }
+ return -1;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/menu_views.h b/engines/mads/menu_views.h
new file mode 100644
index 0000000000..6faa665bff
--- /dev/null
+++ b/engines/mads/menu_views.h
@@ -0,0 +1,226 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_MENU_VIEWS_H
+#define MADS_MENU_VIEWS_H
+
+#include "common/scummsys.h"
+#include "mads/dialogs.h"
+#include "mads/game.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+class MenuView: public FullScreenDialog {
+protected:
+ bool _breakFlag;
+ bool _redrawFlag;
+
+ virtual void doFrame() = 0;
+
+ virtual void display();
+
+ /**
+ * Event handler
+ */
+ virtual bool onEvent(Common::Event &event);
+public:
+ MenuView(MADSEngine *vm);
+
+ virtual ~MenuView() {}
+
+ virtual void show();
+};
+
+struct TextLine {
+ Common::Point _pos;
+ Common::String _line;
+ int _textDisplayIndex;
+};
+
+/**
+ * Scrolling text view
+ */
+class TextView : public MenuView {
+private:
+ static char _resourceName[100];
+
+ bool _animating;
+ Common::Array<TextLine> _textLines;
+ Common::Point _pan;
+ int _panSpeed;
+ MSurface _spareScreens[4];
+ int _scrollCount;
+ int _lineY;
+ uint32 _scrollTimeout;
+ int _panCountdown;
+ int _translationX;
+ Common::File _script;
+ char _currentLine[80];
+ MSurface *_spareScreen;
+ Font *_font;
+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);
+
+ /**
+ * Called when the script is finished
+ */
+ void scriptDone();
+
+ /**
+ * Reset the game palette
+ */
+ void resetPalette();
+protected:
+ virtual void display();
+
+ virtual void doFrame();
+public:
+ /**
+ * Queue the given text resource for display
+ */
+ static void execute(MADSEngine *vm, const Common::String &resName);
+
+ TextView(MADSEngine *vm);
+
+ virtual ~TextView();
+};
+
+enum ResyncMode { NEVER, ALWAYS, BEGINNING };
+
+struct ResourceEntry {
+ Common::String _resourceName;
+ int _fx;
+ bool _soundFlag;
+ bool _bgFlag;
+ bool _showWhiteBars;
+
+ ResourceEntry() {}
+ ResourceEntry(const Common::String &resName, int fx, bool soundFlag,
+ bool bgFlag, bool showWhiteBars) {
+ _resourceName = resName;
+ _fx = fx;
+ _soundFlag = soundFlag;
+ _bgFlag = bgFlag;
+ _showWhiteBars = showWhiteBars;
+ }
+};
+
+struct ResIndexEntry {
+ int _id;
+ int _v;
+ Common::String _resourceName;
+
+ ResIndexEntry() {}
+};
+
+/**
+* Animation cutscene view
+*/
+class AnimationView : public MenuView {
+private:
+ static char _resourceName[100];
+
+ Common::File _script;
+ uint32 _previousUpdate;
+ Common::String _currentLine;
+ bool _soundDriverLoaded;
+ bool _resetPalette;
+ ResyncMode _resyncMode;
+ int _sfx;
+ bool _soundFlag;
+ bool _bgLoadFlag;
+ bool _showWhiteBars;
+ Common::Array<ResourceEntry> _resources;
+ Common::Array<ResIndexEntry> _resIndex;
+ int _v1;
+ int _v2;
+ int _resourceIndex;
+ SceneInfo *_sceneInfo;
+ Animation *_currentAnimation;
+ int _manualFrameNumber;
+ SpriteAsset *_manualSpriteSet;
+ int _manualStartFrame, _manualEndFrame;
+ int _manualFrame2;
+ int _animFrameNumber;
+ bool _nextCyclingActive;
+private:
+ void checkResource(const Common::String &resourceName);
+
+ int scanResourceIndex(const Common::String &resourceName);
+
+ void load();
+
+ void processLines();
+
+ void processCommand();
+
+ int getParameter();
+
+ void scriptDone();
+
+ void loadNextResource();
+protected:
+ virtual void display();
+
+ virtual void doFrame();
+
+ 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 MADS
+
+#endif /* MADS_MENU_VIEWS_H */
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 8a792a70a4..7cb7a91e8c 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -37,6 +37,7 @@ MODULE_OBJS := \
hotspots.o \
inventory.o \
mads.o \
+ menu_views.o \
messages.o \
msurface.o \
palette.o \
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
index 35a7d3bdc6..86244bd3bb 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -553,67 +553,6 @@ void PictureDialog::restore() {
/*------------------------------------------------------------------------*/
-FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
- _screenId = 990;
- _palFlag = true;
-}
-
-FullScreenDialog::~FullScreenDialog() {
- _vm->_screen.resetClipBounds();
- _vm->_game->_scene.restrictScene();
-}
-
-void FullScreenDialog::display() {
- Game &game = *_vm->_game;
- Scene &scene = game._scene;
-
- int nextSceneId = scene._nextSceneId;
- int currentSceneId = scene._currentSceneId;
- int priorSceneId = scene._priorSceneId;
-
- if (_screenId > 0) {
- SceneInfo *sceneInfo = SceneInfo::init(_vm);
- sceneInfo->load(_screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
- }
-
- scene._priorSceneId = priorSceneId;
- scene._currentSceneId = currentSceneId;
- scene._nextSceneId = nextSceneId;
-
- _vm->_events->initVars();
- game._kernelMode = KERNEL_ROOM_INIT;
-
- byte pal[768];
- if (_vm->_screenFade) {
- Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
- _vm->_palette->setFullPalette(pal);
- } else {
- _vm->_palette->getFullPalette(pal);
- _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
- }
-
- // Set Fx state and palette entries
- game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
- game._trigger = 0;
-
- // Clear the screen and draw the upper and lower horizontal lines
- _vm->_screen.empty();
- _vm->_palette->setLowRange();
- _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
- _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
- _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
-
- // Restrict the screen to the area between the two lines
- _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH,
- DIALOG_TOP + MADS_SCENE_HEIGHT));
- _vm->_game->_scene.restrictScene();
-
- if (_screenId > 0)
- scene._spriteSlots.fullRefresh();
-}
-
-/*------------------------------------------------------------------------*/
-
GameDialog::DialogLine::DialogLine() {
_active = true;
_state = DLGSTATE_UNSELECTED;
diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h
index f64f992611..d00cd87ead 100644
--- a/engines/mads/nebular/dialogs_nebular.h
+++ b/engines/mads/nebular/dialogs_nebular.h
@@ -31,8 +31,6 @@ namespace MADS {
namespace Nebular {
-#define DIALOG_TOP 22
-
enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 };
class DialogsNebular : public Dialogs {
@@ -109,36 +107,6 @@ 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: public EventTarget {
-protected:
- /**
- * Engine reference
- */
- MADSEngine *_vm;
-
- /**
- * Screen/scene to show background from
- */
- int _screenId;
-
- /**
- * Flag for palette initialization
- */
- bool _palFlag;
-
- /**
- * Handles displaying the screen background and dialog
- */
- virtual void display();
-public:
- /**
- * Constructor
- */
- FullScreenDialog(MADSEngine *vm);
-
- virtual ~FullScreenDialog();
-};
-
class GameDialog: public FullScreenDialog {
struct DialogLine {
bool _active;
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
index 6a13cea195..717e3f6cf9 100644
--- a/engines/mads/nebular/menu_nebular.cpp
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -23,6 +23,7 @@
#include "common/scummsys.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"
@@ -36,58 +37,6 @@ namespace Nebular {
#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
#define MADS_MENU_ANIM_DELAY 70
-MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
- _breakFlag = false;
- _redrawFlag = true;
- _palFlag = false;
-}
-
-void MenuView::show() {
- Scene &scene = _vm->_game->_scene;
- EventsManager &events = *_vm->_events;
- _vm->_screenFade = SCREEN_FADE_FAST;
-
- scene._spriteSlots.reset(true);
- display();
-
- events.setEventTarget(this);
- events.hideCursor();
-
- while (!_breakFlag && !_vm->shouldQuit()) {
- if (_redrawFlag) {
- scene._kernelMessages.update();
-
- _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
- _redrawFlag = false;
- }
-
- _vm->_events->waitForNextFrame();
- _vm->_game->_fx = kTransitionNone;
- doFrame();
- }
-
- events.setEventTarget(nullptr);
- _vm->_sound->stop();
-}
-
-void MenuView::display() {
- _vm->_palette->resetGamePalette(4, 8);
-
- FullScreenDialog::display();
-}
-
-bool MenuView::onEvent(Common::Event &event) {
- if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
- _breakFlag = true;
- _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
- return true;
- }
-
- return false;
-}
-
-/*------------------------------------------------------------------------*/
-
MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr);
Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1);
@@ -426,706 +375,6 @@ bool AdvertView::onEvent(Common::Event &event) {
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);
- Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
- vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
-}
-
-TextView::TextView(MADSEngine *vm) : MenuView(vm) {
- _animating = false;
- _panSpeed = 0;
- _spareScreen = nullptr;
- _scrollCount = 0;
- _lineY = -1;
- _scrollTimeout = 0;
- _panCountdown = 0;
- _translationX = 0;
- _screenId = -1;
-
- _font = _vm->_font->getFont(FONT_CONVERSATION);
- _vm->_palette->resetGamePalette(4, 0);
-
- load();
-}
-
-TextView::~TextView() {
-}
-
-void TextView::load() {
- Common::String scriptName(_resourceName);
- scriptName += ".txr";
-
- if (!_script.open(scriptName))
- 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()) {
- // Read in the next line
- _script.readLine(_currentLine, 79);
- char *p = _currentLine + strlen(_currentLine) - 1;
- if (*p == '\n')
- *p = '\0';
-
- // 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
- Common::strlcpy(_currentLine, cEnd + 1, sizeof(_currentLine));
-
- cStart = strchr(_currentLine, '[');
- }
-
- if (_currentLine[0]) {
- processText();
- break;
- }
-
- } else {
- processText();
- break;
- }
- }
-}
-
-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;
- resetPalette();
- int screenId = getParameter(&paramP);
-
- SceneInfo *sceneInfo = SceneInfo::init(_vm);
- sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
- scene._spriteSlots.fullRefresh();
- _redrawFlag = true;
-
- } else if (!strncmp(commandStr, "GO", 2)) {
- _animating = true;
-
- } 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;
- }
-
- } else if (!strncmp(commandStr, "DRIVER", 6)) {
- // Set the driver to use
- paramP = commandStr + 7;
-
- if (!strncmp(paramP, "#SOUND.00", 9)) {
- int driverNum = paramP[9] - '0';
- _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 r = getParameter(&paramP);
- byte g = getParameter(&paramP);
- byte b = getParameter(&paramP);
-
- _vm->_palette->setEntry(5 + index, r, g, b);
-
- } 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';
- assert(spareIndex < 4);
- int screenId = getParameter(&paramP);
-
- // Load the spare background
- SceneInfo *sceneInfo = SceneInfo::init(_vm);
- sceneInfo->_width = MADS_SCREEN_WIDTH;
- sceneInfo->_height = MADS_SCENE_HEIGHT;
- _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
- sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
- _spareScreens[spareIndex]);
- delete sceneInfo;
-
- } 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].getPixels() != nullptr) {
- _spareScreen = &_spareScreens[spareIndex];
- _translationX = 0;
- }
-
- } else {
- error("Unknown response command: '%s'", commandStr);
- }
-}
-
-int TextView::getParameter(const char **paramP) {
- if ((**paramP != '=') && (**paramP != ','))
- return 0;
-
- int result = 0;
- ++*paramP;
- while ((**paramP >= '0') && (**paramP <= '9')) {
- result = result * 10 + (**paramP - '0');
- ++*paramP;
- }
-
- return result;
-}
-
-void TextView::processText() {
- int xStart;
-
- if (!strcmp(_currentLine, "***")) {
- // Special signifier for end of script
- _scrollCount = _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) - _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 {
- int lineWidth = _font->getWidth(_currentLine);
- xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
- }
-
- // Add the new line to the list of pending lines
- TextLine tl;
- tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT);
- tl._line = _currentLine;
- tl._textDisplayIndex = -1;
- _textLines.push_back(tl);
-}
-
-void TextView::display() {
- FullScreenDialog::display();
-}
-
-void TextView::resetPalette() {
- _vm->_palette->resetGamePalette(8, 8);
- _vm->_palette->setEntry(5, 0, 63, 63);
- _vm->_palette->setEntry(6, 0, 45, 45);
-}
-
-void TextView::doFrame() {
- Scene &scene = _vm->_game->_scene;
- if (!_animating)
- return;
-
- // Only update state if wait period has expired
- uint32 currTime = g_system->getMillis();
-
- // If a screen transition is in progress and it's time for another column, handle it
- if (_spareScreen) {
- byte *srcP = _spareScreen->getBasePtr(_translationX, 0);
- byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0);
- byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0);
-
- for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
- bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
- *bgP = *srcP;
- *screenP = *srcP;
- }
-
- // Flag the column of the screen is modified
- _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0,
- _translationX + 1, MADS_SCENE_HEIGHT));
-
- // Keep moving the column to copy to the right
- if (++_translationX == MADS_SCREEN_WIDTH) {
- // Surface transition is complete
- _spareScreen = nullptr;
- }
- }
-
- // Make sure it's time for an update
- if (currTime < _scrollTimeout)
- return;
- _scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
- _redrawFlag = true;
-
- // If any panning values are set, pan the background surface
- if ((_pan.x != 0) || (_pan.y != 0)) {
- if (_panCountdown > 0) {
- --_panCountdown;
- return;
- }
-
- // Handle horizontal panning
- if (_pan.x != 0) {
- byte *lineTemp = new byte[_pan.x];
- for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) {
- byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
-
- // Copy the first X pixels into temp buffer, move the rest of the line
- // to the start of the line, and then move temp buffer pixels to end of line
- Common::copy(pixelsP, pixelsP + _pan.x, lineTemp);
- Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP);
- Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x);
- }
-
- delete[] lineTemp;
- }
-
- // Handle vertical panning
- if (_pan.y != 0) {
- // Store the bottom Y lines into a temp buffer, move the rest of the lines down,
- // and then copy the stored lines back to the top of the screen
- byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH];
- byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y);
- Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp);
-
- for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) {
- byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
- byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y);
- Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP);
- }
-
- Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH,
- (byte *)scene._backgroundSurface.getPixels());
- delete[] linesTemp;
- }
-
- // Flag for a full screen refresh
- scene._spriteSlots.fullRefresh();
- }
-
- // Scroll all active text lines up
- for (int i = _textLines.size() - 1; i >= 0; --i) {
- TextLine &tl = _textLines[i];
- if (tl._textDisplayIndex != -1)
- // Expire the text line that's already on-screen
- scene._textDisplay.expire(tl._textDisplayIndex);
-
- tl._pos.y--;
- if (tl._pos.y < 0) {
- _textLines.remove_at(i);
- } else {
- tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y,
- 0x605, -1, tl._line, _font);
- }
- }
-
- if (_scrollCount > 0) {
- // Handling final scrolling of text off of screen
- if (--_scrollCount == 0) {
- scriptDone();
- return;
- }
- } else {
- // Handling a text row
- if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING))
- processLines();
- }
-}
-
-void TextView::scriptDone() {
- _breakFlag = true;
- _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
-}
-
-/*------------------------------------------------------------------------*/
-
-char AnimationView::_resourceName[100];
-
-void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
- assert(resName.size() < 100);
- Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
- vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
-}
-
-AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
- _redrawFlag = false;
-
- _soundDriverLoaded = false;
- _previousUpdate = 0;
- _screenId = -1;
- _resetPalette = false;
- _resyncMode = NEVER;
- _v1 = 0;
- _v2 = -1;
- _resourceIndex = -1;
- _currentAnimation = nullptr;
- _sfx = 0;
- _soundFlag = _bgLoadFlag = true;
- _showWhiteBars = true;
- _manualFrameNumber = 0;
- _manualSpriteSet = nullptr;
- _manualStartFrame = _manualEndFrame = 0;
- _manualFrame2 = 0;
- _animFrameNumber = 0;
- _nextCyclingActive = false;
- _sceneInfo = SceneInfo::init(_vm);
-
- load();
-}
-
-AnimationView::~AnimationView() {
- delete _currentAnimation;
- delete _sceneInfo;
-}
-
-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();
-}
-
-void AnimationView::display() {
- Scene &scene = _vm->_game->_scene;
- _vm->_palette->initPalette();
- Common::fill(&_vm->_palette->_cyclingPalette[0], &_vm->_palette->_cyclingPalette[PALETTE_SIZE], 0);
-
- _vm->_palette->resetGamePalette(1, 8);
- scene._spriteSlots.reset();
- scene._paletteCycles.clear();
-
- MenuView::display();
-}
-
-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 false;
-}
-
-void AnimationView::doFrame() {
- Scene &scene = _vm->_game->_scene;
-
- if (_resourceIndex == -1 || _currentAnimation->freeFlag()) {
- if (++_resourceIndex == (int)_resources.size()) {
- scriptDone();
- } else {
- scene._frameStartTime = 0;
- loadNextResource();
- }
- } else if (_currentAnimation->getCurrentFrame() == 1) {
- scene._cyclingActive = _nextCyclingActive;
- }
-
- if (_currentAnimation) {
- ++scene._frameStartTime;
- _currentAnimation->update();
- _redrawFlag = true;
- }
-}
-
-void AnimationView::loadNextResource() {
- Scene &scene = _vm->_game->_scene;
- Palette &palette = *_vm->_palette;
- ResourceEntry &resEntry = _resources[_resourceIndex];
- Common::Array<PaletteCycle> paletteCycles;
-
- if (resEntry._bgFlag)
- palette.resetGamePalette(1, 8);
-
- palette._mainPalette[253 * 3] = palette._mainPalette[253 * 3 + 1]
- = palette._mainPalette[253 * 3 + 2] = 0xb4;
- palette.setPalette(&palette._mainPalette[253 * 3], 253, 1);
-
- // Free any previous messages
- scene._kernelMessages.reset();
-
- // Handle the bars at the top/bottom
- if (resEntry._showWhiteBars) {
- // For animations the screen has been clipped to the middle 156 rows.
- // So although it's slightly messy, bypass our screen class entirely,
- // and draw the horizontal lines directly on the physiacl screen surface
- Graphics::Surface *s = g_system->lockScreen();
- s->hLine(0, 20, MADS_SCREEN_WIDTH, 253);
- s->hLine(0, 179, MADS_SCREEN_WIDTH, 253);
- g_system->unlockScreen();
- }
-
- // Load the new animation
- delete _currentAnimation;
- _currentAnimation = Animation::init(_vm, &scene);
- int flags = ANIMFLAG_ANIMVIEW | (resEntry._bgFlag ? ANIMFLAG_LOAD_BACKGROUND : 0);
- _currentAnimation->load(scene._backgroundSurface, scene._depthSurface,
- resEntry._resourceName, flags, &paletteCycles, _sceneInfo);
-
- // Signal for a screen refresh
- scene._spriteSlots.fullRefresh();
-
- // If a sound driver has been specified, then load the correct one
- if (!_currentAnimation->_header._soundName.empty()) {
- const char *chP = strchr(_currentAnimation->_header._soundName.c_str(), '.');
- assert(chP);
-
- // Handle both Rex naming (xxx.009) and naming in later games (e.g. xxx.ph9)
- int driverNum = atoi(chP + 3);
- // HACK for Dragon
- if (_currentAnimation->_header._soundName == "#SOUND.DRG")
- driverNum = 9;
- _vm->_sound->init(driverNum);
- }
-
- // Handle any manual setup
- if (_currentAnimation->_header._manualFlag) {
- _manualFrameNumber = _currentAnimation->_header._spritesIndex;
- _manualSpriteSet = _currentAnimation->getSpriteSet(_manualFrameNumber);
- }
-
- // Set the sound data for the animation
- _vm->_sound->setEnabled(resEntry._soundFlag);
-
- Common::String dsrName = _currentAnimation->_header._dsrName;
- if (!dsrName.empty())
- _vm->_audio->setSoundGroup(dsrName);
-
- // Start the new animation
- _currentAnimation->startAnimation(0);
-
- // Handle the palette and cycling palette
- scene._cyclingActive = false;
- Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE],
- &palette._cyclingPalette[0]);
-
- _vm->_game->_fx = (ScreenTransition)resEntry._fx;
- _nextCyclingActive = paletteCycles.size() > 0;
- if (!_vm->_game->_fx) {
- palette.setFullPalette(palette._mainPalette);
- }
-
- scene.initPaletteAnimation(paletteCycles, _nextCyclingActive && !_vm->_game->_fx);
-}
-
-void AnimationView::scriptDone() {
- _breakFlag = true;
- _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
-}
-
-void AnimationView::processLines() {
- if (_script.eos()) {
- // end of script, end animation
- scriptDone();
- return;
- }
-
- while (!_script.eos()) {
- // Get in next line
- _currentLine.clear();
- char c;
- while (!_script.eos() && (c = _script.readByte()) != '\n') {
- if (c != '\r' && c != '\0')
- _currentLine += c;
- }
-
- // Process the line
- while (!_currentLine.empty()) {
- if (_currentLine.hasPrefix("-")) {
- _currentLine.deleteChar(0);
-
- processCommand();
- } else {
- // Get resource name
- Common::String resName;
- while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') {
- _currentLine.deleteChar(0);
- resName += c;
- }
-
- // Add resource into list along with any set state information
- _resources.push_back(ResourceEntry(resName, _sfx, _soundFlag,
- _bgLoadFlag, _showWhiteBars));
-
- // Fx resets between resource entries
- _sfx = 0;
- }
-
- // Skip any spaces
- while (_currentLine.hasPrefix(" "))
- _currentLine.deleteChar(0);
- }
- }
-}
-
-void AnimationView::processCommand() {
- // Get the command character
- char commandChar = toupper(_currentLine[0]);
- _currentLine.deleteChar(0);
-
- // Handle the command
- switch (commandChar) {
- case 'B':
- _soundFlag = !_soundFlag;
- break;
- case 'H':
- // -h[:ex] Disable EMS / XMS high memory support
- if (_currentLine.hasPrefix(":"))
- _currentLine.deleteChar(0);
- while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x"))
- _currentLine.deleteChar(0);
- break;
- case 'O':
- // -o:xxx Specify opening special effect
- assert(_currentLine[0] == ':');
- _currentLine.deleteChar(0);
- _sfx = getParameter();
- break;
- case 'P':
- // Switch to CONCAT mode, which is ignored anyway
- break;
- case 'R': {
- // Resynch timer (always, beginning, never)
- assert(_currentLine[0] == ':');
- _currentLine.deleteChar(0);
-
- char v = toupper(_currentLine[0]);
- _currentLine.deleteChar(0);
- if (v == 'N')
- _resyncMode = NEVER;
- else if (v == 'A')
- _resyncMode = ALWAYS;
- else if (v == 'B')
- _resyncMode = BEGINNING;
- else
- error("Unknown parameter");
- break;
- }
- case 'W':
- // Switch white bars being visible
- _showWhiteBars = !_showWhiteBars;
- break;
- case 'X':
- // Exit after animation finishes. Ignore
- break;
- case 'D':
- // Unimplemented and ignored in the original. Ignore as well
- break;
- case 'Y':
- // Reset palette on startup
- _resetPalette = true;
- break;
- default:
- error("Unknown command char: '%c'", commandChar);
- }
-}
-
-int AnimationView::getParameter() {
- int result = 0;
-
- while (!_currentLine.empty()) {
- char c = _currentLine[0];
-
- if (c >= '0' && c <= '9') {
- _currentLine.deleteChar(0);
- result = result * 10 + (c - '0');
- } else {
- break;
- }
- }
-
- return result;
-}
-
-void AnimationView::checkResource(const Common::String &resourceName) {
- //bool hasSuffix = false;
-
-}
-
-int AnimationView::scanResourceIndex(const Common::String &resourceName) {
- int foundIndex = -1;
-
- if (_v1) {
- const char *chP = strchr(resourceName.c_str(), '\\');
- if (!chP) {
- chP = strchr(resourceName.c_str(), '*');
- }
-
- Common::String resName = chP ? Common::String(chP + 1) : resourceName;
-
- if (_v2 != 3) {
- assert(_resIndex.size() == 0);
- }
-
- // Scan for the resource name
- for (uint resIndex = 0; resIndex < _resIndex.size(); ++resIndex) {
- ResIndexEntry &resEntry = _resIndex[resIndex];
- if (resEntry._resourceName.compareToIgnoreCase(resourceName)) {
- foundIndex = resIndex;
- break;
- }
- }
- }
-
- if (foundIndex >= 0) {
- // TODO
- }
- return -1;
-}
-
-
} // End of namespace Nebular
} // End of namespace MADS
diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h
index c05c87258e..29777a7a7c 100644
--- a/engines/mads/nebular/menu_nebular.h
+++ b/engines/mads/nebular/menu_nebular.h
@@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "mads/game.h"
+#include "mads/menu_views.h"
#include "mads/msurface.h"
#include "mads/nebular/dialogs_nebular.h"
@@ -36,27 +37,6 @@ namespace Nebular {
enum MADSGameAction { START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT };
-class MenuView: public FullScreenDialog {
-protected:
- bool _breakFlag;
- bool _redrawFlag;
-
- virtual void doFrame() = 0;
-
- virtual void display();
-
- /**
- * Event handler
- */
- virtual bool onEvent(Common::Event &event);
-public:
- MenuView(MADSEngine *vm);
-
- virtual ~MenuView() {}
-
- virtual void show();
-};
-
class MainMenu: public MenuView {
private:
SpriteAsset *_menuItems[7];
@@ -148,174 +128,6 @@ public:
void show();
};
-struct TextLine {
- Common::Point _pos;
- Common::String _line;
- int _textDisplayIndex;
-};
-
-/**
- * Scrolling text view
- */
-class TextView : public MenuView {
-private:
- static char _resourceName[100];
-
- bool _animating;
- Common::Array<TextLine> _textLines;
- Common::Point _pan;
- int _panSpeed;
- MSurface _spareScreens[4];
- int _scrollCount;
- int _lineY;
- uint32 _scrollTimeout;
- int _panCountdown;
- int _translationX;
- Common::File _script;
- char _currentLine[80];
- MSurface *_spareScreen;
- Font *_font;
-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);
-
- /**
- * Called when the script is finished
- */
- void scriptDone();
-
- /**
- * Reset the game palette
- */
- void resetPalette();
-protected:
- virtual void display();
-
- virtual void doFrame();
-public:
- /**
- * Queue the given text resource for display
- */
- static void execute(MADSEngine *vm, const Common::String &resName);
-
- TextView(MADSEngine *vm);
-
- virtual ~TextView();
-};
-
-enum ResyncMode { NEVER, ALWAYS, BEGINNING };
-
-struct ResourceEntry {
- Common::String _resourceName;
- int _fx;
- bool _soundFlag;
- bool _bgFlag;
- bool _showWhiteBars;
-
- ResourceEntry() {}
- ResourceEntry(const Common::String &resName, int fx, bool soundFlag,
- bool bgFlag, bool showWhiteBars) {
- _resourceName = resName;
- _fx = fx;
- _soundFlag = soundFlag;
- _bgFlag = bgFlag;
- _showWhiteBars = showWhiteBars;
- }
-};
-
-struct ResIndexEntry {
- int _id;
- int _v;
- Common::String _resourceName;
-
- ResIndexEntry() {}
-};
-
-/**
-* Animation cutscene view
-*/
-class AnimationView : public MenuView {
-private:
- static char _resourceName[100];
-
- Common::File _script;
- uint32 _previousUpdate;
- Common::String _currentLine;
- bool _soundDriverLoaded;
- bool _resetPalette;
- ResyncMode _resyncMode;
- int _sfx;
- bool _soundFlag;
- bool _bgLoadFlag;
- bool _showWhiteBars;
- Common::Array<ResourceEntry> _resources;
- Common::Array<ResIndexEntry> _resIndex;
- int _v1;
- int _v2;
- int _resourceIndex;
- SceneInfo *_sceneInfo;
- Animation *_currentAnimation;
- int _manualFrameNumber;
- SpriteAsset *_manualSpriteSet;
- int _manualStartFrame, _manualEndFrame;
- int _manualFrame2;
- int _animFrameNumber;
- bool _nextCyclingActive;
-private:
- void checkResource(const Common::String &resourceName);
-
- int scanResourceIndex(const Common::String &resourceName);
-
- void load();
-
- void processLines();
-
- void processCommand();
-
- int getParameter();
-
- void scriptDone();
-
- void loadNextResource();
-protected:
- virtual void display();
-
- virtual void doFrame();
-
- 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