diff options
Diffstat (limited to 'engines/sherlock/talk.cpp')
-rw-r--r-- | engines/sherlock/talk.cpp | 833 |
1 files changed, 811 insertions, 22 deletions
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index d284ace8b8..193c0f9a19 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -26,7 +26,42 @@ namespace Sherlock { -#define SFX_COMMAND 140 +enum { + SWITCH_SPEAKER = 128, + RUN_CANIMATION = 129, + ASSIGN_PORTRAIT_LOCATION = 130, + PAUSE = 131, + REMOVE_PORTRAIT = 132, + CLEAR_WINDOW = 133, + ADJUST_OBJ_SEQUENCE = 134, + WALK_TO_COORDS = 135, + PAUSE_WITHOUT_CONTROL = 136, + BANISH_WINDOW = 137, + SUMMON_WINDOW = 138, + SET_FLAG = 139, + SFX_COMMAND = 140, + TOGGLE_OBJECT = 141, + STEALTH_MODE_ACTIVE = 142, + IF_STATEMENT = 143, + ELSE_STATEMENT = 144, + END_IF_STATEMENT = 145, + STEALTH_MODE_DEACTIVATE = 146, + TURN_HOLMES_OFF = 147, + TURN_HOLMES_ON = 148, + GOTO_SCENE = 149, + PLAY_PROLOGUE = 150, + ADD_ITEM_TO_INVENTORY = 151, + SET_OBJECT = 152, + CALL_TALK_FILE = 153, + MOVE_MOUSE = 154, + DISPLAY_INFO_LINE = 155, + CLEAR_INFO_LINE = 156, + WALK_TO_CANIMATION = 157, + REMOVE_ITEM_FROM_INVENTORY = 158, + ENABLE_END_KEY = 159, + DISABLE_END_KEY = 160, + COMMAND_161 = 161 +}; /*----------------------------------------------------------------*/ @@ -99,6 +134,9 @@ Talk::Talk(SherlockEngine *vm): _vm(vm) { _talkStealth = 0; _talkToFlag = -1; _moreTalkDown = _moreTalkUp = false; + _scriptMoreFlag = 1; + _scriptSaveIndex = -1; + _scriptCurrentIndex = -1; } void Talk::setSequences(const byte *talkSequences, const byte *stillSequences, int maxPeople) { @@ -136,13 +174,13 @@ void Talk::talkTo(const Common::String &filename) { // 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; + if (!_scriptMoreFlag) { + _scriptName = filename; + _scriptSaveIndex = 0; // Flag the selection, since we don't yet know which statement yet - scripts._scriptSelect = 100; - scripts._scriptMoreFlag = 3; + _scriptSelect = 100; + _scriptMoreFlag = 3; } return; @@ -172,7 +210,7 @@ void Talk::talkTo(const Common::String &filename) { // 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]; + SequenceEntry &ss = _savedSequences[idx]; for (uint idx2 = 0; idx2 < _savedSequences.size(); ++idx2) scene._bgShapes[ss._objNum]._sequences[idx2] = ss._sequences[idx2]; @@ -181,7 +219,7 @@ void Talk::talkTo(const Common::String &filename) { } } - while (!_sequenceStack.empty()) + while (!_scriptStack.empty()) pullSequence(); // Restore any pressed button @@ -276,7 +314,7 @@ void Talk::talkTo(const Common::String &filename) { select = _talkIndex = idx; } - if (scripts._scriptMoreFlag && _scriptSelect != 0) + if (_scriptMoreFlag && _scriptSelect != 0) select = _scriptSelect; if (select == -1) @@ -288,7 +326,7 @@ void Talk::talkTo(const Common::String &filename) { _talkHistory[_converseNum][select] = true; // Check if the talk file is meant to be a non-seen comment - if (filename[7] != '*') { + if (filename.size() < 8 || filename[7] != '*') { // Should we start in stealth mode? if (_statements[select]._statement.hasPrefix("^")) { _talkStealth = 2; @@ -305,13 +343,13 @@ void Talk::talkTo(const Common::String &filename) { // Handle replies until there's no further linked file, // or the link file isn't a reply first cnversation - for (;;) { + while (!_vm->shouldQuit()) { clearSequences(); _scriptSelect = select; _speaker = _talkTo; Statement &statement = _statements[select]; - scripts.doScript(_statements[select]._reply); + doScript(_statements[select]._reply); if (_talkToAbort) return; @@ -327,7 +365,7 @@ void Talk::talkTo(const Common::String &filename) { } // Check for a linked file - if (!statement._linkFile.empty() && !scripts._scriptMoreFlag) { + if (!statement._linkFile.empty() && !_scriptMoreFlag) { freeTalkVars(); loadTalkFile(statement._linkFile); @@ -422,7 +460,7 @@ void Talk::talkTo(const Common::String &filename) { // If a script was added to the script stack, restore state so that the // previous script can continue - if (!scripts._scriptStack.empty()) { + if (!_scriptStack.empty()) { scripts.popStack(); } @@ -547,7 +585,7 @@ void Talk::loadTalkFile(const Common::String &filename) { // 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)) { + if (!scumm_strnicmp(filename.c_str(), people[(PeopleId)idx]._portrait.c_str(), 4)) { _talkTo = idx; break; } @@ -568,7 +606,7 @@ void Talk::loadTalkFile(const Common::String &filename) { delete talkStream; - if (!sound._voicesOn) + if (!sound._voices) stripVoiceCommands(); setTalkMap(); } @@ -833,7 +871,7 @@ int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt * Clears the stack of pending object sequences associated with speakers in the scene */ void Talk::clearSequences() { - _sequenceStack.clear(); + _scriptStack.clear(); } /** @@ -843,7 +881,7 @@ void Talk::clearSequences() { void Talk::pullSequence() { Scene &scene = *_vm->_scene; - SequenceEntry seq = _sequenceStack.pop(); + SequenceEntry seq = _scriptStack.pop(); if (seq._objNum != -1) { Object &obj = scene._bgShapes[seq._objNum]; @@ -871,7 +909,7 @@ void Talk::pushSequence(int speaker) { if (speaker == -1) return; - SequenceEntry seqEntry; + ScriptStackEntry seqEntry; if (!speaker) { seqEntry._objNum = -1; } else { @@ -885,9 +923,13 @@ void Talk::pushSequence(int speaker) { seqEntry._seqTo = obj._seqTo; } - _sequenceStack.push(seqEntry); - if (_sequenceStack.size() >= 5) - error("sequence stack overflow"); + _scriptStack.push(seqEntry); + if (_scriptStack.size() >= 5) + error("script stack overflow"); +} + +void Talk::setSequence(int speaker) { + // TODO } /** @@ -923,4 +965,751 @@ void Talk::setStillSeq(int speaker) { } } +/** + * Parses a reply for control codes and display text. The found text is printed within + * the text window, handles delays, animations, and animating portraits. + */ +void Talk::doScript(const Common::String &script) { + Animation &anim = *_vm->_animation; + Events &events = *_vm->_events; + Inventory &inv = *_vm->_inventory; + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + Screen &screen = *_vm->_screen; + Sound &sound = *_vm->_sound; + UserInterface &ui = *_vm->_ui; + int wait = 0; + bool pauseFlag = false; + bool endStr = false; + int yp = CONTROLS_Y + 12; + int charCount = 0; + int line = 0; + bool noTextYet = true; + bool openTalkWindow = false; + int obj; + int seqCount; + + _saveSeqNum = 0; + + const char *str = script.c_str(); + if (_scriptMoreFlag) { + _scriptMoreFlag = 0; + str = script.c_str() + _scriptSaveIndex; + } + + // Check if the script begins with a Stealh Mode Active command + if (str[0] == STEALTH_MODE_ACTIVE || _talkStealth) { + _talkStealth = 2; + _speaker |= 128; + } else { + pushSequence(_speaker); + ui.clearWindow(); + + // Need to switch speakers? + if (str[0] == SWITCH_SPEAKER) { + _speaker = str[1] - 1; + str += 2; + pullSequence(); + pushSequence(_speaker); + setSequence(_speaker); + } + else { + setSequence(_speaker); + } + + // Assign portrait location? + if (str[0] == ASSIGN_PORTRAIT_LOCATION) { + switch (str[1] & 15) { + case 1: + people._portraitSide = 20; + break; + case 2: + people._portraitSide = 220; + break; + case 3: + people._portraitSide = 120; + break; + default: + break; + + } + + if (str[1] > 15) + people._speakerFlip = true; + str += 2; + } + + // Remove portrait? + if (str[0] == REMOVE_PORTRAIT) { + _speaker = 255; + } + else { + // Nope, so set the first speaker + setTalking(_speaker); + } + } + + do { + Common::String tempString; + wait = 0; + + if (!str[0]) { + endStr = true; + } else if (str[0] == '{') { + // Start of comment, so skip over it + while (*str++ != '}') + ; + } else if (str[0] >= 128) { + // Handle control code + switch (str[0]) { + case SWITCH_SPEAKER: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + + if (!(_speaker & 128)) + clearTalking(); + if (_talkToAbort) + return; + + ui.clearWindow(); + yp = CONTROLS_Y + 12; + charCount = line = 0; + + _speaker = *++str - 1; + setTalking(_speaker); + pullSequence(); + pushSequence(_speaker); + setSequence(_speaker); + break; + + case RUN_CANIMATION: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + scene.startCAnim((str[0] - 1) & 127, 1 + (str[0] & 128)); + if (_talkToAbort) + return; + + // Check if next character is changing side or changing portrait + if (charCount && (str[1] == SWITCH_SPEAKER || str[1] == ASSIGN_PORTRAIT_LOCATION)) + wait = 1; + break; + + case ASSIGN_PORTRAIT_LOCATION: + ++str; + switch (str[0] & 15) { + case 1: + people._portraitSide = 20; + break; + case 2: + people._portraitSide = 220; + break; + case 3: + people._portraitSide = 120; + break; + default: + break; + } + + if (str[0] > 15) + people._speakerFlip = true; + break; + + case PAUSE: + // Pause + charCount = *++str; + wait = pauseFlag = true; + break; + + case REMOVE_PORTRAIT: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + + if (_speaker < 128) + clearTalking(); + pullSequence(); + if (_talkToAbort) + return; + + _speaker |= 128; + break; + + case CLEAR_WINDOW: + ui.clearWindow(); + yp = CONTROLS_Y + 12; + charCount = line = 0; + break; + + case ADJUST_OBJ_SEQUENCE: + // Get the name of the object to adjust + ++str; + for (int idx = 0; idx < (str[0] & 127); ++idx) + tempString += str[idx + 2]; + + // Scan for object + obj = -1; + for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { + if (scumm_stricmp(tempString.c_str(), scene._bgShapes[idx]._name.c_str()) == 0) + obj = idx; + } + if (obj == -1) + error("Could not find object %s to change", tempString.c_str()); + + // Should the script be overwritten? + if (str[0] > 128) { + // Save the current sequence + _savedSequences.push(SequenceEntry()); + SequenceEntry &seqEntry = _savedSequences.top(); + seqEntry._objNum = obj; + seqEntry._seqTo = scene._bgShapes[obj]._seqTo; + for (uint idx = 0; idx < scene._bgShapes[obj]._seqSize; ++idx) + seqEntry._sequences.push_back(scene._bgShapes[obj]._sequences[idx]); + } + + // Get number of bytes to change + seqCount = str[1]; + str += (str[0] & 127) + 2; + + // Copy in the new sequence + for (int idx = 0; idx < seqCount; ++idx, ++str) + scene._bgShapes[obj]._sequences[idx] = str[0] - 1; + + // Reset object back to beginning of new sequence + scene._bgShapes[obj]._frameNumber = 0; + continue; + + case WALK_TO_COORDS: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + + people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100, str[2] * 100), str[3] - 1); + if (_talkToAbort) + return; + + str += 3; + break; + + case PAUSE_WITHOUT_CONTROL: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + + for (int idx = 0; idx < (str[0] - 1); ++idx) { + scene.doBgAnim(); + if (_talkToAbort) + return; + + // Check for button press + events.pollEvents(); + events.setButtonState(); + } + break; + + case BANISH_WINDOW: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + + if (!(_speaker & 128)) + clearTalking(); + pullSequence(); + + if (_talkToAbort) + return; + + _speaker |= 128; + ui.banishWindow(); + ui._menuMode = TALK_MODE; + noTextYet = true; + break; + + case SUMMON_WINDOW: + drawInterface(); + events._pressed = events._released = false; + events.clearKeyboard(); + noTextYet = false; + + if (_speaker != -1) { + screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit"); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up"); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down"); + } + break; + + case SET_FLAG: { + ++str; + int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0); + int flag = (flag1 & 0x7fff) * (flag1 >= 0x8000 ? -1 : 1); + _vm->setFlags(flag); + ++str; + break; + } + + case SFX_COMMAND: + ++str; + if (sound._voices) { + for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) + tempString += str[idx]; + sound.playSound(tempString); + + // Set voices to wait for more + sound._voices = 2; + sound._speechOn = (*sound._soundIsOn); + } + + wait = 1; + str += 7; + break; + + case TOGGLE_OBJECT: + for (int idx = 0; idx < str[0]; ++idx) + tempString += str[idx + 1]; + + scene.toggleObject(tempString); + str += str[0]; + break; + + case STEALTH_MODE_ACTIVE: + _talkStealth = 2; + break; + + case IF_STATEMENT: { + ++str; + int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0); + ++str; + wait = 0; + + bool result = flag < 0x8000; + if (_vm->readFlags(flag & 0x7fff) != result) { + do { + ++str; + } while (str[0] && str[0] != ELSE_STATEMENT && str[0] != END_IF_STATEMENT); + + if (!str[0]) + endStr = true; + } + break; + } + + case ELSE_STATEMENT: + // If this is encountered here, it means that a preceeding IF statement was found, + // and evaluated to true. Now all the statements for the true block are finished, + // so skip over the block of code that would have executed if the result was false + wait = 0; + do { + ++str; + } while (str[0] && str[0] != END_IF_STATEMENT); + break; + + case STEALTH_MODE_DEACTIVATE: + _talkStealth = 0; + events.clearKeyboard(); + break; + + case TURN_HOLMES_OFF: + people._holmesOn = false; + break; + + case TURN_HOLMES_ON: + people._holmesOn = true; + break; + + case GOTO_SCENE: + scene._goToScene = str[1] - 1; + + if (scene._goToScene != 100) { + // Not going to the map overview + scene._oldCharPoint = scene._goToScene; + scene._overPos.x = _vm->_map[scene._goToScene].x * 100 - 600; + scene._overPos.y = _vm->_map[scene._goToScene].y * 100 + 900; + + // Run a canimation? + if (str[2] > 100) { + scene._hsavedFs = str[2]; + scene._hsavedPos = Common::Point(160, 100); + } + } + str += 6; + + _scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1; + _scriptSaveIndex = str - script.c_str(); + endStr = true; + wait = 0; + break; + + case PLAY_PROLOGUE: + ++str; + for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) + tempString += str[idx]; + + anim.playPrologue(tempString, 1, 3, true, 4); + break; + + case ADD_ITEM_TO_INVENTORY: + ++str; + for (int idx = 0; idx < str[0]; ++idx) + tempString += str[idx]; + str += str[0]; + + inv.putNameInInventory(tempString); + break; + + case SET_OBJECT: { + ++str; + for (int idx = 0; idx < (str[0] & 127); ++idx) + tempString += str[idx + 1]; + str += str[0]; + + // Set comparison state according to if we want to hide or unhide + bool state = (str[0] >= 128); + + for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { + Object &obj = scene._bgShapes[idx]; + if (scumm_stricmp(tempString.c_str(), obj._name.c_str()) == 0) { + // Only toggle the object if it's not in the desired state already + if ((obj._type == HIDDEN && state) || (obj._type != HIDDEN && !state)) + obj.toggleHidden(); + } + } + break; + } + + case CALL_TALK_FILE: + ++str; + for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) + tempString += str[idx]; + str += 8; + + _scriptCurrentIndex = str - script.c_str(); + + // Save the current script position and new talk file + if (_scriptStack.size() < 10) { + ScriptStackEntry rec; + rec._name = _scriptName; + rec._currentIndex = _scriptCurrentIndex; + rec._select = _scriptSelect; + } else { + error("Script stack overflow"); + } + + _scriptMoreFlag = true; + endStr = true; + wait = 0; + break; + + case MOVE_MOUSE: + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2])); + if (_talkToAbort) + return; + str += 3; + break; + + case DISPLAY_INFO_LINE: + ++str; + for (int idx = 0; idx < str[0]; ++idx) + tempString += str[idx + 1]; + str += str[0]; + + screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, tempString.c_str()); + break; + + case CLEAR_INFO_LINE: + ui._infoFlag = true; + ui.clearInfo(); + break; + + case WALK_TO_CANIMATION: { + ++str; + int animIndex = str[0] - 1; + + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = (str + 1) - script.c_str(); + if (_talkToAbort) + return; + break; + } + + case REMOVE_ITEM_FROM_INVENTORY: + ++str; + for (int idx = 0; idx < str[0]; ++idx) + tempString += str[idx + 1]; + str += str[0]; + + inv.deleteItemFromInventory(tempString); + break; + + case ENABLE_END_KEY: + ui._endKeyActive = true; + break; + + case DISABLE_END_KEY: + ui._endKeyActive = false; + break; + + default: + break; + } + + ++str; + } else { + // If the window isn't yet open, draw the window before printing starts + if (!ui._windowOpen && noTextYet) { + noTextYet = false; + drawInterface(); + + if (_talkTo != -1) { + screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit"); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up"); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down"); + } + } + + // If it's the first line, display the speaker + if (!line && _speaker >= 0 && _speaker < MAX_PEOPLE) { + // If the window is open, display the name directly on-screen. + // Otherwise, simply draw it on the back buffer + if (ui._windowOpen) { + screen.print(Common::Point(16, yp), TALK_FOREGROUND, inv._names[_speaker & 127].c_str()); + } else { + screen.gPrint(Common::Point(16, yp - 1), TALK_FOREGROUND, inv._names[_speaker & 127].c_str()); + openTalkWindow = true; + } + + yp += 9; + } + + // Find amound of text that will fit on the line + int width = 0, idx = 0; + do { + width += screen.charWidth(str[idx]); + } while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < 128); + + if (str[idx] || width >= 298) { + if (str[idx] < 128 && str[idx] != '{') { + --idx; + --charCount; + } + } else { + endStr = true; + } + + // If word wrap is needed, find the start of the current word + if (width >= 298) { + while (str[idx] != ' ') { + --idx; + --charCount; + } + } + + // Print the line + Common::String lineStr(str, str + idx); + + // If the speaker indicates a description file, print it in yellow + if (_speaker != -1) { + if (ui._windowOpen) { + screen.print(Common::Point(16, yp), INV_FOREGROUND, lineStr.c_str()); + } else { + screen.gPrint(Common::Point(16, yp - 1), INV_FOREGROUND, lineStr.c_str()); + } + } else { + if (ui._windowOpen) { + screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, lineStr.c_str()); + } + else { + screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, lineStr.c_str()); + } + } + + // Move to end of displayed line + str += idx; + + // If line wrap occurred, then move to after the separating space between the words + if (str[0] < 128 && str[0] != '{') + ++str; + + yp += 9; + ++line; + + // Certain different conditions require a wait + if ((line == 4 && str[0] != SFX_COMMAND && str[0] != PAUSE && _speaker != -1) || + (line == 5 && str[0] != PAUSE && _speaker != -1) || + endStr) { + wait = 1; + } + + switch (str[0]) { + case SWITCH_SPEAKER: + case ASSIGN_PORTRAIT_LOCATION: + case BANISH_WINDOW: + case IF_STATEMENT: + case ELSE_STATEMENT: + case END_IF_STATEMENT: + case GOTO_SCENE: + case CALL_TALK_FILE: + wait = 1; + break; + default: + break; + } + } + + // Open window if it wasn't already open, and text has already been printed + if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= 128 && str[0] != COMMAND_161)) { + if (!ui._windowStyle) { + screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); + } else { + ui.summonWindow(); + } + + ui._windowOpen = true; + openTalkWindow = false; + } + + if (wait) { + // Save the current point in the script, since it might be intterupted by + // doing bg anims in the next call, so we need to know where to return to + _scriptCurrentIndex = str - script.c_str(); + + // Handling pausing + if (!pauseFlag && charCount < 160) + charCount = 160; + + wait = waitForMore(charCount); + if (wait == -1) + endStr = true; + + // If a key was pressed to finish the window, see if further voice files should be skipped + if (wait >= 0 && wait < 254) { + if (str[0] == SFX_COMMAND) + str += 9; + } + + // Clear the window unless the wait was due to a PAUSE command + if (!pauseFlag && wait != -1 && str[0] != SFX_COMMAND) { + if (!_talkStealth) + ui.clearWindow(); + yp = CONTROLS_Y + 12; + charCount = line = 0; + } + + pauseFlag = false; + } + } while (!_vm->shouldQuit() && !endStr); + + if (wait != -1) { + for (int ssIndex = 0; ssIndex < (int)_savedSequences.size(); ++ssIndex) { + SequenceEntry &seq = _savedSequences[ssIndex]; + Object &obj = scene._bgShapes[seq._objNum]; + + for (uint idx = 0; idx < seq._sequences.size(); ++idx) + obj._sequences[idx] = seq._sequences[idx]; + obj._frameNumber = seq._frameNumber; + obj._seqTo = seq._seqTo; + } + + pullSequence(); + if (_speaker < 128) + clearTalking(); + } +} + +void Talk::clearTalking() { + // TODO +} + +void Talk::setTalking(int speaker) { + // TODO +} + +/** + * When the talk window has been displayed, waits a period of time proportional to + * the amount of text that's been displayed + */ +int Talk::waitForMore(int delay) { + Events &events = *_vm->_events; + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + Sound &sound = *_vm->_sound; + UserInterface &ui = *_vm->_ui; + CursorId oldCursor = events.getCursor(); + int key2 = 254; + + // Unless we're in stealth mode, show the appropriate cursor + if (!_talkStealth) { + events.setCursor(ui._lookScriptFlag ? MAGNIFY : ARROW); + } + + do { + if (sound._speechOn && !*sound._soundIsOn) + people._portrait._frameNumber = -1; + + scene.doBgAnim(); + + // If talkTo call was done via doBgAnim, abort out of talk quietly + if (_talkToAbort) { + key2 = -1; + events._released = true; + } else { + // See if there's been a button press + events.setButtonState(); + + if (events.kbHit()) { + Common::KeyState keyState = events.getKey(); + if (keyState.keycode >= 32 && keyState.keycode < 128) + key2 = keyState.keycode; + } + + if (_talkStealth) { + key2 = 254; + events._released = false; + } + } + + // Count down the delay + if ((delay > 0 && !ui._invLookFlag && !ui._lookScriptFlag) || _talkStealth) + --delay; + + // If there are voices playing, reset delay so that they keep playing + if (sound._voices == 2 && *sound._soundIsOn) + delay = 0; + } while (!_vm->shouldQuit() && key2 == 254 && (delay || (sound._voices == 2 && *sound._soundIsOn)) + && !events._released && !events._rightReleased); + + // If voices was set 2 to indicate a voice file was place, then reset it back to 1 + if (sound._voices == 2) + sound._voices = 1; + + if (delay > 0 && sound._diskSoundPlaying) + sound.stopSndFuncPtr(0, 0); + + // Adjust _talkStealth mode: + // mode 1 - It was by a pause without stealth being on before the pause, so reset back to 0 + // mode 3 - It was set by a pause with stealth being on before the pause, to set it to active + // mode 0/2 (Inactive/active) No change + switch (_talkStealth) { + case 1: + _talkStealth = 0; + break; + case 2: + _talkStealth = 2; + break; + default: + break; + } + + sound._speechOn = false; + events.setCursor(_talkToAbort ? ARROW : oldCursor); + events._pressed = events._released = false; + + return key2; +} + + } // End of namespace Sherlock |