From b46a2b4e100e3018d604da240cecf936c629e8a0 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 23 Mar 2010 12:02:23 +0000 Subject: Added further code for the game dialog framework svn-id: r48368 --- engines/m4/mads_menus.cpp | 179 ++++++++++++++++++++++++++++++++++++++++------ engines/m4/mads_menus.h | 22 +++++- engines/m4/mads_scene.cpp | 25 ++----- engines/m4/mads_scene.h | 4 +- engines/m4/viewmgr.cpp | 66 +++++++++++++++++ engines/m4/viewmgr.h | 66 +++++++++++++++++ 6 files changed, 316 insertions(+), 46 deletions(-) (limited to 'engines') diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp index 353b41c9a9..c9cd1b129a 100644 --- a/engines/m4/mads_menus.cpp +++ b/engines/m4/mads_menus.cpp @@ -586,22 +586,32 @@ void DragonMainMenuView::handleAction(MadsGameAction action) { *-------------------------------------------------------------------------- */ -RexDialogView::RexDialogView(): View(_madsVm, Common::Rect(0, 0, _madsVm->_screen->width(), _madsVm->_screen->height())) { +RexDialogView::RexDialogView(): MadsView(_madsVm, Common::Rect(0, 0, _madsVm->_screen->width(), _madsVm->_screen->height())) { _screenType = VIEWID_MENU; - _initialised = false; + // Store the previously active scene + _priorSceneId = _madsVm->_scene->getCurrentScene(); + + // Load necessary quotes + _madsVm->globals()->loadQuoteRange(1, 48); + + initialiseLines(); + initialiseGraphics(); +} + +void RexDialogView::initialiseLines() { // Set up a list of blank entries for use in the various dialogs for (int i = 0; i < DIALOG_LINES_SIZE; ++i) { DialogTextEntry rec; + rec.in_use = false; _dialogText.push_back(rec); } _totalTextEntries = 0; - // Store the previously active scene - _priorSceneId = _madsVm->_scene->getCurrentScene(); - - // Load necessary quotes - _madsVm->globals()->loadQuoteRange(1, 48); + // Set up a default sprite slot entry + _spriteSlotsStart = 1; + _spriteSlots[0].spriteId = -2; + _spriteSlots[0].timerIndex = -1; } void RexDialogView::initialiseGraphics() { @@ -620,20 +630,16 @@ void RexDialogView::initialiseGraphics() { // Set the current cursor _madsVm->_mouse->setCursorNum(CURSOR_ARROW); - - _initialised = true; } RexDialogView::~RexDialogView() { - if (_initialised) { - _madsVm->_palette->deleteRange(_bgPalData); - delete _bgPalData; - delete _backgroundSurface; - _madsVm->_palette->deleteRange(_spritesPalData); - delete _spritesPalData; - delete _menuSprites; - } + _madsVm->_palette->deleteRange(_bgPalData); + delete _bgPalData; + delete _backgroundSurface; + _madsVm->_palette->deleteRange(_spritesPalData); + delete _spritesPalData; + delete _menuSprites; } void RexDialogView::loadBackground() { @@ -683,9 +689,6 @@ void RexDialogView::loadMenuSprites() { void RexDialogView::updateState() { - if (!_initialised) { - initialiseGraphics(); - } } void RexDialogView::onRefresh(RectList *rects, M4Surface *destSurface) { @@ -701,11 +704,147 @@ void RexDialogView::onRefresh(RectList *rects, M4Surface *destSurface) { View::onRefresh(rects, destSurface); } +void RexDialogView::setFrame(int frameNumber, int depth) { + int slotIndex = getSpriteSlotsIndex(); + _spriteSlots[slotIndex].spriteId = 1; + _spriteSlots[slotIndex].timerIndex = 1; + _spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex; + _spriteSlots[slotIndex].frameNumber = frameNumber; + M4Sprite *spr = _menuSprites->getFrame(0); + _spriteSlots[slotIndex].width = spr->width(); + _spriteSlots[slotIndex].height = spr->height(); + _spriteSlots[slotIndex].depth = depth; + _spriteSlots[slotIndex].scale = 100; +} + +void RexDialogView::initVars() { + _word_8502C = -1; + _selectedLine = -1; + _lineIndex = 0; + _enterFlag = false; + _textLines.clear(); +} + +void RexDialogView::addLine(const char *msg_p, Font *font, MadsTextAlignment alignment, int left, int top) { + DialogTextEntry *rec = NULL; + + if (_lineIndex < _totalTextEntries) { + if (strcmp(msg_p, _dialogText[_lineIndex].text) == 0) { + rec = &_dialogText[_lineIndex]; + if (rec->textDisplay_index != 0) { + MadsTextDisplayEntry &tdEntry = _textDisplay[rec->textDisplay_index]; + if (tdEntry.active) { + if (_textLines.size() < 20) { + // Add entry to line list + _textLines.push_back(tdEntry.msg); + tdEntry.msg = _textLines[_textLines.size() - 1].c_str(); + } + } + } + } + } else { + if (_lineIndex < DIALOG_LINES_SIZE) { + rec = &_dialogText[_lineIndex]; + _totalTextEntries = _lineIndex + 1; + } + } + + // Handling for if a line needs to be added + if (rec) { + strcpy(rec->text, msg_p); + rec->font = font; + rec->field_2 = 0; + rec->pos.y = top; + rec->widthAdjust = -1; + rec->in_use = true; + rec->textDisplay_index = -1; + + switch (alignment) { + case ALIGN_CENTER: + // Center text + rec->pos.x = (width() - font->getWidth(rec->text)) / 2; + break; + + case ALIGN_CHAR_CENTER: { + // Text is center aligned on the '@' character within the string + char *p = strchr(rec->text, '@'); + + if (p) { + // '@' string handling + // Get length of string up to the '@' character + *p = '\0'; + int strWidth = font->getWidth(rec->text, rec->widthAdjust); + // Remove the character from the string. strcpy isn't used here because it's unsafe for + // copying within the same string + while ((*p == *(p + 1)) != '\0') ++p; + + rec->pos.x = (width() / 2) - strWidth; + } else { + rec->pos.x = left; + } + break; + } + + case RIGHT_ALIGN: + // Right align (moving left from given passed left) + rec->pos.x = left - font->getWidth(rec->text); + break; + + default: + break; + } + } + + ++_lineIndex; +} + +/** + * Adds a line consisting of either a single quote, or the combination of two quote Ids + */ +void RexDialogView::addQuote(Font *font, MadsTextAlignment alignment, int left, int top, int id1, int id2) { + char buffer[80]; + + // Copy the first quote string into the buffer + const char *quoteStr = _madsVm->globals()->getQuote(id1); + strcpy(buffer, quoteStr); + + // Handle the optional second quote Id + if (id2 != 0) { + quoteStr = _madsVm->globals()->getQuote(id2); + strcat(buffer, " "); + strcat(buffer, quoteStr); + } + + // Add in the generated line + addLine(buffer, font, alignment, left, top); +} + /*-------------------------------------------------------------------------- * RexDialogView is the Rex Nebular Game Menu dialog *-------------------------------------------------------------------------- */ +RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() { + setFrame(1, 2); + initVars(); + + _vm->_font->setFont(FONT_CONVERSATION_MADS); + addLines(); +} + +void RexGameMenuDialog::addLines() { + // Add the title + int top = -((_vm->_font->getHeight() + 1) * 12 - 78); + addQuote(_vm->_font, ALIGN_CENTER, 0, top, 10); + + // Loop for adding the option lines of the dialog + top += 6; + for (int idx = 0; idx < 5; ++idx) { + top += _vm->_font->getHeight() + 1; + addQuote(_vm->_font, ALIGN_CENTER, 0, top, 11 + idx); + } +} + void RexGameMenuDialog::onRefresh(RectList *rects, M4Surface *destSurface) { RexDialogView::onRefresh(rects, destSurface); } diff --git a/engines/m4/mads_menus.h b/engines/m4/mads_menus.h index 0fad0cfb76..5d3258ab46 100644 --- a/engines/m4/mads_menus.h +++ b/engines/m4/mads_menus.h @@ -104,14 +104,28 @@ public: #define DIALOG_LINES_SIZE 20 -class RexDialogView: public View { +enum MadsTextAlignment { ALIGN_CENTER = -1, ALIGN_CHAR_CENTER = -2, RIGHT_ALIGN = -3 }; + + +class RexDialogView: public MadsView { private: int _priorSceneId; - bool _initialised; + void initialiseLines(); void initialiseGraphics(); 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; @@ -131,8 +145,10 @@ public: }; class RexGameMenuDialog: public RexDialogView { +private: + void addLines(); public: - RexGameMenuDialog(): RexDialogView() {}; + RexGameMenuDialog(); virtual void onRefresh(RectList *rects, M4Surface *destSurface); }; diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index df5e6ba220..53f232472d 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -688,7 +688,7 @@ void MadsSceneResources::load(int sId) { /*--------------------------------------------------------------------------*/ MadsScreenText::MadsScreenText() { - for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) + for (int i = 0; i < OLD_TEXT_DISPLAY_SIZE; ++i) _textDisplay[i].active = false; for (int i = 0; i < TIMED_TEXT_SIZE; ++i) _timedText[i].flags = 0; @@ -701,9 +701,9 @@ MadsScreenText::MadsScreenText() { int MadsScreenText::add(const Common::Point &destPos, uint fontColours, int widthAdjust, const char *msg, Font *font) { // Find a free slot int idx = 0; - while ((idx < TEXT_DISPLAY_SIZE) && _textDisplay[idx].active) + while ((idx < OLD_TEXT_DISPLAY_SIZE) && _textDisplay[idx].active) ++idx; - if (idx == TEXT_DISPLAY_SIZE) + if (idx == OLD_TEXT_DISPLAY_SIZE) error("Ran out of text display slots"); // Set up the entry values @@ -766,27 +766,10 @@ int MadsScreenText::addTimed(const Common::Point &destPos, uint fontColours, uin * Draws any text display entries to the screen */ void MadsScreenText::draw(M4Surface *surface) { - for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { - if (_textDisplay[idx].active && (_textDisplay[idx].active2 >= 0)) { - _textDisplay[idx].font->setColours(_textDisplay[idx].colour1, 0xFF, - (_textDisplay[idx].colour2 == 0) ? _textDisplay[idx].colour1 : _textDisplay[idx].colour2); - _textDisplay[idx].font->writeString(surface, _textDisplay[idx].message, - _textDisplay[idx].bounds.left, _textDisplay[idx].bounds.top, _textDisplay[idx].bounds.width(), - _textDisplay[idx].spacing); - } - } - - // Clear up any now inactive text display entries - for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { - if (_textDisplay[idx].active2 < 0) { - _textDisplay[idx].active = false; - _textDisplay[idx].active2 = 0; - } - } } void MadsScreenText::timedDisplay() { - for (int idx = 0; !_abortTimedText && (idx < TEXT_DISPLAY_SIZE); ++idx) { + for (int idx = 0; !_abortTimedText && (idx < OLD_TEXT_DISPLAY_SIZE); ++idx) { if (((_timedText[idx].flags & TEXTFLAG_ACTIVE) != 0) && (_timedText[idx].frameTimer <= g_system->getMillis())) // Add the specified entry diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h index d5d3a5a477..b4cdbafd80 100644 --- a/engines/m4/mads_scene.h +++ b/engines/m4/mads_scene.h @@ -66,7 +66,7 @@ public: }; #define TIMED_TEXT_SIZE 10 -#define TEXT_DISPLAY_SIZE 40 +#define OLD_TEXT_DISPLAY_SIZE 40 #define TEXT_4A_SIZE 30 enum TalkTextFlags {TEXTFLAG_2 = 2, TEXTFLAG_4 = 4, TEXTFLAG_8 = 8, TEXTFLAG_40 = 0x40, @@ -104,7 +104,7 @@ struct Text4A { class MadsScreenText { private: - TextDisplay _textDisplay[TEXT_DISPLAY_SIZE]; + TextDisplay _textDisplay[OLD_TEXT_DISPLAY_SIZE]; TimedText _timedText[TIMED_TEXT_SIZE]; Text4A _text4A[TEXT_4A_SIZE]; bool _abortTimedText; diff --git a/engines/m4/viewmgr.cpp b/engines/m4/viewmgr.cpp index 46b4b5af9d..a1e9c3e584 100644 --- a/engines/m4/viewmgr.cpp +++ b/engines/m4/viewmgr.cpp @@ -194,6 +194,72 @@ 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 dccfffb8aa..308240645d 100644 --- a/engines/m4/viewmgr.h +++ b/engines/m4/viewmgr.h @@ -32,6 +32,7 @@ #include "common/events.h" #include "common/rect.h" +#include "m4/font.h" #include "m4/globals.h" #include "m4/events.h" #include "m4/graphics.h" @@ -147,6 +148,71 @@ 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; -- cgit v1.2.3