SHERLOCK: Beginnings of talk loading, added skeleton Scripts class

This commit is contained in:
Paul Gilbert 2015-03-30 21:07:01 -04:00
parent 3149ce0204
commit 943d0a702f
16 changed files with 542 additions and 77 deletions

View File

@ -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

View File

@ -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();

View File

@ -18,6 +18,7 @@ MODULE_OBJS = \
resources.o \
scene.o \
screen.o \
scripts.o \
sherlock.o \
sound.o \
talk.o \

View File

@ -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; }

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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