From 7e13f488abeb6a7530d591bae880fdb185c8fef1 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 7 Apr 2014 22:37:22 -0400 Subject: [PATCH] MADS: Implement loading logic for UI background animations --- engines/mads/animation.cpp | 72 ++++++++++++++++++++++--------- engines/mads/animation.h | 32 ++++++++++++-- engines/mads/game.cpp | 1 - engines/mads/game.h | 1 - engines/mads/mads.cpp | 1 + engines/mads/mads.h | 1 + engines/mads/palette.h | 13 ++++++ engines/mads/scene.cpp | 22 +++++----- engines/mads/scene.h | 2 - engines/mads/scene_data.h | 5 +++ engines/mads/screen.cpp | 6 +-- engines/mads/user_interface.cpp | 76 ++++++++++++++++++++++++++++++++- engines/mads/user_interface.h | 14 ++++++ 13 files changed, 206 insertions(+), 40 deletions(-) diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp index b557a598ed9..40abdbe26b1 100644 --- a/engines/mads/animation.cpp +++ b/engines/mads/animation.cpp @@ -108,15 +108,24 @@ void AnimMessage::load(Common::SeekableReadStream *f) { f->skip(2); } -void AnimFrameEntry::load(Common::SeekableReadStream *f) { - _frameNumber = f->readUint16LE(); - _seqIndex = f->readByte(); - _spriteSlot._spritesIndex = f->readByte(); - _spriteSlot._frameNumber = f->readUint16LE(); - _spriteSlot._position.x = f->readSint16LE(); - _spriteSlot._position.y = f->readSint16LE(); - _spriteSlot._depth = f->readSByte(); - _spriteSlot._scale = (int8)f->readByte(); +void AnimFrameEntry::load(Common::SeekableReadStream *f, bool uiFlag) { + if (uiFlag) { + f->skip(2); + _seqIndex = f->readByte(); + _spriteSlot._spritesIndex = f->readByte(); + _spriteSlot._frameNumber = f->readUint16LE(); + _spriteSlot._position.x = f->readSint16LE(); + _spriteSlot._position.y = f->readSint16LE(); + } else { + _frameNumber = f->readUint16LE(); + _seqIndex = f->readByte(); + _spriteSlot._spritesIndex = f->readByte(); + _spriteSlot._frameNumber = f->readUint16LE(); + _spriteSlot._position.x = f->readSint16LE(); + _spriteSlot._position.y = f->readSint16LE(); + _spriteSlot._depth = f->readSByte(); + _spriteSlot._scale = (int8)f->readByte(); + } } /*------------------------------------------------------------------------*/ @@ -132,6 +141,22 @@ void AnimMiscEntry::load(Common::SeekableReadStream *f) { /*------------------------------------------------------------------------*/ +void AnimUIEntry::load(Common::SeekableReadStream *f) { + _probability = f->readUint16LE(); + _imageCount = f->readUint16LE(); + _firstImage = f->readUint16LE(); + _lastImage = f->readUint16LE(); + _counter = f->readSint16LE(); + for (int i = 0; i < ANIM_SPAWN_COUNT; ++i) + _spawn[i] = f->readByte(); + for (int i = 0; i < ANIM_SPAWN_COUNT; ++i) + _spawnFrame[i] = f->readUint16LE(); + _sound = f->readUint16LE() & 0xFF; + _soundFrame = f->readUint16LE(); +} + +/*------------------------------------------------------------------------*/ + Animation *Animation::init(MADSEngine *vm, Scene *scene) { return new Animation(vm, scene); } @@ -149,7 +174,7 @@ Animation::~Animation() { if (_header._manualFlag) scene._sprites.remove(_spriteListIndexes[_header._spritesIndex]); - for (uint idx = 0; idx < _header._spriteSetsCount; ++idx) { + for (int idx = 0; idx < _header._spriteSetsCount; ++idx) { if (!_header._manualFlag || _header._spritesIndex != idx) scene._sprites.remove(_spriteListIndexes[idx]); } @@ -195,12 +220,12 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface, delete stream; if (_header._animMode == 4) - flags |= 0x4000; + flags |= PALFLAG_RESERVED; - if (flags & 0x100) { + if (flags & ANIMFLAG_LOAD_BACKGROUND) { loadInterface(interfaceSurface, depthSurface, _header, flags, palAnimData, sceneInfo); } - if (flags & 0x200) { + if (flags & ANIMFLAG_LOAD_BACKGROUND_ONLY) { // No data _header._messagesCount = 0; _header._frameEntriesCount = 0; @@ -234,7 +259,7 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface, for (int i = 0; i < _header._frameEntriesCount; i++) { AnimFrameEntry rec; - rec.load(frameStream); + rec.load(frameStream, flags & ANIMFLAG_LOAD_BACKGROUND); _frameEntries.push_back(rec); } @@ -242,14 +267,23 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface, } _miscEntries.clear(); + _uiEntries.clear(); if (_header._miscEntriesCount > 0) { // Chunk 4: Misc Data Common::SeekableReadStream *miscStream = madsPack.getItemStream(streamIndex++); - for (int i = 0; i < _header._miscEntriesCount; ++i) { - AnimMiscEntry rec; - rec.load(miscStream); - _miscEntries.push_back(rec); + if (flags & ANIMFLAG_LOAD_BACKGROUND) { + for (int i = 0; i < _header._miscEntriesCount; ++i) { + AnimUIEntry rec; + rec.load(miscStream); + _uiEntries.push_back(rec); + } + } else { + for (int i = 0; i < _header._miscEntriesCount; ++i) { + AnimMiscEntry rec; + rec.load(miscStream); + _miscEntries.push_back(rec); + } } delete miscStream; @@ -257,7 +291,7 @@ void Animation::load(UserInterface &interfaceSurface, MSurface &depthSurface, // If the animation specifies a font, then load it for access delete _font; - if (_header._flags & ANIM_CUSTOM_FONT) { + if (_header._flags & ANIMFLAG_CUSTOM_FONT) { Common::String fontName = "*" + _header._fontResource; _font = _vm->_font->getFont(fontName.c_str()); } else { diff --git a/engines/mads/animation.h b/engines/mads/animation.h index 8095bec5e03..75f14a52b34 100644 --- a/engines/mads/animation.h +++ b/engines/mads/animation.h @@ -33,7 +33,12 @@ namespace MADS { -enum AnimFlag { ANIM_CUSTOM_FONT = 0x20 }; +enum AnimFlag { + ANIMFLAG_DITHER = 0x0001, // Dither to 16 colors + ANIMFLAG_CUSTOM_FONT = 0x0020, // Load ccustom font + ANIMFLAG_LOAD_BACKGROUND = 0x0100, // Load background + ANIMFLAG_LOAD_BACKGROUND_ONLY = 0x0200 // Load background only +}; class MADSEngine; class Scene; @@ -63,7 +68,7 @@ public: /** * Loads data for the record */ - void load(Common::SeekableReadStream *f); + void load(Common::SeekableReadStream *f, bool uiFlag); }; class AnimMiscEntry { @@ -80,6 +85,26 @@ public: void load(Common::SeekableReadStream *f); }; +#define ANIM_SPAWN_COUNT 2 + +class AnimUIEntry { +public: + int _probability; + int _imageCount; + int _firstImage; + int _lastImage; + int _counter; + int _spawn[ANIM_SPAWN_COUNT]; + int _spawnFrame[ANIM_SPAWN_COUNT]; + int _sound; + int _soundFrame; + + /** + * Loads the data for the record + */ + void load(Common::SeekableReadStream *f); +}; + class AAHeader { public: int _spriteSetsCount; @@ -115,7 +140,6 @@ private: Common::Array _spriteListIndexes; Common::Array _messages; - Common::Array _frameEntries; Common::Array _miscEntries; Common::Array _spriteSets; Font *_font; @@ -153,6 +177,8 @@ private: protected: Animation(MADSEngine *vm, Scene *scene); public: + Common::Array _frameEntries; + Common::Array _uiEntries; bool _resetFlag; static Animation *init(MADSEngine *vm, Scene *scene); diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 90ea105bd16..fd0294161dd 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -52,7 +52,6 @@ Game::Game(MADSEngine *vm): _vm(vm), _surface(nullptr), _objects(vm), _priorSectionNumber = 0; _currentSectionNumber = -1; _kernelMode = KERNEL_GAME_LOAD; - _v2 = 0; _quoteEmergency = false; _vocabEmergency = false; _aaName = "*I0.AA"; diff --git a/engines/mads/game.h b/engines/mads/game.h index f41e7d248c7..e4880091ccb 100644 --- a/engines/mads/game.h +++ b/engines/mads/game.h @@ -131,7 +131,6 @@ public: VisitedScenes _visitedScenes; Scene _scene; KernelMode _kernelMode; - int _v2; int _trigger; ScreenTransition _fx; TriggerMode _triggerMode; diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 68d8579dc47..229d3fcef88 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -43,6 +43,7 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) : _textWindowStill = false; _screenFade = SCREEN_FADE_SMOOTH; _musicFlag = false; + _dithering = false; _debugger = nullptr; _dialogs = nullptr; diff --git a/engines/mads/mads.h b/engines/mads/mads.h index cf8046f8f61..4ea0758f889 100644 --- a/engines/mads/mads.h +++ b/engines/mads/mads.h @@ -104,6 +104,7 @@ public: bool _textWindowStill; ScreenFade _screenFade; bool _musicFlag; + bool _dithering; public: MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc); virtual ~MADSEngine(); diff --git a/engines/mads/palette.h b/engines/mads/palette.h index dd5eaf6c2b7..cceef094170 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -32,6 +32,19 @@ class MADSEngine; #define PALETTE_USAGE_COUNT 4 +/** + * Palette mapping options + */ +enum { + PALFLAG_BACKGROUND = 0x8000, // Loading initial background + PALFLAG_RESERVED = 0x4000, // Enable mapping reserved colors + PALFLAG_ANY_TO_CLOSEST = 0x2000, // Any color can map to closest + PALFLAG_ALL_TO_CLOSEST = 0x1000, // Any colors that can map must map + PALFLAG_TOP_COLORS = 0x0800, // Allow mapping to high four colors + PALFLAG_DEFINE_RESERVED = 0x0400, // Define initial reserved color + PALFLAG_MASK = 0xfc00 // Mask for all the palette flags +}; + struct RGB4 { byte r; byte g; diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index b178de58397..ac57e0bcbf6 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -123,8 +123,12 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) { _kernelMessages.clear(); // TODO: palletteUsage reset? setPalette(_nullPalette); + int flags = SCENEFLAG_LOAD_SHADOW; + if (_vm->_dithering) + flags |= SCENEFLAG_DITHER; + _sceneInfo = SceneInfo::init(_vm); - _sceneInfo->load(_currentSceneId, _variant, Common::String(), _vm->_game->_v2 ? 17 : 16, + _sceneInfo->load(_currentSceneId, _variant, Common::String(), flags, _depthSurface, _backgroundSurface); // Initialise palette animation for the scene @@ -143,10 +147,12 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) { _vm->_palette->_paletteUsage.load(1, 0xF); // Load interface - int flags = _vm->_game->_v2 ? 0x4101 : 0x4100; - if (!_vm->_textWindowStill) - flags |= 0x200; - + flags = PALFLAG_RESERVED | ANIMFLAG_LOAD_BACKGROUND; + if (_vm->_dithering) + flags |= ANIMFLAG_DITHER; + if (_vm->_textWindowStill) + flags |= ANIMFLAG_LOAD_BACKGROUND_ONLY; + _animationData = Animation::init(_vm, this); MSurface depthSurface; _animationData->load(_userInterface, depthSurface, prefix, flags, nullptr, nullptr); @@ -513,7 +519,7 @@ void Scene::loadAnimation(const Common::String &resName, int abortTimers) { _activeAnimation = Animation::init(_vm, this); _activeAnimation->load(interfaceSurface, depthSurface, resName, - _vm->_game->_v2 ? 1 : 0, nullptr, nullptr); + _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr); _activeAnimation->startAnimation(abortTimers); } @@ -585,8 +591,4 @@ void Scene::resetScene() { _sequences.clear(); } -void Scene::backgroundAnimation() { - warning("TODO: Scene::backgroundAnimation"); -} - } // End of namespace MADS diff --git a/engines/mads/scene.h b/engines/mads/scene.h index b0ecf111e6a..f449ededfc4 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -213,8 +213,6 @@ public: void resetScene(); - void backgroundAnimation(); - /** * Removes all the scene specific sprites fromt the sprites list, * leaving any player sprites list in place at the start of the list. diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h index 2a6032a507b..73ca21d0925 100644 --- a/engines/mads/scene_data.h +++ b/engines/mads/scene_data.h @@ -52,6 +52,11 @@ class SpriteSlot; #define TEXT_DISPLAY_MAX_SIZE 40 #define DIRTY_AREAS_SIZE (SPRITE_SLOTS_MAX_SIZE + TEXT_DISPLAY_MAX_SIZE) +enum { + SCENEFLAG_DITHER = 0x01, // Dither to 16 colors + SCENEFLAG_LOAD_SHADOW = 0x10 // Load hard shadows +}; + class VerbInit { public: int _id; diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp index 25623bc2155..683a56705a2 100644 --- a/engines/mads/screen.cpp +++ b/engines/mads/screen.cpp @@ -354,10 +354,10 @@ void ScreenObjects::check(bool scanFlag) { slot._flags = IMG_ERASE; } - // Any background animation - scene.backgroundAnimation(); + // Any background animation in the user interface + userInterface.doBackgroundAnimation(); - // Handle animating the selected inventory animation + // Handle animating the selected inventory item userInterface.inventoryAnim(); // Set the base time diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp index c371f3d837c..d7f198f3ce1 100644 --- a/engines/mads/user_interface.cpp +++ b/engines/mads/user_interface.cpp @@ -48,7 +48,7 @@ void UISlots::add(const Common::Point &pt, int frameNumber, int spritesIndex) { assert(size() < 50); UISlot ie; - ie._flags = -3; + ie._flags = IMG_OVERPRINT; ie._segmentId = IMG_TEXT_UPDATE; ie._position = pt; ie._frameNumber = frameNumber; @@ -57,6 +57,20 @@ void UISlots::add(const Common::Point &pt, int frameNumber, int spritesIndex) { push_back(ie); } +void UISlots::add(const AnimFrameEntry &frameEntry) { + assert(size() < 50); + + UISlot ie; + ie._flags = IMG_UPDATE; + ie._segmentId = frameEntry._seqIndex; + ie._spritesIndex = frameEntry._spriteSlot._spritesIndex; + ie._frameNumber = frameEntry._frameNumber; + ie._position = frameEntry._spriteSlot._position; + + push_back(ie); +} + + void UISlots::draw(bool updateFlag, bool delFlag) { Scene &scene = _vm->_game->_scene; UserInterface &userInterface = scene._userInterface; @@ -633,6 +647,66 @@ void UserInterface::inventoryAnim() { _uiSlots.push_back(slot); } +void UserInterface::doBackgroundAnimation() { + Scene &scene = _vm->_game->_scene; + Common::Array &uiEntries = scene._animationData->_uiEntries; + Common::Array &frameEntries = scene._animationData->_frameEntries; + + _noSegmentsActive = !_someSegmentsActive; + _someSegmentsActive = false; + + for (int idx = 0; idx < uiEntries.size(); ++idx) { + AnimUIEntry &uiEntry = uiEntries[idx]; + + if (uiEntry._counter < 0) { + if (uiEntry._counter == -1) { + int probabilityRandom = _vm->getRandomNumber(1, 30000); + int probability = uiEntry._probability; + if (uiEntry._probability > 30000) { + if (_noSegmentsActive) { + probability -= 30000; + } else { + probability = -1; + } + } + if (probabilityRandom <= probability) { + uiEntry._counter = uiEntry._firstImage; + _someSegmentsActive = true; + } + } else { + uiEntry._counter = uiEntry._firstImage; + _someSegmentsActive = true; + } + } else { + for (int idx2 = 0; idx2 < ANIM_SPAWN_COUNT; idx2++) { + if (uiEntry._spawnFrame[idx2] == (uiEntry._counter - uiEntry._firstImage)) { + int tempIndex = uiEntry._spawn[idx2]; + if (idx >= tempIndex) { + uiEntries[tempIndex]._counter = uiEntries[tempIndex]._firstImage; + } else { + uiEntries[tempIndex]._counter = -2; + } + _someSegmentsActive = true; + } + } + + ++uiEntry._counter; + if (uiEntry._counter > uiEntry._lastImage) { + uiEntry._counter = -1; + } else { + _someSegmentsActive = true; + } + } + } + + for (int idx = 0; idx < uiEntries.size(); ++idx) { + int imgScan = uiEntries[idx]._counter; + if (imgScan >= 0) { + _uiSlots.add(frameEntries[imgScan]); + } + } +} + void UserInterface::categoryChanged() { _highlightedItemIndex = -1; _vm->_events->initVars(); diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h index 445cd1e4871..86b5622a03f 100644 --- a/engines/mads/user_interface.h +++ b/engines/mads/user_interface.h @@ -33,6 +33,8 @@ namespace MADS { enum { IMG_SPINNING_OBJECT = 200, IMG_TEXT_UPDATE = 201 }; +class AnimFrameEntry; + class UISlot { public: int _flags; @@ -61,6 +63,11 @@ public: */ void add(const Common::Point &pt, int frameNumber, int spritesIndex); + /** + * Loads the data from an aimation frame entry + */ + void add(const AnimFrameEntry &frameEntry); + /** * Adds a special entry for full refresh of the user interface */ @@ -83,6 +90,8 @@ private: int _invFrameNumber; uint32 _scrollMilli; bool _scrollFlag; + int _noSegmentsActive; + int _someSegmentsActive; /** * Loads the elements of the user interface @@ -182,6 +191,11 @@ public: */ void noInventoryAnim(); + /** + * Handles any animation that occurs in the background of the user interface + */ + void doBackgroundAnimation(); + /** * Handles queuing a new frame of an inventory animation for drawing */