aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2015-03-31 07:55:54 -0400
committerPaul Gilbert2015-03-31 07:55:54 -0400
commitcf4226be45ddea933ef17722eac0f5ccadc7357b (patch)
tree3cd3ee4c7af55fc6facba3f1a11da0216b60af0c
parent943d0a702fe468f14fb40f73ef68588705488037 (diff)
downloadscummvm-rg350-cf4226be45ddea933ef17722eac0f5ccadc7357b.tar.gz
scummvm-rg350-cf4226be45ddea933ef17722eac0f5ccadc7357b.tar.bz2
scummvm-rg350-cf4226be45ddea933ef17722eac0f5ccadc7357b.zip
SHERLOCK: Implemented talkTo
-rw-r--r--engines/sherlock/journal.cpp4
-rw-r--r--engines/sherlock/journal.h2
-rw-r--r--engines/sherlock/scripts.cpp26
-rw-r--r--engines/sherlock/scripts.h20
-rw-r--r--engines/sherlock/talk.cpp241
-rw-r--r--engines/sherlock/talk.h19
-rw-r--r--engines/sherlock/user_interface.cpp10
-rw-r--r--engines/sherlock/user_interface.h2
8 files changed, 290 insertions, 34 deletions
diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp
index ad7df48943..34423d2480 100644
--- a/engines/sherlock/journal.cpp
+++ b/engines/sherlock/journal.cpp
@@ -37,4 +37,8 @@ Journal::Journal() {
_page = 0;
}
+void Journal::record(int converseNum, int statementNum) {
+ // TODO
+}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/journal.h b/engines/sherlock/journal.h
index 64158ff123..87e5a4f8f2 100644
--- a/engines/sherlock/journal.h
+++ b/engines/sherlock/journal.h
@@ -39,6 +39,8 @@ public:
int _page;
public:
Journal();
+
+ void record(int converseNum, int statementNum);
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/scripts.cpp b/engines/sherlock/scripts.cpp
index ace957bd76..1da72c976b 100644
--- a/engines/sherlock/scripts.cpp
+++ b/engines/sherlock/scripts.cpp
@@ -29,7 +29,31 @@ Scripts::Scripts(SherlockEngine *vm): _vm(vm) {
_scriptMoreFlag = 0;
_scriptSaveIndex = 0;
_scriptSelect = 0;
- _abortFlag = false;
}
+void Scripts::doScript(const Common::String &str) {
+ // TODO
+}
+
+void Scripts::pullSeq() {
+ // TODO
+}
+
+void Scripts::pushSeq(int speak) {
+ // TODO
+}
+
+void Scripts::setStillSeq(int speak) {
+ // TODO
+}
+
+void Scripts::popStack() {
+ ScriptEntry script = _scriptStack.pop();
+ _scriptName = script._name;
+ _scriptSaveIndex = script._index;
+ _scriptSelect = script._select;
+ _scriptMoreFlag = true;
+}
+
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/scripts.h b/engines/sherlock/scripts.h
index eede1ca103..6c23e72fe4 100644
--- a/engines/sherlock/scripts.h
+++ b/engines/sherlock/scripts.h
@@ -24,23 +24,39 @@
#define SHERLOCK_SCRIPTS_H
#include "common/scummsys.h"
-#include "common/array.h"
+#include "common/stack.h"
namespace Sherlock {
class SherlockEngine;
+struct ScriptEntry {
+ Common::String _name;
+ int _index;
+ int _select;
+};
+
class Scripts {
private:
SherlockEngine *_vm;
public:
+ Common::Stack<ScriptEntry> _scriptStack;
int _scriptMoreFlag;
Common::String _scriptName;
int _scriptSaveIndex;
int _scriptSelect;
- bool _abortFlag;
public:
Scripts(SherlockEngine *vm);
+
+ void doScript(const Common::String &str);
+
+ void pullSeq();
+
+ void pushSeq(int speak);
+
+ void setStillSeq(int speak);
+
+ void popStack();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index d67013b60e..e3c5ebc5e0 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -25,10 +25,14 @@
namespace Sherlock {
+#define SFX_COMMAND 140
+
+/*----------------------------------------------------------------*/
+
/**
* Load the data for a single statement within a talk file
*/
-void Statement::synchronize(Common::SeekableReadStream &s, bool voices) {
+void Statement::synchronize(Common::SeekableReadStream &s) {
int length;
length = s.readUint16LE();
@@ -39,25 +43,6 @@ void Statement::synchronize(Common::SeekableReadStream &s, bool voices) {
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();
@@ -81,6 +66,12 @@ void Statement::synchronize(Common::SeekableReadStream &s, bool voices) {
/*----------------------------------------------------------------*/
+TalkHistoryEntry::TalkHistoryEntry() {
+ Common::fill(&_data[0], &_data[16], false);
+}
+
+/*----------------------------------------------------------------*/
+
Talk::Talk(SherlockEngine *vm): _vm(vm) {
_talkCounter = 0;
_talkToAbort = false;
@@ -88,6 +79,10 @@ Talk::Talk(SherlockEngine *vm): _vm(vm) {
_speaker = 0;
_talkIndex = 0;
_talkTo = 0;
+ _scriptSelect = 0;
+ _converseNum = -1;
+ _talkStealth = 0;
+ _talkToFlag = -1;
}
/**
@@ -98,6 +93,7 @@ Talk::Talk(SherlockEngine *vm): _vm(vm) {
void Talk::talkTo(const Common::String &filename) {
Events &events = *_vm->_events;
Inventory &inv = *_vm->_inventory;
+ Journal &journal = *_vm->_journal;
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
@@ -105,6 +101,7 @@ void Talk::talkTo(const Common::String &filename) {
Talk &talk = *_vm->_talk;
UserInterface &ui = *_vm->_ui;
Common::Rect savedBounds = screen.getDisplayBounds();
+ bool abortFlag = false;
if (filename.empty())
// No filename passed, so exit
@@ -137,7 +134,7 @@ void Talk::talkTo(const Common::String &filename) {
// 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;
+ abortFlag = true;
people.gotoStand(people._player);
}
@@ -206,7 +203,7 @@ void Talk::talkTo(const Common::String &filename) {
ui.banishWindow();
ui._windowBounds.top = CONTROLS_Y1;
- scripts._abortFlag = true;
+ abortFlag = true;
break;
case INV_MODE:
@@ -228,7 +225,7 @@ void Talk::talkTo(const Common::String &filename) {
case FILES_MODE:
ui.banishWindow(true);
ui._windowBounds.top = CONTROLS_Y1;
- scripts._abortFlag = true;
+ abortFlag = true;
break;
case SETUP_MODE:
@@ -237,7 +234,7 @@ void Talk::talkTo(const Common::String &filename) {
ui._temp = ui._oldTemp = ui._lookHelp = ui._invLookFlag = false;
ui._menuMode = STD_MODE;
events._pressed = events._released = events._oldButtons = 0;
- scripts._abortFlag = true;
+ abortFlag = true;
break;
}
}
@@ -250,13 +247,161 @@ void Talk::talkTo(const Common::String &filename) {
// 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])
+ if (_statements[idx]._talkMap == 0)
select = _talkIndex = idx;
- */
}
- // TODOa
+ if (scripts._scriptMoreFlag && _scriptSelect != 0)
+ select = _scriptSelect;
+
+ if (select == -1)
+ error("Couldn't find statement to display");
+
+ // Add the statement into the journal and talk history
+ if (_talkTo != -1 && !_talkHistory[_converseNum][select])
+ journal.record(_converseNum | 2048, select);
+ _talkHistory[_converseNum][select] = true;
+
+ // Check if the talk file is meant to be a non-seen comment
+ if (filename[7] != '*') {
+ // Should we start in stealth mode?
+ if (_statements[select]._statement.hasPrefix("^")) {
+ _talkStealth = 2;
+ } else {
+ // Not in stealth mode, so bring up the ui window
+ _talkStealth = 0;
+ ++_talkToFlag;
+ events.setCursor(WAIT);
+
+ ui._windowBounds.top = CONTROLS_Y;
+ ui._infoFlag = true;
+ ui.clearInfo();
+ }
+
+ // Handle replies until there's no further linked file,
+ // or the link file isn't a reply first cnversation
+ for (;;) {
+ _sequenceStack.clear();
+ _scriptSelect = select;
+ _speaker = _talkTo;
+
+ Statement &statement = _statements[select];
+ scripts.doScript(_statements[select]._reply);
+
+ if (_talkToAbort)
+ return;
+
+ if (!_talkStealth)
+ ui.clearWindow();
+
+ if (statement._modified.size() > 0) {
+ for (uint idx = 0; idx < statement._modified.size(); ++idx)
+ _vm->setFlags(statement._modified[idx]);
+
+ setTalkMap();
+ }
+
+ // Check for a linked file
+ if (!statement._linkFile.empty() && !scripts._scriptMoreFlag) {
+ freeTalkVars();
+ loadTalkFile(statement._linkFile);
+
+ // Scan for the first valid statement in the newly loaded file
+ select = -1;
+ for (uint idx = 0; idx < _statements.size(); ++idx) {
+ if (_statements[idx]._talkMap == 0) {
+ select = idx;
+ break;
+ }
+ }
+
+ if (_talkToFlag == 1)
+ scripts.pullSeq();
+
+ // Set the stealth mode for the new talk file
+ Statement &newStatement = _statements[select];
+ _talkStealth = newStatement._statement.hasPrefix("^") ? 2 : 0;
+
+ // If the new conversion is a reply first, then we don't need
+ // to display any choices, since the reply needs to be shown
+ if (!newStatement._statement.hasPrefix("*") &&
+ !newStatement._statement.hasPrefix("^")) {
+ _sequenceStack.clear();
+ scripts.pushSeq(_talkTo);
+ scripts.setStillSeq(_talkTo);
+ _talkIndex = select;
+ ui._selector = ui._oldSelector = -1;
+
+ if (!ui._windowOpen) {
+ // Draw the talk interface on the back buffer
+ drawInterface();
+ displayTalk(false);
+ } else {
+ displayTalk(true);
+ }
+
+ byte color = ui._endKeyActive ? COMMAND_FOREGROUND : COMMAND_NULL;
+
+ // If the window is alraedy open, simply draw. Otherwise, do it
+ // to the back buffer and then summon the window
+ if (ui._windowOpen) {
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, true, "Exit");
+ } else {
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, "Exit");
+
+ if (!ui._windowStyle) {
+ screen.slamRect(Common::Rect(0, CONTROLS_Y,
+ SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ } else {
+ ui.summonWindow();
+ }
+
+ ui._windowOpen = true;
+ }
+
+ // Break out of loop now that we're waiting for player input
+ events.setCursor(ARROW);
+ break;
+ } else {
+ // Add the statement into the journal and talk history
+ if (_talkTo != -1 && !_talkHistory[_converseNum][select])
+ journal.record(_converseNum | 2048, select);
+ _talkHistory[_converseNum][select] = true;
+
+ }
+
+ ui._key = ui._oldKey = COMMANDS[TALK_MODE - 1];
+ ui._temp = ui._oldTemp = 0;
+ ui._menuMode = TALK_MODE;
+ _talkToFlag = 2;
+ } else {
+ freeTalkVars();
+
+ if (!ui._lookScriptFlag) {
+ ui.banishWindow();
+ ui._windowBounds.top = CONTROLS_Y1;
+ ui._menuMode = STD_MODE;
+ }
+
+ break;
+ }
+ }
+ }
+
+ _talkStealth = 0;
+ events._pressed = events._released = events._oldButtons = 0;
+ events.clearKeyboard();
+
+ screen.setDisplayBounds(savedBounds);
+ _talkToAbort = abortFlag;
+
+ // If a script was added to the script stack, restore state so that the
+ // previous script can continue
+ if (!scripts._scriptStack.empty()) {
+ scripts.popStack();
+ }
+
+ events.setCursor(ARROW);
}
void Talk::talk(int objNum) {
@@ -302,9 +447,12 @@ void Talk::loadTalkFile(const Common::String &filename) {
_statements.resize(talkStream->readByte());
for (uint idx = 0; idx < _statements.size(); ++idx)
- _statements[idx].synchronize(*talkStream, sound._voicesOn);
+ _statements[idx].synchronize(*talkStream);
delete talkStream;
+
+ if (!sound._voicesOn)
+ stripVoiceCommands();
setTalkMap();
}
@@ -313,7 +461,33 @@ void Talk::clearTalking() {
}
/**
- * Form a translate table from the loaded statements from a talk file
+ * Remove any voice commands from a loaded statement list
+ */
+void Talk::stripVoiceCommands() {
+ for (uint sIdx = 0; sIdx < _statements.size(); ++sIdx) {
+ Statement &statement = _statements[sIdx];
+
+ // Scan for an sound effect byte, which indicates to play a sound
+ for (uint idx = 0; idx < statement._reply.size(); ++idx) {
+ if (statement._reply[idx] == SFX_COMMAND) {
+ // Replace instruction character with a space, and delete the
+ // rest of the name following it
+ statement._reply = Common::String(statement._reply.c_str(),
+ statement._reply.c_str() + idx) + " " +
+ Common::String(statement._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 (statement._reply.lastChar() == ' ')
+ statement._reply.deleteLastChar();
+ }
+}
+
+/**
+ * Form a table of the display indexes for statements
*/
void Talk::setTalkMap() {
int statementNum = 0;
@@ -332,5 +506,12 @@ void Talk::setTalkMap() {
}
}
+void Talk::drawInterface() {
+ // TODO
+}
+
+void Talk::displayTalk(bool slamIt) {
+ // TODO
+}
} // End of namespace Sherlock
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index 6ef4a04b6a..6557f6eed6 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -46,7 +46,14 @@ struct Statement {
int _quotient;
int _talkMap;
- void synchronize(Common::SeekableReadStream &s, bool voices);
+ void synchronize(Common::SeekableReadStream &s);
+};
+
+struct TalkHistoryEntry {
+ bool _data[16];
+
+ TalkHistoryEntry();
+ bool &operator[](int index) { return _data[index]; }
};
class SherlockEngine;
@@ -59,9 +66,14 @@ private:
Common::Array<SavedSequence> _savedSequences;
Common::Stack<int> _sequenceStack;
Common::Array<Statement> _statements;
+ TalkHistoryEntry _talkHistory[500];
int _speaker;
int _talkIndex;
int _talkTo;
+ int _scriptSelect;
+ int _converseNum;
+ int _talkStealth;
+ int _talkToFlag;
void pullSequence();
@@ -69,7 +81,10 @@ private:
void clearTalking();
+ void stripVoiceCommands();
void setTalkMap();
+
+ void displayTalk(bool slamIt);
public:
bool _talkToAbort;
int _talkCounter;
@@ -81,6 +96,8 @@ public:
void talk(int objNum);
void freeTalkVars();
+
+ void drawInterface();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 9fe8a0979f..74142ab80e 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -472,6 +472,16 @@ void UserInterface::clearInfo() {
}
/**
+ * Clear any active text window
+ */
+void UserInterface::clearWindow() {
+ if (_windowOpen) {
+ _vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+ SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
+ }
+}
+
+/**
* Handles counting down whilst checking for input, then clears the info line.
*/
void UserInterface::whileMenuCounter() {
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 157900f0aa..1259bed31b 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -50,6 +50,7 @@ enum MenuMode {
SETUP_MODE = 12
};
+extern const char COMMANDS[13];
extern const int MENU_POINTS[12][4];
extern const int INVENTORY_POINTS[8][3];
@@ -132,6 +133,7 @@ public:
void handleInput();
void clearInfo();
+ void clearWindow();
void whileMenuCounter();