aboutsummaryrefslogtreecommitdiff
path: root/engines/mads/scene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mads/scene.cpp')
-rw-r--r--engines/mads/scene.cpp735
1 files changed, 735 insertions, 0 deletions
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
new file mode 100644
index 0000000000..ee5f1a5440
--- /dev/null
+++ b/engines/mads/scene.cpp
@@ -0,0 +1,735 @@
+/* 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/scene.h"
+#include "mads/compression.h"
+#include "mads/mads.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+Scene::Scene(MADSEngine *vm)
+ : _vm(vm), _action(_vm), _depthSurface(),
+ _dirtyAreas(_vm), _dynamicHotspots(vm), _hotspots(vm),
+ _kernelMessages(vm), _sequences(vm), _sprites(vm), _spriteSlots(vm),
+ _textDisplay(vm), _userInterface(vm) {
+ _priorSceneId = 0;
+ _nextSceneId = 0;
+ _currentSceneId = 0;
+ _sceneLogic = nullptr;
+ _sceneInfo = nullptr;
+ _cyclingActive = false;
+ _cyclingThreshold = 0;
+ _cyclingDelay = 0;
+ _totalCycleColors = 0;
+ _depthStyle = 0;
+ _roomChanged = false;
+ _reloadSceneFlag = false;
+ _freeAnimationFlag = false;
+ _animationData = nullptr;
+ _activeAnimation = nullptr;
+ _textSpacing = -1;
+ _frameStartTime = 0;
+ _mode = SCREENMODE_VGA;
+ _lookFlag = false;
+ _bandsRange = 0;
+ _scaleRange = 0;
+ _interfaceY = 0;
+ _spritesCount = 0;
+ _variant = 0;
+
+ _paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF));
+
+ // Set up a scene surface that maps to our physical screen drawing surface
+ restrictScene();
+
+ // Set up the verb list
+ _verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_TAKE, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_PUSH, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_OPEN, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_PUT, VERB_THIS, PREP_RELATIONAL));
+ _verbList.push_back(VerbInit(VERB_TALKTO, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_GIVE, VERB_THIS, PREP_TO));
+ _verbList.push_back(VerbInit(VERB_PULL, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_CLOSE, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_THROW, VERB_THIS, PREP_AT));
+}
+
+Scene::~Scene() {
+ delete _sceneLogic;
+ delete _sceneInfo;
+ delete _animationData;
+}
+
+void Scene::restrictScene() {
+ _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
+ _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
+}
+
+void Scene::clearVocab() {
+ _activeVocabs.clear();
+}
+
+void Scene::addActiveVocab(int vocabId) {
+ if (activeVocabIndexOf(vocabId) == -1) {
+ assert(_activeVocabs.size() < 200);
+ _activeVocabs.push_back(vocabId);
+ }
+}
+
+int Scene::activeVocabIndexOf(int vocabId) {
+ for (uint i = 0; i < _activeVocabs.size(); ++i) {
+ if (_activeVocabs[i] == vocabId)
+ return i;
+ }
+
+ return -1;
+}
+
+void Scene::clearSequenceList() {
+ _sequences.clear();
+}
+
+void Scene::clearMessageList() {
+ _kernelMessages.clear();
+ _talkFont = FONT_CONVERSATION;
+ _textSpacing = -1;
+}
+
+void Scene::loadSceneLogic() {
+ delete _sceneLogic;
+
+ switch (_vm->getGameID()) {
+ case GType_RexNebular:
+ _sceneLogic = Nebular::SceneFactory::createScene(_vm);
+ break;
+ case GType_Dragonsphere:
+ _sceneLogic = Dragonsphere::SceneFactory::createScene(_vm);
+ break;
+ case GType_Phantom:
+ _sceneLogic = Phantom::SceneFactory::createScene(_vm);
+ break;
+ default:
+ error("Scene logic: Unknown game");
+ }
+}
+
+void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) {
+ // Store the previously active scene number and set the new one
+ _priorSceneId = _currentSceneId;
+ _currentSceneId = sceneId;
+
+ _variant = 0;
+ if (palFlag)
+ _vm->_palette->resetGamePalette(18, 10);
+
+ _spriteSlots.reset(false);
+ _sequences.clear();
+ _kernelMessages.clear();
+ _vm->_palette->_paletteUsage.load(&_scenePaletteUsage);
+
+ int flags = SCENEFLAG_LOAD_SHADOW;
+ if (_vm->_dithering)
+ flags |= SCENEFLAG_DITHER;
+
+ _sceneInfo = SceneInfo::init(_vm);
+ _sceneInfo->load(_currentSceneId, _variant, Common::String(), flags,
+ _depthSurface, _backgroundSurface);
+
+ // Initialize palette animation for the scene
+ initPaletteAnimation(_sceneInfo->_paletteCycles, false);
+
+ // Copy over nodes
+ _rails.load(_sceneInfo->_nodes, &_depthSurface, _sceneInfo->_depthStyle);
+
+ // Load hotspots
+ loadHotspots();
+
+ // Load vocab
+ loadVocab();
+
+ // Load palette usage
+ _vm->_palette->_paletteUsage.load(&_paletteUsageF);
+
+ // Load interface
+ 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);
+ DepthSurface depthSurface;
+ _animationData->load(_userInterface, depthSurface, prefix, flags, nullptr, nullptr);
+
+ _vm->_palette->_paletteUsage.load(&_scenePaletteUsage);
+
+ _bandsRange = _sceneInfo->_yBandsEnd - _sceneInfo->_yBandsStart;
+ _scaleRange = _sceneInfo->_maxScale - _sceneInfo->_minScale;
+
+ _spriteSlots.reset(false);
+ _interfaceY = MADS_SCENE_HEIGHT;
+ _spritesCount = _sprites.size();
+
+ _userInterface.setup(_vm->_game->_screenObjects._inputMode);
+
+ _vm->_game->_screenObjects._category = CAT_NONE;
+ _vm->_events->showCursor();
+}
+
+void Scene::loadHotspots() {
+ _hotspots.clear();
+
+ Common::File f;
+ if (f.open(Resources::formatName(RESPREFIX_RM, _currentSceneId, ".HH"))) {
+ MadsPack madsPack(&f);
+ bool isV2 = (_vm->getGameID() != GType_RexNebular);
+
+ Common::SeekableReadStream *stream = madsPack.getItemStream(0);
+ int count = stream->readUint16LE();
+ delete stream;
+
+ stream = madsPack.getItemStream(1);
+ for (int i = 0; i < count; ++i)
+ _hotspots.push_back(Hotspot(*stream, isV2));
+
+ delete stream;
+ f.close();
+ }
+}
+
+void Scene::loadVocab() {
+ // Add all the verbs to the active vocab list
+ for (uint i = 0; i < _verbList.size(); ++i)
+ addActiveVocab(_verbList[i]._id);
+
+ // Load the vocabs for any object descriptions and custom actions
+ for (uint objIndex = 0; objIndex < _vm->_game->_objects.size(); ++objIndex) {
+ InventoryObject &io = _vm->_game->_objects[objIndex];
+ addActiveVocab(io._descId);
+
+ for (int vocabIndex = 0; vocabIndex <io._vocabCount; ++vocabIndex) {
+ addActiveVocab(io._vocabList[vocabIndex]._vocabId);
+ }
+ }
+
+ // Load scene hotspot list vocabs and verbs
+ for (uint i = 0; i < _hotspots.size(); ++i) {
+ addActiveVocab(_hotspots[i]._vocabId);
+ if (_hotspots[i]._verbId)
+ addActiveVocab(_hotspots[i]._verbId);
+ }
+
+ loadVocabStrings();
+}
+
+void Scene::loadVocabStrings() {
+ _vocabStrings.clear();
+ File f("*VOCAB.DAT");
+ Common::String msg;
+
+ for (;;) {
+ char c = (char)f.readByte();
+ if (f.eos()) break;
+
+ if (c == '\0') {
+ _vocabStrings.push_back(msg);
+ msg = "";
+ } else {
+ msg += c;
+ }
+ }
+
+ f.close();
+}
+
+uint32 Scene::getVocabStringsCount() const {
+ return _vocabStrings.size();
+}
+
+void Scene::initPaletteAnimation(Common::Array<PaletteCycle> &palCycles, bool animFlag) {
+ // Initialize the animation palette and ticks list
+ _cycleTicks.clear();
+ _paletteCycles.clear();
+
+ for (uint i = 0; i < palCycles.size(); ++i) {
+ _cycleTicks.push_back(_vm->_events->getFrameCounter());
+ _paletteCycles.push_back(palCycles[i]);
+ }
+
+ // Save the initial starting palette
+ Common::copy(&_vm->_palette->_mainPalette[0], &_vm->_palette->_mainPalette[PALETTE_SIZE],
+ &_vm->_palette->_cyclingPalette[0]);
+
+ // Calculate total
+ _totalCycleColors = 0;
+ for (uint i = 0; i < _paletteCycles.size(); ++i)
+ _totalCycleColors += _paletteCycles[i]._colorCount;
+
+ _cyclingThreshold = (_totalCycleColors > 16) ? 3 : 0;
+ _cyclingActive = animFlag;
+}
+
+void Scene::animatePalette() {
+ byte rgb[3];
+
+ if (_cyclingActive) {
+ Scene::_cyclingDelay++;
+ if (_cyclingDelay >= _cyclingThreshold) {
+ uint32 frameCounter = _vm->_events->getFrameCounter();
+ bool changesFlag = false;
+ for (uint16 idx = 0; idx < _paletteCycles.size(); idx++) {
+ if (frameCounter >= (_cycleTicks[idx] + _paletteCycles[idx]._ticks)) {
+ _cycleTicks[idx] = frameCounter;
+ int count = _paletteCycles[idx]._colorCount;
+ int first = _paletteCycles[idx]._firstColorIndex;
+ int listIndex = _paletteCycles[idx]._firstListColor;
+ changesFlag = true;
+
+ if (count > 1) {
+ // Make a copy of the last color
+ byte *pSrc = &_vm->_palette->_cyclingPalette[first * 3];
+ byte *pEnd = pSrc + count * 3;
+ Common::copy(pEnd - 3, pEnd, &rgb[0]);
+
+ // Shift the cycle palette forward one entry
+ Common::copy_backward(pSrc, pEnd - 3, pEnd);
+
+ // Move the saved color to the start of the cycle
+ Common::copy(&rgb[0], &rgb[3], pSrc);
+
+ if (++listIndex >= count)
+ listIndex = 0;
+ }
+
+ _paletteCycles[idx]._firstListColor = listIndex;
+ }
+ }
+
+ if (changesFlag) {
+ int firstColor = _paletteCycles[0]._firstColorIndex;
+ byte *pSrc = &_vm->_palette->_cyclingPalette[firstColor * 3];
+ _vm->_palette->setPalette(pSrc, firstColor, _totalCycleColors);
+ }
+
+ _cyclingDelay = 0;
+ }
+ }
+}
+
+bool Scene::getDepthHighBits(const Common::Point &pt) {
+ if (_sceneInfo->_depthStyle == 2) {
+ return 0;
+ } else {
+ const byte *p = _depthSurface.getBasePtr(pt.x, pt.y);
+ return (*p & 0x70) >> 4;
+ }
+}
+
+void Scene::loop() {
+ while (!_vm->shouldQuit() && !_reloadSceneFlag && (_nextSceneId == _currentSceneId)) {
+ // Handle drawing a game frame
+ doFrame();
+
+ // Wait for the next frame
+ _vm->_events->waitForNextFrame();
+
+ if (_vm->_dialogs->_pendingDialog != DIALOG_NONE && !_vm->_game->_trigger
+ && _vm->_game->_player._stepEnabled)
+ _reloadSceneFlag = true;
+
+ if (_vm->_game->_winStatus)
+ break;
+ }
+}
+
+void Scene::doFrame() {
+ Player &player = _vm->_game->_player;
+ bool flag = false;
+
+ if (_action._selectedAction || !player._stepEnabled) {
+ _action.clear();
+ _action._selectedAction = 0;
+ }
+
+ if (!_vm->_game->_trigger && !player._trigger) {
+ // Refresh the dynamic hotspots if they've changed
+ if (_dynamicHotspots._changed)
+ _dynamicHotspots.refresh();
+
+ // Check all on-screen visual objects
+ _vm->_game->_screenObjects.check(player._stepEnabled && !player._needToWalk &&
+ !_vm->_game->_fx);
+ }
+
+ if (_action._selectedAction && player._stepEnabled && !player._needToWalk &&
+ !_vm->_game->_trigger && !player._trigger) {
+ _action.startAction();
+ if (_action._activeAction._verbId == Nebular::VERB_LOOK_AT) {
+ _action._activeAction._verbId = VERB_LOOK;
+ _action._savedFields._command = false;
+ }
+
+ flag = true;
+ }
+
+ if (flag || (_vm->_game->_trigger && _vm->_game->_triggerMode == SEQUENCE_TRIGGER_PREPARE)) {
+ doPreactions();
+ }
+
+ player.newWalk();
+ if (!_vm->_game->_fx)
+ _frameStartTime = _vm->_events->getFrameCounter();
+
+ // Handle parser actions as well as game triggers
+ if ((_action._inProgress && !player._moving && !player._needToWalk &&
+ (player._facing == player._turnToFacing) && !_vm->_game->_trigger) ||
+ (_vm->_game->_trigger && (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PARSER))) {
+ doAction();
+ }
+
+ if (_currentSceneId != _nextSceneId) {
+ _freeAnimationFlag = true;
+ } else {
+ doSceneStep();
+ checkKeyboard();
+
+ if (_currentSceneId != _nextSceneId) {
+ _freeAnimationFlag = true;
+ } else {
+ player.nextFrame();
+
+ // Cursor update code
+ updateCursor();
+
+ if (!_vm->_game->_trigger) {
+ // Handle any active sequences
+ _sequences.tick();
+
+ // Handle any active animation
+ if (_activeAnimation)
+ _activeAnimation->update();
+ }
+
+ // If the debugget flag is set, show the mouse position
+ int mouseTextIndex = 0;
+ if (_vm->_debugger->_showMousePos) {
+ Common::Point pt = _vm->_events->mousePos();
+ Common::String msg = Common::String::format("(%d,%d)", pt.x, pt.y);
+ mouseTextIndex = _kernelMessages.add(Common::Point(5, 5),
+ 0x203, 0, 0, 1, msg);
+ }
+
+ if (!_vm->_game->_trigger) {
+ if (_reloadSceneFlag || _currentSceneId != _nextSceneId)
+ _kernelMessages.reset();
+ _kernelMessages.update();
+ }
+
+ _userInterface._uiSlots.draw(!_vm->_game->_fx, _vm->_game->_fx);
+
+ // Write any text needed by the interface
+ if (_vm->_game->_fx)
+ _userInterface.drawTextElements();
+
+ // Draw any elements
+ drawElements((ScreenTransition)_vm->_game->_fx, _vm->_game->_fx);
+
+ // Handle message updates
+ if (_vm->_game->_fx) {
+ uint32 priorTime = _vm->_game->_priorFrameTimer;
+ uint32 newTime = _vm->_events->getFrameCounter();
+ _sequences.delay(priorTime, newTime);
+ _kernelMessages.delay(priorTime, newTime);
+ }
+
+ if (_vm->_debugger->_showMousePos)
+ // Mouse position display isn't persistent, so remove it
+ _kernelMessages.remove(mouseTextIndex);
+
+ // Original had a debugger check/call here to allow pausing after
+ // drawing each frame. Not implemented under ScummVM
+ }
+ }
+
+ if (_vm->_game->_fx)
+ _cyclingActive = true;
+ _vm->_game->_fx = kTransitionNone;
+
+ // Handle freeing animation if necessary
+ if (_activeAnimation && _activeAnimation->freeFlag())
+ _freeAnimationFlag = true;
+ if (_freeAnimationFlag)
+ freeAnimation();
+}
+
+void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
+ // Draw any sprite backgrounds
+ _spriteSlots.drawBackground();
+
+ // Set up dirty areas for any text display
+ _textDisplay.setDirtyAreas();
+
+ // Merge any identified dirty areas
+ _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+
+ // Copy background for the dirty areas to the screen
+ _dirtyAreas.copy(&_backgroundSurface, &_vm->_screen, _posAdjust);
+
+ // Handle dirty areas for foreground objects
+ _spriteSlots.setDirtyAreas();
+ _textDisplay.setDirtyAreas2();
+ _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+
+ // Draw sprites that have changed
+ _spriteSlots.drawSprites(&_sceneSurface);
+
+ // Draw text elements onto the view
+ _textDisplay.draw(&_vm->_screen);
+
+ if (transitionType) {
+ // Fading in the screen
+ _vm->_screen.transition(transitionType, surfaceFlag);
+ _vm->_sound->startQueuedCommands();
+ } else {
+ // Copy dirty areas to the screen
+ _dirtyAreas.copyToScreen();
+ }
+
+ _spriteSlots.cleanUp();
+ _textDisplay.cleanUp();
+}
+
+void Scene::doPreactions() {
+ if (_vm->_game->_screenObjects._inputMode == kInputBuildingSentences ||
+ _vm->_game->_screenObjects._inputMode == kInputLimitedSentences) {
+ _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_PREPARE;
+ _action.checkAction();
+ _sceneLogic->preActions();
+
+ if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PREPARE)
+ _vm->_game->_trigger = 0;
+ }
+}
+
+void Scene::doAction() {
+ bool flag = false;
+
+ _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_PARSER;
+ if ((_action._inProgress || _vm->_game->_trigger) && !_action._savedFields._commandError) {
+ _sceneLogic->actions();
+ flag = !_action._inProgress;
+ }
+
+ if (_vm->_game->_screenObjects._inputMode == kInputConversation) {
+ _action._inProgress = false;
+ } else {
+ if ((_action._inProgress || _vm->_game->_trigger) ||
+ (!flag && _action._savedFields._commandError == flag)) {
+ _vm->_game->_sectionHandler->sectionPtr2();
+ flag = !_action._inProgress;
+ }
+
+ if ((_action._inProgress || _vm->_game->_trigger) &&
+ (!flag || _action._savedFields._commandError == flag)) {
+ _vm->_game->doObjectAction();
+ }
+
+ if (!_action._savedFields._lookFlag) {
+ if (_action._inProgress) {
+ _action._savedFields._commandError = true;
+ _sceneLogic->postActions();
+ }
+
+ if (_action._inProgress) {
+ _action._savedFields._commandError = true;
+ _sceneLogic->unhandledAction();
+ }
+
+ if (_action._inProgress)
+ _vm->_game->unhandledAction();
+ }
+ }
+
+ _action._inProgress = false;
+ if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PARSER)
+ _vm->_game->_trigger = 0;
+}
+
+void Scene::doSceneStep() {
+ _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _sceneLogic->step();
+ _vm->_game->_sectionHandler->step();
+ _vm->_game->step();
+
+ if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_DAEMON)
+ _vm->_game->_trigger = 0;
+}
+
+void Scene::checkKeyboard() {
+ EventsManager &events = *_vm->_events;
+
+ if (events.isKeyPressed()) {
+ Common::KeyState evt = events.getKey();
+ _vm->_game->handleKeypress(evt);
+ }
+
+ if ((events._mouseStatus & 3) == 3 && _vm->_game->_player._stepEnabled) {
+ _reloadSceneFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_GAME_MENU;
+ _action.clear();
+ _action._selectedAction = 0;
+ }
+}
+
+void Scene::loadAnimation(const Common::String &resName, int trigger) {
+ // WORKAROUND: If there's already a previous active animation used by the
+ // scene, then free it before we create the new one
+ if (_activeAnimation)
+ freeAnimation();
+
+ DepthSurface depthSurface;
+ UserInterface interfaceSurface(_vm);
+
+ _activeAnimation = Animation::init(_vm, this);
+ _activeAnimation->load(interfaceSurface, depthSurface, resName,
+ _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr);
+ _activeAnimation->startAnimation(trigger);
+}
+
+void Scene::updateCursor() {
+ Player &player = _vm->_game->_player;
+
+ CursorType cursorId = CURSOR_ARROW;
+ if (_action._interAwaiting == AWAITING_COMMAND && !_vm->_events->_rightMousePressed &&
+ _vm->_game->_screenObjects._category == CAT_HOTSPOT) {
+ int idx = _vm->_game->_screenObjects._selectedObject -
+ _userInterface._categoryIndexes[CAT_HOTSPOT - 1];
+ assert(idx >= 0);
+
+ if (idx >= (int)_hotspots.size()) {
+ idx -= _hotspots.size();
+ _vm->_events->_newCursorId = _dynamicHotspots[idx]._cursor;
+ } else {
+ idx = _hotspots.size() - idx - 1;
+ _vm->_events->_newCursorId = _hotspots[idx]._cursor;
+ }
+
+ cursorId = _vm->_events->_newCursorId == CURSOR_NONE ?
+ CURSOR_ARROW : _vm->_events->_newCursorId;
+ }
+
+ if (!player._stepEnabled)
+ cursorId = CURSOR_WAIT;
+ if (cursorId >= _vm->_events->_cursorSprites->getCount())
+ cursorId = (CursorType)_vm->_events->_cursorSprites->getCount();
+ _vm->_events->_newCursorId = cursorId;
+
+ if (cursorId != _vm->_events->_cursorId) {
+ _vm->_events->setCursor(cursorId);
+ }
+}
+
+void Scene::freeCurrentScene() {
+ if (_animationData) {
+ delete _animationData;
+ _animationData = nullptr;
+ }
+ if (_activeAnimation) {
+ delete _activeAnimation;
+ _activeAnimation = nullptr;
+ }
+
+ _vm->_palette->_paletteUsage.load(nullptr);
+ _cyclingActive = false;
+ _hotspots.clear();
+ _backgroundSurface.free();
+ _depthSurface.free();
+
+ delete _sceneInfo;
+ _sceneInfo = nullptr;
+}
+
+void Scene::removeSprites() {
+ for (int idx = _sprites.size() - 1; idx >= _spritesCount; --idx)
+ _sprites.remove(idx);
+}
+
+void Scene::changeVariant(int variant) {
+ _variant = variant;
+ _sceneInfo->loadCodes(_depthSurface, variant);
+ _spriteSlots.fullRefresh();
+}
+
+void Scene::resetScene() {
+ _vm->_game->clearQuotes();
+ removeSprites();
+ _spriteSlots.fullRefresh(true);
+ _sequences.clear();
+}
+
+void Scene::freeAnimation() {
+ if (_activeAnimation) {
+ Player &player = _vm->_game->_player;
+
+ if (!_freeAnimationFlag) {
+ _spriteSlots.fullRefresh(true);
+ _sequences.scan();
+ }
+
+ // Refresh the player
+ if (player._visible) {
+ player._forceRefresh = true;
+ player.update();
+ }
+
+ // Remove any kernel messages in use by the animation
+ for (uint i = 0; i < _activeAnimation->_messages.size(); ++i) {
+ int msgIndex = _activeAnimation->_messages[i]._kernelMsgIndex;
+ if (msgIndex >= 0)
+ _kernelMessages.remove(msgIndex);
+ }
+
+ // Delete the animation
+ delete _activeAnimation;
+ _activeAnimation = nullptr;
+ }
+
+ _freeAnimationFlag = false;
+}
+
+void Scene::synchronize(Common::Serializer &s) {
+ _action.synchronize(s);
+ _rails.synchronize(s);
+ _userInterface.synchronize(s);
+ s.syncAsByte(_reloadSceneFlag);
+ s.syncAsByte(_roomChanged);
+ s.syncAsUint16LE(_nextSceneId);
+ s.syncAsUint16LE(_priorSceneId);
+ _dynamicHotspots.synchronize(s);
+}
+
+} // End of namespace MADS