aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/made/pmvplayer.cpp5
-rw-r--r--engines/made/screenfx.cpp2
-rw-r--r--engines/made/sound.cpp26
-rw-r--r--engines/made/sound.h17
-rw-r--r--engines/mohawk/riven_external.cpp33
-rw-r--r--engines/sherlock/events.cpp34
-rw-r--r--engines/sherlock/events.h6
-rw-r--r--engines/sherlock/module.mk1
-rw-r--r--engines/sherlock/objects.cpp4
-rw-r--r--engines/sherlock/scene.cpp11
-rw-r--r--engines/sherlock/surface.cpp13
-rw-r--r--engines/sherlock/tattoo/tattoo_scene.cpp3
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.cpp16
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.h20
-rw-r--r--engines/sherlock/tattoo/widget_base.cpp8
-rw-r--r--engines/sherlock/tattoo/widget_inventory.cpp108
-rw-r--r--engines/sherlock/tattoo/widget_inventory.h15
-rw-r--r--engines/sherlock/tattoo/widget_lab.cpp43
-rw-r--r--engines/sherlock/tattoo/widget_lab.h52
-rw-r--r--engines/sherlock/user_interface.cpp2
20 files changed, 314 insertions, 105 deletions
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 6ea0dc24d0..453e2a4872 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -118,6 +118,8 @@ bool PmvPlayer::play(const char *filename) {
// get it to work well?
_audioStream = Audio::makeQueuingAudioStream(soundFreq, false);
+ SoundDecoderData *soundDecoderData = new SoundDecoderData();
+
while (!_vm->shouldQuit() && !_aborted && !_fd->eos() && frameNumber < frameCount) {
int32 frameTime = _vm->_system->getMillis();
@@ -153,7 +155,7 @@ bool PmvPlayer::play(const char *filename) {
soundSize = chunkCount * chunkSize;
soundData = (byte *)malloc(soundSize);
- decompressSound(audioData + 8, soundData, chunkSize, chunkCount);
+ decompressSound(audioData + 8, soundData, chunkSize, chunkCount, NULL, soundDecoderData);
_audioStream->queueBuffer(soundData, soundSize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
}
@@ -213,6 +215,7 @@ bool PmvPlayer::play(const char *filename) {
}
+ delete soundDecoderData;
delete[] frameData;
_audioStream->finish();
diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp
index 3f98cbb9ab..bae59f05cc 100644
--- a/engines/made/screenfx.cpp
+++ b/engines/made/screenfx.cpp
@@ -201,7 +201,7 @@ void ScreenEffects::startBlendedPalette(byte *palette, byte *newPalette, int col
}
void ScreenEffects::stepBlendedPalette() {
- if (_blendedPaletteStatus._active && _blendedPaletteStatus._value < _blendedPaletteStatus._maxValue) {
+ if (_blendedPaletteStatus._active && _blendedPaletteStatus._value <= _blendedPaletteStatus._maxValue) {
setBlendedPalette(_blendedPaletteStatus._palette, _blendedPaletteStatus._newPalette,
_blendedPaletteStatus._colorCount, _blendedPaletteStatus._value, _blendedPaletteStatus._maxValue);
if (_blendedPaletteStatus._value == _blendedPaletteStatus._maxValue)
diff --git a/engines/made/sound.cpp b/engines/made/sound.cpp
index 91e855cbf5..ad49031e7b 100644
--- a/engines/made/sound.cpp
+++ b/engines/made/sound.cpp
@@ -133,10 +133,10 @@ void ManholeEgaSoundDecompressor::update3() {
_sample2 += _sample1;
}
-void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray) {
+void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray, SoundDecoderData *soundDecoderData) {
- int16 prevSample = 0, workSample = 0;
- byte soundBuffer[1025];
+ int16 prevSample, workSample;
+ byte* soundBuffer;
byte deltaSoundBuffer[1024];
int16 soundBuffer2[16];
byte deltaType, type;
@@ -159,6 +159,15 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
if (soundEnergyArray)
soundEnergyArray->clear();
+ if (soundDecoderData) {
+ soundBuffer = soundDecoderData->_soundBuffer;
+ prevSample = soundDecoderData->_prevSample;
+ } else {
+ soundBuffer = new byte[1025];
+ memset(soundBuffer, 0x80, 1025);
+ prevSample = 0;
+ }
+
while (chunkCount--) {
deltaType = (*source) >> 6;
workChunkSize = chunkSize;
@@ -233,6 +242,11 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
}
if (deltaType > 0) {
+ // NB: The original did not add this extra value at the end (as far
+ // as I can tell), and so technically read past the filled part of
+ // soundBuffer.
+ soundBuffer[workChunkSize] = soundBuffer[workChunkSize - 1];
+
if (deltaType == 1) {
for (i = 0; i < chunkSize - 1; i += 2) {
l = i / 2;
@@ -255,9 +269,13 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
prevSample = workSample;
memcpy(dest, soundBuffer, chunkSize);
dest += chunkSize;
-
}
+ if (soundDecoderData) {
+ soundDecoderData->_prevSample = prevSample;
+ } else {
+ delete[] soundBuffer;
+ }
}
} // End of namespace Made
diff --git a/engines/made/sound.h b/engines/made/sound.h
index 6ffca13aaa..72537322f9 100644
--- a/engines/made/sound.h
+++ b/engines/made/sound.h
@@ -53,7 +53,22 @@ struct SoundEnergyItem {
typedef Common::Array<SoundEnergyItem> SoundEnergyArray;
-void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray = NULL);
+
+// Persistent data for decompressSound(). When calling decompressSound()
+// repeatedly (for the same stream), pass the same SoundDecoderData object to
+// ensure decoding properly resumes.
+class SoundDecoderData {
+public:
+ SoundDecoderData() {
+ memset(_soundBuffer, 0x80, sizeof(_soundBuffer));
+ _prevSample = 0;
+ }
+
+ byte _soundBuffer[1025];
+ int16 _prevSample;
+};
+
+void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray = NULL, SoundDecoderData *decoderData = NULL);
} // End of namespace Made
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index c859248055..7ca41e253c 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -2573,26 +2573,47 @@ void RivenExternal::xt7500_checkmarbles(uint16 argc, uint16 *argv) {
void RivenExternal::xt7600_setupmarbles(uint16 argc, uint16 *argv) {
// Draw the small marbles when we're a step away from the waffle
- uint16 baseBitmapId = _vm->findResourceID(ID_TBMP, "*tsmallred");
+
+ // Convert from marble X coordinate to screen X coordinate
+ static const uint16 xPosOffsets[] = {
+ 246, 245, 244, 243, 243, 241, 240, 240, 239, 238, 237, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 226, 225
+ };
+
+ // Convert from marble Y coordinate to screen Y coordinate
+ static const uint16 yPosOffsets[] = {
+ 261, 263, 265, 267, 268, 270, 272, 274, 276, 278, 281, 284, 285, 288, 290, 293, 295, 298, 300, 303, 306, 309, 311, 314, 316
+ };
+
+ // Handle spacing for y coordinates due to the angle
+ static const double yAdjusts[] = {
+ 4.56, 4.68, 4.76, 4.84, 4.84, 4.96, 5.04, 5.04, 5.12, 5.2, 5.28, 5.28, 5.36, 5.44, 5.4, 5.6, 5.72, 5.8, 5.88, 5.96, 6.04, 6.12, 6.2, 6.2, 6.28
+ };
+
+ // Waffle state of 0 is up, 1 down
bool waffleDown = _vm->_vars["twaffle"] != 0;
// Note that each of the small marble images is exactly 4x2
+ // The original seems to scale the marble images from extras.mhk, but
+ // we're using the pre-scaled images in the stack.
+ uint16 baseBitmapId = _vm->findResourceID(ID_TBMP, "*tsmallred");
for (uint16 i = 0; i < kMarbleCount; i++) {
- uint32 &var = _vm->_vars[s_marbleNames[i]];
+ uint32 var = _vm->_vars[s_marbleNames[i]];
if (var == 0) {
// The marble is still in its initial place
// (Note that this is still drawn even if the waffle is down)
- int marbleX = 376 + i * 2;
- int marbleY = 253 + i * 4;
- _vm->_gfx->copyImageToScreen(baseBitmapId + i, marbleX, marbleY, marbleX + kSmallMarbleWidth, marbleY + kSmallMarbleHeight);
+ static const uint16 defaultX[] = { 375, 377, 379, 381, 383, 385 };
+ static const uint16 defaultY[] = { 253, 257, 261, 265, 268, 273 };
+ _vm->_gfx->copyImageToScreen(baseBitmapId + i, defaultX[i], defaultY[i], defaultX[i] + kSmallMarbleWidth, defaultY[i] + kSmallMarbleHeight);
} else if (waffleDown) {
// The marble is on the grid and the waffle is down
// (Nothing to draw here)
} else {
// The marble is on the grid and the waffle is up
- // TODO: Draw them onto the grid
+ int marbleX = (int)round(getMarbleX(var) * yAdjusts[getMarbleY(var)] + xPosOffsets[getMarbleY(var)]);
+ int marbleY = yPosOffsets[getMarbleY(var)];
+ _vm->_gfx->copyImageToScreen(baseBitmapId + i, marbleX, marbleY, marbleX + kSmallMarbleWidth, marbleY + kSmallMarbleHeight);
}
}
}
diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp
index 3f49e347ae..a8912f6f1e 100644
--- a/engines/sherlock/events.cpp
+++ b/engines/sherlock/events.cpp
@@ -89,6 +89,8 @@ void Events::setCursor(CursorId cursorId) {
void Events::setCursor(const Graphics::Surface &src, int hotspotX, int hotspotY) {
_cursorId = INVALID_CURSOR;
+ _hotspotPos = Common::Point(hotspotX, hotspotY);
+
if (!IS_3DO) {
// PC 8-bit palettized
CursorMan.replaceCursor(src.getPixels(), src.w, src.h, hotspotX, hotspotY, 0xff);
@@ -99,6 +101,38 @@ void Events::setCursor(const Graphics::Surface &src, int hotspotX, int hotspotY)
showCursor();
}
+void Events::setCursor(CursorId cursorId, const Graphics::Surface &surface) {
+ _cursorId = cursorId;
+
+ int hotspotX, hotspotY;
+ if (cursorId == MAGNIFY) {
+ hotspotX = 8;
+ hotspotY = 8;
+ } else {
+ hotspotX = 0;
+ hotspotY = 0;
+ }
+
+ // Get the standard cursor frame
+ Graphics::Surface &surface2 = (*_cursorImages)[cursorId]._frame;
+
+ // Form a single surface containing both frames
+ int maxWidth = MAX(surface.w, surface2.w);
+ Graphics::Surface s;
+ s.create(maxWidth, surface.h + surface2.h, Graphics::PixelFormat::createFormatCLUT8());
+ s.fillRect(Common::Rect(0, 0, maxWidth, surface.h + surface2.h), TRANSPARENCY);
+
+ s.copyRectToSurface(surface, (maxWidth - surface.w) / 2, 0, Common::Rect(0, 0, surface.w, surface.h));
+ s.copyRectToSurface(surface2, (maxWidth - surface2.w) / 2, surface.h, Common::Rect(0, 0, surface2.w, surface2.h));
+
+ // Adjust hotspot position
+ hotspotX += (maxWidth - surface2.w) / 2;
+ hotspotY += surface.h;
+
+ // Set the cursor
+ setCursor(s, hotspotX, hotspotY);
+}
+
void Events::animateCursorIfNeeded() {
if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
CursorId newId = (_cursorId == WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
diff --git a/engines/sherlock/events.h b/engines/sherlock/events.h
index ffe6584ae6..93a5e54f81 100644
--- a/engines/sherlock/events.h
+++ b/engines/sherlock/events.h
@@ -59,6 +59,7 @@ public:
bool _oldRightButton;
bool _firstPress;
Common::Stack<Common::KeyState> _pendingKeys;
+ Common::Point _hotspotPos;
public:
Events(SherlockEngine *vm);
~Events();
@@ -79,6 +80,11 @@ public:
void setCursor(const Graphics::Surface &src, int hotspotX = 0, int hotspotY = 0);
/**
+ * Set both a standard cursor as well as an inventory item above it
+ */
+ void setCursor(CursorId cursorId, const Graphics::Surface &surface);
+
+ /**
* Animates the mouse cursor if the Wait cursor is showing
*/
void animateCursorIfNeeded();
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 73067fdc14..32c5d3acc3 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -34,6 +34,7 @@ MODULE_OBJS = \
tattoo/tattoo_user_interface.o \
tattoo/widget_base.o \
tattoo/widget_inventory.o \
+ tattoo/widget_lab.o \
tattoo/widget_talk.o \
tattoo/widget_text.o \
tattoo/widget_tooltip.o \
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 2d939ce6cf..6ef08c28cc 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -508,6 +508,10 @@ int BaseObject::checkNameForCodes(const Common::String &name, FixedTextActionId
break;
}
+ case 'V':
+ // Do nothing for Verb codes. This is only a flag for Inventory syntax
+ break;
+
default:
if (ch >= '0' && ch <= '9') {
scene._goToScene = atoi(name.c_str() + 1);
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index a33574030f..328bf647d4 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -1210,6 +1210,15 @@ void Scene::transitionToScene() {
// Standard info, so set it
people[HOLMES]._position = hSavedPos;
people[HOLMES]._sequenceNumber = hSavedFacing;
+
+ if (saves._justLoaded && IS_ROSE_TATTOO) {
+ Tattoo::TattooUserInterface &ui = *(Tattoo::TattooUserInterface *)_vm->_ui;
+
+ // For scrolling scenes, make sure the player is on-screen
+ ui._targetScroll.x = CLIP(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER -
+ SHERLOCK_SCREEN_WIDTH / 8 - 250, 0, screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH);
+ screen._currentScroll = ui._targetScroll;
+ }
} else {
// It's canimation information
cAnimNum = hSavedFacing - 101;
@@ -1283,7 +1292,7 @@ void Scene::transitionToScene() {
screen.fadeIntoScreen3DO(3);
}
} else {
- screen.blitFrom(screen._backBuffer1);
+ screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
}
screen.update();
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index 729b4e8c44..42194de7a3 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -112,7 +112,7 @@ void Surface::transBlitFrom(const Surface &src, const Common::Point &pt,
void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
bool flipped, int overrideColor, int scaleVal) {
- if (scaleVal == 256) {
+ if (scaleVal == SCALE_THRESHOLD) {
transBlitFromUnscaled(src, pt, flipped, overrideColor);
return;
}
@@ -120,8 +120,11 @@ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &p
int scaleX = SCALE_THRESHOLD * SCALE_THRESHOLD / scaleVal;
int scaleY = scaleX;
int scaleXCtr = 0, scaleYCtr = 0;
+ int destX, destY;
+ int xCtr, yCtr;
+ int maxX = pt.x;
- for (int yCtr = 0, destY = pt.y; yCtr < src.h && destY < this->h(); ++yCtr) {
+ for (yCtr = 0, destY = pt.y; yCtr < src.h && destY < this->h(); ++yCtr) {
// Handle skipping lines if Y scaling
scaleYCtr += scaleY;
@@ -134,7 +137,7 @@ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &p
byte *pDest = (byte *)getBasePtr(pt.x, destY);
scaleXCtr = 0;
- for (int xCtr = 0, destX = pt.x; xCtr < src.w && destX < this->w(); ++xCtr) {
+ for (xCtr = 0, destX = pt.x; xCtr < src.w && destX < this->w(); ++xCtr) {
// Handle horizontal scaling
scaleXCtr += scaleX;
@@ -149,6 +152,7 @@ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &p
++destX;
}
+ maxX = MAX(maxX, destX);
pSrc = pSrc + (flipped ? -1 : 1);
}
}
@@ -156,6 +160,9 @@ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &p
++destY;
}
}
+
+ // Mark the affected area
+ addDirtyRect(Common::Rect(pt.x, pt.y, maxX, destY));
}
void Surface::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt,
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
index 0f61109c9d..a171da10cc 100644
--- a/engines/sherlock/tattoo/tattoo_scene.cpp
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -101,6 +101,9 @@ bool TattooScene::loadScene(const Common::String &filename) {
// Set the menu/ui mode and whether we're in a lab table close-up scene
_labTableScene = _currentScene > 91 && _currentScene < 100;
ui._menuMode = _labTableScene ? LAB_MODE : STD_MODE;
+
+ if (_labTableScene)
+ ui._labWidget.summonWindow();
}
return result;
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp
index bffdb550cf..e846db2701 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.cpp
+++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp
@@ -30,7 +30,8 @@ namespace Sherlock {
namespace Tattoo {
TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm),
- _inventoryWidget(vm), _messageWidget(vm), _textWidget(vm), _tooltipWidget(vm), _verbsWidget(vm) {
+ _inventoryWidget(vm), _messageWidget(vm), _textWidget(vm), _tooltipWidget(vm), _verbsWidget(vm),
+ _labWidget(vm) {
Common::fill(&_lookupTable[0], &_lookupTable[PALETTE_COUNT], 0);
Common::fill(&_lookupTable1[0], &_lookupTable1[PALETTE_COUNT], 0);
_scrollSize = 0;
@@ -222,6 +223,8 @@ void TattooUserInterface::doJournal() {
void TattooUserInterface::reset() {
UserInterface::reset();
_lookPos = Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2);
+ _tooltipWidget.setText("");
+ _widgets.clear();
}
void TattooUserInterface::handleInput() {
@@ -280,9 +283,6 @@ void TattooUserInterface::handleInput() {
case FILES_MODE:
doFileControl();
break;
- case LAB_MODE:
- doLabControl();
- break;
default:
break;
}
@@ -356,7 +356,6 @@ void TattooUserInterface::doStandardControl() {
Events &events = *_vm->_events;
People &people = *_vm->_people;
TattooScene &scene = *(TattooScene *)_vm->_scene;
- Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
Common::Point mousePos = events.mousePos();
bool noDesc = false;
@@ -477,7 +476,7 @@ void TattooUserInterface::doStandardControl() {
events._pressed = events._released = false;
} else {
// Walk to where the mouse was clicked
- people[HOLMES]._walkDest = mousePos + screen._currentScroll;
+ people[HOLMES]._walkDest = mousePos;
people[HOLMES].goAllTheWay();
}
}
@@ -527,10 +526,6 @@ void TattooUserInterface::doFileControl() {
warning("TODO: ui control (file)");
}
-void TattooUserInterface::doLabControl() {
- warning("TODO: ui control (lab)");
-}
-
void TattooUserInterface::displayObjectNames() {
Events &events = *_vm->_events;
Scene &scene = *_vm->_scene;
@@ -583,6 +578,7 @@ void TattooUserInterface::putMessage(const char *formatStr, ...) {
va_end(args);
// Open the message widget
+ _menuMode = MESSAGE_MODE;
_messageWidget.load(str, 25);
_messageWidget.summonWindow();
}
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h
index 8dcfaddbd2..7f284531de 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.h
+++ b/engines/sherlock/tattoo/tattoo_user_interface.h
@@ -29,6 +29,7 @@
#include "sherlock/screen.h"
#include "sherlock/user_interface.h"
#include "sherlock/tattoo/widget_inventory.h"
+#include "sherlock/tattoo/widget_lab.h"
#include "sherlock/tattoo/widget_text.h"
#include "sherlock/tattoo/widget_tooltip.h"
#include "sherlock/tattoo/widget_verbs.h"
@@ -77,17 +78,6 @@ private:
* Handle input while the verb menu is open
*/
void doVerbControl();
-
- /**
- * Handles input when the player is in the Lab Table scene
- */
- void doLabControl();
-
- /**
- * If the mouse cursor is point at the cursor, then display the name of the object on the screen.
- * If there is no object being pointed it, clear any previously displayed name
- */
- void displayObjectNames();
/**
* Set up to display the Files menu
@@ -119,7 +109,7 @@ public:
int _maskCounter;
ImageFile *_interfaceImages;
WidgetText _textWidget;
- Common::String _action;
+ WidgetLab _labWidget;
public:
TattooUserInterface(SherlockEngine *vm);
virtual ~TattooUserInterface();
@@ -197,6 +187,12 @@ public:
* Draws all the dialog rectangles for any items that need them
*/
void drawDialogRect(Surface &s, const Common::Rect &r, bool raised);
+
+ /**
+ * If the mouse cursor is point at the cursor, then display the name of the object on the screen.
+ * If there is no object being pointed it, clear any previously displayed name
+ */
+ void displayObjectNames();
public:
/**
* Resets the user interface
diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp
index 5f16e8800d..66ade474c2 100644
--- a/engines/sherlock/tattoo/widget_base.cpp
+++ b/engines/sherlock/tattoo/widget_base.cpp
@@ -35,6 +35,14 @@ WidgetBase::WidgetBase(SherlockEngine *vm) : _vm(vm) {
void WidgetBase::summonWindow() {
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ // Double-check that the same widget isn't added twice
+ for (Common::List<WidgetBase *>::iterator i = ui._widgets.begin(); i != ui._widgets.end(); ++i) {
+ if ((*i) == this)
+ error("Tried to add a widget twice");
+ }
+
+ // Add widget to the screen
ui._widgets.push_back(this);
_outsideMenu = false;
diff --git a/engines/sherlock/tattoo/widget_inventory.cpp b/engines/sherlock/tattoo/widget_inventory.cpp
index 241eaca182..170fb02481 100644
--- a/engines/sherlock/tattoo/widget_inventory.cpp
+++ b/engines/sherlock/tattoo/widget_inventory.cpp
@@ -122,17 +122,6 @@ void WidgetInventoryTooltip::handleEvents() {
Common::String strWith = fixedText.getText(kFixedText_With);
Common::String strUse = fixedText.getText(kFixedText_Use);
- // If there's a floating graphic for a selected inventory item, update it's bounds
- if (_owner->_invVerbMode == 2 || _owner->_invVerbMode == 3) {
- _oldInvGraphicBounds = _invGraphicBounds;
-
- // Set the New position of the graphic
- int xp = CLIP(mousePos.x - _invGraphicBounds.width() / 2, 0, SHERLOCK_SCENE_WIDTH - _invGraphicBounds.width());
- int yp = CLIP(mousePos.y - _invGraphicBounds.height() / 2, 0, SHERLOCK_SCREEN_HEIGHT - _invGraphicBounds.height());
-
- _invGraphicBounds.moveTo(xp, yp);
- }
-
// If we are using an inventory item on an object in the room, display the appropriate text above the mouse cursor
if (_owner->_invVerbMode == 3) {
select = ui._bgFound;
@@ -147,18 +136,18 @@ void WidgetInventoryTooltip::handleEvents() {
if (_vm->getLanguage() == Common::GR_GRE) {
if (!_owner->_swapItems)
- str = Common::String::format("%s %s %s %s", ui._action.c_str(), obj._description.c_str(),
- inv[_owner->_invSelect]._name.c_str(), _owner->_invVerb.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), obj._description.c_str(),
+ inv[_owner->_invSelect]._name.c_str(), _owner->_verb.c_str());
else
- str = Common::String::format("%s %s %s %s", ui._action.c_str(), inv[_owner->_invSelect]._name.c_str(),
- obj._description.c_str(), _owner->_invVerb.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ obj._description.c_str(), _owner->_verb.c_str());
} else {
if (_owner->_swapItems)
- str = Common::String::format("%s %s %s %s", _owner->_invVerb.c_str(), obj._description.c_str(), ui._action.c_str(),
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(), obj._description.c_str(), _owner->_action.c_str(),
inv[_owner->_invSelect]._name.c_str());
else
- str = Common::String::format("%s %s %s %s", _owner->_invVerb.c_str(), inv[_owner->_invSelect]._name.c_str(),
- ui._action.c_str(), obj._description.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ _owner->_action.c_str(), obj._description.c_str());
}
}
} else {
@@ -167,19 +156,19 @@ void WidgetInventoryTooltip::handleEvents() {
if (!person._description.empty() && !person._description.hasPrefix(" ")) {
if (_vm->getLanguage() == Common::GR_GRE) {
if (!_owner->_swapItems)
- str = Common::String::format("%s %s %s %s", ui._action.c_str(), person._description.c_str(),
- inv[_owner->_invSelect]._name.c_str(), _owner->_invVerb.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), person._description.c_str(),
+ inv[_owner->_invSelect]._name.c_str(), _owner->_verb.c_str());
else
- str = Common::String::format("%s %s %s %s", ui._action.c_str(), inv[_owner->_invSelect]._name.c_str(),
- person._description.c_str(), _owner->_invVerb.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ person._description.c_str(), _owner->_verb.c_str());
} else {
if (_owner->_swapItems)
- str = Common::String::format("%s %s %s %s", _owner->_invVerb.c_str(), person._description.c_str(),
- ui._action.c_str(), inv[_owner->_invSelect]._name.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(), person._description.c_str(),
+ _owner->_action.c_str(), inv[_owner->_invSelect]._name.c_str());
else
- str = Common::String::format("%s %s %s %s", _owner->_invVerb.c_str(),
- inv[_owner->_invSelect]._name.c_str(), ui._action.c_str(), person._description.c_str());
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(),
+ inv[_owner->_invSelect]._name.c_str(), _owner->_action.c_str(), person._description.c_str());
}
}
}
@@ -241,6 +230,10 @@ void WidgetInventoryTooltip::handleEvents() {
return;
}
+ if (_owner->_invVerbMode == 3)
+ // Adjust tooltip to be above the inventory item being shown above the standard cursor
+ mousePos.y -= events._hotspotPos.y;
+
// Update the position of the tooltip
int xs = CLIP(mousePos.x - _bounds.width() / 2, 0, SHERLOCK_SCENE_WIDTH - _bounds.width());
int ys = CLIP(mousePos.y - _bounds.height(), 0, SHERLOCK_SCREEN_HEIGHT - _bounds.height());
@@ -267,7 +260,7 @@ void WidgetInventoryVerbs::load() {
_inventCommands.push_back(FIXED(Look));
// Default the Action word to "with"
- _action = _vm->getLanguage() == Common::GR_GRE ? "" : FIXED(With);
+ _owner->_action = _vm->getLanguage() == Common::GR_GRE ? "" : FIXED(With);
// Search all the bgshapes for any matching Target Fields
for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
@@ -275,7 +268,7 @@ void WidgetInventoryVerbs::load() {
if (obj._type != INVALID && obj._type != HIDDEN) {
for (int useNum = 0; useNum < 6; ++useNum) {
- if (obj._use[useNum]._verb.hasPrefix("*") &&
+ if (!obj._use[useNum]._verb.hasPrefix("*") &&
!obj._use[useNum]._target.compareToIgnoreCase(inv[_owner->_invSelect]._name)) {
// Make sure the Verb is not already in the list
bool found1 = false;
@@ -293,7 +286,7 @@ void WidgetInventoryVerbs::load() {
if (!scumm_strnicmp(obj._use[useNum]._names[nameNum].c_str(), "*VSWAP", 6))
_owner->_swapItems = true;
else
- _action = Common::String(obj._use[useNum]._names[nameNum].c_str() + 2);
+ _owner->_action = Common::String(obj._use[useNum]._names[nameNum].c_str() + 2);
}
}
}
@@ -428,29 +421,19 @@ void WidgetInventoryVerbs::handleEvents() {
events.clearEvents();
ui.checkAction(inv[_owner->_invSelect]._verb, 2000);
} else {
- _owner->_invVerb = _inventCommands[_invVerbSelect];
+ _owner->_verb = _inventCommands[_invVerbSelect];
}
// If we are still in Inventory Mode, setup the graphic to float in front of the mouse cursor
if (ui._menuMode == INV_MODE) {
+ // Add the inventory item to the cursor
ImageFrame &imgFrame = (*inv._invShapes[_owner->_invSelect - inv._invIndex])[0];
- _owner->_invGraphicBounds = Common::Rect(imgFrame._width, imgFrame._height);
- _owner->_invGraphicBounds.moveTo(mousePos.x - _owner->_invGraphicBounds.width() / 2,
- mousePos.y - _owner->_invGraphicBounds.height() / 2);
-
- // Constrain it to the screen
- if (_owner->_invGraphicBounds.left < 0)
- _owner->_invGraphicBounds.moveTo(0, _owner->_invGraphicBounds.top);
- if (_owner->_invGraphicBounds.top < 0)
- _owner->_invGraphicBounds.moveTo(_owner->_invGraphicBounds.left, 0);
- if (_owner->_invGraphicBounds.right > SHERLOCK_SCREEN_WIDTH)
- _owner->_invGraphicBounds.moveTo(SHERLOCK_SCREEN_WIDTH - _owner->_invGraphicBounds.width(), _owner->_invGraphicBounds.top);
- if (_owner->_invGraphicBounds.bottom > SHERLOCK_SCREEN_HEIGHT)
- _owner->_invGraphicBounds.moveTo(_owner->_invGraphicBounds.left, SHERLOCK_SCREEN_HEIGHT - _owner->_invGraphicBounds.height());
-
- // Make a copy of the inventory image
- _owner->_invGraphic.create(imgFrame._width, imgFrame._height);
- _owner->_invGraphic.blitFrom(imgFrame, Common::Point(0, 0));
+ events.setCursor(ARROW, imgFrame._frame);
+
+ // Close the inventory dialog without banishing it, so it can keep getting events
+ // to handle tooltips and actually making the selection of what object to use them item on
+ inv.freeInv();
+ _owner->_surface.free();
}
}
}
@@ -624,11 +607,7 @@ void WidgetInventory::handleEvents() {
if (_invVerbMode == 3) {
// Selecting object after inventory verb has been selected
_tooltipWidget.banishWindow();
- _invGraphic.free();
- inv.freeInv();
-
- ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
- events.clearEvents();
+ close();
if (ui._keyState.keycode != Common::KEYCODE_ESCAPE) {
// If user pointed at an item, use the selected inventory item with this item
@@ -636,7 +615,7 @@ void WidgetInventory::handleEvents() {
if (ui._bgFound != -1) {
if (ui._personFound) {
for (int idx = 0; idx < 2; ++idx) {
- if (!people[ui._bgFound - 1000]._use[idx]._verb.compareToIgnoreCase(_invVerb) &&
+ if (!people[ui._bgFound - 1000]._use[idx]._verb.compareToIgnoreCase(_verb) &&
!people[ui._bgFound - 1000]._use[idx]._target.compareToIgnoreCase(_invTarget)) {
ui.checkAction(people[ui._bgFound - 1000]._use[idx], ui._bgFound);
found = true;
@@ -644,7 +623,7 @@ void WidgetInventory::handleEvents() {
}
} else {
for (int idx = 0; idx < 6; ++idx) {
- if (!ui._bgShape->_use[idx]._verb.compareToIgnoreCase(_invVerb) &&
+ if (!ui._bgShape->_use[idx]._verb.compareToIgnoreCase(_verb) &&
!ui._bgShape->_use[idx]._target.compareToIgnoreCase(_invTarget)) {
ui.checkAction(ui._bgShape->_use[idx], ui._bgFound);
found = true;
@@ -658,13 +637,8 @@ void WidgetInventory::handleEvents() {
}
} else if ((_outsideMenu && !_bounds.contains(mousePos)) || ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
// Want to close the window (clicked outside of it). So close the window and return to Standard
- banishWindow();
- inv.freeInv();
+ close();
- events.clearEvents();
- events.setCursor(ARROW);
- banishWindow();
- ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
} else if (_bounds.contains(mousePos)) {
// Mouse button was released inside the inventory window
_outsideMenu = false;
@@ -769,6 +743,20 @@ void WidgetInventory::erase() {
_tooltipWidget.erase();
}
+void WidgetInventory::close() {
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ banishWindow();
+ inv.freeInv();
+ events.clearEvents();
+
+ events.setCursor(ARROW);
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+}
+
} // End of namespace Tattoo
} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_inventory.h b/engines/sherlock/tattoo/widget_inventory.h
index bfc1c7f50f..53bc2038e0 100644
--- a/engines/sherlock/tattoo/widget_inventory.h
+++ b/engines/sherlock/tattoo/widget_inventory.h
@@ -40,7 +40,6 @@ class WidgetInventory;
class WidgetInventoryTooltip: public WidgetTooltipBase {
private:
WidgetInventory *_owner;
- Common::Rect _oldInvGraphicBounds, _invGraphicBounds;
protected:
/**
* Overriden from base class, since tooltips have a completely transparent background
@@ -65,7 +64,6 @@ class WidgetInventoryVerbs : public WidgetBase {
private:
WidgetInventory *_owner;
Common::StringArray _inventCommands;
- Common::String _action;
void highlightControls();
public:
@@ -92,12 +90,9 @@ private:
int _dialogTimer;
WidgetInventoryTooltip _tooltipWidget;
WidgetInventoryVerbs _verbList;
- Common::Rect _invGraphicBounds;
- Surface _invGraphic;
bool _swapItems;
Surface _menuSurface;
Common::String _invTarget;
- Common::String _invVerb;
/**
* Draw the bars within the dialog
@@ -115,10 +110,15 @@ private:
void highlightControls();
public:
int _invMode;
+ Common::String _action;
+ Common::String _verb;
public:
WidgetInventory(SherlockEngine *vm);
virtual ~WidgetInventory() {}
+ /**
+ * Load the inventory window
+ */
void load(int mode);
/**
@@ -127,6 +127,11 @@ public:
void drawInventory();
/**
+ * Close the window
+ */
+ void close();
+
+ /**
* Handle events whilst the widget is on-screen
*/
virtual void handleEvents();
diff --git a/engines/sherlock/tattoo/widget_lab.cpp b/engines/sherlock/tattoo/widget_lab.cpp
new file mode 100644
index 0000000000..47955a0d26
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_lab.cpp
@@ -0,0 +1,43 @@
+/* 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/tattoo/widget_lab.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetLab::WidgetLab(SherlockEngine *vm) : WidgetBase(vm) {
+}
+
+void WidgetLab::handleEvents() {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ WidgetBase::handleEvents();
+
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_lab.h b/engines/sherlock/tattoo/widget_lab.h
new file mode 100644
index 0000000000..344dae7934
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_lab.h
@@ -0,0 +1,52 @@
+/* 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.
+ *
+ */
+
+#ifndef SHERLOCK_TATTOO_WIDGET_LAB_H
+#define SHERLOCK_TATTOO_WIDGET_LAB_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetLab: public WidgetBase {
+public:
+ Common::String _remainingText;
+public:
+ WidgetLab(SherlockEngine *vm);
+ virtual ~WidgetLab() {}
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 9db29023c8..9df3f1dc24 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -179,7 +179,7 @@ void UserInterface::checkAction(ActionType &action, int objNum, FixedTextActionI
}
// Unless we're leaving the scene, print a "Done" message unless the printed flag has been set
- if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
+ if (IS_SERRATED_SCALPEL && scene._goToScene != 1 && !printed && !talk._talkToAbort) {
_infoFlag = true;
clearInfo();
screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "Done...");