aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sherlock')
-rw-r--r--engines/sherlock/inventory.cpp42
-rw-r--r--engines/sherlock/inventory.h15
-rw-r--r--engines/sherlock/module.mk1
-rw-r--r--engines/sherlock/people.h13
-rw-r--r--engines/sherlock/scene.cpp16
-rw-r--r--engines/sherlock/scene.h11
-rw-r--r--engines/sherlock/screen.cpp11
-rw-r--r--engines/sherlock/screen.h4
-rw-r--r--engines/sherlock/scripts.cpp35
-rw-r--r--engines/sherlock/scripts.h48
-rw-r--r--engines/sherlock/sherlock.cpp14
-rw-r--r--engines/sherlock/sherlock.h6
-rw-r--r--engines/sherlock/talk.cpp291
-rw-r--r--engines/sherlock/talk.h43
-rw-r--r--engines/sherlock/user_interface.cpp58
-rw-r--r--engines/sherlock/user_interface.h11
16 files changed, 542 insertions, 77 deletions
diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp
index a7691fc866..ac37e7c587 100644
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@ -40,7 +40,7 @@ Inventory::Inventory(SherlockEngine *vm) : Common::Array<InventoryItem>(), _vm(v
_holdings = 0;
_oldFlag = 0;
_invFlag = 0;
- _invMode = 0;
+ _invMode = INVMODE_EXIT;
}
Inventory::~Inventory() {
@@ -117,7 +117,7 @@ void Inventory::loadGraphics() {
* and returns the numer that matches the passed name
*/
int Inventory::findInv(const Common::String &name) {
- for (int idx = 0; idx < size(); ++idx) {
+ for (int idx = 0; idx < (int)size(); ++idx) {
if (scumm_stricmp(name.c_str(), _names[idx].c_str()) == 0)
return idx;
}
@@ -219,25 +219,25 @@ void Inventory::drawInventory(int flag) {
// Draw the buttons
screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[4][2], "^^");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2], "^^");
screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[5][2], "^");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2], "^");
screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[6][2], "_");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2], "_");
screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
- CONTROLS_Y1 + 9), INVENTORY_POINTS[7][2], "__");
+ CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__");
if (tempFlag == 128)
flag = 1;
- _invMode = flag;
+ _invMode = (InvMode)flag;
if (flag) {
ui._oldKey = INVENTORY_COMMANDS[flag];
@@ -334,7 +334,25 @@ void Inventory::doInvLite(int index, byte color) {
}
void Inventory::doInvJF() {
- // TODO
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ UserInterface &ui = *_vm->_ui;
+
+ ui._invLookFlag = true;
+ freeInv();
+
+ ui._infoFlag = true;
+ ui.clearInfo();
+
+ screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
+ Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ ui.examine();
+
+ if (!talk._talkToAbort) {
+ screen._backBuffer2.blitFrom((*ui._controlPanel)[0]._frame,
+ Common::Point(0, CONTROLS_Y));
+ loadInv();
+ }
}
} // End of namespace Sherlock
diff --git a/engines/sherlock/inventory.h b/engines/sherlock/inventory.h
index e9a4ba5548..3c01dc38da 100644
--- a/engines/sherlock/inventory.h
+++ b/engines/sherlock/inventory.h
@@ -32,6 +32,19 @@ namespace Sherlock {
#define MAX_VISIBLE_INVENTORY 6
+enum InvMode {
+ INVMODE_EXIT = 0,
+ INVMODE_LOOK = 1,
+ INVMODE_USE = 2,
+ INVMODE_GIVE = 3,
+ INVMODE_FIRST = 4,
+ INVMODE_PREVIOUS = 5,
+ INVMODE_NEXT = 6,
+ INVMODE_LAST = 7,
+ INVMODE_INVALID = 8,
+ INVMODE_USE55 = 255
+};
+
struct InventoryItem {
int _requiredFlag;
Common::String _name;
@@ -50,7 +63,7 @@ public:
ImageFile *_invShapes[MAX_VISIBLE_INVENTORY];
Common::StringArray _names;
bool _invGraphicsLoaded;
- int _invMode;
+ InvMode _invMode;
int _invIndex;
int _holdings;
void freeGraphics();
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 4101769a80..a01f9f0f71 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -18,6 +18,7 @@ MODULE_OBJS = \
resources.o \
scene.o \
screen.o \
+ scripts.o \
sherlock.o \
sound.o \
talk.o \
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 0393528095..6b5c59b1bd 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -52,17 +52,24 @@ enum {
class SherlockEngine;
+class Person: public Sprite {
+public:
+ Person() : Sprite() {}
+
+ Common::String _portrait;
+};
+
class People {
private:
SherlockEngine *_vm;
- Sprite _data[MAX_PEOPLE];
- Sprite &_player;
+ Person _data[MAX_PEOPLE];
bool _walkLoaded;
int _oldWalkSequence;
int _srcZone, _destZone;
public:
Common::Point _walkDest;
Common::Stack<Common::Point> _walkTo;
+ Person &_player;
bool _holmesOn;
bool _portraitLoaded;
Object _portrait;
@@ -72,7 +79,7 @@ public:
People(SherlockEngine *vm);
~People();
- Sprite &operator[](PeopleId id) { return _data[id]; }
+ Person &operator[](PeopleId id) { return _data[id]; }
bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index c3afc4a0d4..7c66a1dc62 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -99,7 +99,6 @@ Scene::Scene(SherlockEngine *vm): _vm(vm) {
_hsavedPos = Common::Point(-1, -1);
_hsavedFs = -1;
_cAnimFramePause = 0;
- _invMode = INVMODE_0;
_restoreFlag = false;
_invLookFlag = false;
_lookHelp = false;
@@ -119,6 +118,7 @@ void Scene::selectScene() {
Events &events = *_vm->_events;
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
+ Scripts &scripts = *_vm->_scripts;
UserInterface &ui = *_vm->_ui;
// Reset fields
@@ -150,8 +150,8 @@ void Scene::selectScene() {
// If there were any scripst waiting to be run, but were interrupt by a running
// canimation (probably the last scene's exit canim), clear the _scriptMoreFlag
- if (_vm->_scriptMoreFlag == 3)
- _vm->_scriptMoreFlag = 0;
+ if (scripts._scriptMoreFlag == 3)
+ scripts._scriptMoreFlag = 0;
}
/**
@@ -1050,8 +1050,10 @@ int Scene::startCAnim(int cAnimNum, int playRate) {
*/
void Scene::doBgAnim() {
Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
+ Scripts &scripts = *_vm->_scripts;
Sound &sound = *_vm->_sound;
Talk &talk = *_vm->_talk;
UserInterface &ui = *_vm->_ui;
@@ -1079,7 +1081,7 @@ void Scene::doBgAnim() {
// Check for setting magnifying glass cursor
if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
- if (_invMode == INVMODE_1) {
+ if (inv._invMode == INVMODE_LOOK) {
// Only show Magnifying glass cursor if it's not on the inventory command line
if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
events.setCursor(MAGNIFY);
@@ -1357,10 +1359,10 @@ void Scene::doBgAnim() {
// Check if the method was called for calling a portrait, and a talk was
// interrupting it. This talk file would not have been executed at the time,
// since we needed to finish the 'doBgAnim' to finish clearing the portrait
- if (people._clearingThePortrait && _vm->_scriptMoreFlag == 3) {
+ if (people._clearingThePortrait && scripts._scriptMoreFlag == 3) {
// Reset the flags and call to talk
- people._clearingThePortrait = _vm->_scriptMoreFlag = 0;
- talk.talkTo(_vm->_scriptName);
+ people._clearingThePortrait = scripts._scriptMoreFlag = 0;
+ talk.talkTo(scripts._scriptName);
}
}
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index d89a47e560..cd64073621 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -35,14 +35,6 @@ namespace Sherlock {
#define MAX_ZONES 40
#define INFO_LINE 140
-enum InvMode {
- INVMODE_0 = 0,
- INVMODE_1 = 1,
- INVMODE_2 = 2,
- INVMODE_3 = 3,
- INVMODE_255 = 255
-};
-
class SherlockEngine;
struct BgFileHeader {
@@ -94,9 +86,7 @@ class Scene {
private:
SherlockEngine *_vm;
Common::String _rrmName;
- InvMode _invMode;
int _selector;
- bool _invLookFlag;
bool _lookHelp;
bool loadScene(const Common::String &filename);
@@ -149,6 +139,7 @@ public:
bool _doBgAnimDone;
int _tempFadeStyle;
int _cAnimFramePause;
+ bool _invLookFlag;
public:
Scene(SherlockEngine *vm);
~Scene();
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index a3705b54da..0eeddf2a5f 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -468,4 +468,15 @@ void Screen::makePanel(const Common::Rect &r) {
_backBuffer->hLine(r.left + 1, r.bottom - 2, r.right - 1, BUTTON_BOTTOM);
}
+void Screen::setDisplayBounds(const Common::Rect &r) {
+ // TODO: See if needed
+}
+void Screen::resetDisplayBounds() {
+ setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+}
+
+Common::Rect Screen::getDisplayBounds() {
+ return Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index 5047d40216..597c47c83a 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -120,6 +120,10 @@ public:
void buttonPrint(const Common::Point &pt, byte color, bool slamIt, const Common::String &str);
void makePanel(const Common::Rect &r);
+
+ void setDisplayBounds(const Common::Rect &r);
+ void resetDisplayBounds();
+ Common::Rect getDisplayBounds();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/scripts.cpp b/engines/sherlock/scripts.cpp
new file mode 100644
index 0000000000..ace957bd76
--- /dev/null
+++ b/engines/sherlock/scripts.cpp
@@ -0,0 +1,35 @@
+/* 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/scripts.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+Scripts::Scripts(SherlockEngine *vm): _vm(vm) {
+ _scriptMoreFlag = 0;
+ _scriptSaveIndex = 0;
+ _scriptSelect = 0;
+ _abortFlag = false;
+}
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scripts.h b/engines/sherlock/scripts.h
new file mode 100644
index 0000000000..eede1ca103
--- /dev/null
+++ b/engines/sherlock/scripts.h
@@ -0,0 +1,48 @@
+/* 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_SCRIPTS_H
+#define SHERLOCK_SCRIPTS_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+class Scripts {
+private:
+ SherlockEngine *_vm;
+public:
+ int _scriptMoreFlag;
+ Common::String _scriptName;
+ int _scriptSaveIndex;
+ int _scriptSelect;
+ bool _abortFlag;
+public:
+ Scripts(SherlockEngine *vm);
+};
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index 107dee5a41..04a9ed54d5 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -39,6 +39,7 @@ SherlockEngine::SherlockEngine(OSystem *syst, const SherlockGameDescription *gam
_res = nullptr;
_scene = nullptr;
_screen = nullptr;
+ _scripts = nullptr;
_sound = nullptr;
_talk = nullptr;
_ui = nullptr;
@@ -47,7 +48,6 @@ SherlockEngine::SherlockEngine(OSystem *syst, const SherlockGameDescription *gam
_loadingSavedGame = false;
_onChessboard = false;
_slowChess = false;
- _scriptMoreFlag = 0;
}
SherlockEngine::~SherlockEngine() {
@@ -58,6 +58,7 @@ SherlockEngine::~SherlockEngine() {
delete _people;
delete _scene;
delete _screen;
+ delete _scripts;
delete _sound;
delete _talk;
delete _ui;
@@ -82,6 +83,7 @@ void SherlockEngine::initialize() {
_people = new People(this);
_scene = new Scene(this);
_screen = new Screen(this);
+ _scripts = new Scripts(this);
_sound = new Sound(this);
_talk = new Talk(this);
_ui = new UserInterface(this);
@@ -120,10 +122,10 @@ void SherlockEngine::sceneLoop() {
while (!shouldQuit() && _scene->_goToScene == -1) {
// See if a script needs to be completed from either a goto room code,
// or a script that was interrupted by another script
- if (_scriptMoreFlag == 1 || _scriptMoreFlag == 3)
- _talk->talkTo(_scriptName);
+ if (_scripts->_scriptMoreFlag == 1 || _scripts->_scriptMoreFlag == 3)
+ _talk->talkTo(_scripts->_scriptName);
else
- _scriptMoreFlag = 0;
+ _scripts->_scriptMoreFlag = 0;
// Handle any input from the keyboard or mouse
handleInput();
@@ -171,4 +173,8 @@ void SherlockEngine::setFlags(int flagNum) {
_scene->checkSceneFlags(true);
}
+void SherlockEngine::freeSaveGameList() {
+ // TODO
+}
+
} // End of namespace Comet
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index 392f55839e..7b562e0a23 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -40,6 +40,7 @@
#include "sherlock/resources.h"
#include "sherlock/scene.h"
#include "sherlock/screen.h"
+#include "sherlock/scripts.h"
#include "sherlock/sound.h"
#include "sherlock/talk.h"
#include "sherlock/user_interface.h"
@@ -89,6 +90,7 @@ public:
Resources *_res;
Scene *_scene;
Screen *_screen;
+ Scripts *_scripts;
Sound *_sound;
Talk *_talk;
UserInterface *_ui;
@@ -104,8 +106,6 @@ public:
Common::Array<Common::Point> _map; // Map locations for each scene
bool _onChessboard;
bool _slowChess;
- int _scriptMoreFlag;
- Common::String _scriptName;
public:
SherlockEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
virtual ~SherlockEngine();
@@ -125,6 +125,8 @@ public:
bool readFlags(int flagNum);
void setFlags(int flagNum);
+
+ void freeSaveGameList();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index ff71d37a2f..d67013b60e 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -25,13 +25,238 @@
namespace Sherlock {
+/**
+ * Load the data for a single statement within a talk file
+ */
+void Statement::synchronize(Common::SeekableReadStream &s, bool voices) {
+ int length;
+
+ length = s.readUint16LE();
+ for (int idx = 0; idx < length; ++idx)
+ _statement += (char)s.readByte();
+
+ length = s.readUint16LE();
+ for (int idx = 0; idx < length; ++idx)
+ _reply += (char)s.readByte();
+
+ // If we don't have digital sound, we'll need to strip out voice commands from reply
+ if (!voices) {
+ // Scan for a 140 byte, which indicates playing a sound
+ for (uint idx = 0; idx < _reply.size(); ++idx) {
+ if (_reply[idx] == 140) {
+ // Replace instruction character with a space, and delete the
+ // rest of the name following it
+ _reply = Common::String(_reply.c_str(), _reply.c_str() + idx) + " " +
+ Common::String(_reply.c_str() + 9);
+ }
+ }
+
+ // Ensure the last character of the reply is not a space from the prior
+ // conversion loop, to avoid any issues with the space ever causing a page
+ // wrap, and ending up displaying another empty page
+ while (_reply.lastChar() == ' ')
+ _reply.deleteLastChar();
+ }
+
+ length = s.readUint16LE();
+ for (int idx = 0; idx < length; ++idx)
+ _linkFile += (char)s.readByte();
+
+ length = s.readUint16LE();
+ for (int idx = 0; idx < length; ++idx)
+ _voiceFile += (char)s.readByte();
+
+ _required.resize(s.readByte());
+ _modified.resize(s.readByte());
+
+ // Read in flag required/modified data
+ for (uint idx = 0; idx < _required.size(); ++idx)
+ _required[idx] = s.readUint16LE();
+ for (uint idx = 0; idx < _modified.size(); ++idx)
+ _modified[idx] = s.readUint16LE();
+
+ _portraitSide = s.readByte();
+ _quotient = s.readUint16LE();
+}
+
+/*----------------------------------------------------------------*/
+
Talk::Talk(SherlockEngine *vm): _vm(vm) {
_talkCounter = 0;
_talkToAbort = false;
+ _saveSeqNum = 0;
+ _speaker = 0;
+ _talkIndex = 0;
+ _talkTo = 0;
}
-void Talk::talkTo(const Common::String &name) {
- // TODO
+/**
+ * Called when either an NPC initiates a conversation or for inventory item
+ * descriptions. It opens up a description window similar to how 'talk' does,
+ * but shows a 'reply' directly instead of waiting for a statement option.
+ */
+void Talk::talkTo(const Common::String &filename) {
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ Scripts &scripts = *_vm->_scripts;
+ Talk &talk = *_vm->_talk;
+ UserInterface &ui = *_vm->_ui;
+ Common::Rect savedBounds = screen.getDisplayBounds();
+
+ if (filename.empty())
+ // No filename passed, so exit
+ return;
+
+ // If there any canimations currently running, or a portrait is being cleared,
+ // save the filename for later executing when the canimation is done
+ if (scene._ongoingCans || people._clearingThePortrait) {
+ // Make sure we're not in the middle of a script
+ if (!scripts._scriptMoreFlag) {
+ scripts._scriptName = filename;
+ scripts._scriptSaveIndex = 0;
+
+ // Flag the selection, since we don't yet know which statement yet
+ scripts._scriptSelect = 100;
+ scripts._scriptMoreFlag = 3;
+ }
+
+ return;
+ }
+
+ // Save the ui mode temporarily and switch to talk mode
+ int savedMode = ui._menuMode;
+ ui._menuMode = TALK_MODE;
+
+ // Turn on the Exit option
+ ui._endKeyActive = true;
+
+ if (people[AL]._walkCount || people._walkTo.size() > 0) {
+ // Only interrupt if an action if trying to do an action, and not just
+ // if the player is walking around the scene
+ if (people._allowWalkAbort)
+ scripts._abortFlag = true;
+
+ people.gotoStand(people._player);
+ }
+
+ if (talk._talkToAbort)
+ return;
+
+ talk.freeTalkVars();
+
+ // If any sequences have changed in the prior talk file, restore them
+ if (_savedSequences.size() > 0) {
+ for (uint idx = 0; idx < _savedSequences.size(); ++idx) {
+ SavedSequence &ss = _savedSequences[idx];
+ for (uint idx2 = 0; idx2 < _savedSequences.size(); ++idx2)
+ scene._bgShapes[ss._objNum]._sequences[idx2] = ss._sequences[idx2];
+
+ // Reset the object's frame to the beginning of the sequence
+ scene._bgShapes[ss._objNum]._frameNumber = 0;
+ }
+ }
+
+ while (_sequenceStack.empty())
+ pullSequence();
+
+ // Restore any pressed button
+ if (!ui._windowOpen && savedMode != STD_MODE)
+ ui.restoreButton(savedMode - 1);
+
+ // Clear the ui counter so that anything displayed on the info line
+ // before the window was opened isn't cleared
+ ui._menuCounter = 0;
+
+ // Close any previous window before starting the talk
+ if (ui._windowOpen) {
+ switch (savedMode) {
+ case LOOK_MODE:
+ events.setCursor(ARROW);
+
+ if (ui._invLookFlag) {
+ screen.resetDisplayBounds();
+ ui.drawInterface(2);
+ }
+
+ ui.banishWindow();
+ ui._windowBounds.top = CONTROLS_Y1;
+ ui._temp = ui._oldTemp = ui._lookHelp = 0;
+ ui._menuMode = STD_MODE;
+ events._pressed = events._released = events._oldButtons = 0;
+ ui._invLookFlag = false;
+ break;
+
+ case TALK_MODE:
+ if (_speaker < 128)
+ clearTalking();
+ if (_talkCounter)
+ return;
+
+ // If we were in inventory mode looking at an object, restore the
+ // back buffers before closing the window, so we get the ui restored
+ // rather than the inventory again
+ if (ui._invLookFlag) {
+ screen.resetDisplayBounds();
+ ui.drawInterface(2);
+ ui._invLookFlag = ui._lookScriptFlag = false;
+ }
+
+ ui.banishWindow();
+ ui._windowBounds.top = CONTROLS_Y1;
+ scripts._abortFlag = true;
+ break;
+
+ case INV_MODE:
+ case USE_MODE:
+ case GIVE_MODE:
+ inv.freeInv();
+ if (ui._invLookFlag) {
+ screen.resetDisplayBounds();
+ ui.drawInterface(2);
+ ui._invLookFlag = ui._lookScriptFlag = false;
+ }
+
+ ui._infoFlag = true;
+ ui.clearInfo();
+ ui.banishWindow(false);
+ ui._key = -1;
+ break;
+
+ case FILES_MODE:
+ ui.banishWindow(true);
+ ui._windowBounds.top = CONTROLS_Y1;
+ scripts._abortFlag = true;
+ break;
+
+ case SETUP_MODE:
+ ui.banishWindow(true);
+ ui._windowBounds.top = CONTROLS_Y1;
+ ui._temp = ui._oldTemp = ui._lookHelp = ui._invLookFlag = false;
+ ui._menuMode = STD_MODE;
+ events._pressed = events._released = events._oldButtons = 0;
+ scripts._abortFlag = true;
+ break;
+ }
+ }
+
+ screen.resetDisplayBounds();
+ events._pressed = events._released = false;
+ loadTalkFile(filename);
+ ui._selector = ui._oldSelector = ui._key = ui._oldKey = -1;
+
+ // Find the first statement that has the correct flags
+ int select = -1;
+ for (uint idx = 0; idx < _statements.size() && select == -1; ++idx) {
+ /*
+ if (!_talkMap[idx])
+ select = _talkIndex = idx;
+ */
+ }
+
+ // TODOa
}
void Talk::talk(int objNum) {
@@ -45,5 +270,67 @@ void Talk::freeTalkVars() {
_statements.clear();
}
+void Talk::pullSequence() {
+ // TODO
+}
+
+/**
+ * Opens the talk file 'talk.tlk' and searches the index for the specified
+ * conversation. If found, the data for that conversation is loaded
+ */
+void Talk::loadTalkFile(const Common::String &filename) {
+ People &people = *_vm->_people;
+ Resources &res = *_vm->_res;
+ Sound &sound = *_vm->_sound;
+
+ // Check for an existing person being talked to
+ _talkTo = -1;
+ for (int idx = 0; idx < MAX_PEOPLE; ++idx) {
+ if (scumm_strnicmp(filename.c_str(), people[(PeopleId)idx]._portrait.c_str(), 4)) {
+ _talkTo = idx;
+ break;
+ }
+ }
+
+ const char *chP = strchr(filename.c_str(), '.');
+ Common::String talkFile = !chP ? filename + ".tlk" :
+ Common::String(filename.c_str(), chP) + ".tlk";
+
+ // Open the talk file for reading
+ Common::SeekableReadStream *talkStream = res.load(talkFile);
+ talkStream->skip(2); // Skip talk file version num
+
+ _statements.resize(talkStream->readByte());
+ for (uint idx = 0; idx < _statements.size(); ++idx)
+ _statements[idx].synchronize(*talkStream, sound._voicesOn);
+
+ delete talkStream;
+ setTalkMap();
+}
+
+void Talk::clearTalking() {
+ // TODO
+}
+
+/**
+ * Form a translate table from the loaded statements from a talk file
+ */
+void Talk::setTalkMap() {
+ int statementNum = 0;
+
+ for (uint sIdx = 0; sIdx < _statements.size(); ++sIdx) {
+ Statement &statement = _statements[sIdx];
+
+ // Set up talk map entry for the statement
+ bool valid = true;
+ for (uint idx = 0; idx < statement._required.size(); ++idx) {
+ if (!_vm->readFlags(statement._required[idx]))
+ valid = false;
+ }
+
+ statement._talkMap = valid ? statementNum++ : -1;
+ }
+}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index 9359b77e87..6ef4a04b6a 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -25,31 +25,58 @@
#include "common/scummsys.h"
#include "common/array.h"
+#include "common/stream.h"
+#include "common/stack.h"
namespace Sherlock {
-struct TalkHistoryEntry {
-private:
- int _data[2];
-public:
- TalkHistoryEntry() { _data[0] = _data[1] = 0; }
+struct SavedSequence {
+ int _objNum;
+ Common::Array<byte> _sequences;
+};
- int &operator[](int idx) { return _data[idx]; }
+struct Statement {
+ Common::String _statement;
+ Common::String _reply;
+ Common::String _linkFile;
+ Common::String _voiceFile;
+ Common::Array<int> _required;
+ Common::Array<int> _modified;
+ int _portraitSide;
+ int _quotient;
+ int _talkMap;
+
+ void synchronize(Common::SeekableReadStream &s, bool voices);
};
class SherlockEngine;
class Talk {
+
private:
SherlockEngine *_vm;
+ int _saveSeqNum;
+ Common::Array<SavedSequence> _savedSequences;
+ Common::Stack<int> _sequenceStack;
+ Common::Array<Statement> _statements;
+ int _speaker;
+ int _talkIndex;
+ int _talkTo;
+
+ void pullSequence();
+
+ void loadTalkFile(const Common::String &filename);
+
+ void clearTalking();
+
+ void setTalkMap();
public:
- Common::Array<TalkHistoryEntry> _statements;
bool _talkToAbort;
int _talkCounter;
public:
Talk(SherlockEngine *vm);
- void talkTo(const Common::String &name);
+ void talkTo(const Common::String &filename);
void talk(int objNum);
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 5e8b3287f0..9fe8a0979f 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -43,14 +43,14 @@ const int MENU_POINTS[12][4] = {
// Inventory control locations */
const int INVENTORY_POINTS[8][3] = {
- { 4, 50, 28 },
- { 52, 99, 76 },
- { 101, 140, 122 },
- { 142, 187, 165 },
- { 189, 219, 197 },
- { 221, 251, 233 },
- { 253, 283, 265 },
- { 285, 315, 293 }
+ { 4, 50, 29 },
+ { 52, 99, 77 },
+ { 101, 140, 123 },
+ { 142, 187, 166 },
+ { 189, 219, 198 },
+ { 221, 251, 234 },
+ { 253, 283, 266 },
+ { 285, 315, 294 }
};
const char COMMANDS[13] = "LMTPOCIUGJFS";
@@ -85,6 +85,7 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
_windowStyle = 1; // Sliding windows
_find = 0;
_oldUse = 0;
+ _endKeyActive = true;
}
UserInterface::~UserInterface() {
@@ -101,12 +102,15 @@ void UserInterface::reset() {
/**
* Draw the user interface onto the screen's back buffers
*/
-void UserInterface::drawInterface() {
+void UserInterface::drawInterface(int bufferNum) {
Screen &screen = *_vm->_screen;
- screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
- screen._backBuffer1.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
- screen._backBuffer2.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ if (bufferNum & 1)
+ screen._backBuffer1.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ if (bufferNum & 2)
+ screen._backBuffer2.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ if (bufferNum == 3)
+ screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
}
/**
@@ -118,6 +122,7 @@ void UserInterface::handleInput() {
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
+ Scripts &scripts = *_vm->_scripts;
Talk &talk = *_vm->_talk;
if (_menuCounter)
@@ -143,7 +148,7 @@ void UserInterface::handleInput() {
}
// Do button highlighting check
- if (!_vm->_scriptMoreFlag) { // Don't if scripts are running
+ if (!scripts._scriptMoreFlag) { // Don't if scripts are running
if (((events._rightPressed || events._rightReleased) && _helpStyle) ||
(!_helpStyle && !_menuCounter)) {
// Handle any default commands if we're in STD_MODE
@@ -276,7 +281,7 @@ void UserInterface::handleInput() {
case GIVE_MODE:
case INV_MODE:
if (inv._invMode == 1 || inv._invMode == 2 || inv._invMode == 3) {
- if (pt.y < CONTROLS_Y)
+ if (pt.y > CONTROLS_Y)
lookInv();
else
lookScreen(pt);
@@ -713,7 +718,7 @@ void UserInterface::doInvControl() {
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), colors[1], true, "Look");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), colors[1], true, "Use");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), colors[1], true, "Give");
- inv._invMode = found;
+ inv._invMode = (InvMode)found;
_selector = -1;
}
@@ -734,7 +739,11 @@ void UserInterface::doInvControl() {
bool flag = false;
if (inv._invMode == 1 || inv._invMode == 2 || inv._invMode == 3) {
Common::Rect r(15, CONTROLS_Y1 + 11, 314, SHERLOCK_SCREEN_HEIGHT - 2);
- flag = (_selector < inv._holdings);
+ if (r.contains(mousePos)) {
+ _selector = (mousePos.x - 6) / 52 + inv._invIndex;
+ if (_selector < inv._holdings)
+ flag = true;
+ }
}
if (!flag && mousePos.y >(CONTROLS_Y1 + 11))
@@ -753,13 +762,13 @@ void UserInterface::doInvControl() {
int temp = inv._invMode;
const char *chP = strchr(INVENTORY_COMMANDS, _key);
- inv._invMode = !chP ? 8 : chP - INVENTORY_COMMANDS;
+ inv._invMode = !chP ? INVMODE_INVALID : (InvMode)(chP - INVENTORY_COMMANDS);
inv.invCommands(true);
- inv._invMode = temp;
+ inv._invMode = (InvMode)temp;
_keyboardInput = true;
if (_key == 'E')
- inv._invMode = STD_MODE;
+ inv._invMode = INVMODE_EXIT;
_selector = -1;
} else {
_selector = -1;
@@ -789,11 +798,11 @@ void UserInterface::doInvControl() {
events.clearEvents();
events.setCursor(ARROW);
} else if ((found == 1 && events._released) || (_key == 'L')) {
- inv._invMode = 1;
+ inv._invMode = INVMODE_LOOK;
} else if ((found == 2 && events._released) || (_key == 'U')) {
- inv._invMode = 2;
+ inv._invMode = INVMODE_USE;
} else if ((found == 3 && events._released) || (_key == 'G')) {
- inv._invMode = 3;
+ inv._invMode = INVMODE_GIVE;
} else if (((found == 4 && events._released) || _key == ',') && inv._invIndex) {
if (inv._invIndex >= 6)
inv._invIndex -= 6;
@@ -855,7 +864,8 @@ void UserInterface::doInvControl() {
// If it's -1, then no inventory item is highlighted yet. Otherwise,
// an object in the scene has been clicked.
- if (_selector != -1 && inv._invMode == 1 && mousePos.y >(CONTROLS_Y1 + 11))
+ if (_selector != -1 && inv._invMode == INVMODE_LOOK
+ && mousePos.y >(CONTROLS_Y1 + 11))
inv.doInvJF();
if (talk._talkToAbort)
@@ -879,7 +889,7 @@ void UserInterface::doInvControl() {
inv.putInv(1);
_selector = temp; // Restore it
temp = inv._invMode;
- inv._invMode = -1;
+ inv._invMode = INVMODE_USE55;
inv.invCommands(true);
_infoFlag = true;
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 14462d6a34..157900f0aa 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -57,9 +57,11 @@ extern const char INVENTORY_COMMANDS[9];
class SherlockEngine;
class Inventory;
+class Talk;
class UserInterface {
friend class Inventory;
+ friend class Talk;
private:
SherlockEngine *_vm;
ImageFile *_controlPanel;
@@ -72,7 +74,6 @@ private:
int _help, _oldHelp;
int _key, _oldKey;
int _temp, _oldTemp;
- int _invLookFlag;
int _oldLook;
bool _keyboardInput;
bool _pause;
@@ -89,8 +90,6 @@ private:
private:
void depressButton(int num);
- void restoreButton(int num);
-
void pushButton(int num);
void toggleButton(int num);
@@ -120,13 +119,15 @@ public:
int _menuCounter;
bool _infoFlag;
bool _windowOpen;
+ bool _endKeyActive;
+ int _invLookFlag;
public:
UserInterface(SherlockEngine *vm);
~UserInterface();
void reset();
- void drawInterface();
+ void drawInterface(int bufferNum = 3);
void handleInput();
@@ -140,6 +141,8 @@ public:
void summonWindow(const Surface &bgSurface, bool slideUp = true);
void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
void banishWindow(bool slideUp = true);
+
+ void restoreButton(int num);
};
} // End of namespace Sherlock