aboutsummaryrefslogtreecommitdiff
path: root/engines/m4
diff options
context:
space:
mode:
Diffstat (limited to 'engines/m4')
-rw-r--r--engines/m4/mads_menus.cpp113
-rw-r--r--engines/m4/mads_menus.h32
-rw-r--r--engines/m4/mads_views.cpp130
-rw-r--r--engines/m4/mads_views.h100
-rw-r--r--engines/m4/viewmgr.cpp66
-rw-r--r--engines/m4/viewmgr.h65
6 files changed, 360 insertions, 146 deletions
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp
index c9cd1b129a..8b34d2c139 100644
--- a/engines/m4/mads_menus.cpp
+++ b/engines/m4/mads_menus.cpp
@@ -701,7 +701,10 @@ void RexDialogView::onRefresh(RectList *rects, M4Surface *destSurface) {
// Add in the loaded background vertically centred
_backgroundSurface->copyTo(this, 0, (height() - MADS_SURFACE_HEIGHT) / 2);
- View::onRefresh(rects, destSurface);
+ // Check whether any of the dialog text entries need to be refreshed
+ refreshText();
+
+ MadsView::onRefresh(rects, destSurface);
}
void RexDialogView::setFrame(int frameNumber, int depth) {
@@ -753,7 +756,7 @@ void RexDialogView::addLine(const char *msg_p, Font *font, MadsTextAlignment ali
if (rec) {
strcpy(rec->text, msg_p);
rec->font = font;
- rec->field_2 = 0;
+ rec->state = 0;
rec->pos.y = top;
rec->widthAdjust = -1;
rec->in_use = true;
@@ -819,6 +822,65 @@ void RexDialogView::addQuote(Font *font, MadsTextAlignment alignment, int left,
addLine(buffer, font, alignment, left, top);
}
+/**
+ * Sets any previously created dialog text entries as clickable items
+ */
+void RexDialogView::setClickableLines() {
+ _screenObjects.clear();
+
+ for (int i = 0; i < DIALOG_LINES_SIZE; ++i) {
+ if (_dialogText[i].in_use) {
+ // Add an entry for the line
+ _screenObjects.add(Common::Rect(_dialogText[i].pos.x, _dialogText[i].pos.y,
+ _dialogText[i].pos.x + _dialogText[i].font->getWidth(_dialogText[i].text, _dialogText[i].widthAdjust),
+ _dialogText[i].pos.y + _dialogText[i].font->getHeight()), 19, i, 1);
+ }
+ }
+
+ if ((_madsVm->globals()->dialogType == DIALOG_SAVE) || (_madsVm->globals()->dialogType == DIALOG_RESTORE)) {
+ // Extra entries for the scroller areas of the Save and Restor dialogs
+ _screenObjects.add(Common::Rect(293, 26, 312, 75), LAYER_GUI, 50, 2);
+ _screenObjects.add(Common::Rect(293, 78, 312, 127), LAYER_GUI, 51, 2);
+ }
+}
+
+/**
+ * Handles creating text display objects for each dialog line initially, and when the selected state
+ * of any entry changes
+ */
+void RexDialogView::refreshText() {
+ for (uint i = 0; i < _dialogText.size(); ++i) {
+ if (!_dialogText[i].in_use)
+ continue;
+
+ // Get the item's colours
+ uint colour;
+ if (_dialogText[i].state == STATE_DESELECTED)
+ colour = 0xB0A;
+ else if (_dialogText[i].state == STATE_HIGHLIGHTED)
+ colour = 0xD0C;
+ else
+ colour = 0xF0E;
+
+ // If there's an associated text display entry, check to see if it's colour needs to change
+ if (_dialogText[i].textDisplay_index >= 0) {
+ MadsTextDisplayEntry &tdEntry = _textDisplay[_dialogText[i].textDisplay_index];
+
+ if ((tdEntry.colour1 == (colour & 0xff)) && (tdEntry.colour2 == (colour >> 8)))
+ // It's still the same, so no further action needed
+ continue;
+
+ // Flag the currently assigned text display to be expired, so it can be re-created
+ _textDisplay.expire(_dialogText[i].textDisplay_index);
+ _dialogText[i].textDisplay_index = -1;
+ }
+
+ // Create a new text display entry for the dialog text line
+ _dialogText[i].textDisplay_index = _textDisplay.add(_dialogText[i].pos.x, _dialogText[i].pos.y,
+ colour, _dialogText[i].widthAdjust, _dialogText[i].text, _dialogText[i].font);
+ }
+}
+
/*--------------------------------------------------------------------------
* RexDialogView is the Rex Nebular Game Menu dialog
*--------------------------------------------------------------------------
@@ -830,11 +892,13 @@ RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() {
_vm->_font->setFont(FONT_CONVERSATION_MADS);
addLines();
+ setClickableLines();
}
void RexGameMenuDialog::addLines() {
// Add the title
- int top = -((_vm->_font->getHeight() + 1) * 12 - 78);
+ int top = (height() - MADS_SURFACE_HEIGHT) / 2 + -((((_vm->_font->getHeight() + 2) * 6) >> 1) - 78);
+
addQuote(_vm->_font, ALIGN_CENTER, 0, top, 10);
// Loop for adding the option lines of the dialog
@@ -849,4 +913,47 @@ void RexGameMenuDialog::onRefresh(RectList *rects, M4Surface *destSurface) {
RexDialogView::onRefresh(rects, destSurface);
}
+bool RexGameMenuDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
+ bool handled = false;
+
+ // Handle various event types
+ switch (eventType) {
+ case MEVENT_LEFT_CLICK:
+ // Left mouse click
+ // TODO: Check and figure out _selectedLine
+ handled = true;
+ break;
+
+ case KEVENT_KEY:
+ // Handle standard dialog keypresses
+
+ handled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_selectedLine > 0) {
+ switch (_selectedLine) {
+ case 1:
+ _madsVm->globals()->dialogType = DIALOG_SAVE;
+ case 2:
+ _madsVm->globals()->dialogType = DIALOG_RESTORE;
+ case 3:
+ _madsVm->globals()->dialogType = DIALOG_OPTIONS;
+ default:
+ // TODO: Extra logic for such as resuming scene if necessary
+ _madsVm->globals()->dialogType = DIALOG_NONE;
+ break;
+ }
+
+ // Close this dialog
+ _madsVm->_viewManager->deleteView(this);
+ }
+
+ return handled;
+}
+
+
}
diff --git a/engines/m4/mads_menus.h b/engines/m4/mads_menus.h
index 5d3258ab46..d732723fcf 100644
--- a/engines/m4/mads_menus.h
+++ b/engines/m4/mads_menus.h
@@ -28,6 +28,7 @@
#include "common/str-array.h"
#include "m4/viewmgr.h"
+#include "m4/mads_views.h"
#include "m4/font.h"
namespace M4 {
@@ -36,6 +37,8 @@ namespace M4 {
enum MadsGameAction {START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT};
+enum MadsLayers {LAYER_GUI = 19};
+
class RexMainMenuView : public View {
private:
M4Surface *_bgSurface;
@@ -88,10 +91,12 @@ public:
void updateState();
};
+enum DialogTextState {STATE_DESELECTED = 0, STATE_HIGHLIGHTED = 1, STATE_SELECTED = 2};
+
class DialogTextEntry {
public:
bool in_use;
- int16 field_2;
+ int state;
Common::Point pos;
char text[80];
Font *font;
@@ -116,26 +121,28 @@ private:
void loadBackground();
void loadMenuSprites();
protected:
- int _word_8502C;
- int _selectedLine;
- int _lineIndex;
- bool _enterFlag;
- Common::StringArray _textLines;
-
- void setFrame(int frameNumber, int depth);
- void initVars();
- void addLine(const char *msg_p, Font *font, MadsTextAlignment alignment, int left, int top);
- void addQuote(Font *font, MadsTextAlignment alignment, int left, int top, int id1, int id2 = 0);
-protected:
M4Surface *_backgroundSurface;
RGBList *_bgPalData;
SpriteAsset *_menuSprites;
RGBList *_spritesPalData;
Common::Array<DialogTextEntry> _dialogText;
+ Common::StringArray _textLines;
int _totalTextEntries;
int _dialogSelectedLine;
Common::StringArray _saveList;
+
+ int _word_8502C;
+ int _selectedLine;
+ int _lineIndex;
+ bool _enterFlag;
+
+ void setFrame(int frameNumber, int depth);
+ void initVars();
+ void addLine(const char *msg_p, Font *font, MadsTextAlignment alignment, int left, int top);
+ void addQuote(Font *font, MadsTextAlignment alignment, int left, int top, int id1, int id2 = 0);
+ void setClickableLines();
+ void refreshText();
public:
RexDialogView();
~RexDialogView();
@@ -151,6 +158,7 @@ public:
RexGameMenuDialog();
virtual void onRefresh(RectList *rects, M4Surface *destSurface);
+ virtual bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents);
};
}
diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp
index 7aff856792..8b17a935f2 100644
--- a/engines/m4/mads_views.cpp
+++ b/engines/m4/mads_views.cpp
@@ -39,6 +39,136 @@ static const int INVENTORY_X = 160;
static const int INVENTORY_Y = 159;
static const int SCROLLER_DELAY = 200;
+//--------------------------------------------------------------------------
+
+MadsTextDisplay::MadsTextDisplay() {
+ for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) {
+ MadsTextDisplayEntry rec;
+ rec.active = false;
+ _entries.push_back(rec);
+ }
+}
+
+int MadsTextDisplay::add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font) {
+ int usedSlot = -1;
+
+ for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) {
+ if (!_entries[idx].active) {
+ usedSlot = idx;
+
+ _entries[idx].bounds.left = xp;
+ _entries[idx].bounds.top = yp;
+ _entries[idx].font = font;
+ _entries[idx].msg = msg;
+ _entries[idx].bounds.setWidth(font->getWidth(msg, charSpacing));
+ _entries[idx].bounds.setHeight(font->getHeight());
+ _entries[idx].colour1 = fontColour & 0xff;
+ _entries[idx].colour2 = fontColour >> 8;
+ _entries[idx].spacing = charSpacing;
+ _entries[idx].expire = 1;
+ _entries[idx].active = true;
+ break;
+ }
+ }
+
+ return usedSlot;
+}
+
+void MadsTextDisplay::draw(View *view) {
+ for (uint idx = 0; idx < _entries.size(); ++idx) {
+ if (_entries[idx].active && (_entries[idx].expire >= 0)) {
+ _entries[idx].font->setColours(_entries[idx].colour1, 0xFF,
+ (_entries[idx].colour2 == 0) ? _entries[idx].colour1 : _entries[idx].colour2);
+ _entries[idx].font->writeString(view, _entries[idx].msg,
+ _entries[idx].bounds.left, _entries[idx].bounds.top, _entries[idx].bounds.width(),
+ _entries[idx].spacing);
+ }
+ }
+
+ // Clear up any now text display entries that are to be expired
+ for (uint idx = 0; idx < _entries.size(); ++idx) {
+ if (_entries[idx].expire < 0) {
+ _entries[idx].active = false;
+ _entries[idx].expire = 0;
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Clears the entries list
+ */
+void ScreenObjects::clear() {
+ _entries.clear();
+}
+
+/**
+ * Adds a new entry to the list of screen objects
+ */
+void ScreenObjects::add(const Common::Rect &bounds, int layer, int idx, int category) {
+ ScreenObjectEntry rec;
+ rec.bounds = bounds;
+ rec.layer = layer;
+ rec.index = idx;
+ rec.category = category;
+ rec.active = true;
+
+ _entries.push_back(rec);
+}
+
+/**
+ * Scans the list for an element that contains the given mode. The result will be 1 based for a match,
+ * with 0 indicating no entry was found
+ */
+int ScreenObjects::scan(int xp, int yp, int layer) {
+ for (uint i = 0; i < _entries.size(); ++i) {
+ if (_entries[i].active && _entries[i].bounds.contains(xp, yp) && (_entries[i].layer == layer))
+ return i + 1;
+ }
+
+ // Entry not found
+ return 0;
+}
+
+int ScreenObjects::scanBackwards(int xp, int yp, int layer) {
+ for (uint i = _entries.size() - 1; i >= 0; --i) {
+ if (_entries[i].active && _entries[i].bounds.contains(xp, yp) && (_entries[i].layer == layer))
+ return i + 1;
+ }
+
+ // Entry not found
+ return 0;
+}
+
+void ScreenObjects::setActive(int category, int idx, bool active) {
+ for (uint i = 0; i < _entries.size(); ++i) {
+ if (_entries[i].active && (_entries[i].category == category) && (_entries[i].index == idx))
+ _entries[i].active = active;
+ }
+}
+
+//--------------------------------------------------------------------------
+
+MadsView::MadsView(MadsM4Engine *vm, const Common::Rect &viewBounds, bool transparent): View(vm, viewBounds, transparent) {
+ _spriteSlotsStart = 0;
+}
+
+MadsView::MadsView(MadsM4Engine *vm, int x, int y, bool transparent): View(vm, x, y, transparent) {
+ _spriteSlotsStart = 0;
+}
+
+int MadsView::getSpriteSlotsIndex() {
+ return _spriteSlotsStart++;
+}
+
+void MadsView::onRefresh(RectList *rects, M4Surface *destSurface) {
+ // Draw text elements onto the view
+ _textDisplay.draw(this);
+
+ View::onRefresh(rects, destSurface);
+}
+
/*--------------------------------------------------------------------------
* MadsInterfaceView handles the user interface section at the bottom of
* game screens in MADS games
diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h
index 4a80671ddc..98219e04bb 100644
--- a/engines/m4/mads_views.h
+++ b/engines/m4/mads_views.h
@@ -34,6 +34,106 @@
namespace M4 {
+class MadsSpriteSlot {
+public:
+ int spriteId;
+ int timerIndex;
+ int spriteListIndex;
+ int frameNumber;
+ int width;
+ int height;
+ int depth;
+ int scale;
+
+ MadsSpriteSlot() { };
+};
+
+#define SPRITE_SLOTS_SIZE 50
+
+class MadsTextDisplayEntry {
+public:
+ bool active;
+ int expire;
+ int spacing;
+ Common::Rect bounds;
+ uint8 colour1;
+ uint8 colour2;
+ Font *font;
+ const char *msg;
+
+ MadsTextDisplayEntry() { active = false; }
+};
+
+#define TEXT_DISPLAY_SIZE 40
+
+class MadsTextDisplay {
+private:
+ Common::Array<MadsTextDisplayEntry> _entries;
+public:
+ MadsTextDisplay();
+
+ MadsTextDisplayEntry &operator[](int idx) {
+ assert(idx < TEXT_DISPLAY_SIZE);
+ return _entries[idx];
+ }
+
+ void expire(int idx) {
+ assert(idx < TEXT_DISPLAY_SIZE);
+ _entries[idx].expire = -1;
+ }
+
+ int add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font);
+ void draw(View *view);
+};
+
+class ScreenObjectEntry {
+public:
+ Common::Rect bounds;
+ int category;
+ int index;
+ int layer;
+ bool active;
+
+ ScreenObjectEntry() { active = false; }
+};
+
+#define SCREEN_OBJECTS_SIZE
+
+class ScreenObjects {
+private:
+ Common::Array<ScreenObjectEntry> _entries;
+public:
+ ScreenObjects() {}
+
+ ScreenObjectEntry &operator[](uint idx) {
+ assert(idx < _entries.size());
+ return _entries[idx];
+ }
+
+ void clear();
+ void add(const Common::Rect &bounds, int layer, int idx, int category);
+ void draw(View *view);
+ int scan(int xp, int yp, int layer);
+ int scanBackwards(int xp, int yp, int layer);
+ void setActive(int category, int idx, bool active);
+};
+
+
+class MadsView: public View {
+protected:
+ MadsSpriteSlot _spriteSlots[SPRITE_SLOTS_SIZE];
+ MadsTextDisplay _textDisplay;
+ int _spriteSlotsStart;
+ ScreenObjects _screenObjects;
+
+ int getSpriteSlotsIndex();
+public:
+ MadsView(MadsM4Engine *vm, const Common::Rect &viewBounds, bool transparent = false);
+ MadsView(MadsM4Engine *vm, int x = 0, int y = 0, bool transparent = false);
+
+ void onRefresh(RectList *rects, M4Surface *destSurface);
+};
+
#define CHEAT_SEQUENCE_MAX 8
class IntegerList : public Common::Array<int> {
diff --git a/engines/m4/viewmgr.cpp b/engines/m4/viewmgr.cpp
index a1e9c3e584..46b4b5af9d 100644
--- a/engines/m4/viewmgr.cpp
+++ b/engines/m4/viewmgr.cpp
@@ -194,72 +194,6 @@ void View::onRefresh(RectList *rects, M4Surface *destSurface) {
//--------------------------------------------------------------------------
-MadsTextDisplay::MadsTextDisplay() {
- for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i)
- _entries[i].active = false;
-}
-
-int MadsTextDisplay::add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font) {
- int usedSlot = -1;
-
- for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) {
- if (!_entries[idx].active) {
- usedSlot = idx;
-
- _entries[idx].bounds.left = xp;
- _entries[idx].bounds.top = yp;
- _entries[idx].font = font;
- _entries[idx].msg = msg;
- _entries[idx].bounds.setWidth(font->getWidth(msg, charSpacing));
- _entries[idx].bounds.setHeight(font->getHeight());
- _entries[idx].colour1 = fontColour & 0xff;
- _entries[idx].colour2 = fontColour >> 8;
- _entries[idx].spacing = charSpacing;
- _entries[idx].active2 = 1;
- _entries[idx].active = true;
- break;
- }
- }
-
- return usedSlot;
-}
-
-void MadsTextDisplay::draw(View *view) {
- for (int idx = 0; idx < OLD_TEXT_DISPLAY_SIZE; ++idx) {
- if (_entries[idx].active && (_entries[idx].active2 >= 0)) {
- _entries[idx].font->setColours(_entries[idx].colour1, 0xFF,
- (_entries[idx].colour2 == 0) ? _entries[idx].colour1 : _entries[idx].colour2);
- _entries[idx].font->writeString(view, _entries[idx].msg,
- _entries[idx].bounds.left, _entries[idx].bounds.top, _entries[idx].bounds.width(),
- _entries[idx].spacing);
- }
- }
-
- // Clear up any now inactive text display entries
- for (int idx = 0; idx < OLD_TEXT_DISPLAY_SIZE; ++idx) {
- if (_entries[idx].active2 < 0) {
- _entries[idx].active = false;
- _entries[idx].active2 = 0;
- }
- }
-}
-
-//--------------------------------------------------------------------------
-
-MadsView::MadsView(MadsM4Engine *vm, const Common::Rect &viewBounds, bool transparent): View(vm, viewBounds, transparent) {
- _spriteSlotsStart = 0;
-}
-
-MadsView::MadsView(MadsM4Engine *vm, int x, int y, bool transparent): View(vm, x, y, transparent) {
- _spriteSlotsStart = 0;
-}
-
-int MadsView::getSpriteSlotsIndex() {
- return _spriteSlotsStart++;
-}
-
-//--------------------------------------------------------------------------
-
ViewManager::ViewManager(MadsM4Engine *vm): _systemHotkeys(HotkeyList(NULL)), _vm(vm) {
_captureScreen = NULL;
_captureEvents = false;
diff --git a/engines/m4/viewmgr.h b/engines/m4/viewmgr.h
index 308240645d..16c3d6ecc3 100644
--- a/engines/m4/viewmgr.h
+++ b/engines/m4/viewmgr.h
@@ -148,71 +148,6 @@ protected:
bool _transparent;
};
-class MadsSpriteSlot {
-public:
- int spriteId;
- int timerIndex;
- int spriteListIndex;
- int frameNumber;
- int width;
- int height;
- int depth;
- int scale;
-
- MadsSpriteSlot() { };
-};
-
-#define SPRITE_SLOTS_SIZE 50
-
-class MadsTextDisplayEntry {
-public:
- bool active;
- int spacing;
- Common::Rect bounds;
- int active2;
- uint8 colour1;
- uint8 colour2;
- Font *font;
- const char *msg;
-
- MadsTextDisplayEntry() { active = false; }
-};
-
-#define TEXT_DISPLAY_SIZE 40
-
-class MadsTextDisplay {
-private:
- MadsTextDisplayEntry _entries[TEXT_DISPLAY_SIZE];
-public:
- MadsTextDisplay();
-
- MadsTextDisplayEntry &operator[](int idx) {
- assert(idx < TEXT_DISPLAY_SIZE);
- return _entries[idx];
- }
-
- int setActive2(int idx) {
- assert(idx < TEXT_DISPLAY_SIZE);
- _entries[idx].active2 = -1;
- }
-
- int add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font);
- void draw(View *view);
-};
-
-class MadsView: public View {
-protected:
- MadsSpriteSlot _spriteSlots[SPRITE_SLOTS_SIZE];
- MadsTextDisplay _textDisplay;
- int _spriteSlotsStart;
-
- int getSpriteSlotsIndex();
-public:
- MadsView(MadsM4Engine *vm, const Common::Rect &viewBounds, bool transparent = false);
- MadsView(MadsM4Engine *vm, int x = 0, int y = 0, bool transparent = false);
-
-};
-
class ViewManager {
private:
MadsM4Engine *_vm;