aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock/scalpel/scalpel_scene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sherlock/scalpel/scalpel_scene.cpp')
-rw-r--r--engines/sherlock/scalpel/scalpel_scene.cpp726
1 files changed, 726 insertions, 0 deletions
diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp
new file mode 100644
index 0000000000..4e6e9e4c7c
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_scene.cpp
@@ -0,0 +1,726 @@
+/* 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 "sherlock/scalpel/scalpel_scene.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/events.h"
+#include "sherlock/people.h"
+#include "sherlock/screen.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+bool ScalpelScene::loadScene(const Common::String &filename) {
+ ScalpelMap &map = *(ScalpelMap *)_vm->_map;
+ bool result = Scene::loadScene(filename);
+
+ if (!_vm->isDemo()) {
+ // Reset the previous map location and position on overhead map
+ map._oldCharPoint = _currentScene;
+
+ map._overPos.x = (map[_currentScene].x - 6) * FIXED_INT_MULTIPLIER;
+ map._overPos.y = (map[_currentScene].y + 9) * FIXED_INT_MULTIPLIER;
+
+ }
+
+ return result;
+}
+
+void ScalpelScene::drawAllShapes() {
+ People &people = *_vm->_people;
+ Screen &screen = *_vm->_screen;
+
+ // Restrict drawing window
+ screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+
+ // Draw all active shapes which are behind the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE && _bgShapes[idx]._misc == BEHIND)
+ screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all canimations which are behind the person
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if (_canimShapes[idx]._type == ACTIVE_BG_SHAPE && _canimShapes[idx]._misc == BEHIND)
+ screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame,
+ _canimShapes[idx]._position, _canimShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all active shapes which are normal and behind the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE && _bgShapes[idx]._misc == NORMAL_BEHIND)
+ screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all canimations which are normal and behind the person
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if (_canimShapes[idx]._type == ACTIVE_BG_SHAPE && _canimShapes[idx]._misc == NORMAL_BEHIND)
+ screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame, _canimShapes[idx]._position,
+ _canimShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw any active characters
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ Person &p = people[idx];
+ if (p._type == CHARACTER && p._walkLoaded) {
+ bool flipped = IS_SERRATED_SCALPEL && (
+ p._sequenceNumber == WALK_LEFT || p._sequenceNumber == STOP_LEFT ||
+ p._sequenceNumber == WALK_UPLEFT || p._sequenceNumber == STOP_UPLEFT ||
+ p._sequenceNumber == WALK_DOWNRIGHT || p._sequenceNumber == STOP_DOWNRIGHT);
+
+ screen._backBuffer->transBlitFrom(*p._imageFrame, Common::Point(p._position.x / FIXED_INT_MULTIPLIER,
+ p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight()), flipped);
+ }
+ }
+
+ // Draw all static and active shapes that are NORMAL and are in front of the player
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) &&
+ _bgShapes[idx]._misc == NORMAL_FORWARD)
+ screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
+ _bgShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all static and active canimations that are NORMAL and are in front of the player
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if ((_canimShapes[idx]._type == ACTIVE_BG_SHAPE || _canimShapes[idx]._type == STATIC_BG_SHAPE) &&
+ _canimShapes[idx]._misc == NORMAL_FORWARD)
+ screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame, _canimShapes[idx]._position,
+ _canimShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all static and active shapes that are FORWARD
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ _bgShapes[idx]._oldPosition = _bgShapes[idx]._position;
+ _bgShapes[idx]._oldSize = Common::Point(_bgShapes[idx].frameWidth(),
+ _bgShapes[idx].frameHeight());
+
+ if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) &&
+ _bgShapes[idx]._misc == FORWARD)
+ screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
+ _bgShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all static and active canimations that are forward
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if ((_canimShapes[idx]._type == ACTIVE_BG_SHAPE || _canimShapes[idx]._type == STATIC_BG_SHAPE) &&
+ _canimShapes[idx]._misc == FORWARD)
+ screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame, _canimShapes[idx]._position,
+ _canimShapes[idx]._flags & OBJ_FLIPPED);
+ }
+
+ screen.resetDisplayBounds();
+}
+
+void ScalpelScene::checkBgShapes() {
+ People &people = *_vm->_people;
+ Person &holmes = people[HOLMES];
+ Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+ // Call the base scene method to handle bg shapes
+ Scene::checkBgShapes();
+
+ // Iterate through the canim list
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ Object &obj = _canimShapes[idx];
+ if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
+ if ((obj._flags & 5) == 1) {
+ obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
+ NORMAL_FORWARD : NORMAL_BEHIND;
+ } else if (!(obj._flags & 1)) {
+ obj._misc = BEHIND;
+ } else if (obj._flags & 4) {
+ obj._misc = FORWARD;
+ }
+ }
+ }
+}
+
+void ScalpelScene::doBgAnimCheckCursor() {
+ Inventory &inv = *_vm->_inventory;
+ Events &events = *_vm->_events;
+ Sound &sound = *_vm->_sound;
+ UserInterface &ui = *_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ events.animateCursorIfNeeded();
+
+ if (ui._menuMode == LOOK_MODE) {
+ if (mousePos.y > CONTROLS_Y1)
+ events.setCursor(ARROW);
+ else if (mousePos.y < CONTROLS_Y)
+ events.setCursor(MAGNIFY);
+ }
+
+ // Check for setting magnifying glass cursor
+ if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
+ if (inv._invMode == INVMODE_LOOK) {
+ // Only show Magnifying glass cursor if it's not on the inventory command line
+ if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
+ events.setCursor(MAGNIFY);
+ else
+ events.setCursor(ARROW);
+ } else {
+ events.setCursor(ARROW);
+ }
+ }
+
+ if (sound._diskSoundPlaying && !*sound._soundIsOn) {
+ // Loaded sound just finished playing
+ sound.freeDigiSound();
+ }
+}
+
+void ScalpelScene::doBgAnim() {
+ ScalpelEngine &vm = *((ScalpelEngine *)_vm);
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+
+ doBgAnimCheckCursor();
+
+ screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+ talk._talkToAbort = false;
+
+ if (_restoreFlag) {
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ if (people[idx]._type == CHARACTER)
+ people[idx].checkSprite();
+ }
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
+ _bgShapes[idx].checkObject();
+ }
+
+ if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
+ people._portrait.checkObject();
+
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if (_canimShapes[idx]._type != INVALID && _canimShapes[idx]._type != REMOVE)
+ _canimShapes[idx].checkObject();
+ }
+
+ if (_currentScene == 12)
+ vm.eraseMirror12();
+
+ // Restore the back buffer from the back buffer 2 in the changed area
+ Common::Rect bounds(people[HOLMES]._oldPosition.x, people[HOLMES]._oldPosition.y,
+ people[HOLMES]._oldPosition.x + people[HOLMES]._oldSize.x,
+ people[HOLMES]._oldPosition.y + people[HOLMES]._oldSize.y);
+ Common::Point pt(bounds.left, bounds.top);
+
+ if (people[HOLMES]._type == CHARACTER)
+ screen.restoreBackground(bounds);
+ else if (people[HOLMES]._type == REMOVE)
+ screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds);
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
+ screen.restoreBackground(o.getOldBounds());
+ }
+
+ if (people._portraitLoaded)
+ screen.restoreBackground(Common::Rect(
+ people._portrait._oldPosition.x, people._portrait._oldPosition.y,
+ people._portrait._oldPosition.x + people._portrait._oldSize.x,
+ people._portrait._oldPosition.y + people._portrait._oldSize.y
+ ));
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) {
+ // Restore screen area
+ screen._backBuffer->blitFrom(screen._backBuffer2, o._position,
+ Common::Rect(o._position.x, o._position.y,
+ o._position.x + o._noShapeSize.x, o._position.y + o._noShapeSize.y));
+
+ o._oldPosition = o._position;
+ o._oldSize = o._noShapeSize;
+ }
+ }
+
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ Object &o = _canimShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
+ screen.restoreBackground(Common::Rect(o._oldPosition.x, o._oldPosition.y,
+ o._oldPosition.x + o._oldSize.x, o._oldPosition.y + o._oldSize.y));
+ }
+ }
+
+ //
+ // Update the background objects and canimations
+ //
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE || o._type == NO_SHAPE)
+ o.adjustObject();
+ }
+
+ if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
+ people._portrait.adjustObject();
+
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ if (_canimShapes[idx]._type != INVALID)
+ _canimShapes[idx].adjustObject();
+ }
+
+ if (people[HOLMES]._type == CHARACTER && people._holmesOn)
+ people[HOLMES].adjustSprite();
+
+ // Flag the bg shapes which need to be redrawn
+ checkBgShapes();
+
+ if (_currentScene == 12)
+ vm.doMirror12();
+
+ // Draw all active shapes which are behind the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND)
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all canimations which are behind the person
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ Object &o = _canimShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) {
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+ }
+
+ // Draw all active shapes which are HAPPEN and behind the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND)
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all canimations which are NORMAL and behind the person
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ Object &o = _canimShapes[idx];
+ if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) {
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+ }
+
+ // Draw the person if not animating
+ if (people[HOLMES]._type == CHARACTER && people[HOLMES]._walkLoaded) {
+ // If Holmes is too far to the right, move him back so he's on-screen
+ int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[HOLMES]._imageFrame->_frame.w;
+ int tempX = MIN(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER, xRight);
+
+ bool flipped = people[HOLMES]._sequenceNumber == WALK_LEFT || people[HOLMES]._sequenceNumber == STOP_LEFT ||
+ people[HOLMES]._sequenceNumber == WALK_UPLEFT || people[HOLMES]._sequenceNumber == STOP_UPLEFT ||
+ people[HOLMES]._sequenceNumber == WALK_DOWNRIGHT || people[HOLMES]._sequenceNumber == STOP_DOWNRIGHT;
+ screen._backBuffer->transBlitFrom(*people[HOLMES]._imageFrame,
+ Common::Point(tempX, people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES]._imageFrame->_frame.h), flipped);
+ }
+
+ // Draw all static and active shapes are NORMAL and are in front of the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD)
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+
+ // Draw all static and active canimations that are NORMAL and are in front of the person
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ Object &o = _canimShapes[idx];
+ if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) {
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+ }
+
+ // Draw all static and active shapes that are in front of the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD)
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+
+ // Draw any active portrait
+ if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
+ screen._backBuffer->transBlitFrom(*people._portrait._imageFrame,
+ people._portrait._position, people._portrait._flags & OBJ_FLIPPED);
+
+ // Draw all static and active canimations that are in front of the person
+ for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+ Object &o = _canimShapes[idx];
+ if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) {
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+ }
+
+ // Draw all NO_SHAPE shapes which have flag bit 0 clear
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0)
+ screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ }
+
+ // Bring the newly built picture to the screen
+ if (_animating == 2) {
+ _animating = 0;
+ screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+ } else {
+ if (people[HOLMES]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) {
+ if (people[HOLMES]._type == REMOVE) {
+ screen.slamRect(Common::Rect(
+ people[HOLMES]._oldPosition.x, people[HOLMES]._oldPosition.y,
+ people[HOLMES]._oldPosition.x + people[HOLMES]._oldSize.x,
+ people[HOLMES]._oldPosition.y + people[HOLMES]._oldSize.y
+ ));
+ people[HOLMES]._type = INVALID;
+ } else {
+ screen.flushImage(people[HOLMES]._imageFrame,
+ Common::Point(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER,
+ people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES].frameHeight()),
+ &people[HOLMES]._oldPosition.x, &people[HOLMES]._oldPosition.y,
+ &people[HOLMES]._oldSize.x, &people[HOLMES]._oldSize.y);
+ }
+ }
+
+ if (_currentScene == 12)
+ vm.flushMirror12();
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if ((o._type == ACTIVE_BG_SHAPE || o._type == REMOVE) && _goToScene == -1) {
+ screen.flushImage(o._imageFrame, o._position,
+ &o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
+ }
+ }
+
+ if (people._portraitLoaded) {
+ if (people._portrait._type == REMOVE)
+ screen.slamRect(Common::Rect(
+ people._portrait._position.x, people._portrait._position.y,
+ people._portrait._position.x + people._portrait._delta.x,
+ people._portrait._position.y + people._portrait._delta.y
+ ));
+ else
+ screen.flushImage(people._portrait._imageFrame, people._portrait._position,
+ &people._portrait._oldPosition.x, &people._portrait._oldPosition.y,
+ &people._portrait._oldSize.x, &people._portrait._oldSize.y);
+
+ if (people._portrait._type == REMOVE)
+ people._portrait._type = INVALID;
+ }
+
+ if (_goToScene == -1) {
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) {
+ screen.slamArea(o._position.x, o._position.y, o._oldSize.x, o._oldSize.y);
+ screen.slamArea(o._oldPosition.x, o._oldPosition.y, o._oldSize.x, o._oldSize.y);
+ } else if (o._type == HIDE_SHAPE) {
+ // Hiding shape, so flush it out and mark it as hidden
+ screen.flushImage(o._imageFrame, o._position,
+ &o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
+ o._type = HIDDEN;
+ }
+ }
+ }
+
+ for (int idx = _canimShapes.size() - 1; idx >= 0; --idx) {
+ Object &o = _canimShapes[idx];
+
+ if (o._type == INVALID) {
+ // Anim shape was invalidated by checkEndOfSequence, so at this point we can remove it
+ _canimShapes.remove_at(idx);
+ } else if (o._type == REMOVE) {
+ if (_goToScene == -1)
+ screen.slamArea(o._position.x, o._position.y, o._delta.x, o._delta.y);
+
+ // Shape for an animation is no longer needed, so remove it completely
+ _canimShapes.remove_at(idx);
+ } else if (o._type == ACTIVE_BG_SHAPE) {
+ screen.flushImage(o._imageFrame, o._position,
+ &o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
+ }
+ }
+ }
+
+ _restoreFlag = true;
+ _doBgAnimDone = true;
+
+ events.wait(3);
+ screen.resetDisplayBounds();
+
+ // Check if the method was called for calling a portrait, and a talk was
+ // interrupting it. This talk file would not have been executed at the time,
+ // since we needed to finish the 'doBgAnim' to finish clearing the portrait
+ if (people._clearingThePortrait && talk._scriptMoreFlag == 3) {
+ // Reset the flags and call to talk
+ people._clearingThePortrait = false;
+ talk._scriptMoreFlag = 0;
+ talk.talkTo(talk._scriptName);
+ }
+}
+
+int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
+ Events &events = *_vm->_events;
+ ScalpelMap &map = *(ScalpelMap *)_vm->_map;
+ People &people = *_vm->_people;
+ Resources &res = *_vm->_res;
+ Talk &talk = *_vm->_talk;
+ ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
+ Point32 tpPos, walkPos;
+ int tpDir, walkDir;
+ int tFrames = 0;
+ int gotoCode = -1;
+
+ // Validation
+ if (cAnimNum >= (int)_cAnim.size())
+ // number out of bounds
+ return -1;
+ if (_canimShapes.size() >= 3 || playRate == 0)
+ // Too many active animations, or invalid play rate
+ return 0;
+
+ CAnim &cAnim = _cAnim[cAnimNum];
+ if (playRate < 0) {
+ // Reverse direction
+ walkPos = cAnim._teleport[0];
+ walkDir = cAnim._teleport[0]._facing;
+ tpPos = cAnim._goto[0];
+ tpDir = cAnim._goto[0]._facing;
+ } else {
+ // Forward direction
+ walkPos = cAnim._goto[0];
+ walkDir = cAnim._goto[0]._facing;
+ tpPos = cAnim._teleport[0];
+ tpDir = cAnim._teleport[0]._facing;
+ }
+
+ CursorId oldCursor = events.getCursor();
+ events.setCursor(WAIT);
+
+ if (walkPos.x != -1) {
+ // Holmes must walk to the walk point before the cAnimation is started
+ if (people[HOLMES]._position != walkPos)
+ people[HOLMES].walkToCoords(walkPos, walkDir);
+ }
+
+ if (talk._talkToAbort)
+ return 1;
+
+ // Add new anim shape entry for displaying the animation
+ _canimShapes.push_back(Object());
+ Object &cObj = _canimShapes[_canimShapes.size() - 1];
+
+ // Copy the canimation into the bgShapes type canimation structure so it can be played
+ cObj._allow = cAnimNum + 1; // Keep track of the parent structure
+ cObj._name = _cAnim[cAnimNum]._name; // Copy name
+
+ // Remove any attempt to draw object frame
+ if (cAnim._type == NO_SHAPE && cAnim._sequences[0] < 100)
+ cAnim._sequences[0] = 0;
+
+ cObj._sequences = cAnim._sequences;
+ cObj._images = nullptr;
+ cObj._position = cAnim._position;
+ cObj._delta = Common::Point(0, 0);
+ cObj._type = cAnim._type;
+ cObj._flags = cAnim._flags;
+
+ cObj._maxFrames = 0;
+ cObj._frameNumber = -1;
+ cObj._sequenceNumber = cAnimNum;
+ cObj._oldPosition = Common::Point(0, 0);
+ cObj._oldSize = Common::Point(0, 0);
+ cObj._goto = Common::Point(0, 0);
+ cObj._status = 0;
+ cObj._misc = 0;
+ cObj._imageFrame = nullptr;
+
+ if (cAnim._name.size() > 0 && cAnim._type != NO_SHAPE) {
+ if (tpPos.x != -1)
+ people[HOLMES]._type = REMOVE;
+
+ Common::String fname = cAnim._name + ".vgs";
+ if (!res.isInCache(fname)) {
+ // Set up RRM scene data
+ Common::SeekableReadStream *roomStream = res.load(_roomFilename);
+ roomStream->seek(cAnim._dataOffset);
+ //rrmStream->seek(44 + cAnimNum * 4);
+ //rrmStream->seek(rrmStream->readUint32LE());
+
+ // Load the canimation into the cache
+ Common::SeekableReadStream *imgStream = !_compressed ? roomStream->readStream(cAnim._dataSize) :
+ Resources::decompressLZ(*roomStream, cAnim._dataSize);
+ res.addToCache(fname, *imgStream);
+
+ delete imgStream;
+ delete roomStream;
+ }
+
+ // Now load the resource as an image
+ if (!IS_3DO) {
+ cObj._images = new ImageFile(fname);
+ } else {
+ cObj._images = new ImageFile3DO(fname, kImageFile3DOType_RoomFormat);
+ }
+ cObj._imageFrame = &(*cObj._images)[0];
+ cObj._maxFrames = cObj._images->size();
+
+ int frames = 0;
+ if (playRate < 0) {
+ // Reverse direction
+ // Count number of frames
+ while (frames < MAX_FRAME && cObj._sequences[frames])
+ ++frames;
+ } else {
+ // Forward direction
+ BaseObject::_countCAnimFrames = true;
+
+ while (cObj._type == ACTIVE_BG_SHAPE) {
+ cObj.checkObject();
+ ++frames;
+
+ if (frames >= 1000)
+ error("CAnim has infinite loop sequence");
+ }
+
+ if (frames > 1)
+ --frames;
+
+ BaseObject::_countCAnimFrames = false;
+
+ cObj._type = cAnim._type;
+ cObj._frameNumber = -1;
+ cObj._position = cAnim._position;
+ cObj._delta = Common::Point(0, 0);
+ }
+
+ // Return if animation has no frames in it
+ if (frames == 0)
+ return -2;
+
+ ++frames;
+ int repeat = ABS(playRate);
+ int dir;
+
+ if (playRate < 0) {
+ // Play in reverse
+ dir = -2;
+ cObj._frameNumber = frames - 3;
+ } else {
+ dir = 0;
+ }
+
+ tFrames = frames - 1;
+ int pauseFrame = (_cAnimFramePause) ? frames - _cAnimFramePause : -1;
+
+ while (--frames) {
+ if (frames == pauseFrame)
+ ui.printObjectDesc();
+
+ doBgAnim();
+
+ // Repeat same frame
+ int temp = repeat;
+ while (--temp > 0) {
+ cObj._frameNumber--;
+ doBgAnim();
+
+ if (_vm->shouldQuit())
+ return 0;
+ }
+
+ cObj._frameNumber += dir;
+ }
+
+ people[HOLMES]._type = CHARACTER;
+ }
+
+ // Teleport to ending coordinates if necessary
+ if (tpPos.x != -1) {
+ people[HOLMES]._position = tpPos; // Place the player
+ people[HOLMES]._sequenceNumber = tpDir;
+ people[HOLMES].gotoStand();
+ }
+
+ if (playRate < 0)
+ // Reverse direction - set to end sequence
+ cObj._frameNumber = tFrames - 1;
+
+ if (cObj._frameNumber <= 26)
+ gotoCode = cObj._sequences[cObj._frameNumber + 3];
+
+ // Unless anim shape has already been freed, set it to REMOVE so doBgAnim can free it
+ if (_canimShapes.indexOf(cObj) != -1)
+ cObj.checkObject();
+
+ if (gotoCode > 0 && !talk._talkToAbort) {
+ _goToScene = gotoCode;
+
+ if (_goToScene < 97 && map[_goToScene].x) {
+ map._overPos = map[_goToScene];
+ }
+ }
+
+ people.loadWalk();
+
+ if (tpPos.x != -1 && !talk._talkToAbort) {
+ // Teleport to ending coordinates
+ people[HOLMES]._position = tpPos;
+ people[HOLMES]._sequenceNumber = tpDir;
+
+ people[HOLMES].gotoStand();
+ }
+
+ events.setCursor(oldCursor);
+
+ return 1;
+}
+
+int ScalpelScene::closestZone(const Common::Point &pt) {
+ int dist = 1000;
+ int zone = -1;
+
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ Common::Point zc((_zones[idx].left + _zones[idx].right) / 2,
+ (_zones[idx].top + _zones[idx].bottom) / 2);
+ int d = ABS(zc.x - pt.x) + ABS(zc.y - pt.y);
+
+ if (d < dist) {
+ // Found a closer zone
+ dist = d;
+ zone = idx;
+ }
+ }
+
+ return zone;
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock