diff options
Diffstat (limited to 'engines/sherlock')
-rw-r--r-- | engines/sherlock/inventory.cpp | 42 | ||||
-rw-r--r-- | engines/sherlock/inventory.h | 15 | ||||
-rw-r--r-- | engines/sherlock/module.mk | 1 | ||||
-rw-r--r-- | engines/sherlock/people.h | 13 | ||||
-rw-r--r-- | engines/sherlock/scene.cpp | 16 | ||||
-rw-r--r-- | engines/sherlock/scene.h | 11 | ||||
-rw-r--r-- | engines/sherlock/screen.cpp | 11 | ||||
-rw-r--r-- | engines/sherlock/screen.h | 4 | ||||
-rw-r--r-- | engines/sherlock/scripts.cpp | 35 | ||||
-rw-r--r-- | engines/sherlock/scripts.h | 48 | ||||
-rw-r--r-- | engines/sherlock/sherlock.cpp | 14 | ||||
-rw-r--r-- | engines/sherlock/sherlock.h | 6 | ||||
-rw-r--r-- | engines/sherlock/talk.cpp | 291 | ||||
-rw-r--r-- | engines/sherlock/talk.h | 43 | ||||
-rw-r--r-- | engines/sherlock/user_interface.cpp | 58 | ||||
-rw-r--r-- | engines/sherlock/user_interface.h | 11 |
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 |