diff options
Diffstat (limited to 'engines/sherlock/people.cpp')
-rw-r--r-- | engines/sherlock/people.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp new file mode 100644 index 0000000000..8057e26204 --- /dev/null +++ b/engines/sherlock/people.cpp @@ -0,0 +1,305 @@ +/* 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/people.h" +#include "sherlock/sherlock.h" +#include "sherlock/scalpel/scalpel_people.h" +#include "sherlock/tattoo/tattoo_people.h" + +namespace Sherlock { + +// Characer animation sequences +static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = { + { 29, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Right + { 22, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Down + { 29, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Left + { 15, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Up + { 42, 1, 2, 3, 4, 5, 0 }, // Goto Stand Right + { 47, 1, 2, 3, 4, 5, 0 }, // Goto Stand Down + { 42, 1, 2, 3, 4, 5, 0 }, // Goto Stand Left + { 36, 1, 0 }, // Goto Stand Up + { 8, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Up Right + { 1, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Down Right + { 8, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Up Left + { 1, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Down Left + { 37, 1, 2, 3, 4, 5, 0 }, // Goto Stand Up Right + { 37, 1, 2, 3, 4, 5, 0 }, // Goto Stand Up Left + { 52, 1, 2, 3, 4, 0 }, // Goto Stand Down Right + { 52, 1, 2, 3, 4, 0 } // Goto Stand Down Left +}; + +// Rose Tattoo walk image libraries +// Walk resources within WALK.LIB +const char *const WALK_LIB_NAMES[NUM_IN_WALK_LIB] = { + "SVGAWALK.VGS", + "COATWALK.VGS", + "WATSON.VGS", + "NOHAT.VGS", + "TUPRIGHT.VGS", + "TRIGHT.VGS", + "TDOWNRG.VGS", + "TWUPRIGH.VGS", + "TWRIGHT.VGS", + "TWDOWNRG.VGS" +}; + +/*----------------------------------------------------------------*/ + +Person::Person() : Sprite() { + _walkLoaded = false; + _oldWalkSequence = -1; + _srcZone = _destZone = 0; +} + +void Person::goAllTheWay() { + Scene &scene = *_vm->_scene; + Common::Point srcPt = getSourcePoint(); + + // Get the zone the player is currently in + _srcZone = scene.whichZone(srcPt); + if (_srcZone == -1) + _srcZone = scene.closestZone(srcPt); + + // Get the zone of the destination + _destZone = scene.whichZone(_walkDest); + if (_destZone == -1) { + _destZone = scene.closestZone(_walkDest); + + // Check for any restriction of final destination position + _walkDest = _vm->_people->restrictToZone(_destZone, _walkDest); + } + + // Only do a walk if both zones are acceptable + if (_srcZone == -2 || _destZone == -2) + return; + + // If the start and dest zones are the same, walk directly to the dest point + if (_srcZone == _destZone) { + setWalking(); + } else { + // Otherwise a path needs to be formed from the path information + int i = scene._walkDirectory[_srcZone][_destZone]; + + // See if we need to use a reverse path + if (i == -1) + i = scene._walkDirectory[_destZone][_srcZone]; + + const WalkArray &points = scene._walkPoints[i]; + + // See how many points there are between the src and dest zones + if (!points._pointsCount || points._pointsCount == -1) { + // There are none, so just walk to the new zone + setWalking(); + } else { + // There are points, so set up a multi-step path between points + // to reach the given destination + _walkTo.clear(); + + if (scene._walkDirectory[_srcZone][_destZone] != -1) { + for (int idx = (int)points.size() - 1; idx >= 0; --idx) + _walkTo.push(points[idx]); + } else { + for (int idx = 0; idx < (int)points.size(); ++idx) { + _walkTo.push(points[idx]); + } + } + + // Final position + _walkTo.push(_walkDest); + + // Start walking + _walkDest = _walkTo.pop(); + setWalking(); + } + } +} + +/*----------------------------------------------------------------*/ + +People *People::init(SherlockEngine *vm) { + if (vm->getGameID() == GType_SerratedScalpel) + return new Scalpel::ScalpelPeople(vm); + else + return new Tattoo::TattooPeople(vm); +} + +People::People(SherlockEngine *vm) : _vm(vm) { + _holmesOn = true; + _allowWalkAbort = true; + _portraitLoaded = false; + _portraitsOn = true; + _clearingThePortrait = false; + _talkPics = nullptr; + _portraitSide = 0; + _speakerFlip = false; + _holmesFlip = false; + _holmesQuotient = 0; + _savedPos = Point32(-1, -1); + _savedPos._facing = -1; + _forceWalkReload = false; + _useWalkLib = false; + _walkControl = 0; + + _portrait._sequences = new byte[32]; +} + +People::~People() { + for (uint idx = 0; idx < _data.size(); ++idx) { + if (_data[idx]->_walkLoaded) + delete _data[idx]->_images; + delete _data[idx]; + } + + delete _talkPics; + delete[] _portrait._sequences; +} + +void People::reset() { + SaveManager &saves = *_vm->_saves; + Talk &talk = *_vm->_talk; + _data[HOLMES]->_description = "Sherlock Holmes!"; + + // Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites + int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS; + for (int idx = 0; idx < count; ++idx) { + Person &p = *_data[idx]; + + if (IS_SERRATED_SCALPEL) { + p._type = _holmesOn ? CHARACTER : HIDDEN; + if (!saves._justLoaded) + p._position = Point32(100 * FIXED_INT_MULTIPLIER, 110 * FIXED_INT_MULTIPLIER); + } else if (!talk._scriptMoreFlag && !saves._justLoaded) { + p._type = (idx == 0) ? CHARACTER : INVALID; + p._position = Point32(36 * FIXED_INT_MULTIPLIER, 29 * FIXED_INT_MULTIPLIER); + p._use[0]._verb = ""; + p._use[1]._verb = ""; + } + + p._sequenceNumber = IS_SERRATED_SCALPEL ? (int)Scalpel::STOP_DOWNRIGHT : (int)Tattoo::STOP_DOWNRIGHT; + p._imageFrame = nullptr; + p._frameNumber = 1; + p._startSeq = 0; + p._delta = Point32(0, 0); + p._oldPosition = Common::Point(0, 0); + p._oldSize = Common::Point(0, 0); + p._misc = 0; + p._pickUp = ""; + p._allow = 0; + p._noShapeSize = Common::Point(0, 0); + p._goto = Common::Point(0, 0); + p._status = 0; + p._seqTo = 0; + p._seqCounter = p._seqCounter2 = 0; + p._seqStack = 0; + p._gotoSeq = p._talkSeq = 0; + p._restoreSlot = 0; + p._startSeq = 0; + p._altImages = nullptr; + p._altSeq = 0; + p._centerWalk = true; + p._adjust = Common::Point(0, 0); + + // Load the default walk sequences + p._walkCount = 0; + p._walkTo.clear(); + p._oldWalkSequence = -1; + p._walkSequences.clear(); + if (IS_SERRATED_SCALPEL) { + p._walkSequences.resize(MAX_HOLMES_SEQUENCE); + for (int seqIdx = 0; seqIdx < MAX_HOLMES_SEQUENCE; ++seqIdx) { + p._walkSequences[seqIdx]._sequences.clear(); + + const byte *pSrc = &CHARACTER_SEQUENCES[seqIdx][0]; + do { + p._walkSequences[seqIdx]._sequences.push_back(*pSrc); + } while (*pSrc++); + } + } + } +} + +bool People::freeWalk() { + bool result = false; + + for (int idx = 0; idx < MAX_CHARACTERS; ++idx) { + if (_data[idx]->_walkLoaded) { + delete _data[idx]->_images; + _data[idx]->_images = nullptr; + + _data[idx]->_walkLoaded = false; + result = true; + } + } + + return result; +} + +int People::findSpeaker(int speaker) { + Scene &scene = *_vm->_scene; + const char *portrait = _characters[speaker]._portrait; + + for (int idx = 0; idx < (int)scene._bgShapes.size(); ++idx) { + Object &obj = scene._bgShapes[idx]; + + if (obj._type == ACTIVE_BG_SHAPE) { + Common::String name(obj._name.c_str(), obj._name.c_str() + 4); + + if (name.equalsIgnoreCase(portrait) + && obj._name[4] >= '0' && obj._name[4] <= '9') + return idx; + } + } + + return -1; +} + +void People::clearTalking() { + Scene &scene = *_vm->_scene; + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + + if (_portraitsOn) { + Common::Point pt = _portrait._position; + int width, height; + _portrait._imageFrame = _talkPics ? &(*_talkPics)[0] : (ImageFrame *)nullptr; + + // Flag portrait for removal, and save the size of the frame to use erasing it + _portrait._type = REMOVE; + _portrait._delta.x = width = _portrait.frameWidth(); + _portrait._delta.y = height = _portrait.frameHeight(); + + delete _talkPics; + _talkPics = nullptr; + + // Flag to let the talk code know not to interrupt on the next doBgAnim + _clearingThePortrait = true; + scene.doBgAnim(); + _clearingThePortrait = false; + + screen.slamArea(pt.x, pt.y, width, height); + + if (!talk._talkToAbort) + _portraitLoaded = false; + } +} + +} // End of namespace Sherlock |