[Scummvm-git-logs] scummvm master -> d2c9a9df4888e112dcc1f4822d962747f7c90783
dreammaster
noreply at scummvm.org
Sat Feb 28 10:02:14 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
d2c9a9df48 MADS: PHANTOM: Beginnings of menu menu dialogs
Commit: d2c9a9df4888e112dcc1f4822d962747f7c90783
https://github.com/scummvm/scummvm/commit/d2c9a9df4888e112dcc1f4822d962747f7c90783
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-02-28T21:02:00+11:00
Commit Message:
MADS: PHANTOM: Beginnings of menu menu dialogs
Changed paths:
A engines/mads/phantom/dialogs_phantom.cpp
A engines/mads/phantom/dialogs_phantom.h
A engines/mads/phantom/menu_phantom.cpp
A engines/mads/phantom/menu_phantom.h
engines/mads/dialogs.cpp
engines/mads/module.mk
engines/mads/phantom/game_phantom.cpp
engines/mads/phantom/game_phantom.h
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
index 15bf276d521..d83e8c2945f 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/dialogs.cpp
@@ -21,12 +21,14 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
+#include "common/text-to-speech.h"
#include "mads/mads.h"
#include "mads/screen.h"
#include "mads/msurface.h"
#include "mads/nebular/dialogs_nebular.h"
-#include "common/config-manager.h"
-#include "common/text-to-speech.h"
+#ifdef MADSV2
+#include "mads/phantom/dialogs_phantom.h"
+#endif
namespace MADS {
@@ -455,12 +457,14 @@ Dialogs *Dialogs::init(MADSEngine *vm) {
switch (vm->getGameID()) {
case GType_RexNebular:
return new Nebular::DialogsNebular(vm);
+#ifdef MADSV2
case GType_Phantom:
- // return new Phantom::DialogsPhantom(vm);
+ return new Phantom::DialogsPhantom(vm);
case GType_Dragonsphere:
// return new DragonSphere::DialogsDragonSphere(vm);
case GType_Forest:
// return new Forest::DialogsForest(vm);
+#endif
default:
// Throw a warning for now, since the associated Dialogs class isn't implemented yet
warning("Dialogs: Unknown game");
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 56561d92e1a..d60d33291ac 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -59,8 +59,10 @@ MODULE_OBJS += \
forest/game_forest.o \
forest/forest_scenes.o \
forest/globals_forest.o \
+ phantom/dialogs_phantom.o \
phantom/game_phantom.o \
phantom/globals_phantom.o \
+ phantom/menu_phantom.o \
phantom/phantom_scenes.o \
phantom/phantom_scenes1.o \
phantom/phantom_scenes2.o \
diff --git a/engines/mads/phantom/dialogs_phantom.cpp b/engines/mads/phantom/dialogs_phantom.cpp
new file mode 100644
index 00000000000..157b448b96f
--- /dev/null
+++ b/engines/mads/phantom/dialogs_phantom.cpp
@@ -0,0 +1,1211 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/util.h"
+#include "common/translation.h"
+#include "backends/keymapper/keymapper.h"
+#include "gui/saveload.h"
+#include "mads/mads.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/staticres.h"
+#include "mads/phantom/dialogs_phantom.h"
+#include "mads/phantom/game_phantom.h"
+#include "mads/phantom/menu_phantom.h"
+
+namespace MADS {
+namespace Phantom {
+
+bool DialogsPhantom::show(int messageId, int objectId) {
+ MADSAction &action = _vm->_game->_scene._action;
+ Common::StringArray msg = _vm->_game->getMessage(messageId);
+ Common::String title;
+ Common::String commandText;
+ Common::String valStr;
+ Common::String dialogText;
+ bool result = true;
+ bool centerFlag = false;
+ bool underlineFlag = false;
+ bool commandFlag = false;
+ bool crFlag = false;
+ TextDialog *dialog = nullptr;
+ _dialogWidth = 17;
+ _capitalizationMode = kUppercase;
+
+ // Loop through the lines of the returned text
+ for (uint idx = 0; idx < msg.size(); ++idx) {
+ Common::String srcLine = msg[idx];
+ const char *srcP = srcLine.c_str();
+
+ // Loop through the text of the line
+ while (srcP < srcLine.c_str() + srcLine.size()) {
+ if (*srcP == '[') {
+ // Starting a command
+ commandText = "";
+ commandFlag = true;
+ } else if (*srcP == ']') {
+ // Ending a command
+ if (commandFlag) {
+ if (commandCheck("CENTER", valStr, commandText)) {
+ centerFlag = true;
+ } else if (commandCheck("TITLE", valStr, commandText)) {
+ centerFlag = true;
+ underlineFlag = true;
+ crFlag = true;
+ int v = atoi(valStr.c_str());
+ if (v != 0)
+ _dialogWidth = v;
+ } else if (commandCheck("CR", valStr, commandText)) {
+ if (centerFlag) {
+ crFlag = true;
+ } else {
+ if (dialog)
+ delete dialog;
+
+ if (objectId == -1)
+ dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
+ else
+ dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
+
+ dialog->wordWrap(dialogText);
+ dialog->incNumLines();
+ }
+ } else if (commandCheck("ASK", valStr, commandText)) {
+ if (!dialog)
+ error("DialogsPhantom::show - Uninitialized dialog");
+ dialog->addInput();
+ } else if (commandCheck("VERB", valStr, commandText)) {
+ dialogText += getVocab(action._activeAction._verbId);
+ } else if (commandCheck("INDEX", valStr, commandText)) {
+ int idxLocal = atoi(valStr.c_str());
+ if (_indexList[idxLocal])
+ dialogText += getVocab(_indexList[idxLocal]);
+ } else if (commandCheck("NUMBER", valStr, commandText)) {
+ int idxLocal = atoi(valStr.c_str());
+ dialogText += Common::String::format("%.4d", _indexList[idxLocal]);
+ } else if (commandCheck("NOUN1", valStr, commandText)) {
+ if (!textNoun(dialogText, 1, valStr))
+ dialogText += getVocab(action._activeAction._objectNameId);
+ } else if (commandCheck("NOUN2", valStr, commandText)) {
+ if (!textNoun(dialogText, 2, valStr))
+ dialogText += getVocab(action._activeAction._indirectObjectId);
+ } else if (commandCheck("PREP", valStr, commandText)) {
+ dialogText += kArticleList[action._savedFields._articleNumber];
+ } else if (commandCheck("SENTENCE", valStr, commandText)) {
+ dialogText += action._sentence;
+ } else if (commandCheck("WIDTH", valStr, commandText)) {
+ _dialogWidth = atoi(valStr.c_str());
+ } else if (commandCheck("BAR", valStr, commandText)) {
+ if (!dialog)
+ error("DialogsPhantom::show - Uninitialized dialog");
+ dialog->addBarLine();
+ } else if (commandCheck("UNDER", valStr, commandText)) {
+ underlineFlag = true;
+ } else if (commandCheck("DOWN", valStr, commandText)) {
+ if (!dialog)
+ error("DialogsPhantom::show - Uninitialized dialog");
+ dialog->downPixelLine();
+ } else if (commandCheck("TAB", valStr, commandText)) {
+ if (!dialog)
+ error("DialogsPhantom::show - Uninitialized dialog");
+ int xp = atoi(valStr.c_str());
+ dialog->setLineXp(xp);
+ }
+ }
+
+ commandFlag = false;
+ } else if (commandFlag) {
+ // Add the next character to the command
+ commandText += *srcP;
+ } else {
+ // Add to the text to be displayed in the dialog
+ dialogText += *srcP;
+ }
+
+ ++srcP;
+ }
+
+ if (!dialog) {
+ if (objectId == -1)
+ dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
+ else
+ dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
+ }
+
+ if (centerFlag) {
+ dialog->addLine(dialogText, underlineFlag);
+ if (crFlag)
+ dialog->incNumLines();
+ } else {
+ dialog->wordWrap(dialogText);
+ }
+
+ // Reset line processing flags in preparation for next line
+ dialogText = "";
+ commandFlag = false;
+ underlineFlag = false;
+ centerFlag = false;
+ crFlag = false;
+ }
+
+ if (!dialog)
+ error("DialogsPhantom::show - Uninitialized dialog");
+
+ if (!centerFlag)
+ dialog->incNumLines();
+
+ // Show the dialog
+ _vm->_events->setCursor(CURSOR_ARROW);
+ dialog->show();
+
+ delete dialog;
+ return result;
+}
+
+void DialogsPhantom::showItem(int objectId, int messageId, int speech) {
+ // MADS engine doesn't currently support speech
+ assert(!speech);
+
+ show(messageId, objectId);
+}
+
+Common::String DialogsPhantom::getVocab(int vocabId) {
+ assert(vocabId > 0);
+
+ Common::String vocab = _vm->_game->_scene.getVocab(vocabId);
+
+ switch (_capitalizationMode) {
+ case kUppercase:
+ vocab.toUppercase();
+ break;
+ case kLowercase:
+ vocab.toLowercase();
+ break;
+ case kUpperAndLower:
+ vocab.toLowercase();
+ vocab.setChar(toupper(vocab[0]), 0);
+ default:
+ break;
+ }
+
+ return vocab;
+}
+
+bool DialogsPhantom::textNoun(Common::String &dest, int nounId, const Common::String &source) {
+ // Ensure the destination has parameter specifications
+ if (!source.hasPrefix(":"))
+ return false;
+
+ // Extract the first (singular) result value
+ Common::String param1 = Common::String(source.c_str() + 1);
+ Common::String param2;
+ const char *sepChar = strchr(source.c_str() + 1, ':');
+ if (sepChar) {
+ param1 = Common::String(source.c_str() + 1, sepChar);
+
+ // Get the second, plural form
+ param2 = Common::String(sepChar + 1);
+ }
+
+ // Get the vocab to use
+ MADSAction &action = _vm->_game->_scene._action;
+ Common::String vocab = _vm->_dialogs->getVocab(action._activeAction._verbId);
+ Common::String *str;
+
+ if (vocab.hasSuffix("s") || vocab.hasSuffix("S")) {
+ str = ¶m2;
+ } else {
+ str = ¶m1;
+
+ if (param1 == "a ") {
+ switch (toupper(vocab[0])) {
+ case 'A':
+ case 'E':
+ case 'I':
+ case 'O':
+ case 'U':
+ param1 = "an ";
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ dest += *str;
+ return true;
+}
+
+bool DialogsPhantom::commandCheck(const char *idStr, Common::String &valStr,
+ const Common::String &command) {
+ uint idLen = strlen(idStr);
+
+ valStr = (command.size() <= idLen) ? "" : Common::String(command.c_str() + idLen);
+
+ // Check whether the command starts with the given Id
+ int result = scumm_strnicmp(idStr, command.c_str(), idLen) == 0;
+ if (!result)
+ return false;
+
+ // It does, so set the command case mode
+ if (Common::isUpper(command[0]) && Common::isUpper(command[1])) {
+ _capitalizationMode = kUppercase;
+ } else if (Common::isUpper(command[0])) {
+ _capitalizationMode = kUpperAndLower;
+ } else {
+ _capitalizationMode = kLowercase;
+ }
+
+ return true;
+}
+
+void DialogsPhantom::showDialog() {
+ while (_pendingDialog != DIALOG_NONE && !_vm->shouldQuit()) {
+ DialogId dialogId = _pendingDialog;
+ _pendingDialog = DIALOG_NONE;
+
+ Common::Keymapper *keymapper = _vm->getEventManager()->getKeymapper();
+ if (dialogId == MADS::DIALOG_MAIN_MENU) {
+ keymapper->getKeymap("menu-shortcuts")->setEnabled(true);
+ } else {
+ keymapper->getKeymap("menu-shortcuts")->setEnabled(false);
+ }
+
+ 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;
+ }
+ case DIALOG_TEXTVIEW: {
+ TextView *dlg = new PhantomTextView(_vm);
+ dlg->show();
+ delete dlg;
+ return;
+ }
+ case DIALOG_ANIMVIEW: {
+ AnimationView *dlg = new PhantomAnimationView(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void DialogsPhantom::showScummVMSaveDialog() {
+ auto &game = *(Phantom::GamePhantom *)_vm->_game;
+ Scene &scene = game._scene;
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ Common::String desc = dialog->getResultString();
+
+ if (desc.empty()) {
+ // create our own description for the saved game, the user didn't enter it
+ desc = dialog->createDefaultSaveDescription(slot);
+ }
+
+ scene._spriteSlots.reset();
+ scene.loadScene(scene._currentSceneId, game._aaName, true);
+ scene._userInterface.noInventoryAnim();
+ game._scene.drawElements(kTransitionFadeIn, false);
+
+ game.saveGame(slot, desc);
+ }
+
+ // Flag for scene loading that we're returning from a dialog
+ scene._currentSceneId = RETURNING_FROM_DIALOG;
+
+ delete dialog;
+}
+
+void DialogsPhantom::showScummVMRestoreDialog() {
+ auto &game = *(Phantom::GamePhantom *)_vm->_game;
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ Scene &scene = game._scene;
+
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ game._loadGameSlot = slot;
+ game._scene._currentSceneId = RETURNING_FROM_LOADING;
+ game._currentSectionNumber = -1;
+ } else {
+ // Flag for scene loading that we're returning from a dialog
+ scene._currentSceneId = RETURNING_FROM_DIALOG;
+ }
+
+ delete dialog;
+}
+
+/*------------------------------------------------------------------------*/
+
+CopyProtectionDialog::CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong) :
+TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), 32) {
+ getHogAnusEntry(_hogEntry);
+
+ if (priorAnswerWrong) {
+ addLine("ANSWER INCORRECT!", true);
+ wordWrap("\n");
+ addLine("(But we'll give you another chance!)");
+ } else {
+ addLine("REX NEBULAR version 8.43", true);
+ wordWrap("\n");
+ addLine("(Copy Protection, for your convenience)");
+ }
+ wordWrap("\n");
+
+ wordWrap("Now comes the part that everybody hates. But if we don't");
+ wordWrap("do this, nasty rodent-like people will pirate this game");
+ wordWrap("and a whole generation of talented designers, programmers,");
+ wordWrap("artists, and playtesters will go hungry, and will wander");
+ wordWrap("aimlessly through the land at night searching for peace.");
+ wordWrap("So let's grit our teeth and get it over with. Just get");
+
+ Common::String line = "out your copy of ";
+ line += _hogEntry._bookId == 103 ? "the GAME MANUAL" : "REX'S LOGBOOK";
+ line += ". See! That was easy. ";
+ wordWrap(line);
+
+ line = Common::String::format("Next, just turn to page %d. On line %d, find word number %d, ",
+ _hogEntry._pageNum, _hogEntry._lineNum, _hogEntry._wordNum);
+ wordWrap(line);
+
+ wordWrap("and type it on the line below (we've even given you");
+ wordWrap("first letter as a hint). As soon as you do that, we can get");
+ wordWrap("right into this really COOL adventure game!\n");
+ wordWrap("\n");
+ wordWrap(" ");
+ addInput();
+ wordWrap("\n");
+}
+
+void CopyProtectionDialog::show() {
+ draw();
+
+ Common::KeyState curKey;
+ const Common::Rect inputArea(110, 165, 210, 175);
+ MSurface *origInput = new MSurface(inputArea.width(), inputArea.height());
+ _vm->_screen->frameRect(inputArea, TEXTDIALOG_BLACK);
+ origInput->blitFrom(*_vm->_screen, inputArea, Common::Point(0, 0));
+ _font->setColors(TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE);
+ _vm->_screen->update();
+
+ bool firstTime = true;
+
+ while (!_vm->shouldQuit()) {
+ if (!firstTime) {
+ while (!_vm->shouldQuit() && !_vm->_events->isKeyPressed()) {
+ _vm->_events->delay(1);
+ }
+
+ if (_vm->shouldQuit())
+ break;
+
+ curKey = _vm->_events->getKey();
+
+ if (curKey.keycode == Common::KEYCODE_RETURN || curKey.keycode == Common::KEYCODE_KP_ENTER)
+ break;
+ else if (curKey.keycode == Common::KEYCODE_BACKSPACE)
+ _textInput.deleteLastChar();
+ else if (_textInput.size() < 14)
+ _textInput += curKey.ascii;
+
+ _vm->_events->_pendingKeys.clear();
+ } else {
+ firstTime = false;
+ _textInput = _hogEntry._word[0];
+ }
+
+ _vm->_screen->blitFrom(*origInput, Common::Point(inputArea.left, inputArea.top));
+ _font->writeString(_vm->_screen, _textInput,
+ Common::Point(inputArea.left + 2, inputArea.top + 1), 1);
+ _vm->_screen->update();
+ }
+
+ origInput->free();
+ delete origInput;
+}
+
+bool CopyProtectionDialog::isCorrectAnswer() {
+ return _hogEntry._word == _textInput;
+}
+
+
+bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) {
+ File f;
+ f.open("*HOGANUS.DAT");
+
+ // Read in the total number of entries, and randomly pick an entry to use
+ int numEntries = f.readUint16LE();
+ int entryIndex = _vm->getRandomNumber(1, numEntries);
+
+ // Read in the encrypted entry
+ f.seek(28 * entryIndex + 2);
+ byte entryData[28];
+ f.read(entryData, 28);
+
+ // Decrypt it
+ for (int i = 0; i < 28; ++i)
+ entryData[i] = ~entryData[i];
+
+ // Fill out the fields
+ entry._bookId = entryData[0];
+ entry._pageNum = READ_LE_UINT16(&entryData[2]);
+ entry._lineNum = READ_LE_UINT16(&entryData[4]);
+ entry._wordNum = READ_LE_UINT16(&entryData[6]);
+ entry._word = Common::String((char *)&entryData[8]);
+
+ f.close();
+ return true;
+}
+
+/*------------------------------------------------------------------------*/
+
+PictureDialog::PictureDialog(MADSEngine *vm, const Common::Point &pos,
+ int maxChars, int objectId) :
+ TextDialog(vm, FONT_INTERFACE, pos, maxChars), _objectId(objectId) {
+ // Turn off cycling if active
+ Scene &scene = _vm->_game->_scene;
+ _cyclingActive = scene._cyclingActive;
+ scene._cyclingActive = false;
+}
+
+PictureDialog::~PictureDialog() {
+ // Restore cycling flag
+ Scene &scene = _vm->_game->_scene;
+ scene._cyclingActive = _cyclingActive;
+}
+
+void PictureDialog::save() {
+ Palette &palette = *_vm->_palette;
+ byte map[PALETTE_COUNT];
+
+ // Save the entire screen
+ _savedSurface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
+ _savedSurface->blitFrom(*_vm->_screen);
+
+ // Save palette information
+ Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE], &_palette[0]);
+ Common::copy(&palette._palFlags[0], &palette._palFlags[PALETTE_COUNT], &_palFlags[0]);
+ _rgbList.copy(palette._rgbList);
+
+ // Set up palette allocation
+ Common::fill(&palette._colorFlags[0], &palette._colorFlags[3], true);
+
+ uint32 *palFlagP = &palette._palFlags[0];
+ for (int idx = 0; idx < PALETTE_COUNT; ++idx, ++palFlagP) {
+ if (idx < PALETTE_RESERVED_LOW_COUNT ||
+ idx >= (PALETTE_COUNT - PALETTE_RESERVED_HIGH_COUNT - 10)) {
+ *palFlagP = 1;
+ map[idx] = idx;
+ } else {
+ *palFlagP = 0;
+ }
+ }
+
+ // Reset the flag list
+ palette._rgbList.reset();
+
+ // Fade the screen to grey
+ int numColors = PALETTE_COUNT - PALETTE_RESERVED_LOW_COUNT - PALETTE_RESERVED_HIGH_COUNT;
+ palette.fadeOut(palette._mainPalette, &map[PALETTE_RESERVED_LOW_COUNT],
+ PALETTE_RESERVED_LOW_COUNT, numColors, 248, 8, 1, 16);
+
+ // Remap the greyed out screen to use the small greyscale range
+ // at the top end of the palette
+ _vm->_screen->translate(map);
+
+ // Load the inventory picture
+ Common::Path setName(Common::String::format("*OB%.3d.SS", _objectId));
+ SpriteAsset *asset = new SpriteAsset(_vm, setName, 0x8000);
+ palette.setFullPalette(palette._mainPalette);
+
+ // Get the inventory frame, and adjust the dialog position to allow for it
+ MSprite *frame = asset->getFrame(0);
+ _position.y = frame->h + 12;
+ if ((_position.y + _height) > _vm->_screen->h)
+ _position.y -= (_position.y + _height) - _vm->_screen->h;
+
+ // Draw the inventory picture
+ _vm->_screen->transBlitFrom(*frame, Common::Point(160 - frame->w / 2, 6),
+ frame->getTransparencyIndex());
+
+ // Adjust the dialog colors to use
+ TEXTDIALOG_CONTENT1 -= 10;
+ TEXTDIALOG_CONTENT2 -= 10;
+ TEXTDIALOG_EDGE -= 10;
+ TEXTDIALOG_BACKGROUND -= 10;
+ TEXTDIALOG_FC -= 10;
+ TEXTDIALOG_FD -= 10;
+ TEXTDIALOG_FE -= 10;
+}
+
+void PictureDialog::restore() {
+ if (_savedSurface) {
+ _vm->_screen->blitFrom(*_savedSurface);
+ _savedSurface->free();
+ delete _savedSurface;
+ _savedSurface = nullptr;
+
+ // Restore palette information
+ Palette &palette = *_vm->_palette;
+ Common::copy(&_palette[0], &_palette[PALETTE_SIZE], &palette._mainPalette[0]);
+ _vm->_palette->setFullPalette(palette._mainPalette);
+ Common::copy(&_palFlags[0], &_palFlags[PALETTE_COUNT], &palette._palFlags[0]);
+ palette._rgbList.copy(_rgbList);
+
+ _vm->_dialogs->_defaultPosition.y = -1;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+GameDialog::DialogLine::DialogLine() {
+ _active = true;
+ _state = DLGSTATE_UNSELECTED;
+ _textDisplayIndex = -1;
+ _font = nullptr;
+ _widthAdjust = 0;
+ _msg = "";
+}
+
+GameDialog::DialogLine::DialogLine(const Common::String &s) {
+ _active = true;
+ _state = DLGSTATE_UNSELECTED;
+ _textDisplayIndex = -1;
+ _font = nullptr;
+ _widthAdjust = -1;
+ _msg = s;
+}
+
+/*------------------------------------------------------------------------*/
+
+GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) {
+ Game &game = *_vm->_game;
+ Scene &scene = game._scene;
+
+ _tempLine = 0;
+ _movedFlag = false;
+ _redrawFlag = false;
+ _selectedLine = -1;
+ _dirFlag = false;
+ _textLineCount = 0;
+ _lineIndex = -1;
+ _screenId = 920;
+
+ chooseBackground();
+ game.loadQuoteSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 0);
+ game._kernelMode = KERNEL_ROOM_PRELOAD;
+ _vm->_events->waitCursor();
+ scene.clearVocab();
+ scene._dynamicHotspots.clear();
+ // Clear scene sprites and objects
+ scene._spriteSlots.reset();
+ _vm->_game->_screenObjects.clear();
+ _vm->_dialogs->_defaultPosition = Common::Point(-1, -1);
+ _menuSpritesIndex = 0;
+}
+
+void GameDialog::display() {
+ Palette &palette = *_vm->_palette;
+ palette.initPalette();
+ palette.resetGamePalette(18, 10);
+
+ FullScreenDialog::display();
+
+ palette.setEntry(10, 0, 63, 0);
+ palette.setEntry(11, 0, 45, 0);
+ palette.setEntry(12, 63, 63, 0);
+ palette.setEntry(13, 45, 45, 0);
+ palette.setEntry(14, 63, 63, 63);
+ palette.setEntry(15, 45, 45, 45);
+
+ Scene &scene = _vm->_game->_scene;
+ SpriteAsset *menuSprites = new SpriteAsset(_vm, "*MENU", 0);
+ _menuSpritesIndex = scene._sprites.add(menuSprites);
+
+ _lineIndex = -1;
+ setClickableLines();
+
+ _vm->_events->setCursor(CURSOR_ARROW);
+}
+
+GameDialog::~GameDialog() {
+ _vm->_game->_scene._currentSceneId = RETURNING_FROM_DIALOG;
+}
+
+void GameDialog::clearLines() {
+ Scene &scene = _vm->_game->_scene;
+ _movedFlag = false;
+ _lines.clear();
+ scene._spriteSlots.fullRefresh(true);
+}
+
+void GameDialog::setClickableLines() {
+ ScreenObjects &screenObjects = _vm->_game->_screenObjects;
+
+ for (uint idx = 0; idx < _lines.size(); ++idx) {
+ if (_lines[idx]._active) {
+ const Common::Point &pt = _lines[idx]._pos;
+ int strWidth = _lines[idx]._font->getWidth(_lines[idx]._msg);
+ int maxHeight = _lines[idx]._font->getHeight();
+
+ screenObjects.add(Common::Rect(pt.x, pt.y, pt.x + strWidth, pt.y + maxHeight - 1),
+ SCREENMODE_VGA, CAT_COMMAND, idx);
+ }
+ }
+
+ if (_vm->_dialogs->_pendingDialog == DIALOG_SAVE ||
+ _vm->_dialogs->_pendingDialog == DIALOG_RESTORE) {
+ screenObjects.add(Common::Rect(293, 26, 312, 75), SCREENMODE_VGA, CAT_INV_LIST, 50);
+ screenObjects.add(Common::Rect(293, 78, 312, 127), SCREENMODE_VGA, CAT_INV_LIST, 51);
+ }
+}
+
+void GameDialog::addQuote(int id1, int id2, DialogTextAlign align,
+ const Common::Point &pt, Font *font) {
+ Common::String msg = _vm->_game->getQuote(id1).c_str(); // c_str() because we need a copy
+
+ if (id2 > 0)
+ msg += _vm->_game->getQuote(id2);
+
+ addLine(msg, align, pt, font);
+}
+
+void GameDialog::addLine(const Common::String &msg, DialogTextAlign align,
+ const Common::Point &pt, Font *font) {
+ Scene &scene = _vm->_game->_scene;
+ DialogLine *line;
+
+ if (font == nullptr)
+ font = _vm->_font->getFont(FONT_CONVERSATION);
+
+ if (_lineIndex < (int)_lines.size()) {
+ if (_lines.size() >= 20) {
+ ++_lineIndex;
+ return;
+ }
+
+ _lines.push_back(msg);
+ line = &_lines[_lines.size() - 1];
+ } else {
+ line = &_lines[_lineIndex];
+ if (msg.compareToIgnoreCase(msg)) {
+ ++_lineIndex;
+ return;
+ }
+
+ if (line->_textDisplayIndex >= 0) {
+ TextDisplay &textDisplay = scene._textDisplay[line->_textDisplayIndex];
+ if (textDisplay._active) {
+ textDisplay._expire = -1;
+ if (_textLineCount < 20) {
+ textDisplay._msg = msg;
+ ++_textLineCount;
+ }
+ }
+ }
+ }
+
+ line->_font = font;
+ line->_state = DLGSTATE_UNSELECTED;
+ line->_pos = pt;
+ line->_widthAdjust = -1;
+ line->_textDisplayIndex = -1;
+
+ int xOffset;
+ switch (align) {
+ case ALIGN_NONE:
+ // No adjustment
+ break;
+
+ case ALIGN_CENTER:
+ xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(msg, -1) / 2;
+ line->_pos.x += xOffset;
+ break;
+
+ case ALIGN_AT_CENTER: {
+ const char *msgP = msg.c_str();
+ const char *ch = strchr(msgP, '@');
+ if (ch) {
+ xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(
+ Common::String(msgP, ch), line->_widthAdjust);
+ line->_pos.x += xOffset;
+
+ Common::String newMsg = msg.c_str();
+ newMsg.deleteChar(ch - msgP);
+ line->_msg = newMsg;
+ }
+ break;
+ }
+
+ case ALIGN_RIGHT:
+ xOffset = font->getWidth(msg, -1);
+ line->_pos.x -= xOffset;
+ break;
+
+ default:
+ break;
+ }
+
+ ++_lineIndex;
+}
+
+void GameDialog::initVars() {
+ _tempLine = -1;
+ _selectedLine = -1;
+ _lineIndex = 0;
+ _textLineCount = 0;
+}
+
+void GameDialog::chooseBackground() {
+ switch (_vm->_game->_currentSectionNumber) {
+ case 1:
+ case 2:
+ _screenId = 921;
+ break;
+ case 3:
+ case 4:
+ _screenId = 922;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ _screenId = 923;
+ break;
+ case 8:
+ _screenId = 924;
+ break;
+ default:
+ _screenId = 920;
+ break;
+ }
+}
+
+void GameDialog::setFrame(int frameNumber, int depth) {
+ Scene &scene = _vm->_game->_scene;
+ SpriteAsset *menuSprites = scene._sprites[_menuSpritesIndex];
+ MSprite *frame = menuSprites->getFrame(frameNumber - 1);
+
+ SpriteSlot &spriteSlot = scene._spriteSlots[scene._spriteSlots.add()];
+ spriteSlot._flags = IMG_UPDATE;
+ spriteSlot._seqIndex = 1;
+ spriteSlot._spritesIndex = _menuSpritesIndex;
+ spriteSlot._frameNumber = frameNumber;
+ spriteSlot._position = frame->_offset;
+ spriteSlot._depth = depth;
+ spriteSlot._scale = 100;
+}
+
+void GameDialog::show() {
+ display();
+
+ Scene &scene = _vm->_game->_scene;
+
+ while (_selectedLine == -1 && !_vm->shouldQuit()) {
+ handleEvents();
+ if (_redrawFlag) {
+ if (!_tempLine)
+ _tempLine = -1;
+
+ refreshText();
+ scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
+ _redrawFlag = false;
+ }
+
+ _vm->_events->waitForNextFrame();
+ _vm->_game->_fx = kTransitionNone;
+ }
+}
+
+void GameDialog::handleEvents() {
+ ScreenObjects &screenObjects = _vm->_game->_screenObjects;
+ EventsManager &events = *_vm->_events;
+ auto &dialogs = *(Phantom::DialogsPhantom *)_vm->_dialogs;
+ int tempLine = _tempLine;
+
+ // Mark all the lines as initially unselected
+ for (uint i = 0; i < _lines.size(); ++i)
+ _lines[i]._state = DLGSTATE_UNSELECTED;
+
+ // Process pending events
+ events.pollEvents();
+
+ if (events.isActionTriggered()) {
+ switch (events.getAction()) {
+ case kActionEscape:
+ _selectedLine = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Scan for objects in the dialog
+ Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP);
+ int objIndex = screenObjects.scan(mousePos, SCREENMODE_VGA);
+
+ if (_movedFlag) {
+ int yp = mousePos.y;
+ if (yp < screenObjects[1]._bounds.top) {
+ if (!events._mouseReleased)
+ _lines[1]._state = DLGSTATE_SELECTED;
+ objIndex = 19;
+ }
+
+ if (yp < screenObjects[7]._bounds.bottom) {
+ if (!events._mouseReleased)
+ _lines[1]._state = DLGSTATE_SELECTED;
+ objIndex = 20;
+ }
+ }
+
+ int line = -1;
+ if (objIndex > 0 && (events._mouseStatus || events._mouseReleased)) {
+ line = screenObjects[objIndex]._descId;
+ if (dialogs._pendingDialog == DIALOG_SAVE || dialogs._pendingDialog == DIALOG_RESTORE) {
+ if (line > 7 && line <= 14) {
+ _lines[line]._state = DLGSTATE_UNSELECTED;
+ line -= 7;
+ }
+
+ bool movedFlag = line > 0 && line < 8;
+ if (events._mouseMoved)
+ _movedFlag = movedFlag;
+ }
+
+ if (screenObjects[objIndex]._category == CAT_COMMAND) {
+ _lines[line]._state = DLGSTATE_SELECTED;
+ }
+ }
+ if (!line)
+ line = -1;
+
+ if (dialogs._pendingDialog == DIALOG_ERROR && line == 1)
+ line = -1;
+
+ if (events._mouseReleased) {
+ if (!_movedFlag || line <= 18)
+ _selectedLine = line;
+ _redrawFlag = true;
+ }
+
+ _tempLine = line;
+ if (tempLine != line || _selectedLine >= 0)
+ _redrawFlag = true;
+}
+
+void GameDialog::refreshText() {
+ Scene &scene = _vm->_game->_scene;
+
+ for (uint i = 0; i < _lines.size(); ++i) {
+ if (_lines[i]._active) {
+ int fontColor;
+ switch (_lines[i]._state) {
+ case DLGSTATE_UNSELECTED:
+ fontColor = 0xB0A;
+ break;
+ case DLGSTATE_SELECTED:
+ fontColor = 0xD0C;
+ break;
+ default:
+ fontColor = 0xF0E;
+ break;
+ }
+
+ bool skipFlag = false;
+ if (_lines[i]._textDisplayIndex >= 0) {
+ TextDisplay &textDisplay = scene._textDisplay[_lines[i]._textDisplayIndex];
+ int currCol = textDisplay._color1;
+ if (currCol != fontColor) {
+ scene._textDisplay.expire(_lines[i]._textDisplayIndex);
+ _lines[i]._textDisplayIndex = -1;
+ } else {
+ skipFlag = true;
+ }
+ }
+
+ if (!skipFlag) {
+ _lines[i]._textDisplayIndex = scene._textDisplay.add(_lines[i]._pos.x, _lines[i]._pos.y,
+ fontColor, _lines[i]._widthAdjust, _lines[i]._msg, _lines[i]._font);
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+DifficultyDialog::DifficultyDialog(MADSEngine *vm) : GameDialog(vm) {
+ setLines();
+ _vm->_palette->resetGamePalette(18, 10);
+}
+
+void DifficultyDialog::setLines() {
+ Font *font = _vm->_font->getFont(FONT_CONVERSATION);
+ int yp = 78 - ((font->getHeight() + 1) * 4 + 6) / 2;
+
+ addQuote(41, 0, ALIGN_CENTER, Common::Point(0, yp), font);
+ yp += 6;
+
+ for (int id = 42; id <= 44; ++id) {
+ yp += font->getHeight();
+ addQuote(id, 0, ALIGN_CENTER, Common::Point(0, yp));
+ }
+}
+
+void DifficultyDialog::display() {
+ GameDialog::display();
+ setFrame(8, 2);
+}
+
+void DifficultyDialog::show() {
+ GameDialog::show();
+ auto &game = *(Phantom::GamePhantom *)_vm->_game;
+
+ switch (_selectedLine) {
+ case 1:
+ game._difficulty = Phantom::DIFFICULTY_EASY;
+ break;
+ case 2:
+ game._difficulty = Phantom::DIFFICULTY_HARD;
+ break;
+ default:
+ _vm->quitGame();
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+GameMenuDialog::GameMenuDialog(MADSEngine *vm) : GameDialog(vm) {
+ setLines();
+}
+
+void GameMenuDialog::setLines() {
+ Font *font = _vm->_font->getFont(FONT_CONVERSATION);
+
+ int yp = 64 - ((font->getHeight() + 1) * 4 + 6) / 2;
+
+ addQuote(10, 0, ALIGN_CENTER, Common::Point(0, yp), font);
+ yp += 6;
+
+ for (int id = 11; id <= 15; ++id) {
+ yp += font->getHeight();
+ addQuote(id, 0, ALIGN_CENTER, Common::Point(0, yp));
+ }
+}
+
+void GameMenuDialog::display() {
+ GameDialog::display();
+ setFrame(1, 2);
+}
+
+void GameMenuDialog::show() {
+ GameDialog::show();
+
+ switch (_selectedLine) {
+ case 1:
+ _vm->_dialogs->_pendingDialog = DIALOG_SAVE;
+ _vm->_dialogs->showDialog();
+ break;
+ case 2:
+ _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
+ _vm->_dialogs->showDialog();
+ break;
+ case 3:
+ _vm->_dialogs->_pendingDialog = DIALOG_OPTIONS;
+ _vm->_dialogs->showDialog();
+ break;
+ case 5:
+ _vm->quitGame();
+ break;
+ case 4:
+ default:
+ // Resume game
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+OptionsDialog::OptionsDialog(MADSEngine *vm) : GameDialog(vm) {
+ setLines();
+}
+
+int OptionsDialog::getOptionQuote(int option) {
+#ifdef TODO
+ auto &game = *(Phantom::GamePhantom *)_vm->_game;
+
+ switch (option) {
+ case 17: // Music
+ return _vm->_musicFlag ? 24 : 25; // 24: ON, 25: OFF
+ case 18: // Sound
+ return _vm->_soundFlag ? 26 : 27; // 26: ON, 27: OFF
+ case 19: // Interface
+ return !_vm->_easyMouse ? 28 : 29; // 28: Standard, 29: Easy
+ case 20: // Inventory
+ return _vm->_invObjectsAnimated ? 30 : 31; // 30: Spinning, 31: Still
+ case 21: // Text window
+ return !_vm->_textWindowStill ? 32 : 33; // 32: Animated, 33: Still
+ case 22: // Screen fade
+ return 34 + _vm->_screenFade; // 34: Smooth, 35: Medium, 36: Fast
+ case 23: // Storyline
+ return (game._storyMode == STORYMODE_NAUGHTY) ? 37 : 38; // 37: Naughty, 38: Nice
+ default:
+ error("getOptionQuote: Unknown option");
+ }
+#endif
+ return 0;
+}
+
+void OptionsDialog::setLines() {
+ Font *font = _vm->_font->getFont(FONT_CONVERSATION);
+
+ int yp = 40 - ((font->getHeight() + 1) * 4 + 6) / 2;
+
+ addQuote(16, 0, ALIGN_CENTER, Common::Point(0, yp), font);
+ yp += 6;
+
+ for (int id = 17; id <= 23; ++id) {
+ yp += font->getHeight();
+ addQuote(id, getOptionQuote(id), ALIGN_AT_CENTER, Common::Point(0, yp));
+ }
+
+ yp += 28;
+ addQuote(1, 0, ALIGN_NONE, Common::Point(90, yp));
+ addQuote(2, 0, ALIGN_NONE, Common::Point(190, yp));
+}
+
+void OptionsDialog::display() {
+ GameDialog::display();
+ setFrame(2, 2);
+}
+
+void OptionsDialog::show() {
+// auto &game = *(Phantom::GamePhantom *)_vm->_game;
+
+ // Previous options, restored when cancel is selected
+ bool prevMusicFlag = _vm->_musicFlag;
+ bool prevEasyMouse = _vm->_easyMouse;
+ bool prevInvObjectsAnimated = _vm->_invObjectsAnimated;
+ bool prevTextWindowStill = _vm->_textWindowStill;
+ ScreenFade prevScreenFade = _vm->_screenFade;
+// StoryMode prevStoryMode = game._storyMode;
+
+ do {
+ _selectedLine = -1;
+ GameDialog::show();
+
+ switch (_selectedLine) {
+ case 1: // Music
+ _vm->_musicFlag = _vm->_soundFlag = !_vm->_musicFlag;
+ break;
+ case 2: // Sound
+ _vm->_musicFlag = _vm->_soundFlag = !_vm->_musicFlag;
+ break;
+ case 3: // Interface
+ _vm->_easyMouse = !_vm->_easyMouse;
+ break;
+ case 4: // Inventory
+ _vm->_invObjectsAnimated = !_vm->_invObjectsAnimated;
+ break;
+ case 5: // Text window
+ _vm->_textWindowStill = !_vm->_textWindowStill;
+ break;
+ case 6: // Screen fade
+ if (_vm->_screenFade == SCREEN_FADE_FAST)
+ _vm->_screenFade = SCREEN_FADE_MEDIUM;
+ else if (_vm->_screenFade == SCREEN_FADE_MEDIUM)
+ _vm->_screenFade = SCREEN_FADE_SMOOTH;
+ else
+ _vm->_screenFade = SCREEN_FADE_FAST;
+ break;
+// case 7: // Storyline
+// game._storyMode = (game._storyMode == STORYMODE_NAUGHTY) ? STORYMODE_NICE : STORYMODE_NAUGHTY;
+// break;
+ default:
+ break;
+ }
+
+ // Reload menu
+ _lineIndex = -1;
+ clearLines();
+ _vm->_game->_screenObjects.clear();
+ _vm->_game->_scene._spriteSlots.reset();
+ setLines();
+ } while (!_vm->shouldQuit() && _selectedLine != 0 && _selectedLine <= 7);
+
+ if (_selectedLine == 8) {
+ // OK button, save settings
+ _vm->saveOptions();
+ } else if (_selectedLine == 9) {
+ // Cancel button, revert all options from the saved ones
+ _vm->_musicFlag = _vm->_soundFlag = prevMusicFlag;
+ _vm->_easyMouse = prevEasyMouse;
+ _vm->_invObjectsAnimated = prevInvObjectsAnimated;
+ _vm->_textWindowStill = prevTextWindowStill;
+ _vm->_screenFade = prevScreenFade;
+ //game._storyMode = prevStoryMode;
+ }
+}
+
+} // namespace Phantom
+} // namespace MADS
diff --git a/engines/mads/phantom/dialogs_phantom.h b/engines/mads/phantom/dialogs_phantom.h
new file mode 100644
index 00000000000..f669aa42754
--- /dev/null
+++ b/engines/mads/phantom/dialogs_phantom.h
@@ -0,0 +1,269 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_DIALOGS_PHANTOM_H
+#define MADS_DIALOGS_PHANTOM_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/dialogs.h"
+
+namespace MADS {
+namespace Phantom {
+
+enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 };
+
+class DialogsPhantom : public Dialogs {
+ friend class Dialogs;
+private:
+ int _dialogWidth;
+ CapitalizationMode _capitalizationMode;
+
+ DialogsPhantom(MADSEngine *vm): Dialogs(vm), _capitalizationMode(kUppercase), _dialogWidth(0) {}
+
+ Common::String getVocab(int vocabId) override;
+
+ bool textNoun(Common::String &dest, int nounId, const Common::String &source);
+
+ bool commandCheck(const char *idStr, Common::String &valStr, const Common::String &command);
+
+ void showScummVMSaveDialog();
+ void showScummVMRestoreDialog();
+
+public:
+ void showDialog() override;
+
+ void showItem(int objectId, int messageId, int speech = -1) override;
+
+ bool show(int messageId, int objectId = -1) override;
+};
+
+struct HOGANUS {
+ int _bookId;
+ int _pageNum;
+ int _lineNum;
+ int _wordNum;
+ Common::String _word;
+};
+
+class CopyProtectionDialog : public TextDialog {
+private:
+ HOGANUS _hogEntry;
+ Common::String _textInput;
+
+ /**
+ * Get a random copy protection entry from the HOGANUS resource
+ */
+ bool getHogAnusEntry(HOGANUS &entry);
+public:
+ /**
+ * Constructor
+ */
+ CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong);
+
+ /**
+ * Show the dialog
+ */
+ void show() override;
+
+ bool isCorrectAnswer();
+};
+
+class PictureDialog : public TextDialog {
+private:
+ int _objectId;
+ bool _cyclingActive;
+ byte _palette[PALETTE_SIZE];
+ uint32 _palFlags[PALETTE_COUNT];
+ RGBList _rgbList;
+protected:
+ void save() override;
+
+ void restore() override;
+public:
+ PictureDialog(MADSEngine *vm, const Common::Point &pos, int maxChars, int objectId);
+
+ ~PictureDialog() override;
+};
+
+enum DialogTextAlign { ALIGN_NONE = 0, ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 };
+
+enum DialogState { DLGSTATE_UNSELECTED = 0, DLGSTATE_SELECTED = 1, DLGSTATE_FOCUSED = 2 };
+
+class GameDialog: public FullScreenDialog {
+ struct DialogLine {
+ bool _active;
+ DialogState _state;
+ Common::Point _pos;
+ int _textDisplayIndex;
+ Common::String _msg;
+ Font *_font;
+ int _widthAdjust;
+
+ DialogLine();
+ DialogLine(const Common::String &s);
+ };
+protected:
+ Common::Array<DialogLine> _lines;
+ int _tempLine;
+ bool _movedFlag;
+ bool _redrawFlag;
+ int _selectedLine;
+ bool _dirFlag;
+ int _menuSpritesIndex;
+ int _lineIndex;
+ int _textLineCount;
+
+ /**
+ * Display the dialog
+ */
+ void display() override;
+
+ /**
+ * Reset the lines list for the dialog
+ */
+ void clearLines();
+
+ /**
+ * Setup lines to be clickable
+ */
+ void setClickableLines();
+
+ /**
+ * Add a quote to the lines list
+ */
+ void addQuote(int id1, int id2, DialogTextAlign align, const Common::Point &pt, Font *font = nullptr);
+
+ /**
+ * Adds a line to the lines list
+ */
+ void addLine(const Common::String &msg, DialogTextAlign align, const Common::Point &pt, Font *font = nullptr);
+
+ /**
+ * Initializes variables
+ */
+ void initVars();
+
+ /**
+ * Sets the display for the screen background behind the dialog
+ */
+ void setFrame(int frameNumber, int depth);
+
+ /**
+ * Choose the background to display for the dialog
+ */
+ void chooseBackground();
+
+ /**
+ * Handle events whilst the dialog is active
+ */
+ void handleEvents();
+
+ /**
+ * Refresh the display of the dialog's text
+ */
+ void refreshText();
+public:
+ /**
+ * Constructor
+ */
+ GameDialog(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ ~GameDialog() override;
+
+ /**
+ * Show the dialog
+ */
+ virtual void show();
+};
+
+class DifficultyDialog : public GameDialog {
+private:
+ /**
+ * Set the lines for the dialog
+ */
+ void setLines();
+public:
+ DifficultyDialog(MADSEngine *vm);
+
+ /**
+ * Display the dialog
+ */
+ void display() override;
+
+ /**
+ * Show the dialog
+ */
+ void show() override;
+};
+
+class GameMenuDialog : public GameDialog {
+private:
+ /**
+ * Set the lines for the dialog
+ */
+ void setLines();
+public:
+ GameMenuDialog(MADSEngine *vm);
+
+ /**
+ * Display the dialog
+ */
+ void display() override;
+
+ /**
+ * Show the dialog
+ */
+ void show() override;
+};
+
+class OptionsDialog : public GameDialog {
+private:
+ /**
+ * Set the lines for the dialog
+ */
+ void setLines();
+
+ /**
+ * Gets the quote to be shown for an option
+ */
+ int getOptionQuote(int option);
+public:
+ OptionsDialog(MADSEngine *vm);
+
+ /**
+ * Display the dialog
+ */
+ void display() override;
+
+ /**
+ * Show the dialog
+ */
+ void show() override;
+};
+
+} // namespace Phantom
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
index 571add473b9..daa31b51ba3 100644
--- a/engines/mads/phantom/game_phantom.cpp
+++ b/engines/mads/phantom/game_phantom.cpp
@@ -23,8 +23,8 @@
#include "mads/game.h"
#include "mads/screen.h"
#include "mads/msurface.h"
+#include "mads/menu_views.h"
#include "mads/phantom/game_phantom.h"
-//#include "mads/nebular/dialogs_nebular.h"
#include "mads/phantom/globals_phantom.h"
#include "mads/phantom/phantom_scenes.h"
@@ -139,6 +139,47 @@ GamePhantom::GamePhantom(MADSEngine *vm) : Game(vm) {
}
void GamePhantom::startGame() {
+ // First handle any ending credits from a just finished game session.
+ // Note that, with the exception of the decompression ending, which doesn't
+ // use animations, the remaining animations will automatically launch their
+ // own text view credits when the animation is completed
+ switch (_winStatus) {
+ case 1:
+ // No shields failure ending
+ AnimationView::execute(_vm, "rexend1");
+ break;
+ case 2:
+ // Shields, but no targeting failure ending
+ AnimationView::execute(_vm, "rexend2");
+ break;
+ case 3:
+ AnimationView::execute(_vm, "rexend3");
+ break;
+ case 4:
+ // Decompression ending
+ TextView::execute(_vm, "ending4");
+ break;
+ default:
+ break;
+ }
+
+ do {
+ checkShowDialog();
+ _winStatus = 0;
+
+ _sectionNumber = 1;
+ initSection(_sectionNumber);
+ _vm->_events->setCursor(CURSOR_ARROW);
+ _statusFlag = true;
+
+ // Show the main menu
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+ _vm->_dialogs->showDialog();
+ } while (!_vm->shouldQuit() && _vm->_dialogs->_pendingDialog != DIALOG_NONE);
+
+ if (_vm->shouldQuit())
+ return;
+
_scene._priorSceneId = 0;
_scene._currentSceneId = -1;
_scene._nextSceneId = 101;
diff --git a/engines/mads/phantom/game_phantom.h b/engines/mads/phantom/game_phantom.h
index 67406831728..c4076474c40 100644
--- a/engines/mads/phantom/game_phantom.h
+++ b/engines/mads/phantom/game_phantom.h
@@ -144,7 +144,7 @@ typedef Section1Handler Section3Handler;
typedef Section1Handler Section4Handler;
typedef Section1Handler Section5Handler;
-} // End of namespace Nebular
+} // End of namespace Phantom
} // End of namespace MADS
#endif
diff --git a/engines/mads/phantom/menu_phantom.cpp b/engines/mads/phantom/menu_phantom.cpp
new file mode 100644
index 00000000000..521aa5fefb6
--- /dev/null
+++ b/engines/mads/phantom/menu_phantom.cpp
@@ -0,0 +1,435 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "mads/game.h"
+#include "mads/mads.h"
+#include "mads/menu_views.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/screen.h"
+#include "mads/phantom/menu_phantom.h"
+
+namespace MADS {
+namespace Phantom {
+
+#define NEBULAR_MENUSCREEN 990
+#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
+#define MADS_MENU_ANIM_DELAY 70
+
+MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
+ Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr);
+ Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1);
+ _delayTimeout = 0;
+ _menuItemIndex = -1;
+ _frameIndex = 0;
+ _skipFlag = false;
+ _highlightedIndex = -1;
+ _selectedIndex = -1;
+ _buttonDown = false;
+ _showEvolve = _showSets = false;
+
+ for (int i = 0; i < 7; ++i)
+ _menuItems[i] = nullptr;
+}
+
+MainMenu::~MainMenu() {
+ Scene &scene = _vm->_game->_scene;
+ for (int i = 0; i < 7; ++i) {
+ if (_menuItemIndexes[i] != -1)
+ scene._sprites.remove(_menuItemIndexes[i]);
+ }
+
+ scene._spriteSlots.reset();
+}
+
+bool MainMenu::shouldShowQuotes() {
+ return ConfMan.hasKey("ShowQuotes") && ConfMan.getBool("ShowQuotes");
+}
+
+void MainMenu::display() {
+ MenuView::display();
+ Scene &scene = _vm->_game->_scene;
+ ScreenObjects &screenObjects = _vm->_game->_screenObjects;
+ screenObjects.clear();
+
+ // Load each of the menu item assets and add to the scene sprites list
+ for (int i = 0; i < 7; ++i) {
+ Common::Path spritesName = Resources::formatName(NEBULAR_MENUSCREEN,
+ 'A', i + 1, EXT_SS, "");
+ _menuItems[i] = new SpriteAsset(_vm, spritesName, 0);
+ _menuItemIndexes[i] = scene._sprites.add(_menuItems[i]);
+
+ // Register the menu item area in the screen objects
+ MSprite *frame0 = _menuItems[i]->getFrame(0);
+ Common::Point pt(frame0->_offset.x - (frame0->w / 2),
+ frame0->_offset.y - frame0->h);
+ screenObjects.add(
+ Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w,
+ pt.y + frame0->h + DIALOG_TOP), SCREENMODE_VGA, CAT_COMMAND, i);
+ }
+
+ // Set the cursor for when it's shown
+ _vm->_events->setCursor(CURSOR_ARROW);
+}
+
+void MainMenu::doFrame() {
+ // Delay between animation frames on the menu
+ uint32 currTime = g_system->getMillis();
+ if (currTime < _delayTimeout)
+ return;
+ _delayTimeout = currTime + MADS_MENU_ANIM_DELAY;
+
+ // If an item has already been selected, handle rotating out the other menu items
+ if (_selectedIndex != -1) {
+ if (_frameIndex == _menuItems[0]->getCount()) {
+ handleAction((MADSGameAction)_selectedIndex);
+ } else {
+ for (_menuItemIndex = 0; _menuItemIndex < 6; ++_menuItemIndex) {
+ if (_menuItemIndex == 4 && !shouldShowQuotes())
+ continue;
+
+ if (_menuItemIndex != _selectedIndex) {
+ addSpriteSlot();
+ }
+ }
+
+ // Move the menu items to the next frame
+ ++_frameIndex;
+ }
+ return;
+ }
+
+ // If we've alerady reached the end of the menuitem animation, exit immediately
+ if (_menuItemIndex == 6)
+ return;
+
+ // If the user has chosen to skip the animation, show the full menu immediately
+ if (_skipFlag && _menuItemIndex >= 0) {
+ // Quickly loop through all the menu items to display each's final frame
+ for (; _menuItemIndex < 6; ++_menuItemIndex) {
+ if (_menuItemIndex == 4 && !shouldShowQuotes())
+ continue;
+
+ // Draw the final frame of the menuitem
+ _frameIndex = 0;
+ addSpriteSlot();
+ }
+
+ _vm->_events->showCursor();
+ showBonusItems();
+ } else {
+ if ((_menuItemIndex == -1) || (_frameIndex == 0)) {
+ if (++_menuItemIndex == 6) {
+
+ // Reached end of display animation
+ _vm->_events->showCursor();
+ showBonusItems();
+ return;
+ } else if (_menuItemIndex == 4 && !shouldShowQuotes()) {
+ ++_menuItemIndex;
+ }
+
+ _frameIndex = _menuItems[_menuItemIndex]->getCount() - 1;
+ } else {
+ --_frameIndex;
+ }
+
+ // Move to the next menuitem frame
+ addSpriteSlot();
+ }
+}
+
+void MainMenu::addSpriteSlot() {
+ Scene &scene = _vm->_game->_scene;
+ SpriteSlots &spriteSlots = scene._spriteSlots;
+
+ int seqIndex = (_menuItemIndex < 6) ? _menuItemIndex : _frameIndex;
+ spriteSlots.deleteTimer(seqIndex);
+
+ SpriteAsset *menuItem = _menuItems[_menuItemIndex];
+ MSprite *spr = menuItem->getFrame(_frameIndex);
+
+ SpriteSlot &slot = spriteSlots[spriteSlots.add()];
+ slot._flags = IMG_UPDATE;
+ slot._seqIndex = seqIndex;
+ slot._spritesIndex = _menuItemIndexes[_menuItemIndex];
+ slot._frameNumber = _frameIndex + 1;
+ slot._position = spr->_offset;
+ slot._depth = 1;
+ slot._scale = 100;
+
+ _redrawFlag = true;
+}
+
+void MainMenu::showBonusItems() {
+ Scene &scene = _vm->_game->_scene;
+ _showEvolve = Common::File::exists("SECTION0.HAG") && Common::File::exists("evolve.res");
+ _showSets = Common::File::exists("SECTION0.HAG") && Common::File::exists("sets.res");
+
+ if (_showSets)
+ scene._kernelMessages.add(Common::Point(290, 143), 0x4140, 0, 0, 0, "S");
+ if (_showEvolve)
+ scene._kernelMessages.add(Common::Point(305, 143), 0x4140, 0, 0, 0, "E");
+}
+
+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_CUSTOM_ENGINE_ACTION_START) {
+ switch (event.customType) {
+ case kActionEscape:
+ handleAction(EXIT);
+ break;
+
+ case kActionStartGame:
+ handleAction(START_GAME);
+ break;
+
+ case kActionResumeGame:
+ handleAction(RESUME_GAME);
+ break;
+
+ case kActionShowIntro:
+ handleAction(SHOW_INTRO);
+ break;
+
+ case kActionCredits:
+ handleAction(CREDITS);
+ break;
+
+ case kActionQuotes:
+ handleAction(QUOTES);
+ break;
+
+ case kActionRestartAnimation: {
+ // Goodness knows why, but Rex has a key to restart the menuitem animations
+ // Restart the animation
+ _menuItemIndex = -1;
+ for (int i = 0; i < 6; ++i)
+ scene._spriteSlots.deleteTimer(i);
+
+ _skipFlag = false;
+ _vm->_events->hideCursor();
+ break;
+ }
+
+ default:
+ _skipFlag = true;
+ return false;
+ }
+
+ return true;
+ } else if (event.type == Common::EVENT_KEYDOWN) {
+ // Any other key skips the menu animation
+ _skipFlag = true;
+ return false;
+ }
+
+ switch (event.type) {
+ case Common::EVENT_LBUTTONDOWN:
+ if (_vm->_events->isCursorVisible()) {
+ _buttonDown = true;
+ int menuIndex = getHighlightedItem(event.mouse);
+
+ if (menuIndex != _highlightedIndex) {
+ scene._spriteSlots.deleteTimer(menuIndex);
+
+ _highlightedIndex = menuIndex;
+ if (_highlightedIndex != -1) {
+ _frameIndex = _highlightedIndex;
+ addSpriteSlot();
+ }
+ }
+ } else {
+ // Skip the menu animation
+ _skipFlag = true;
+ }
+ return true;
+
+ case Common::EVENT_MOUSEMOVE:
+ if (_buttonDown) {
+ int menuIndex = getHighlightedItem(event.mouse);
+ if (menuIndex != _highlightedIndex) {
+ if (_highlightedIndex != -1) {
+ // Revert to the unselected menu item
+ unhighlightItem();
+ }
+
+ if (menuIndex != -1) {
+ // Highlight new item
+ _highlightedIndex = menuIndex;
+ _frameIndex = _highlightedIndex;
+ addSpriteSlot();
+ }
+ }
+ }
+ break;
+
+ case Common::EVENT_LBUTTONUP:
+ _buttonDown = false;
+ if (_highlightedIndex != -1) {
+ _selectedIndex = _highlightedIndex;
+ unhighlightItem();
+ _frameIndex = 0;
+ } else if (_showSets && Common::Rect(290, 165, 300, 185).contains(event.mouse)) {
+ handleAction(SETS);
+ } else if (_showEvolve && Common::Rect(305, 165, 315, 185).contains(event.mouse)) {
+ handleAction(EVOLVE);
+ }
+
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+int MainMenu::getHighlightedItem(const Common::Point &pt) {
+ return _vm->_game->_screenObjects.scan(pt, SCREENMODE_VGA) - 1;
+}
+
+void MainMenu::unhighlightItem() {
+ // Revert to the unselected menu item
+ _vm->_game->_scene._spriteSlots.deleteTimer(_highlightedIndex);
+ _menuItemIndex = _highlightedIndex;
+ _frameIndex = 0;
+ addSpriteSlot();
+
+ _menuItemIndex = 6;
+ _highlightedIndex = -1;
+}
+
+void MainMenu::handleAction(MADSGameAction action) {
+ _vm->_events->hideCursor();
+ _breakFlag = true;
+
+ switch (action) {
+ case START_GAME:
+ // Show the difficulty dialog
+ _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY;
+ break;
+
+ case RESUME_GAME:
+ // The original resumed the most recently saved game. Instead,
+ // just show the load game scren
+ _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
+ return;
+
+ case SHOW_INTRO:
+ AnimationView::execute(_vm, "rexopen");
+ break;
+
+ case CREDITS:
+ TextView::execute(_vm, "credits");
+ return;
+
+ case QUOTES:
+ TextView::execute(_vm, "quotes");
+ return;
+
+ case SETS:
+ AnimationView::execute(_vm, "sets");
+ break;
+
+ case EVOLVE:
+ AnimationView::execute(_vm, "evolve");
+ break;
+
+ 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->markAllDirty();
+ _vm->_palette->setFullPalette(_vm->_palette->_mainPalette);
+
+ delete sceneInfo;
+
+ EventsManager &events = *_vm->_events;
+ events.setEventTarget(this);
+ events.hideCursor();
+
+ while (!_breakFlag && !_vm->shouldQuit()) {
+ _vm->_events->waitForNextFrame();
+ _vm->_game->_fx = kTransitionNone;
+
+ _breakFlag |= g_system->getMillis() >= expiryTime;
+ }
+
+ events.setEventTarget(nullptr);
+ _vm->quitGame();
+ events.pollEvents();
+}
+
+bool AdvertView::onEvent(Common::Event &event) {
+ if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START || event.type == Common::EVENT_KEYDOWN
+ || event.type == Common::EVENT_JOYBUTTON_DOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _breakFlag = true;
+ return true;
+ }
+
+ return false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void PhantomAnimationView::scriptDone() {
+ AnimationView::scriptDone();
+
+ Common::String s = getResourceName();
+ if (s == "rexend1") {
+ TextView::execute(_vm, "ending1");
+ } else if (s == "rexend2") {
+ TextView::execute(_vm, "ending2");
+ } else if (s == "rexend3") {
+ TextView::execute(_vm, "credits");
+ }
+}
+
+} // namespace Phantom
+} // namespace MADS
diff --git a/engines/mads/phantom/menu_phantom.h b/engines/mads/phantom/menu_phantom.h
new file mode 100644
index 00000000000..d68a960514c
--- /dev/null
+++ b/engines/mads/phantom/menu_phantom.h
@@ -0,0 +1,160 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_MENU_PHANTOM_H
+#define MADS_MENU_PHANTOM_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/menu_views.h"
+#include "mads/msurface.h"
+#include "mads/phantom/dialogs_phantom.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+namespace Phantom {
+
+enum MADSGameAction {
+ START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT,
+ SETS, EVOLVE
+};
+
+class MainMenu: public MenuView {
+private:
+ SpriteAsset *_menuItems[7];
+ int _menuItemIndexes[7];
+ int _menuItemIndex;
+ int _frameIndex;
+ uint32 _delayTimeout;
+ bool _skipFlag;
+ bool _showEvolve, _showSets;
+
+ /**
+ * Currently highlighted menu item
+ */
+ int _highlightedIndex;
+
+ /**
+ * 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();
+
+ /**
+ * Returns true if the Quotes item should be shown.
+ * i.e. if the player has completed the game
+ */
+ bool shouldShowQuotes();
+
+ /**
+ * Show the bonus item icons, if available
+ */
+ void showBonusItems();
+protected:
+ /**
+ * Display the menu
+ */
+ void display() override;
+
+ /**
+ * Handle the menu item animations
+ */
+ void doFrame() override;
+
+ /**
+ * Event handler
+ */
+ bool onEvent(Common::Event &event) override;
+public:
+ MainMenu(MADSEngine *vm);
+
+ ~MainMenu() override;
+};
+
+class AdvertView : public EventTarget {
+private:
+ /**
+ * Engine reference
+ */
+ MADSEngine *_vm;
+
+ /**
+ * Signals when to close the dialog
+ */
+ bool _breakFlag;
+protected:
+ /**
+ * Event handler
+ */
+ bool onEvent(Common::Event &event) override;
+public:
+ AdvertView(MADSEngine *vm);
+
+ ~AdvertView() override {}
+
+ /**
+ * Show the dialog
+ */
+ void show();
+};
+
+class PhantomAnimationView : public AnimationView {
+protected:
+ void scriptDone() override;
+public:
+ PhantomAnimationView(MADSEngine *vm) : AnimationView(vm) {}
+};
+
+class PhantomTextView : public TextView {
+public:
+ PhantomTextView(MADSEngine *vm) : TextView(vm) {}
+};
+
+} // namespace Phantom
+} // namespace MADS
+
+#endif
More information about the Scummvm-git-logs
mailing list