diff options
-rw-r--r-- | engines/sherlock/decompress.cpp | 128 | ||||
-rw-r--r-- | engines/sherlock/inventory.cpp | 8 | ||||
-rw-r--r-- | engines/sherlock/map.cpp | 10 | ||||
-rw-r--r-- | engines/sherlock/objects.cpp | 90 | ||||
-rw-r--r-- | engines/sherlock/objects.h | 34 | ||||
-rw-r--r-- | engines/sherlock/resources.cpp | 94 | ||||
-rw-r--r-- | engines/sherlock/resources.h | 25 | ||||
-rw-r--r-- | engines/sherlock/scalpel/scalpel.cpp | 17 | ||||
-rw-r--r-- | engines/sherlock/scene.cpp | 211 | ||||
-rw-r--r-- | engines/sherlock/scene.h | 41 | ||||
-rw-r--r-- | engines/sherlock/screen.cpp | 74 | ||||
-rw-r--r-- | engines/sherlock/screen.h | 19 | ||||
-rw-r--r-- | engines/sherlock/settings.cpp | 3 | ||||
-rw-r--r-- | engines/sherlock/sherlock.cpp | 5 | ||||
-rw-r--r-- | engines/sherlock/sherlock.h | 7 | ||||
-rw-r--r-- | engines/sherlock/sound.cpp | 1 | ||||
-rw-r--r-- | engines/sherlock/talk.cpp | 8 | ||||
-rw-r--r-- | engines/sherlock/talk.h | 4 | ||||
-rw-r--r-- | engines/sherlock/tattoo/tattoo.cpp | 28 | ||||
-rw-r--r-- | engines/sherlock/tattoo/tattoo.h | 5 | ||||
-rw-r--r-- | engines/sherlock/user_interface.cpp | 125 | ||||
-rw-r--r-- | engines/sherlock/user_interface.h | 170 |
22 files changed, 861 insertions, 246 deletions
diff --git a/engines/sherlock/decompress.cpp b/engines/sherlock/decompress.cpp new file mode 100644 index 0000000000..8e02da3212 --- /dev/null +++ b/engines/sherlock/decompress.cpp @@ -0,0 +1,128 @@ +/* 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/decompress.h" + +namespace Sherlock { + +/** + * Decompresses an LZW compressed resource. If no outSize is specified, it will + * decompress the entire resource. If, however, an explicit size is specified, + * then it means we're already within a resource, and only want to decompress + * part of it. + */ +Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, int32 outSize) { + if (outSize == -1) { + source.seek(5); + outSize = source.readSint32LE(); + } + + byte lzWindow[4096]; + uint16 lzWindowPos; + uint16 cmd; + + byte *outBuffer = new byte[outSize]; + byte *outBufferEnd = outBuffer + outSize; + Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); + + memset(lzWindow, 0xFF, 0xFEE); + lzWindowPos = 0xFEE; + cmd = 0; + + do { + cmd >>= 1; + if (!(cmd & 0x100)) + cmd = source.readByte() | 0xFF00; + + if (cmd & 1) { + byte literal = source.readByte(); + *outBuffer++ = literal; + lzWindow[lzWindowPos] = literal; + lzWindowPos = (lzWindowPos + 1) & 0x0FFF; + } else { + int copyPos, copyLen; + copyPos = source.readByte(); + copyLen = source.readByte(); + copyPos = copyPos | ((copyLen & 0xF0) << 4); + copyLen = (copyLen & 0x0F) + 3; + while (copyLen--) { + byte literal = lzWindow[copyPos]; + copyPos = (copyPos + 1) & 0x0FFF; + *outBuffer++ = literal; + lzWindow[lzWindowPos] = literal; + lzWindowPos = (lzWindowPos + 1) & 0x0FFF; + } + } + } while (outBuffer < outBufferEnd); + + return outS; +} + + +/** + * Decompresses a Rose Tattoo resource + * +Common::SeekableReadStream *decompress32(Common::SeekableReadStream &source, int32 outSize) { + if (outSize == -1) { + outSize = source.readSint32LE(); + } + + byte lzWindow[8192]; + byte *outBuffer = new byte[outSize]; + byte *outBufferEnd = outBuffer + outSize; + Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); + + memset(lzWindow, 0xFF, 8192); + int lzWindowPos = 0xFEE; + int cmd = 0; + + do { + cmd >>= 1; + if (!(cmd & 0x100)) + cmd = source.readByte() | 0xFF00; + + if (cmd & 1) { + byte literal = source.readByte(); + *outBuffer++ = literal; + lzWindow[lzWindowPos] = literal; + lzWindowPos = (lzWindowPos + 1) & 0x0FFF; + } else { + int copyPos, copyLen; + copyPos = source.readByte(); + copyLen = source.readByte(); + copyPos = copyPos | ((copyLen & 0xF0) << 4); + copyLen = (copyLen & 0x0F) + 3; + while (copyLen--) { + byte literal = lzWindow[copyPos]; + copyPos = (copyPos + 1) & 0x0FFF; + *outBuffer++ = literal; + lzWindow[lzWindowPos] = literal; + lzWindowPos = (lzWindowPos + 1) & 0x0FFF; + } + } + } while (outBuffer < outBufferEnd); + + return outS; +} +*/ + +} // namespace Sherlock diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp index 7f216a35c3..bbb7c75aea 100644 --- a/engines/sherlock/inventory.cpp +++ b/engines/sherlock/inventory.cpp @@ -243,7 +243,8 @@ void Inventory::drawInventory(InvNewMode mode) { screen._backBuffer = &screen._backBuffer1; } - ui._oldUse = -1; + assert(IS_SERRATED_SCALPEL); + ((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1; } void Inventory::invCommands(bool slamIt) { @@ -318,9 +319,12 @@ void Inventory::highlight(int index, byte color) { } void Inventory::refreshInv() { + if (IS_ROSE_TATTOO) + return; + Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; - UserInterface &ui = *_vm->_ui; + ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui; ui._invLookFlag = true; freeInv(); diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp index 42775ae4b0..44ca7cd44c 100644 --- a/engines/sherlock/map.cpp +++ b/engines/sherlock/map.cpp @@ -22,6 +22,7 @@ #include "sherlock/map.h" #include "sherlock/sherlock.h" +#include "common/system.h" namespace Sherlock { @@ -50,7 +51,7 @@ const byte *MapPaths::getPath(int srcLocation, int destLocation) { /*----------------------------------------------------------------*/ -Map::Map(SherlockEngine *vm) : _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) { +Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) { _active = false; _mapCursors = nullptr; _shapes = nullptr; @@ -83,8 +84,13 @@ void Map::loadSequences(int count, const byte *seq) { } void Map::loadData() { + // TODO: Remove this + if (_vm->getGameID() == GType_RoseTattoo) + return; + // Load the list of location names - Common::SeekableReadStream *txtStream = _vm->_res->load("chess.txt"); + Common::SeekableReadStream *txtStream = _vm->_res->load( + _vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt"); int streamSize = txtStream->size(); while (txtStream->pos() < streamSize) { diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 02f2526ae9..f3803518ee 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -113,8 +113,8 @@ void Sprite::adjustSprite() { people.gotoStand(*this); } } else if (!map._active) { - _position.y = CLIP((int)_position.y, UPPER_LIMIT, LOWER_LIMIT); - _position.x = CLIP((int)_position.x, LEFT_LIMIT, RIGHT_LIMIT); + _position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT); + _position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT); } if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag)) @@ -373,9 +373,14 @@ UseType::UseType() { _useFlag = 0; } -void UseType::load(Common::SeekableReadStream &s) { +void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) { char buffer[12]; + if (isRoseTattoo) { + s.read(buffer, 12); + _verb = Common::String(buffer); + } + _cAnimNum = s.readByte(); _cAnimSpeed = s.readByte(); if (_cAnimSpeed & 0x80) @@ -387,7 +392,9 @@ void UseType::load(Common::SeekableReadStream &s) { } _useFlag = s.readSint16LE(); - s.skip(6); + + if (!isRoseTattoo) + s.skip(6); s.read(buffer, 12); _target = Common::String(buffer); @@ -434,9 +441,16 @@ Object::Object() { _descOffset = 0; _seqCounter2 = 0; _seqSize = 0; + + _quickDraw = 0; + _scaleVal = 0; + _requiredFlag1 = 0; + _gotoSeq = 0; + _talkSeq = 0; + _restoreSlot = 0; } -void Object::load(Common::SeekableReadStream &s) { +void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { char buffer[41]; s.read(buffer, 12); _name = Common::String(buffer); @@ -468,10 +482,10 @@ void Object::load(Common::SeekableReadStream &s) { _goto.x = s.readSint16LE(); _goto.y = s.readSint16LE(); - _pickup = s.readByte(); - _defaultCommand = s.readByte(); - _lookFlag = s.readUint16LE(); - _pickupFlag = s.readUint16LE(); + _pickup = isRoseTattoo ? 0 : s.readByte(); + _defaultCommand = isRoseTattoo ? 0 : s.readByte(); + _lookFlag = s.readSint16LE(); + _pickupFlag = isRoseTattoo ? 0 : s.readSint16LE(); _requiredFlag = s.readSint16LE(); _noShapeSize.x = s.readUint16LE(); _noShapeSize.y = s.readUint16LE(); @@ -479,26 +493,45 @@ void Object::load(Common::SeekableReadStream &s) { _misc = s.readByte(); _maxFrames = s.readUint16LE(); _flags = s.readByte(); - _aOpen.load(s); + + if (!isRoseTattoo) + _aOpen.load(s); + _aType = (AType)s.readByte(); _lookFrames = s.readByte(); _seqCounter = s.readByte(); _lookPosition.x = s.readUint16LE(); - _lookPosition.y = s.readByte(); + _lookPosition.y = isRoseTattoo ? s.readSint16LE() : s.readByte(); _lookFacing = s.readByte(); _lookcAnim = s.readByte(); - _aClose.load(s); + + if (!isRoseTattoo) + _aClose.load(s); + _seqStack = s.readByte(); _seqTo = s.readByte(); _descOffset = s.readUint16LE(); _seqCounter2 = s.readByte(); _seqSize = s.readUint16LE(); - s.skip(1); - _aMove.load(s); - s.skip(8); - for (int idx = 0; idx < USE_COUNT; ++idx) - _use[idx].load(s); + if (isRoseTattoo) { + for (int idx = 0; idx < 6; ++idx) + _use[idx].load(s, true); + + _quickDraw = s.readByte(); + _scaleVal = s.readUint16LE(); + _requiredFlag1 = s.readSint16LE(); + _gotoSeq = s.readByte(); + _talkSeq = s.readByte(); + _restoreSlot = s.readByte(); + } else { + s.skip(1); + _aMove.load(s); + s.skip(8); + + for (int idx = 0; idx < 4; ++idx) + _use[idx].load(s, false); + } } void Object::toggleHidden() { @@ -1032,17 +1065,30 @@ const Common::Rect Object::getOldBounds() const { /*----------------------------------------------------------------*/ -void CAnim::load(Common::SeekableReadStream &s) { +void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) { char buffer[12]; s.read(buffer, 12); _name = Common::String(buffer); - s.read(_sequences, 30); + if (isRoseTattoo) { + Common::fill(&_sequences[0], &_sequences[30], 0); + _size = s.readUint32LE(); + } else { + s.read(_sequences, 30); + } + _position.x = s.readSint16LE(); _position.y = s.readSint16LE(); - _size = s.readUint32LE(); - _type = (SpriteType)s.readUint16LE(); - _flags = s.readByte(); + + if (isRoseTattoo) { + _flags = s.readByte(); + _scaleVal = s.readSint16LE(); + } else { + _size = s.readUint32LE(); + _type = (SpriteType)s.readUint16LE(); + _flags = s.readByte(); + } + _goto.x = s.readSint16LE(); _goto.y = s.readSint16LE(); _gotoDir = s.readSint16LE(); diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index bbd068eef7..b61e7e24fe 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -179,13 +179,14 @@ struct UseType { Common::String _names[NAMES_COUNT]; int _useFlag; // Which flag USE will set (if any) Common::String _target; + Common::String _verb; UseType(); /** * Load the data for the UseType */ - void load(Common::SeekableReadStream &s); + void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 }; @@ -233,35 +234,45 @@ public: int _pickup; int _defaultCommand; // Default right-click command int _lookFlag; // Which flag LOOK will set (if any) - int _pickupFlag; // Which flag PICKUP will set (if any) int _requiredFlag; // Object will be hidden if not set Common::Point _noShapeSize; // Size of a NO_SHAPE int _status; // Status (open/closed, moved/not) int8 _misc; // Misc field -- use varies with type int _maxFrames; // Number of frames int _flags; // Tells if object can be walked behind - ActionType _aOpen; // Holds data for moving object AType _aType; // Tells if this is an object, person, talk, etc. int _lookFrames; // How many frames to play of the look anim before pausing int _seqCounter; // How many times this sequence has been executed Common::Point _lookPosition; // Where to walk when examining object int _lookFacing; // Direction to face when examining object int _lookcAnim; - ActionType _aClose; int _seqStack; // Allows gosubs to return to calling frame int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes uint _descOffset; // Tells where description starts in DescText int _seqCounter2; // Counter of calling frame sequence uint _seqSize; // Tells where description starts + UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6 + + // Serrated Scalpel fields + int _pickupFlag; // Which flag PICKUP will set (if any) + ActionType _aOpen; // Holds data for moving object + ActionType _aClose; ActionType _aMove; - UseType _use[USE_COUNT]; + + // Rose Tattoo fields + int _quickDraw; + int _scaleVal; + int _requiredFlag1; + int _gotoSeq; + int _talkSeq; + int _restoreSlot; Object(); /** * Load the data for the object */ - void load(Common::SeekableReadStream &s); + void load(Common::SeekableReadStream &s, bool isRoseTattoo); /** * Toggle the type of an object between hidden and active @@ -326,20 +337,25 @@ public: struct CAnim { Common::String _name; // Name - byte _sequences[MAX_FRAME]; // Animation sequences Common::Point _position; // Position int _size; // Size of uncompressed animation - SpriteType _type; int _flags; // Tells if can be walked behind Common::Point _goto; // coords holmes should walk to before starting canim int _gotoDir; Common::Point _teleportPos; // Location Holmes shoul teleport to after int _teleportDir; // playing canim + // Scalpel specific + byte _sequences[MAX_FRAME]; // Animation sequences + SpriteType _type; + + // Rose Tattoo specific + int _scaleVal; // How much the canim is scaled + /** * Load the data for the animation */ - void load(Common::SeekableReadStream &s); + void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; struct SceneImage { diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp index 091ef3ea12..864622e74b 100644 --- a/engines/sherlock/resources.cpp +++ b/engines/sherlock/resources.cpp @@ -65,7 +65,7 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream) // Check whether the file is compressed if (signature == MKTAG('L', 'Z', 'V', 26)) { // It's compressed, so decompress the file and store it's data in the cache entry - Common::SeekableReadStream *decompressed = _vm->_res->decompressLZ(stream); + Common::SeekableReadStream *decompressed = _vm->_res->decompress(stream); cacheEntry.resize(decompressed->size()); decompressed->read(&cacheEntry[0], decompressed->size()); @@ -103,8 +103,11 @@ void Resources::addToCache(const Common::String &filename) { // Check to see if the file is a library Common::SeekableReadStream *stream = load(filename); uint32 header = stream->readUint32BE(); + if (header == MKTAG('L', 'I', 'B', 26)) - loadLibraryIndex(filename, stream); + loadLibraryIndex(filename, stream, false); + else if (header == MKTAG('L', 'I', 'C', 26)) + loadLibraryIndex(filename, stream, true); delete stream; } @@ -159,12 +162,14 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) { void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) { bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26); - stream->seek(-4, SEEK_CUR); if (isCompressed) { - Common::SeekableReadStream *newStream = decompressLZ(*stream); + int outSize = stream->readUint32LE(); + Common::SeekableReadStream *newStream = decompressLZ(*stream, outSize); delete stream; stream = newStream; + } else { + stream->seek(-4, SEEK_CUR); } } @@ -174,7 +179,7 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename, cons // Check if the library has already had it's index read, and if not, load it if (!_indexes.contains(libraryFile)) - loadLibraryIndex(libraryFile, libStream); + loadLibraryIndex(libraryFile, libStream, false); // Extract the data for the specified resource and return it LibraryEntry &entry = _indexes[libraryFile][filename]; @@ -192,7 +197,7 @@ bool Resources::exists(const Common::String &filename) const { } void Resources::loadLibraryIndex(const Common::String &libFilename, - Common::SeekableReadStream *stream) { + Common::SeekableReadStream *stream, bool isNewStyle) { uint32 offset, nextOffset; // Create an index entry @@ -203,6 +208,9 @@ void Resources::loadLibraryIndex(const Common::String &libFilename, stream->seek(4); int count = stream->readUint16LE(); + if (isNewStyle) + stream->seek((count + 1) * 8, SEEK_CUR); + // Loop through reading in the entries for (int idx = 0; idx < count; ++idx) { // Read the name of the resource @@ -231,24 +239,48 @@ int Resources::resourceIndex() const { return _resourceIndex; } -Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source) { - if (_vm->getGameID() == GType_SerratedScalpel) { - uint32 id = source.readUint32BE(); - assert(id == MKTAG('L', 'Z', 'V', 0x1A)); - } +Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) { + // This variation can't be used by Rose Tattoo, since compressed resources include the input size, + // not the output size. Which means their decompression has to be done via passed buffers + assert(_vm->getGameID() == GType_SerratedScalpel); + + uint32 id = source.readUint32BE(); + assert(id == MKTAG('L', 'Z', 'V', 0x1A)); + + uint32 outputSize = source.readUint32LE(); + return decompressLZ(source, outputSize); +} + +Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) { + int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1; + byte *outBuffer = (byte *)malloc(outSize); + Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); + + decompressLZ(source, outBuffer, outSize, inSize); + + return outStream; +} - uint32 size = source.readUint32LE(); - return decompressLZ(source, size); +void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) { + int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1; + + decompressLZ(source, buffer, outSize, inputSize); } Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) { + byte *dataOut = (byte *)malloc(outSize); + decompressLZ(source, dataOut, outSize, -1); + + return new Common::MemoryReadStream(dataOut, outSize, DisposeAfterUse::YES); +} + +void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) { byte lzWindow[4096]; uint16 lzWindowPos; uint16 cmd; - byte *outBuffer = (byte *)malloc(outSize); byte *outBufferEnd = outBuffer + outSize; - Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES); + int endPos = source.pos() + inSize; memset(lzWindow, 0xFF, 0xFEE); lzWindowPos = 0xFEE; @@ -264,8 +296,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream & *outBuffer++ = literal; lzWindow[lzWindowPos] = literal; lzWindowPos = (lzWindowPos + 1) & 0x0FFF; - } - else { + } else { int copyPos, copyLen; copyPos = source.readByte(); copyLen = source.readByte(); @@ -279,9 +310,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream & lzWindowPos = (lzWindowPos + 1) & 0x0FFF; } } - } while (outBuffer < outBufferEnd); - - return outS; + } while ((outSize == -1 || outBuffer < outBufferEnd) || (inSize == -1 || source.pos() < endPos)); } /*----------------------------------------------------------------*/ @@ -325,13 +354,14 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool // Animation cutscene image files use a 16-bit x offset frame._offset.x = stream.readUint16LE(); frame._rleEncoded = (frame._offset.x & 0xff) == 1; + frame._offset.y = stream.readByte(); } else { // Standard image files have a separate byte for the RLE flag, and an 8-bit X offset frame._rleEncoded = stream.readByte() == 1; frame._offset.x = stream.readByte(); + frame._offset.y = stream.readByte(); } - frame._offset.y = stream.readByte(); frame._rleEncoded = !skipPalette && frame._rleEncoded; if (frame._paletteBase) { @@ -385,6 +415,28 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) { *pDest++ = *src & 0xF; *pDest++ = (*src >> 4); } + } else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) { + // Rose Tattoo run length encoding doesn't use the RLE marker byte + byte *dst = (byte *)frame._frame.getPixels(); + + for (int yp = 0; yp < frame._height; ++yp) { + int xSize = frame._width; + while (xSize > 0) { + // Skip a given number of pixels + byte skip = *src++; + dst += skip; + xSize -= skip; + if (!xSize) + break; + + // Get a run length, and copy the following number of pixels + int rleCount = *src++; + xSize -= rleCount; + while (rleCount-- > 0) + *dst++ = *src++; + } + assert(xSize == 0); + } } else if (frame._rleEncoded) { // RLE encoded byte *dst = (byte *)frame._frame.getPixels(); diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h index fb91b30f94..659ecf0110 100644 --- a/engines/sherlock/resources.h +++ b/engines/sherlock/resources.h @@ -90,7 +90,7 @@ private: /** * Reads in the index from a library file, and caches it's index for later use */ - void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream); + void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle); public: Resources(SherlockEngine *vm); @@ -140,14 +140,29 @@ public: int resourceIndex() const; /** - * Decompresses an LZW block of data with a specified output size + * Decompresses LZW compressed data + */ + Common::SeekableReadStream *decompress(Common::SeekableReadStream &source); + + /** + * Decompresses LZW compressed data + */ + Common::SeekableReadStream *decompress(Common::SeekableReadStream &source, uint32 outSize); + + /** + * Decompresses LZW compressed data + */ + void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize); + + /** + * Decompresses LZW compressed data */ static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize); - + /** - * Decompress an LZW compressed resource + * Decompresses LZW compressed data */ - Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source); + static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize); }; struct ImageFrame { diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index 7875f22c47..ccc9c8abca 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -23,6 +23,7 @@ #include "sherlock/scalpel/scalpel.h" #include "sherlock/sherlock.h" #include "sherlock/animation.h" +#include "engines/util.h" namespace Sherlock { @@ -378,6 +379,9 @@ ScalpelEngine::~ScalpelEngine() { } void ScalpelEngine::initialize() { + initGraphics(320, 200, false); + + // Let the base engine intialize SherlockEngine::initialize(); _darts = new Darts(this); @@ -386,6 +390,13 @@ void ScalpelEngine::initialize() { _flags[3] = true; // Turn on Alley _flags[39] = true; // Turn on Baker Street + // Add some more files to the cache + _res->addToCache("portrait.lib"); + _res->addToCache("sequence.txt"); + _res->addToCache("EPILOGUE.SND"); + _res->addToCache("snd.snd"); + _res->addToCache("title.snd"); + if (!isDemo()) { // Load the map co-ordinates for each scene and sequence data _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]); @@ -579,9 +590,9 @@ bool ScalpelEngine::scrollCredits() { _screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0); // Don't show credit text on the top and bottom ten rows of the screen - _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 10)); - _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 10), - Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); + _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w(), 10)); + _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10), + Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h())); _events->delay(100); } diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index 5ae7e25258..2c80bfbd39 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -23,6 +23,7 @@ #include "sherlock/scene.h" #include "sherlock/sherlock.h" #include "sherlock/scalpel/scalpel.h" +#include "sherlock/screen.h" namespace Sherlock { @@ -33,13 +34,38 @@ static const int FS_TRANS[8] = { /*----------------------------------------------------------------*/ -void BgFileHeader::load(Common::SeekableReadStream &s) { +BgFileHeader::BgFileHeader() { + _numStructs = -1; + _numImages = -1; + _numcAnimations = -1; + _descSize = -1; + _seqSize = -1; + + // Serrated Scalpel + _fill = -1; + + // Rose Tattoo + _scrollSize = -1; + _bytesWritten = -1; + _fadeStyle = -1; + Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0); +} + +void BgFileHeader::load(Common::SeekableReadStream &s, bool isRoseTattoo) { _numStructs = s.readUint16LE(); _numImages = s.readUint16LE(); _numcAnimations = s.readUint16LE(); _descSize = s.readUint16LE(); _seqSize = s.readUint16LE(); - _fill = s.readUint16LE(); + + if (isRoseTattoo) { + _scrollSize = s.readUint16LE(); + _bytesWritten = s.readUint32LE(); + _fadeStyle = s.readByte(); + } else { + _fill = s.readUint16LE(); + + } } /*----------------------------------------------------------------*/ @@ -55,18 +81,30 @@ void BgFileHeaderInfo::load(Common::SeekableReadStream &s) { /*----------------------------------------------------------------*/ -void Exit::load(Common::SeekableReadStream &s) { - int xp = s.readSint16LE(); - int yp = s.readSint16LE(); - int xSize = s.readSint16LE(); - int ySize = s.readSint16LE(); - _bounds = Common::Rect(xp, yp, xp + xSize, yp + ySize); +void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) { + if (isRoseTattoo) { + char buffer[41]; + s.read(buffer, 41); + _dest = Common::String(buffer); + } + left = s.readSint16LE(); + top = s.readSint16LE(); + setWidth(s.readUint16LE()); + setHeight(s.readUint16LE()); + + _image = isRoseTattoo ? s.readByte() : 0; _scene = s.readSint16LE(); - _allow = s.readSint16LE(); + + if (!isRoseTattoo) + _allow = s.readSint16LE(); + _people.x = s.readSint16LE(); _people.y = s.readSint16LE(); _peopleDir = s.readUint16LE(); + + if (isRoseTattoo) + _allow = s.readSint16LE(); } /*----------------------------------------------------------------*/ @@ -100,7 +138,19 @@ int ObjectArray::indexOf(const Object &obj) const { /*----------------------------------------------------------------*/ -Scene::Scene(SherlockEngine *vm) : _vm(vm) { +void ScaleZone::load(Common::SeekableReadStream &s) { + left = s.readSint16LE(); + top = s.readSint16LE(); + setWidth(s.readUint16LE()); + setHeight(s.readUint16LE()); + + _topNumber = s.readByte(); + _bottomNumber = s.readByte(); +} + +/*----------------------------------------------------------------*/ + +Scene::Scene(SherlockEngine *vm): _vm(vm) { for (int idx = 0; idx < SCENES_COUNT; ++idx) Common::fill(&_sceneStats[idx][0], &_sceneStats[idx][65], false); _currentScene = -1; @@ -115,6 +165,7 @@ Scene::Scene(SherlockEngine *vm) : _vm(vm) { _animating = 0; _doBgAnimDone = true; _tempFadeStyle = 0; + _exitZone = -1; } Scene::~Scene() { @@ -194,6 +245,7 @@ bool Scene::loadScene(const Common::String &filename) { Events &events = *_vm->_events; Map &map = *_vm->_map; People &people = *_vm->_people; + Resources &res = *_vm->_res; SaveManager &saves = *_vm->_saves; Screen &screen = *_vm->_screen; Sound &sound = *_vm->_sound; @@ -213,7 +265,7 @@ bool Scene::loadScene(const Common::String &filename) { _sequenceBuffer.clear(); // - // Load background shapes from <filename>.rrm + // Load the room resource file for the scene // Common::String rrmFile = filename + ".rrm"; @@ -222,15 +274,35 @@ bool Scene::loadScene(const Common::String &filename) { Common::SeekableReadStream *rrmStream = _vm->_res->load(rrmFile); rrmStream->seek(39); - _version = rrmStream->readByte(); - _lzwMode = _version == 10; + if (IS_SERRATED_SCALPEL) { + _version = rrmStream->readByte(); + _lzwMode = _version == 10; + } else { + _lzwMode = rrmStream->readByte() > 0; + } // Go to header and read it in rrmStream->seek(rrmStream->readUint32LE()); + BgFileHeader bgHeader; - bgHeader.load(*rrmStream); + bgHeader.load(*rrmStream, IS_ROSE_TATTOO); _invGraphicItems = bgHeader._numImages + 1; + if (IS_ROSE_TATTOO) { + screen.initPaletteFade(bgHeader._bytesWritten); + screen.fadeRead(*rrmStream, screen._cMap, PALETTE_SIZE); + screen.setupBGArea(screen._cMap); + + screen.initScrollVars(); + + // Read in background + if (_lzwMode) { + res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); + } else { + rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); + } + } + // Read in the shapes header info Common::Array<BgFileHeaderInfo> bgInfo; bgInfo.resize(bgHeader._numStructs); @@ -239,10 +311,30 @@ bool Scene::loadScene(const Common::String &filename) { bgInfo[idx].load(*rrmStream); // Read information - if (!_lzwMode) { + if (IS_SERRATED_SCALPEL) { + Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : + res.decompress(*rrmStream, bgHeader._numStructs * 569 + bgHeader._descSize + bgHeader._seqSize); + _bgShapes.resize(bgHeader._numStructs); for (int idx = 0; idx < bgHeader._numStructs; ++idx) - _bgShapes[idx].load(*rrmStream); + _bgShapes[idx].load(*infoStream, false); + + if (bgHeader._descSize) { + _descText.resize(bgHeader._descSize); + infoStream->read(&_descText[0], bgHeader._descSize); + } + + if (bgHeader._seqSize) { + _sequenceBuffer.resize(bgHeader._seqSize); + infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize); + } + + if (_lzwMode) + delete infoStream; + } else if (!_lzwMode) { + _bgShapes.resize(bgHeader._numStructs); + for (int idx = 0; idx < bgHeader._numStructs; ++idx) + _bgShapes[idx].load(*rrmStream, false); if (bgHeader._descSize) { _descText.resize(bgHeader._descSize); @@ -261,7 +353,7 @@ bool Scene::loadScene(const Common::String &filename) { _bgShapes.resize(bgHeader._numStructs); for (int idx = 0; idx < bgHeader._numStructs; ++idx) - _bgShapes[idx].load(*infoStream); + _bgShapes[idx].load(*infoStream, false); delete infoStream; @@ -294,7 +386,7 @@ bool Scene::loadScene(const Common::String &filename) { // Read in the image data Common::SeekableReadStream *imageStream = _lzwMode ? - Resources::decompressLZ(*rrmStream, bgInfo[idx]._filesize) : + res.decompress(*rrmStream, bgInfo[idx]._filesize) : rrmStream->readStream(bgInfo[idx]._filesize); _images[idx + 1]._images = new ImageFile(*imageStream); @@ -322,13 +414,14 @@ bool Scene::loadScene(const Common::String &filename) { // Load in cAnim list _cAnim.clear(); if (bgHeader._numcAnimations) { + int animSize = IS_SERRATED_SCALPEL ? 65 : 47; Common::SeekableReadStream *canimStream = _lzwMode ? - Resources::decompressLZ(*rrmStream, 65 * bgHeader._numcAnimations) : - rrmStream->readStream(65 * bgHeader._numcAnimations); + res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) : + rrmStream->readStream(animSize * bgHeader._numcAnimations); _cAnim.resize(bgHeader._numcAnimations); for (uint idx = 0; idx < _cAnim.size(); ++idx) - _cAnim[idx].load(*canimStream); + _cAnim[idx].load(*canimStream, IS_ROSE_TATTOO); delete canimStream; } @@ -336,7 +429,7 @@ bool Scene::loadScene(const Common::String &filename) { // Read in the room bounding areas int size = rrmStream->readUint16LE(); Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream : - Resources::decompressLZ(*rrmStream, size); + res.decompress(*rrmStream, size); _zones.resize(size / 10); for (uint idx = 0; idx < _zones.size(); ++idx) { @@ -351,10 +444,11 @@ bool Scene::loadScene(const Common::String &filename) { delete boundsStream; // Ensure we've reached the path version byte - if (rrmStream->readByte() != 254) + if (rrmStream->readByte() != (IS_SERRATED_SCALPEL ? 254 : 251)) error("Invalid scene path data"); // Load the walk directory + assert(_zones.size() < MAX_ZONES); for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) { for (uint idx2 = 0; idx2 < _zones.size(); ++idx2) _walkDirectory[idx1][idx2] = rrmStream->readSint16LE(); @@ -363,7 +457,7 @@ bool Scene::loadScene(const Common::String &filename) { // Read in the walk data size = rrmStream->readUint16LE(); Common::SeekableReadStream *walkStream = !_lzwMode ? rrmStream : - Resources::decompressLZ(*rrmStream, size); + res.decompress(*rrmStream, size); _walkData.resize(size); walkStream->read(&_walkData[0], size); @@ -371,15 +465,27 @@ bool Scene::loadScene(const Common::String &filename) { if (_lzwMode) delete walkStream; + if (IS_ROSE_TATTOO) { + // Read in the entrance + _entrance.load(*rrmStream); + + // Load scale zones + _scaleZones.resize(rrmStream->readByte()); + for (uint idx = 0; idx < _scaleZones.size(); ++idx) + _scaleZones[idx].load(*rrmStream); + } + // Read in the exits + _exitZone = -1; int numExits = rrmStream->readByte(); _exits.resize(numExits); for (int idx = 0; idx < numExits; ++idx) - _exits[idx].load(*rrmStream); + _exits[idx].load(*rrmStream, IS_ROSE_TATTOO); - // Read in the entrance - _entrance.load(*rrmStream); + if (IS_SERRATED_SCALPEL) + // Read in the entrance + _entrance.load(*rrmStream); // Initialize sound list int numSounds = rrmStream->readByte(); @@ -388,24 +494,34 @@ bool Scene::loadScene(const Common::String &filename) { for (int idx = 0; idx < numSounds; ++idx) _sounds[idx].load(*rrmStream); - for (int idx = 0; idx < numSounds; ++idx) - sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority); + loadSceneSounds(); - // Read in palette - rrmStream->read(screen._cMap, PALETTE_SIZE); - for (int idx = 0; idx < PALETTE_SIZE; ++idx) - screen._cMap[idx] = VGA_COLOR_TRANS(screen._cMap[idx]); + if (IS_ROSE_TATTOO) { + // Load the object sound list + char buffer[27]; + + _objSoundList.resize(rrmStream->readUint16LE()); + for (uint idx = 0; idx < _objSoundList.size(); ++idx) { + rrmStream->read(buffer, 27); + _objSoundList[idx] = Common::String(buffer); + } + } else { + // Read in palette + rrmStream->read(screen._cMap, PALETTE_SIZE); + for (int idx = 0; idx < PALETTE_SIZE; ++idx) + screen._cMap[idx] = VGA_COLOR_TRANS(screen._cMap[idx]); - Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap); + Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap); - // Read in the background - Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream : - Resources::decompressLZ(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); + // Read in the background + Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream : + res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); - bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); + bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); - if (_lzwMode) - delete bgStream; + if (_lzwMode) + delete bgStream; + } // Backup the image and set the palette screen._backBuffer2.blitFrom(screen._backBuffer1); @@ -472,6 +588,13 @@ bool Scene::loadScene(const Common::String &filename) { return flag; } +void Scene::loadSceneSounds() { + Sound &sound = *_vm->_sound; + + for (uint idx = 0; idx < _sounds.size(); ++idx) + sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority); +} + void Scene::checkSceneStatus() { if (_sceneStats[_currentScene][64]) { for (uint idx = 0; idx < 64; ++idx) { @@ -793,7 +916,7 @@ void Scene::updateBackground() { Exit *Scene::checkForExit(const Common::Rect &r) { for (uint idx = 0; idx < _exits.size(); ++idx) { - if (_exits[idx]._bounds.intersects(r)) + if (_exits[idx].intersects(r)) return &_exits[idx]; } @@ -1112,7 +1235,7 @@ void Scene::doBgAnim() { _canimShapes[idx].checkObject(); } - if (_currentScene == 12 && _vm->getGameID() == GType_SerratedScalpel) + if (_currentScene == 12 && IS_SERRATED_SCALPEL) ((Scalpel::ScalpelEngine *)_vm)->eraseMirror12(); // Restore the back buffer from the back buffer 2 in the changed area @@ -1185,7 +1308,7 @@ void Scene::doBgAnim() { checkBgShapes(people[AL]._imageFrame, Common::Point(people[AL]._position.x / 100, people[AL]._position.y / 100)); - if (_currentScene == 12 && _vm->getGameID() == GType_SerratedScalpel) + if (_currentScene == 12 && IS_SERRATED_SCALPEL) ((Scalpel::ScalpelEngine *)_vm)->doMirror12(); // Draw all active shapes which are behind the person @@ -1295,7 +1418,7 @@ void Scene::doBgAnim() { } } - if (_currentScene == 12 && _vm->getGameID() == GType_SerratedScalpel) + if (_currentScene == 12 && IS_SERRATED_SCALPEL) ((Scalpel::ScalpelEngine *)_vm)->flushMirror12(); for (uint idx = 0; idx < _bgShapes.size(); ++idx) { diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h index 88d12a3fb0..0cbd775c56 100644 --- a/engines/sherlock/scene.h +++ b/engines/sherlock/scene.h @@ -29,6 +29,7 @@ #include "common/serializer.h" #include "sherlock/objects.h" #include "sherlock/resources.h" +#include "sherlock/screen.h" namespace Sherlock { @@ -44,12 +45,23 @@ struct BgFileHeader { int _numcAnimations; int _descSize; int _seqSize; + + // Serrated Scalpel int _fill; + // Rose Tattoo + int _scrollSize; + int _bytesWritten; // Size of the main body of the RRM + int _fadeStyle; // Fade style + byte _palette[PALETTE_SIZE]; // Palette + + + BgFileHeader(); + /** * Load the data for the object */ - void load(Common::SeekableReadStream &s); + void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; struct BgFileHeaderInfo { @@ -63,18 +75,20 @@ struct BgFileHeaderInfo { void load(Common::SeekableReadStream &s); }; -struct Exit { - Common::Rect _bounds; - +class Exit: public Common::Rect { +public: int _scene; int _allow; Common::Point _people; int _peopleDir; + Common::String _dest; + int _image; // Arrow image to use + /** * Load the data for the object */ - void load(Common::SeekableReadStream &s); + void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; struct SceneEntry { @@ -106,6 +120,14 @@ public: int indexOf(const Object &obj) const; }; +class ScaleZone: public Common::Rect { +public: + int _topNumber; // Numerator of scale size at the top of the zone + int _bottomNumber; // Numerator of scale size at the bottom of the zone + + void load(Common::SeekableReadStream &s); +}; + class Scene { private: SherlockEngine *_vm; @@ -124,6 +146,11 @@ private: bool loadScene(const Common::String &filename); /** + * Loads sounds for the scene + */ + void loadSceneSounds(); + + /** * Set objects to their current persistent state. This includes things such as * opening or moving them */ @@ -154,6 +181,7 @@ private: * will remain the same on future visits to the scene */ void saveSceneStatus(); + public: int _currentScene; int _goToScene; @@ -173,9 +201,12 @@ public: int _walkDirectory[MAX_ZONES][MAX_ZONES]; Common::Array<byte> _walkData; Common::Array<Exit> _exits; + int _exitZone; SceneEntry _entrance; Common::Array<SceneSound> _sounds; ObjectArray _canimShapes; + Common::Array<ScaleZone> _scaleZones; + Common::StringArray _objSoundList; bool _restoreFlag; int _animating; bool _doBgAnimDone; diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp index e70d0614d1..24f7660743 100644 --- a/engines/sherlock/screen.cpp +++ b/engines/sherlock/screen.cpp @@ -28,9 +28,9 @@ namespace Sherlock { -Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _vm(vm), - _backBuffer1(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), - _backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), +Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm), + _backBuffer1(g_system->getWidth(), g_system->getHeight()), + _backBuffer2(g_system->getWidth(), g_system->getHeight()), _backBuffer(&_backBuffer1) { _transitionSeed = 1; _fadeStyle = false; @@ -38,7 +38,15 @@ Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCR _fontHeight = 0; Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0); Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0); + Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0); setFont(1); + + // Rose Tattoo specific fields + _fadeBytesRead = _fadeBytesToRead = 0; + _oldFadePercent = 0; + _scrollSize = 0; + _currentScroll = 0; + _targetScroll = 0; } Screen::~Screen() { @@ -179,7 +187,7 @@ void Screen::randomTransition() { _transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1; int offset = _transitionSeed & 0xFFFF; - if (offset < (SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT)) + if (offset < (this->w() * this->h())) *((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset); if (idx != 0 && (idx % 300) == 0) { @@ -199,12 +207,12 @@ void Screen::randomTransition() { void Screen::verticalTransition() { Events &events = *_vm->_events; - byte table[SHERLOCK_SCREEN_WIDTH]; - Common::fill(&table[0], &table[SHERLOCK_SCREEN_WIDTH], 0); + byte table[640]; + Common::fill(&table[0], &table[640], 0); - for (int yp = 0; yp < SHERLOCK_SCREEN_HEIGHT; ++yp) { - for (int xp = 0; xp < SHERLOCK_SCREEN_WIDTH; ++xp) { - int temp = (table[xp] >= 197) ? SHERLOCK_SCREEN_HEIGHT - table[xp] : + for (int yp = 0; yp < this->h(); ++yp) { + for (int xp = 0; xp < this->w(); ++xp) { + int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] : _vm->getRandomNumber(3) + 1; if (temp) { @@ -221,7 +229,7 @@ void Screen::verticalTransition() { void Screen::restoreBackground(const Common::Rect &r) { if (r.width() > 0 && r.height() > 0) { Common::Rect tempRect = r; - tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT)); + tempRect.clip(Common::Rect(0, 0, this->w(), SHERLOCK_SCENE_HEIGHT)); if (tempRect.isValidRect()) _backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect); @@ -235,7 +243,7 @@ void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) { void Screen::slamRect(const Common::Rect &r) { if (r.width() && r.height() > 0) { Common::Rect tempRect = r; - tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); + tempRect.clip(Common::Rect(0, 0, this->w(), this->h())); if (tempRect.isValidRect()) blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect); @@ -281,13 +289,13 @@ void Screen::print(const Common::Point &pt, byte color, const char *formatStr, . pos.y--; // Font is always drawing one line higher if (!pos.x) // Center text horizontally - pos.x = (SHERLOCK_SCREEN_WIDTH - width) / 2; + pos.x = (this->w() - width) / 2; Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight); - if (textBounds.right > SHERLOCK_SCREEN_WIDTH) - textBounds.moveTo(SHERLOCK_SCREEN_WIDTH - width, textBounds.top); - if (textBounds.bottom > SHERLOCK_SCREEN_HEIGHT) - textBounds.moveTo(textBounds.left, SHERLOCK_SCREEN_HEIGHT - _fontHeight); + if (textBounds.right > this->w()) + textBounds.moveTo(this->w() - width, textBounds.top); + if (textBounds.bottom > this->h()) + textBounds.moveTo(textBounds.left, this->h() - _fontHeight); // Write out the string at the given position writeString(str, Common::Point(textBounds.left, textBounds.top), color); @@ -416,7 +424,7 @@ void Screen::resetDisplayBounds() { Common::Rect Screen::getDisplayBounds() { return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) : - Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + Common::Rect(0, 0, this->w(), this->h()); } void Screen::synchronize(Common::Serializer &s) { @@ -426,4 +434,36 @@ void Screen::synchronize(Common::Serializer &s) { setFont(fontNumb); } +void Screen::initPaletteFade(int bytesToRead) { + Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_sMap[0]); + Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_tMap[0]); + + // Set how many bytes need to be read / have been read + _fadeBytesRead = 0; + _fadeBytesToRead = bytesToRead; + _oldFadePercent = 0; +} + +int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize) { + warning("TODO: fadeRead"); + stream.read(buf, totalSize); + return totalSize; +} + +/** + * Creates a grey-scale version of the passed palette + */ +void Screen::setupBGArea(const byte cMap[PALETTE_SIZE]) { + warning("TODO"); +} + +/** + * Initializes scroll variables + */ +void Screen::initScrollVars() { + _scrollSize = 0; + _currentScroll = 0; + _targetScroll = 0; +} + } // End of namespace Sherlock diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h index a2c0aa3c84..f4cd6fd955 100644 --- a/engines/sherlock/screen.h +++ b/engines/sherlock/screen.h @@ -66,6 +66,15 @@ private: int _fontHeight; Surface _sceneSurface; + // Rose Tattoo fields + int _fadeBytesRead, _fadeBytesToRead; + int _oldFadePercent; + byte _lookupTable[PALETTE_COUNT]; + byte _lookupTable1[PALETTE_COUNT]; + int _scrollSize; + int _currentScroll; + int _targetScroll; +private: /** * Merges together overlapping dirty areas of the screen */ @@ -92,6 +101,7 @@ public: bool _fadeStyle; byte _cMap[PALETTE_SIZE]; byte _sMap[PALETTE_SIZE]; + byte _tMap[PALETTE_SIZE]; public: Screen(SherlockEngine *vm); virtual ~Screen(); @@ -232,6 +242,15 @@ public: * Synchronize the data for a savegame */ void synchronize(Common::Serializer &s); + + // Rose Tattoo specific methods + void initPaletteFade(int bytesToRead); + + int fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize); + + void setupBGArea(const byte cMap[PALETTE_SIZE]); + + void initScrollVars(); }; } // End of namespace Sherlock diff --git a/engines/sherlock/settings.cpp b/engines/sherlock/settings.cpp index bf5294f08b..cae5c6c67a 100644 --- a/engines/sherlock/settings.cpp +++ b/engines/sherlock/settings.cpp @@ -209,9 +209,10 @@ void Settings::show(SherlockEngine *vm) { Screen &screen = *vm->_screen; Sound &sound = *vm->_sound; Talk &talk = *vm->_talk; - UserInterface &ui = *vm->_ui; + ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui; bool updateConfig = false; + assert(vm->getGameID() == GType_SerratedScalpel); Settings settings(vm); settings.drawInteface(false); diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp index d4644d4d9d..5973823f96 100644 --- a/engines/sherlock/sherlock.cpp +++ b/engines/sherlock/sherlock.cpp @@ -25,7 +25,6 @@ #include "common/scummsys.h" #include "common/config-manager.h" #include "common/debug-channels.h" -#include "engines/util.h" namespace Sherlock { @@ -70,8 +69,6 @@ SherlockEngine::~SherlockEngine() { } void SherlockEngine::initialize() { - initGraphics(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, false); - DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level"); ImageFile::setVm(this); @@ -99,7 +96,7 @@ void SherlockEngine::initialize() { _screen = new Screen(this); _sound = new Sound(this, _mixer); _talk = new Talk(this); - _ui = new UserInterface(this); + _ui = UserInterface::init(this); // Load game settings loadConfig(); diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h index 24a72076ef..bf8c0d6aaf 100644 --- a/engines/sherlock/sherlock.h +++ b/engines/sherlock/sherlock.h @@ -58,8 +58,8 @@ enum GameType { GType_RoseTattoo = 1 }; -#define SHERLOCK_SCREEN_WIDTH 320 -#define SHERLOCK_SCREEN_HEIGHT 200 +#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w() +#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h() #define SHERLOCK_SCENE_HEIGHT 138 struct SherlockGameDescription; @@ -197,6 +197,9 @@ public: void synchronize(Common::Serializer &s); }; +#define IS_ROSE_TATTOO (_vm->getGameID() == GType_RoseTattoo) +#define IS_SERRATED_SCALPEL (_vm->getGameID() == GType_SerratedScalpel) + } // End of namespace Sherlock #endif diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp index 4f27481f5b..06f6a0f264 100644 --- a/engines/sherlock/sound.cpp +++ b/engines/sherlock/sound.cpp @@ -63,6 +63,7 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { _musicOn = true; _speechOn = true; + _vm->_res->addToCache("MUSIC.LIB"); if (!_vm->_interactiveFl) _vm->_res->addToCache("TITLE.SND"); else { diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index 319d1a383f..1a926a543d 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -172,9 +172,11 @@ void Talk::talkTo(const Common::String &filename) { while (!_sequenceStack.empty()) pullSequence(); - // Restore any pressed button - if (!ui._windowOpen && savedMode != STD_MODE) - ui.restoreButton((int)(savedMode - 1)); + if (IS_SERRATED_SCALPEL) { + // Restore any pressed button + if (!ui._windowOpen && savedMode != STD_MODE) + ((ScalpelUserInterface *)_vm->_ui)->restoreButton((int)(savedMode - 1)); + } // Clear the ui counter so that anything displayed on the info line // before the window was opened isn't cleared diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h index d26259dbfd..48290e965e 100644 --- a/engines/sherlock/talk.h +++ b/engines/sherlock/talk.h @@ -123,10 +123,10 @@ struct TalkSequences { }; class SherlockEngine; -class UserInterface; +class ScalpelUserInterface; class Talk { - friend class UserInterface; + friend class ScalpelUserInterface; private: SherlockEngine *_vm; Common::Stack<SequenceEntry> _savedSequences; diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp index d4059ac413..3c684ff3ee 100644 --- a/engines/sherlock/tattoo/tattoo.cpp +++ b/engines/sherlock/tattoo/tattoo.cpp @@ -21,6 +21,7 @@ */ #include "sherlock/tattoo/tattoo.h" +#include "engines/util.h" namespace Sherlock { @@ -30,6 +31,33 @@ void TattooEngine::showOpening() { // TODO } +/** + * Initialize the engine + */ +void TattooEngine::initialize() { + initGraphics(640, 480, true); + + // Initialize the base engine + SherlockEngine::initialize(); + + _flags.resize(100 * 8); + + // Add some more files to the cache + _res->addToCache("walk.lib"); + _res->addToCache("sound.lib"); + + // Starting scene + _scene->_goToScene = 91; +} + +/** + * Starting a scene within the game + */ +void TattooEngine::startScene() { + // TODO +} + + } // End of namespace Tattoo } // End of namespace Scalpel diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h index b98395597c..7bdeec55d1 100644 --- a/engines/sherlock/tattoo/tattoo.h +++ b/engines/sherlock/tattoo/tattoo.h @@ -31,10 +31,15 @@ namespace Tattoo { class TattooEngine : public SherlockEngine { protected: + virtual void initialize(); + virtual void showOpening(); + + virtual void startScene(); public: TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) : SherlockEngine(syst, gameDesc) {} + virtual ~TattooEngine() {} }; diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp index 524ecf3d2f..7a6722a218 100644 --- a/engines/sherlock/user_interface.cpp +++ b/engines/sherlock/user_interface.cpp @@ -78,57 +78,66 @@ const char *const MUSE[] = { "Doors don't smoke" }; -/*----------------------------------------------------------------*/ + + +UserInterface *UserInterface::init(SherlockEngine *vm) { + if (vm->getGameID() == GType_SerratedScalpel) + return new ScalpelUserInterface(vm); + else + return new TattooUserInterface(vm); +} UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) { - if (_vm->_interactiveFl) { - _controls = new ImageFile("menu.all"); - _controlPanel = new ImageFile("controls.vgs"); - } else { - _controls = nullptr; - _controlPanel = nullptr; - } + _menuMode = STD_MODE; + _menuCounter = 0; + _infoFlag = false; + _windowOpen = false; + _endKeyActive = true; + _invLookFlag = 0; + _slideWindows = true; + _helpStyle = false; + _windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1, SHERLOCK_SCREEN_HEIGHT - 1); + _lookScriptFlag = false; + + _key = _oldKey = '\0'; + _selector = _oldSelector = -1; + _temp = _oldTemp = 0; + _temp1 = 0; + _lookHelp = 0; +} + +/*----------------------------------------------------------------*/ +ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) { + _controls = new ImageFile("menu.all"); + _controlPanel = new ImageFile("controls.vgs"); + _keyPress = '\0'; + _lookHelp = 0; _bgFound = 0; _oldBgFound = -1; - _keyPress = '\0'; - _helpStyle = false; - _menuCounter = 0; - _menuMode = STD_MODE; _help = _oldHelp = 0; - _lookHelp = 0; _key = _oldKey = '\0'; _temp = _oldTemp = 0; - _temp1 = 0; - _invLookFlag = 0; - _windowOpen = false; - _oldLook = false; + _oldLook = 0; _keyboardInput = false; _pause = false; _cNum = 0; - _selector = _oldSelector = -1; - _windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1, - SHERLOCK_SCREEN_HEIGHT - 1); - _slideWindows = true; _find = 0; _oldUse = 0; - _endKeyActive = true; - _lookScriptFlag = false; - _infoFlag = false; } -UserInterface::~UserInterface() { +ScalpelUserInterface::~ScalpelUserInterface() { delete _controls; delete _controlPanel; } -void UserInterface::reset() { +void ScalpelUserInterface::reset() { _oldKey = -1; _help = _oldHelp = -1; _oldTemp = _temp = -1; } -void UserInterface::drawInterface(int bufferNum) { +void ScalpelUserInterface::drawInterface(int bufferNum) { Screen &screen = *_vm->_screen; if (bufferNum & 1) @@ -139,7 +148,7 @@ void UserInterface::drawInterface(int bufferNum) { screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK); } -void UserInterface::handleInput() { +void ScalpelUserInterface::handleInput() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; People &people = *_vm->_people; @@ -392,7 +401,7 @@ void UserInterface::handleInput() { } } -void UserInterface::depressButton(int num) { +void ScalpelUserInterface::depressButton(int num) { Screen &screen = *_vm->_screen; Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]); @@ -401,7 +410,7 @@ void UserInterface::depressButton(int num) { screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height); } -void UserInterface::restoreButton(int num) { +void ScalpelUserInterface::restoreButton(int num) { Screen &screen = *_vm->_screen; Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]); Graphics::Surface &frame = (*_controls)[num]._frame; @@ -416,7 +425,7 @@ void UserInterface::restoreButton(int num) { } } -void UserInterface::pushButton(int num) { +void ScalpelUserInterface::pushButton(int num) { Events &events = *_vm->_events; _oldKey = -1; @@ -433,7 +442,7 @@ void UserInterface::pushButton(int num) { restoreButton(num); } -void UserInterface::toggleButton(int num) { +void ScalpelUserInterface::toggleButton(int num) { Screen &screen = *_vm->_screen; if (_menuMode != (MenuMode)(num + 1)) { @@ -461,7 +470,7 @@ void UserInterface::toggleButton(int num) { } } -void UserInterface::clearInfo() { +void ScalpelUserInterface::clearInfo() { if (_infoFlag) { _vm->_screen->vgaBar(Common::Rect(16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - 19, INFO_LINE + 10), INFO_BLACK); @@ -470,14 +479,14 @@ void UserInterface::clearInfo() { } } -void UserInterface::clearWindow() { +void ScalpelUserInterface::clearWindow() { if (_windowOpen) { _vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND); } } -void UserInterface::whileMenuCounter() { +void ScalpelUserInterface::whileMenuCounter() { if (!(--_menuCounter) || _vm->_events->checkInput()) { _menuCounter = 0; _infoFlag = true; @@ -485,7 +494,7 @@ void UserInterface::whileMenuCounter() { } } -void UserInterface::examine() { +void ScalpelUserInterface::examine() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; People &people = *_vm->_people; @@ -536,7 +545,7 @@ void UserInterface::examine() { } } -void UserInterface::lookScreen(const Common::Point &pt) { +void ScalpelUserInterface::lookScreen(const Common::Point &pt) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Scene &scene = *_vm->_scene; @@ -649,7 +658,7 @@ void UserInterface::lookScreen(const Common::Point &pt) { } } -void UserInterface::lookInv() { +void ScalpelUserInterface::lookInv() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Screen &screen = *_vm->_screen; @@ -674,7 +683,7 @@ void UserInterface::lookInv() { } } -void UserInterface::doEnvControl() { +void ScalpelUserInterface::doEnvControl() { Events &events = *_vm->_events; SaveManager &saves = *_vm->_saves; Scene &scene = *_vm->_scene; @@ -976,7 +985,7 @@ void UserInterface::doEnvControl() { } } -void UserInterface::doInvControl() { +void ScalpelUserInterface::doInvControl() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Scene &scene = *_vm->_scene; @@ -1199,7 +1208,7 @@ void UserInterface::doInvControl() { } } -void UserInterface::doLookControl() { +void ScalpelUserInterface::doLookControl() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Screen &screen = *_vm->_screen; @@ -1260,7 +1269,7 @@ void UserInterface::doLookControl() { } } -void UserInterface::doMainControl() { +void ScalpelUserInterface::doMainControl() { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; SaveManager &saves = *_vm->_saves; @@ -1398,7 +1407,7 @@ void UserInterface::doMainControl() { } } -void UserInterface::doMiscControl(int allowed) { +void ScalpelUserInterface::doMiscControl(int allowed) { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; Talk &talk = *_vm->_talk; @@ -1447,7 +1456,7 @@ void UserInterface::doMiscControl(int allowed) { } } -void UserInterface::doPickControl() { +void ScalpelUserInterface::doPickControl() { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; Talk &talk = *_vm->_talk; @@ -1470,7 +1479,7 @@ void UserInterface::doPickControl() { } } -void UserInterface::doTalkControl() { +void ScalpelUserInterface::doTalkControl() { Events &events = *_vm->_events; Journal &journal = *_vm->_journal; People &people = *_vm->_people; @@ -1720,7 +1729,7 @@ void UserInterface::doTalkControl() { } } -void UserInterface::journalControl() { +void ScalpelUserInterface::journalControl() { Events &events = *_vm->_events; Journal &journal = *_vm->_journal; Scene &scene = *_vm->_scene; @@ -1768,7 +1777,7 @@ void UserInterface::journalControl() { screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } -void UserInterface::printObjectDesc(const Common::String &str, bool firstTime) { +void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; Screen &screen = *_vm->_screen; @@ -1936,11 +1945,11 @@ void UserInterface::printObjectDesc(const Common::String &str, bool firstTime) { } } -void UserInterface::printObjectDesc() { +void ScalpelUserInterface::printObjectDesc() { printObjectDesc(_cAnimStr, true); } -void UserInterface::summonWindow(const Surface &bgSurface, bool slideUp) { +void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -1979,7 +1988,7 @@ void UserInterface::summonWindow(const Surface &bgSurface, bool slideUp) { _windowOpen = true; } -void UserInterface::summonWindow(bool slideUp, int height) { +void ScalpelUserInterface::summonWindow(bool slideUp, int height) { Screen &screen = *_vm->_screen; // Extract the window that's been drawn on the back buffer @@ -1996,7 +2005,7 @@ void UserInterface::summonWindow(bool slideUp, int height) { summonWindow(tempSurface, slideUp); } -void UserInterface::banishWindow(bool slideUp) { +void ScalpelUserInterface::banishWindow(bool slideUp) { Events &events = *_vm->_events; Screen &screen = *_vm->_screen; @@ -2062,7 +2071,7 @@ void UserInterface::banishWindow(bool slideUp) { _menuMode = STD_MODE; } -void UserInterface::checkUseAction(const UseType *use, const Common::String &invName, +void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[], int objNum, bool giveMode) { Events &events = *_vm->_events; Inventory &inv = *_vm->_inventory; @@ -2155,7 +2164,7 @@ void UserInterface::checkUseAction(const UseType *use, const Common::String &inv events.setCursor(ARROW); } -void UserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) { +void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) { Events &events = *_vm->_events; People &people = *_vm->_people; Scene &scene = *_vm->_scene; @@ -2287,4 +2296,14 @@ void UserInterface::checkAction(ActionType &action, const char *const messages[] events.setCursor(ARROW); } +/*----------------------------------------------------------------*/ + +TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) { + // +} + +void TattooUserInterface::handleInput() { + // TODO +} + } // End of namespace Sherlock diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h index 1f7b5feaab..8a0f4f5613 100644 --- a/engines/sherlock/user_interface.h +++ b/engines/sherlock/user_interface.h @@ -61,20 +61,91 @@ extern const char *const PRESS_KEY_TO_CONTINUE; class SherlockEngine; class Inventory; class Talk; -class UserInterface; class UserInterface { +protected: + SherlockEngine *_vm; + + UserInterface(SherlockEngine *vm); +public: + MenuMode _menuMode; + int _menuCounter; + bool _infoFlag; + bool _windowOpen; + bool _endKeyActive; + int _invLookFlag; + bool _slideWindows; + bool _helpStyle; + Common::Rect _windowBounds; + bool _lookScriptFlag; + + // TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor + // various Scalpel dialogs to keep their own private state of key/selections + char _key, _oldKey; + int _selector, _oldSelector; + int _temp, _oldTemp; + int _temp1; + int _lookHelp; +public: + static UserInterface *init(SherlockEngine *vm); + + /** + * Resets the user interface + */ + virtual void reset() {} + + /** + * Draw the user interface onto the screen's back buffers + */ + virtual void drawInterface(int bufferNum = 3) {} + + /** + * Main input handler for the user interface + */ + virtual void handleInput() {} + + /** + * Displays a passed window by gradually scrolling it vertically on-screen + */ + virtual void summonWindow(const Surface &bgSurface, bool slideUp = true) {} + + /** + * Slide the window stored in the back buffer onto the screen + */ + virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y) {} + + /** + * Close a currently open window + * @param flag 0 = slide old window down, 1 = slide prior UI back up + */ + virtual void banishWindow(bool slideUp = true) {} + + /** + * Clears the info line of the screen + */ + virtual void clearInfo() {} + + /** + * Clear any active text window + */ + virtual void clearWindow() {} + + /** + * Print the previously selected object's decription + */ + virtual void printObjectDesc() {} +}; + +class ScalpelUserInterface: public UserInterface { friend class Inventory; friend class Settings; friend class Talk; private: - SherlockEngine *_vm; ImageFile *_controlPanel; ImageFile *_controls; - int _bgFound; - int _oldBgFound; char _keyPress; int _lookHelp; + int _bgFound, _oldBgFound; int _help, _oldHelp; char _key, _oldKey; int _temp, _oldTemp; @@ -82,10 +153,7 @@ private: bool _keyboardInput; bool _pause; int _cNum; - int _selector, _oldSelector; Common::String _cAnimStr; - bool _lookScriptFlag; - Common::Rect _windowBounds; Common::String _descStr; int _find; int _oldUse; @@ -178,81 +246,81 @@ private: * Called for OPEN, CLOSE, and MOVE actions are being done */ void checkAction(ActionType &action, const char *const messages[], int objNum); -public: - MenuMode _menuMode; - int _menuCounter; - bool _infoFlag; - bool _windowOpen; - bool _endKeyActive; - int _invLookFlag; - int _temp1; - bool _slideWindows; - bool _helpStyle; -public: - UserInterface(SherlockEngine *vm); - ~UserInterface(); /** - * Resets the user interface + * Print the previously selected object's decription */ - void reset(); + void printObjectDesc(const Common::String &str, bool firstTime); +public: + ScalpelUserInterface(SherlockEngine *vm); + ~ScalpelUserInterface(); /** - * Draw the user interface onto the screen's back buffers + * Handles counting down whilst checking for input, then clears the info line. */ - void drawInterface(int bufferNum = 3); + void whileMenuCounter(); /** - * Main input handler for the user interface + * Draws the image for the given user interface button in the up + * (not selected) position */ - void handleInput(); - + void restoreButton(int num); +public: /** - * Clears the info line of the screen + * Resets the user interface */ - void clearInfo(); + virtual void reset(); /** - * Clear any active text window + * Main input handler for the user interface */ - void clearWindow(); + virtual void handleInput(); /** - * Handles counting down whilst checking for input, then clears the info line. - */ - void whileMenuCounter(); + * Draw the user interface onto the screen's back buffers + */ + virtual void drawInterface(int bufferNum = 3); /** - * Print the description of an object + * Displays a passed window by gradually scrolling it vertically on-screen */ - void printObjectDesc(const Common::String &str, bool firstTime); - + virtual void summonWindow(const Surface &bgSurface, bool slideUp = true); + /** - * Print the previously selected object's decription + * Slide the window stored in the back buffer onto the screen */ - void printObjectDesc(); + virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y); /** - * Displays a passed window by gradually scrolling it vertically on-screen + * Close a currently open window + * @param flag 0 = slide old window down, 1 = slide prior UI back up */ - void summonWindow(const Surface &bgSurface, bool slideUp = true); - + virtual void banishWindow(bool slideUp = true); + /** - * Slide the window stored in the back buffer onto the screen + * Clears the info line of the screen */ - void summonWindow(bool slideUp = true, int height = CONTROLS_Y); - + virtual void clearInfo(); + /** - * Close a currently open window - * @param flag 0 = slide old window down, 1 = slide prior UI back up + * Clear any active text window */ - void banishWindow(bool slideUp = true); + virtual void clearWindow(); /** - * Draws the image for the given user interface button in the up - * (not selected) position + * Print the previously selected object's decription + */ + virtual void printObjectDesc(); +}; + +class TattooUserInterface : public UserInterface { +public: + TattooUserInterface(SherlockEngine *vm); +public: + /** + * Main input handler for the user interface */ - void restoreButton(int num); + virtual void handleInput(); }; } // End of namespace Sherlock |