diff options
author | Paul Gilbert | 2014-03-03 23:40:23 -0500 |
---|---|---|
committer | Paul Gilbert | 2014-03-03 23:40:23 -0500 |
commit | 9e356dd945863a4c4dfa89f2a94dd1a56c2d03a6 (patch) | |
tree | 6480a01d1dfb99a7fd5f73237f9e7b523187ab34 | |
parent | 3a3a295758a87817e9d66d3c06df56859ef55529 (diff) | |
download | scummvm-rg350-9e356dd945863a4c4dfa89f2a94dd1a56c2d03a6.tar.gz scummvm-rg350-9e356dd945863a4c4dfa89f2a94dd1a56c2d03a6.tar.bz2 scummvm-rg350-9e356dd945863a4c4dfa89f2a94dd1a56c2d03a6.zip |
MADS: Implemented extra message and dirty area classes
-rw-r--r-- | engines/mads/animation.cpp | 4 | ||||
-rw-r--r-- | engines/mads/animation.h | 5 | ||||
-rw-r--r-- | engines/mads/debugger.cpp | 12 | ||||
-rw-r--r-- | engines/mads/debugger.h | 6 | ||||
-rw-r--r-- | engines/mads/font.cpp | 1 | ||||
-rw-r--r-- | engines/mads/game.cpp | 18 | ||||
-rw-r--r-- | engines/mads/game.h | 5 | ||||
-rw-r--r-- | engines/mads/messages.cpp | 384 | ||||
-rw-r--r-- | engines/mads/messages.h | 148 | ||||
-rw-r--r-- | engines/mads/module.mk | 1 | ||||
-rw-r--r-- | engines/mads/scene.cpp | 20 | ||||
-rw-r--r-- | engines/mads/scene.h | 8 | ||||
-rw-r--r-- | engines/mads/scene_data.cpp | 164 | ||||
-rw-r--r-- | engines/mads/scene_data.h | 79 |
14 files changed, 802 insertions, 53 deletions
diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp index 8ea95ee168..0546fc3d34 100644 --- a/engines/mads/animation.cpp +++ b/engines/mads/animation.cpp @@ -297,4 +297,8 @@ void Animation::loadInterface(InterfaceSurface &interfaceSurface, MSurface &dept } } +void Animation::update() { + warning("TODO: Animation::update"); +} + } // End of namespace MADS diff --git a/engines/mads/animation.h b/engines/mads/animation.h index ce145cdd35..1f0e1fda65 100644 --- a/engines/mads/animation.h +++ b/engines/mads/animation.h @@ -135,6 +135,11 @@ public: */ void load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, const Common::String &resName, int flags, Common::Array<RGB4> *palAnimData, SceneInfo *sceneInfo); + + /** + * Update the animation + */ + void update(); }; } // End of namespace MADS diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp index ceaeeaa5dd..34b12c1680 100644 --- a/engines/mads/debugger.cpp +++ b/engines/mads/debugger.cpp @@ -26,6 +26,8 @@ namespace MADS { Debugger::Debugger(MADSEngine *vm) : GUI::Debugger(), _vm(vm) { + _showMousePos = false; + DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); } /* @@ -46,4 +48,14 @@ static int strToInt(const char *s) { } */ +bool Debugger::Cmd_Mouse(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("Format: mouse [ on | off ]\n"); + } else { + _showMousePos = strcmp(argv[1], "on") == 0; + } + + return true; +} + } // End of namespace MADS diff --git a/engines/mads/debugger.h b/engines/mads/debugger.h index 044151c0bb..983b9931fc 100644 --- a/engines/mads/debugger.h +++ b/engines/mads/debugger.h @@ -33,11 +33,13 @@ class MADSEngine; class Debugger : public GUI::Debugger { private: MADSEngine *_vm; +protected: + bool Cmd_Mouse(int argc, const char **argv); +public: + bool _showMousePos; public: Debugger(MADSEngine *vm); virtual ~Debugger() {} - -protected: }; } // End of namespace MADS diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp index 10d51fbbc0..0ff01905ce 100644 --- a/engines/mads/font.cpp +++ b/engines/mads/font.cpp @@ -93,7 +93,6 @@ void Font::setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4) { _fontColors[0] = v1; _fontColors[1] = v2; _fontColors[2] = v3; - _fontColors[3] = v4; } int Font::write(MSurface *surface, const Common::String &msg, const Common::Point &pt, int width, int spaceWidth, uint8 colors[]) { diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 37027685dd..479c48cc2f 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -278,4 +278,22 @@ void Game::loadResourceSequence(const Common::String prefix, int v) { warning("TODO: loadResourceSequence"); } +Common::String Game::getQuote(int quoteId) { + if (_quotes && *_quotes) { + // Loop through the list of quotes + char *p = (char *)_quotes; + while (*p) { + // Get a pointer to the quote Id after the string + char *idP = p + strlen(p) + 1; + if (READ_LE_UINT16(idP) == quoteId) + // Found the correct string, so return it + return Common::String(p); + + p = idP + 2; + } + } + + return Common::String(); +} + } // End of namespace MADS diff --git a/engines/mads/game.h b/engines/mads/game.h index 148fc121cd..47eed34393 100644 --- a/engines/mads/game.h +++ b/engines/mads/game.h @@ -124,6 +124,11 @@ public: * Run the game */ void run(); + + /** + * Get a quote + */ + Common::String getQuote(int quoteId); }; } // End of namespace MADS diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp new file mode 100644 index 0000000000..c08f29fd91 --- /dev/null +++ b/engines/mads/messages.cpp @@ -0,0 +1,384 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "mads/mads.h" +#include "mads/font.h" +#include "mads/graphics.h" +#include "mads/messages.h" +#include "mads/scene_data.h" + +namespace MADS { + +KernelMessages::KernelMessages(MADSEngine *vm): _vm(vm) { + Scene &scene = _vm->_game->_scene; + + for (int i = 0; i < KERNEL_MESSAGES_SIZE; ++i) { + KernelMessage rec; + _entries.push_back(rec); + } + + scene._textSpacing = -1; + _talkFont = _vm->_font->getFont(FONT_CONVERSATION); + word_8469E = 0; +} + +void KernelMessages::clear() { + Scene &scene = _vm->_game->_scene; + + for (uint i = 0; i < _entries.size(); ++i) + _entries[i]._flags = 0; + + scene._textSpacing = -1; + _talkFont = _vm->_font->getFont(FONT_CONVERSATION); +} + +int KernelMessages::add(const Common::Point &pt, uint fontColor, uint8 flags, + uint8 abortTimers, uint32 timeout, const Common::String &msg) { + Scene &scene = _vm->_game->_scene; + + // Find a free slot + uint idx = 0; + while ((idx < _entries.size()) && ((_entries[idx]._flags & KMSG_ACTIVE) != 0)) + ++idx; + if (idx == _entries.size()) { + if (abortTimers == 0) + return -1; + + error("KernelMessages overflow"); + } + + KernelMessage &rec = _entries[idx]; + rec._msg = msg; + rec._flags = flags | KMSG_ACTIVE; + rec._color1 = fontColor & 0xff; + rec._color2 = fontColor >> 8; + rec._position = pt; + rec._textDisplayIndex = -1; + rec._timeout = timeout; + rec._frameTimer = _vm->_game->_currentTimer; + rec._abortTimers = abortTimers; + rec._abortMode = _vm->_game->_abortTimersMode2; + + rec._actionDetails = scene._action._activeAction; + + if (flags & KMSG_PLAYER_TIMEOUT) + rec._frameTimer = _vm->_game->_player._ticksAmount + + _vm->_game->_player._priorTimer; + + return idx; +} + +int KernelMessages::addQuote(int quoteId, int abortTimers, uint32 timeout) { + Common::String quoteStr = _vm->_game->getQuote(quoteId); + return add(Common::Point(), 0x1110, KMSG_PLAYER_TIMEOUT | KMSG_CENTER_ALIGN, abortTimers, timeout, quoteStr); +} + +void KernelMessages::scrollMessage(int msgIndex, int numTicks, bool quoted) { + if (msgIndex < 0) + return; + + _entries[msgIndex]._flags |= quoted ? (KMSG_SCROLL | KMSG_QUOTED) : KMSG_SCROLL; + _entries[msgIndex]._msgOffset = 0; + _entries[msgIndex]._numTicks = numTicks; + _entries[msgIndex]._frameTimer2 = _vm->_game->_currentTimer; + + Common::String msg = _entries[msgIndex]._msg; + _entries[msgIndex]._asciiChar = msg[0]; + _entries[msgIndex]._asciiChar2 = msg[1]; + + if (_entries[msgIndex]._flags & KMSG_PLAYER_TIMEOUT) + _entries[msgIndex]._frameTimer2 = _vm->_game->_player._ticksAmount + + _vm->_game->_player._priorTimer; + + _entries[msgIndex]._frameTimer = _entries[msgIndex]._frameTimer2; +} + +void KernelMessages::setSeqIndex(int msgIndex, int seqIndex) { + if (msgIndex >= 0) { + _entries[msgIndex]._flags |= KMSG_SEQ_ENTRY; + _entries[msgIndex]._sequenceIndex = seqIndex; + } +} + +void KernelMessages::remove(int msgIndex) { + KernelMessage &rec = _entries[msgIndex]; + Scene &scene = _vm->_game->_scene; + + if (rec._flags & KMSG_ACTIVE) { + if (rec._flags & KMSG_SCROLL) { + rec._msg.setChar(rec._asciiChar, rec._msgOffset); + rec._msg.setChar(rec._asciiChar2, rec._msgOffset + 1); + } + + if (rec._textDisplayIndex >= 0) + scene._textDisplay.expire(rec._textDisplayIndex); + + rec._flags &= ~KMSG_ACTIVE; + } +} + +void KernelMessages::reset() { + for (uint i = 0; i < _entries.size(); ++i) + remove(i); + + warning("TODO: KernelMessages::reset - sub_20454"); +} + +void KernelMessages::update() { + uint32 currentTimer = _vm->_game->_currentTimer; + + for (uint i = 0; i < _entries.size(); ++i) { + if (((_entries[i]._flags & KMSG_ACTIVE) != 0) && + (currentTimer >= _entries[i]._frameTimer)) + processText(i); + } +} + +void KernelMessages::processText(int msgIndex) { + Scene &scene = _vm->_game->_scene; + KernelMessage &msg = _entries[msgIndex]; + uint32 currentTimer = _vm->_game->_currentTimer; + bool flag = false; + + if ((msg._flags & KMSG_EXPIRE) != 0) { + scene._textDisplay.expire(msg._textDisplayIndex); + msg._flags &= !KMSG_ACTIVE; + return; + } + + if ((msg._flags & KMSG_SCROLL) == 0) { + msg._timeout -= 3; + } + + if (msg._flags & KMSG_SEQ_ENTRY) { + SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex]; + if (seqEntry._doneFlag || !seqEntry._active) + msg._timeout = 0; + } + + if ((msg._timeout <= 0) && (_vm->_game->_abortTimers == 0)) { + msg._flags |= KMSG_EXPIRE; + if (msg._abortTimers != 0) { + _vm->_game->_abortTimers = msg._abortTimers; + _vm->_game->_abortTimersMode = msg._abortMode; + + if (_vm->_game->_abortTimersMode != ABORTMODE_1) { + scene._action._activeAction = msg._actionDetails; + } + } + } + + msg._frameTimer = currentTimer + 3; + int x1 = 0, y1 = 0; + + if (msg._flags & KMSG_SEQ_ENTRY) { + SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex]; + if (!seqEntry._nonFixed) { + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(seqEntry._spritesIndex); + MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1); + x1 = frame->getBounds().left; + y1 = frame->getBounds().top; + } else { + x1 = seqEntry._msgPos.x; + y1 = seqEntry._msgPos.y; + } + } + + if (msg._flags & KMSG_PLAYER_TIMEOUT) { + if (word_8469E != 0) { + warning("TODO: KernelMessages::processText"); + // TODO: Figure out various flags + } else { + x1 = 160; + y1 = 78; + } + } + + x1 += msg._position.x; + y1 += msg._position.y; + + if ((msg._flags & KMSG_SCROLL) && (msg._frameTimer >= currentTimer)) { + msg._msg.setChar(msg._asciiChar, msg._msgOffset); + + ++msg._msgOffset; + msg._msg.setChar(msg._asciiChar2, msg._msgOffset); + msg._asciiChar = msg._msg[msg._msgOffset]; + msg._asciiChar2 = msg._msg[msg._msgOffset + 1]; + + if (!msg._asciiChar) { + // End of message + msg._msg.setChar('\0', msg._msgOffset); + msg._flags &= ~KMSG_SCROLL; + } else if (msg._flags & KMSG_QUOTED) { + msg._msg.setChar('"', msg._msgOffset); + msg._msg.setChar('\0', msg._msgOffset + 1); + } + + msg._frameTimer = msg._frameTimer2 = currentTimer + msg._numTicks; + flag = true; + } + + int strWidth = _talkFont->getWidth(msg._msg, scene._textSpacing); + + if (msg._flags & (KMSG_RIGHT_ALIGN | KMSG_CENTER_ALIGN)) { + x1 -= (msg._flags & KMSG_CENTER_ALIGN) ? strWidth / 2 : strWidth; + } + + // Make sure text appears entirely on-screen + int x2 = x1 + strWidth; + if (x2 > MADS_SCREEN_WIDTH) + x1 -= x2 - MADS_SCREEN_WIDTH; + if (x1 > (MADS_SCREEN_WIDTH - 1)) + x1 = MADS_SCREEN_WIDTH - 1; + if (x1 < 0) + x1 = 0; + + if (y1 >(MADS_SCENE_HEIGHT - 1)) + y1 = MADS_SCENE_HEIGHT - 1; + if (y1 < 0) + y1 = 0; + + if (msg._textDisplayIndex >= 0) { + TextDisplay &textEntry = scene._textDisplay[msg._textDisplayIndex]; + + if (flag || (textEntry._bounds.left != x1) || (textEntry._bounds.top != y1)) { + // Mark the associated text entry as deleted, so it can be re-created + scene._textDisplay.expire(msg._textDisplayIndex); + msg._textDisplayIndex = -1; + } + } + + if (msg._textDisplayIndex < 0) { + // Need to create a new text display entry for this message + int idx = scene._textDisplay.add(x1, y1, msg._color1 | (msg._color2 << 8), + scene._textSpacing, msg._msg, _talkFont); + if (idx >= 0) + msg._textDisplayIndex = idx; + } +} + +/*------------------------------------------------------------------------*/ + +TextDisplay::TextDisplay() { + _active = false; + _expire = 0; + _spacing = 0; + _color1 = 0; + _color2 = 0; + _font = nullptr; +} + +/*------------------------------------------------------------------------*/ + +TextDisplayList::TextDisplayList(MADSEngine *vm) : _vm(vm) { + for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) { + TextDisplay rec; + rec._active = false; + rec._expire = 0; + _entries.push_back(rec); + } +} + +void TextDisplayList::clear() { + for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) + _entries[i]._active = false; +} + +int TextDisplayList::add(int xp, int yp, uint fontColor, int charSpacing, + const Common::String &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]._color1 = fontColor & 0xff; + _entries[idx]._color2 = fontColor >> 8; + _entries[idx]._spacing = charSpacing; + _entries[idx]._expire = 1; + _entries[idx]._active = true; + break; + } + } + + return usedSlot; +} + +void TextDisplayList::setDirtyAreas() { + Scene &scene = _vm->_game->_scene; + + for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) { + if ((_entries[idx]._expire >= 0) || !_entries[idx]._active) + scene._dirtyAreas[dirtyIdx]._active = false; + else { + scene._dirtyAreas[dirtyIdx]._textActive = true; + scene._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]); + } + } +} + +void TextDisplayList::setDirtyAreas2() { + Scene &scene = _vm->_game->_scene; + + for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) { + if (_entries[idx]._active && (_entries[idx]._expire >= 0)) { + scene._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]); + scene._dirtyAreas[dirtyIdx]._textActive = (_entries[idx]._expire <= 0) ? 0 : 1; + } + } +} + +void TextDisplayList::draw(MSurface *view) { + error("TODO"); + /* + for (uint idx = 0; idx < _entries.size(); ++idx) { + if (_entries[idx]._active && (_entries[idx]._expire >= 0)) { + _entries[idx]._font->setColors(_entries[idx]._color1, _entries[idx]._color2, 0); + _entries[idx]._font->writeString(view, _entries[idx]._msg, + Common::Point(_entries[idx]._bounds.left, _entries[idx]._bounds.top), + _entries[idx]._bounds.width(), _entries[idx]._spacing); + } + } + */ +} + +void TextDisplayList::cleanUp() { + for (uint idx = 0; idx < _entries.size(); ++idx) { + if (_entries[idx]._expire < 0) { + _entries[idx]._active = false; + _entries[idx]._expire = 0; + } + } +} + +void TextDisplayList::expire(int idx) { + _entries[idx]._expire = -1; +} + +} // End of namespace MADS diff --git a/engines/mads/messages.h b/engines/mads/messages.h new file mode 100644 index 0000000000..b60ca8cedc --- /dev/null +++ b/engines/mads/messages.h @@ -0,0 +1,148 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MADS_MESSAGES_H +#define MADS_MESSAGES_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "mads/action.h" +#include "mads/font.h" +#include "mads/msurface.h" + +namespace MADS { + +#define KERNEL_MESSAGES_SIZE 10 +#define INDEFINITE_TIMEOUT 9999999 +#define TEXT_DISPLAY_SIZE 40 + +enum KernelMessageFlags { + KMSG_QUOTED = 1, KMSG_PLAYER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8, + KMSG_RIGHT_ALIGN = 0x10, KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40, + KMSG_ACTIVE = 0x80 +}; + +class MADSEngine; + +class KernelMessage { +public: + uint8 _flags; + int _sequenceIndex; + char _asciiChar; + char _asciiChar2; + int _color1; + int _color2; + Common::Point _position; + int _textDisplayIndex; + int _msgOffset; + int _numTicks; + uint32 _frameTimer2; + uint32 _frameTimer; + uint32 _timeout; + int _abortTimers; + AbortTimerMode _abortMode; + ActionDetails _actionDetails; + Common::String _msg; + + KernelMessage(); +}; + +class KernelMessages { +private: + MADSEngine *_vm; + Common::Array<KernelMessage> _entries; + Font *_talkFont; +public: + int word_8469E; +public: + KernelMessages(MADSEngine *vm); + + void clear(); + int add(const Common::Point &pt, uint fontColor, uint8 flags, uint8 abortTimers, + uint32 timeout, const Common::String &msg); + int addQuote(int quoteId, int abortTimers, uint32 timeout); + void scrollMessage(int msgIndex, int numTicks, bool quoted); + void setSeqIndex(int msgIndex, int seqIndex); + void remove(int msgIndex); + void reset(); + void update(); + void processText(int msgIndex); +}; + +class TextDisplay { +public: + bool _active; + int _expire; + int _spacing; + Common::Rect _bounds; + uint8 _color1; + uint8 _color2; + Font *_font; + Common::String _msg; + + TextDisplay(); +}; + +#define TEXT_DISPLAY_SIZE 40 + +class TextDisplayList { +private: + MADSEngine *_vm; + Common::Array<TextDisplay> _entries; + + /** + * Determine dirty areas for active text areas + */ + void setDirtyAreas2(); +public: + TextDisplayList(MADSEngine *vm); + + /** + * Item operator + */ + TextDisplay &operator[](int idx) { + return _entries[idx]; + } + + /** + * Expire a given text display entry + */ + void expire(int idx); + + int add(int xp, int yp, uint fontColor, int charSpacing, const Common::String &, Font *font); + void clear(); + void draw(MSurface *view); + + /** + * Determine dirty areas for active text areas + */ + void setDirtyAreas(); + + /** + * Deactivates any text display entries that are finished + */ + void cleanUp(); +}; + +} // End of namespace MADS + +#endif /* MADS_MESSAGES_H */ diff --git a/engines/mads/module.mk b/engines/mads/module.mk index 826e54f8fd..36d0c49ff7 100644 --- a/engines/mads/module.mk +++ b/engines/mads/module.mk @@ -19,6 +19,7 @@ MODULE_OBJS := \ game_data.o \ graphics.o \ mads.o \ + messages.o \ msprite.o \ msurface.o \ palette.o \ diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index 6efbdf5072..a0888f7d68 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -29,8 +29,8 @@ namespace MADS { Scene::Scene(MADSEngine *vm): _vm(vm), _spriteSlots(vm), _action(_vm), - _dynamicHotspots(vm), _screenObjects(vm), _interface(vm), - _sequences(vm) { + _dirtyAreas(_vm), _dynamicHotspots(vm), _interface(vm), _messages(vm), + _screenObjects(vm), _sequences(vm), _textDisplay(vm) { _priorSceneId = 0; _nextSceneId = 0; _currentSceneId = 0; @@ -45,6 +45,8 @@ Scene::Scene(MADSEngine *vm): _vm(vm), _spriteSlots(vm), _action(_vm), _reloadSceneFlag = false; _destFacing = 0; _freeAnimationFlag = false; + _animation = nullptr; + _activeAnimation = nullptr; _verbList.push_back(VerbInit(VERB_LOOK, 2, 0)); _verbList.push_back(VerbInit(VERB_TAKE, 2, 0)); @@ -356,9 +358,21 @@ void Scene::doFrame() { _vm->_events->setCursor(cursorId); } - if (!_vm->_game->_abortTimers) + if (!_vm->_game->_abortTimers) { + // Handle any active sequences _sequences.tick(); + // Handle any active animation + if (_activeAnimation) + _activeAnimation->update(); + } + + // If the debugget flag is set, show the mouse position + if (_vm->_debugger->_showMousePos) { + Common::Point pt = _vm->_events->mousePos(); + Common::String msg = Common::String::format("(%d,%d)", pt.x, pt.y); + _messages.add(Common::Point(5, 5), 0x203, 0, 0, 1, msg); + } // TODO: Rest of Scene::doFrame } diff --git a/engines/mads/scene.h b/engines/mads/scene.h index 71bfe317d9..f6eecbf093 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -27,6 +27,7 @@ #include "common/array.h" #include "common/rect.h" #include "mads/assets.h" +#include "mads/messages.h" #include "mads/msurface.h" #include "mads/scene_data.h" #include "mads/animation.h" @@ -78,7 +79,7 @@ public: int _nextSceneId; int _currentSceneId; Common::Array<VerbInit> _verbList; - Common::Array<TextDisplay> _textDisplay; + TextDisplayList _textDisplay; SpriteSlots _spriteSlots; SpriteSets _sprites; int _spritesIndex; @@ -86,11 +87,12 @@ public: byte *_vocabBuffer; Common::Array<int> _activeVocabs; SequenceList _sequences; - Common::Array<KernelMessage> _messages; + KernelMessages _messages; Common::String _talkFont; int _textSpacing; Common::Array<Hotspot> _hotspots; ScreenObjects _screenObjects; + DirtyAreas _dirtyAreas; int _v1; SceneInfo *_sceneInfo; MSurface _backgroundSurface; @@ -104,6 +106,7 @@ public: SceneNodeList _nodes; Common::StringArray _vocabStrings; Animation *_animation; + Animation *_activeAnimation; bool _freeAnimationFlag; int _depthStyle; int _bandsRange; @@ -118,6 +121,7 @@ public: bool _reloadSceneFlag; Common::Point _destPos; int _destFacing; + Common::Point _posAdjust; /** * Constructor diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp index 6fa2f5b326..985b961e00 100644 --- a/engines/mads/scene_data.cpp +++ b/engines/mads/scene_data.cpp @@ -202,11 +202,152 @@ int SpriteSets::add(SpriteAsset *asset, int idx) { /*------------------------------------------------------------------------*/ -TextDisplay::TextDisplay() { - _active = false; - _spacing = 0; - _expire = 0; - _col1 = _col2 = 0; +void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) { + if (_bounds.left % 2) { + --_bounds.left; + ++width; + } + + if (_bounds.left < 0) + _bounds.left = 0; + else if (_bounds.left > maxWidth) + _bounds.left = maxWidth; + int right = _bounds.left + width; + if (right < 0) + right = 0; + if (right > maxWidth) + right = maxWidth; + + _bounds.right = right; + _bounds2.left = _bounds.width() / 2; + _bounds2.right = _bounds.left + (_bounds.width() + 1) / 2 - 1; + + if (_bounds.top < 0) + _bounds.top = 0; + else if (_bounds.top > maxHeight) + _bounds.top = maxHeight; + int bottom = _bounds.top + height; + if (bottom < 0) + bottom = 0; + if (bottom > maxHeight) + bottom = maxHeight; + + _bounds.bottom = bottom; + _bounds2.top = _bounds.height() / 2; + _bounds2.bottom = _bounds.top + (_bounds.height() + 1) / 2 - 1; + + _active = true; +} + +/*------------------------------------------------------------------------*/ + +DirtyAreas::DirtyAreas(MADSEngine *vm) : _vm(vm) { + for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) { + DirtyArea rec; + rec._active = false; + _entries.push_back(rec); + } +} + +void DirtyAreas::setSpriteSlot(int dirtyIdx, const SpriteSlot &spriteSlot) { + int width, height; + DirtyArea &dirtyArea = _entries[dirtyIdx]; + Scene &scene = _vm->_game->_scene; + + if (spriteSlot._spriteType == ST_FULL_SCREEN_REFRESH) { + // Special entry to refresh the entire screen + dirtyArea._bounds.left = 0; + dirtyArea._bounds.top = 0; + width = MADS_SCREEN_WIDTH; + height = MADS_SCENE_HEIGHT; + } else { + // Standard sprite slots + dirtyArea._bounds.left = spriteSlot._position.x - scene._posAdjust.x; + dirtyArea._bounds.top = spriteSlot._position.y - scene._posAdjust.y; + + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(spriteSlot._spritesIndex); + MSprite *frame = spriteSet.getFrame(((spriteSlot._frameNumber & 0x7fff) - 1) & 0x7f); + + if (spriteSlot._scale == -1) { + width = frame->getWidth(); + height = frame->getHeight(); + } else { + width = frame->getWidth() * spriteSlot._scale / 100; + height = frame->getHeight() * spriteSlot._scale / 100; + + dirtyArea._bounds.left -= width / 2; + dirtyArea._bounds.top += -(height - 1); + } + } + + dirtyArea.setArea(width, height, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); +} + +void DirtyAreas::setTextDisplay(int dirtyIdx, const TextDisplay &textDisplay) { + DirtyArea &dirtyArea = _entries[dirtyIdx]; + dirtyArea._bounds.left = textDisplay._bounds.left; + dirtyArea._bounds.top = textDisplay._bounds.top; + + dirtyArea.setArea(textDisplay._bounds.width(), textDisplay._bounds.height(), + MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); +} + +void DirtyAreas::merge(int startIndex, int count) { + error("TODO: DirtyAreas::merge"); + if (startIndex >= count) + return; + + for (int outerCtr = startIndex - 1, idx = 0; idx < count; ++outerCtr, ++idx) { + if (!_entries[outerCtr]._active) + continue; + + for (int innerCtr = outerCtr + 1; innerCtr < count; ++innerCtr) { + if (!_entries[innerCtr]._active || !intersects(outerCtr, innerCtr)) + continue; + + if (_entries[outerCtr]._textActive && _entries[innerCtr]._textActive) + mergeAreas(outerCtr, innerCtr); + } + } +} + +/** +* Returns true if two dirty areas intersect +*/ +bool DirtyAreas::intersects(int idx1, int idx2) { + return _entries[idx1]._bounds2.intersects(_entries[idx2]._bounds2); +} + +void DirtyAreas::mergeAreas(int idx1, int idx2) { + DirtyArea &da1 = _entries[idx1]; + DirtyArea &da2 = _entries[idx2]; + + da1._bounds.extend(da2._bounds); + + da1._bounds2.left = da1._bounds.width() / 2; + da1._bounds2.right = da1._bounds.left + (da1._bounds.width() + 1) / 2 - 1; + da1._bounds2.top = da1._bounds.height() / 2; + da1._bounds2.bottom = da1._bounds.top + (da1._bounds.height() + 1) / 2 - 1; + + da2._active = false; + da1._textActive = true; +} + +void DirtyAreas::copy(MSurface *dest, MSurface *src, const Common::Point &posAdjust) { + for (uint i = 0; i < _entries.size(); ++i) { + const Common::Rect &srcBounds = _entries[i]._bounds; + + Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y, + srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y); + + if (_entries[i]._active && _entries[i]._bounds.isValidRect()) + src->copyTo(dest, bounds, Common::Point(_entries[i]._bounds.left, _entries[i]._bounds.top)); + } +} + +void DirtyAreas::clear() { + for (uint i = 0; i < _entries.size(); ++i) + _entries[i]._active = false; } /*------------------------------------------------------------------------*/ @@ -315,18 +456,21 @@ void DynamicHotspots::refresh() { KernelMessage::KernelMessage() { _flags = 0; - _seqInex = 0; + _sequenceIndex = 0; _asciiChar = '\0'; _asciiChar2 = '\0'; - _colors = 0; + _color1 = 0; + _color2 = 0; _msgOffset = 0; _numTicks = 0; _frameTimer2 = 0; _frameTimer = 0; _timeout = 0; - _field1C = 0; - _abortMode = 0; - _nounList[0] = _nounList[1] = _nounList[2] = 0; + _abortTimers = 0; + _abortMode = ABORTMODE_0; + _actionDetails._verbId = 0; + _actionDetails._objectNameId = 0; + _actionDetails._indirectObjectId = 0; } /*------------------------------------------------------------------------*/ diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h index dc59bff4cf..f26069ca7e 100644 --- a/engines/mads/scene_data.h +++ b/engines/mads/scene_data.h @@ -32,6 +32,7 @@ #include "mads/assets.h" #include "mads/events.h" #include "mads/game_data.h" +#include "mads/messages.h" namespace MADS { @@ -44,6 +45,9 @@ class Scene; #define DEPTH_BANDS_SIZE 15 #define MAX_ROUTE_NODES 22 +#define DIRTY_AREAS_SIZE 90 +#define DIRTY_AREAS_TEXT_DISPLAY_IDX 50 + enum ScrCategory { CAT_NONE = 0, CAT_ACTION = 1, CAT_INV_LIST = 2, CAT_INV_VOCAB = 3, CAT_HOTSPOT = 4, CAT_INV_ANIM = 5, CAT_6 = 6, CAT_INV_SCROLLER = 7, @@ -175,20 +179,6 @@ public: int add(SpriteAsset *asset, int idx = 0); }; -class TextDisplay { -public: - bool _active; - int _spacing; - Common::Rect _bounds; - int _expire; - int _col1; - int _col2; - Common::String _fontName; - Common::String _msg; - - TextDisplay(); -}; - class DynamicHotspot { public: bool _active; @@ -226,27 +216,6 @@ public: void refresh(); }; -class KernelMessage { -public: - int _flags; - int _seqInex; - char _asciiChar; - char _asciiChar2; - int _colors; - Common::Point _posiition; - int _msgOffset; - int _numTicks; - int _frameTimer2; - int _frameTimer; - int _timeout; - int _field1C; - int _abortMode; - int _nounList[3]; - Common::String _msg; - - KernelMessage(); -}; - class Hotspot { public: Common::Rect _bounds; @@ -261,6 +230,46 @@ public: Hotspot(Common::SeekableReadStream &f); }; +class DirtyArea { +public: + Common::Rect _bounds; + Common::Rect _bounds2; + bool _textActive; + bool _active; + + DirtyArea() { _active = false; } + void setArea(int width, int height, int maxWidth, int maxHeight); +}; + +class DirtyAreas { +private: + MADSEngine *_vm; + Common::Array<DirtyArea> _entries; +public: + DirtyAreas(MADSEngine *vm); + + DirtyArea &operator[](uint idx) { + assert(idx < _entries.size()); + return _entries[idx]; + } + + void setSpriteSlot(int dirtyIdx, const SpriteSlot &spriteSlot); + + void setTextDisplay(int dirtyIdx, const TextDisplay &textDisplay); + + /** + * Merge together any designated dirty areas that overlap + * @param startIndex 1-based starting dirty area starting index + * @param count Number of entries to process + */ + void merge(int startIndex, int count); + + bool intersects(int idx1, int idx2); + void mergeAreas(int idx1, int idx2); + void copy(MSurface *dest, MSurface *src, const Common::Point &posAdjust); + void clear(); +}; + class SceneLogic { protected: Scene *_scene; |