diff options
Diffstat (limited to 'engines/sherlock/scalpel/scalpel_talk.cpp')
-rw-r--r-- | engines/sherlock/scalpel/scalpel_talk.cpp | 296 |
1 files changed, 234 insertions, 62 deletions
diff --git a/engines/sherlock/scalpel/scalpel_talk.cpp b/engines/sherlock/scalpel/scalpel_talk.cpp index f9a10ebc70..ff38c07537 100644 --- a/engines/sherlock/scalpel/scalpel_talk.cpp +++ b/engines/sherlock/scalpel/scalpel_talk.cpp @@ -22,6 +22,7 @@ #include "sherlock/scalpel/scalpel_talk.h" #include "sherlock/scalpel/scalpel_fixed_text.h" +#include "sherlock/scalpel/scalpel_journal.h" #include "sherlock/scalpel/scalpel_map.h" #include "sherlock/scalpel/scalpel_people.h" #include "sherlock/scalpel/scalpel_scene.h" @@ -169,26 +170,44 @@ ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) { _opcodes = opcodes; } + _fixedTextWindowExit = FIXED(Window_Exit); + _fixedTextWindowUp = FIXED(Window_Up); + _fixedTextWindowDown = FIXED(Window_Down); + + _hotkeyWindowExit = toupper(_fixedTextWindowExit[0]); + _hotkeyWindowUp = toupper(_fixedTextWindowUp[0]); + _hotkeyWindowDown = toupper(_fixedTextWindowDown[0]); +} + +void ScalpelTalk::talkTo(const Common::String filename) { + ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui; + + Talk::talkTo(filename); + + if (filename == "Tube59c") { + // WORKAROUND: Original game bug causes the results of testing the powdery substance + // to disappear too quickly. Introduce a delay to allow it to be properly displayed + ui._menuCounter = 30; + } } void ScalpelTalk::talkInterface(const byte *&str) { - FixedText &fixedText = *_vm->_fixedText; People &people = *_vm->_people; ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen; UserInterface &ui = *_vm->_ui; + if (_vm->getLanguage() == Common::DE_DEU) + skipBadText(str); + // If the window isn't yet open, draw the window before printing starts if (!ui._windowOpen && _noTextYet) { _noTextYet = false; drawInterface(); if (_talkTo != -1) { - Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit); - Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up); - Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down); - screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, fixedText_Exit); - screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, fixedText_Up); - screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down); + screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowExit); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowUp); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowDown); } } @@ -199,8 +218,7 @@ void ScalpelTalk::talkInterface(const byte *&str) { if (ui._windowOpen) { screen.print(Common::Point(16, _yp), TALK_FOREGROUND, "%s", people._characters[_speaker & 127]._name); - } - else { + } else { screen.gPrint(Common::Point(16, _yp - 1), TALK_FOREGROUND, "%s", people._characters[_speaker & 127]._name); _openTalkWindow = true; @@ -222,8 +240,7 @@ void ScalpelTalk::talkInterface(const byte *&str) { --idx; --_charCount; } - } - else { + } else { _endStr = true; } @@ -242,17 +259,14 @@ void ScalpelTalk::talkInterface(const byte *&str) { if (_speaker != -1) { if (ui._windowOpen) { screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str()); - } - else { + } else { screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str()); _openTalkWindow = true; } - } - else { + } else { if (ui._windowOpen) { screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str()); - } - else { + } else { screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str()); _openTalkWindow = true; } @@ -262,7 +276,7 @@ void ScalpelTalk::talkInterface(const byte *&str) { str += idx; // If line wrap occurred, then move to after the separating space between the words - if ((!isOpcode(str[0])) && str[0] != '{') + if (str[0] && (!isOpcode(str[0])) && str[0] != '{') ++str; _yp += 9; @@ -487,11 +501,10 @@ OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) { if (sound._voices) { for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) tempString += str[idx]; - sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY); + sound.playSpeech(tempString); // Set voices to wait for more sound._voices = 2; - sound._speechOn = (*sound._soundIsOn); } _wait = 1; @@ -502,7 +515,6 @@ OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) { OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) { Events &events = *_vm->_events; - FixedText &fixedText = *_vm->_fixedText; ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen; drawInterface(); @@ -511,17 +523,19 @@ OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) { _noTextYet = false; if (_speaker != -1) { - Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit); - Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up); - Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down); - screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, fixedText_Exit); - screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, fixedText_Up); - screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down); + screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowExit); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowUp); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowDown); } return RET_SUCCESS; } +void ScalpelTalk::loadTalkFile(const Common::String &filename) { + Talk::loadTalkFile(filename); + _3doSpeechIndex = 0; +} + void ScalpelTalk::talkWait(const byte *&str) { UserInterface &ui = *_vm->_ui; bool pauseFlag = _pauseFlag; @@ -537,12 +551,54 @@ void ScalpelTalk::talkWait(const byte *&str) { } } -void ScalpelTalk::talk3DOMovieTrigger(int subIndex) { +void ScalpelTalk::nothingToSay() { + error("Character had no talk options available"); +} + +void ScalpelTalk::switchSpeaker() { +} + +int ScalpelTalk::waitForMore(int delay) { + Events &events = *_vm->_events; + if (!IS_3DO) { - // No 3DO? No movie! - return; + return Talk::waitForMore(delay); + } + + // Hide the cursor + events.hideCursor(); + events.wait(1); + + switchSpeaker(); + + // Play the video + talk3DOMovieTrigger(_3doSpeechIndex++); + + // 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; } + events.showCursor(); + events._pressed = events._released = false; + + return 254; +} + +bool ScalpelTalk::talk3DOMovieTrigger(int subIndex) { + ScalpelEngine &vm = *(ScalpelEngine *)_vm; + Screen &screen = *_vm->_screen; + // Find out a few things that we need int userSelector = _vm->_ui->_selector; int scriptSelector = _scriptSelect; @@ -556,15 +612,14 @@ void ScalpelTalk::talk3DOMovieTrigger(int subIndex) { if (scriptSelector >= 0) { // Script-selected dialog selector = scriptSelector; - subIndex--; // for scripts we adjust subIndex, b/c we won't get called from doTalkControl() } else { - warning("talk3DOMovieTrigger: unable to find selector"); - return; + warning("talk3DOMovieTrigger: unable to find selector"); + return true; } } // Make a quick update, so that current text is shown on screen - _vm->_screen->update(); + screen.update(); // Figure out that movie filename Common::String movieFilename; @@ -586,16 +641,50 @@ void ScalpelTalk::talk3DOMovieTrigger(int subIndex) { warning("selector: %d", selector); warning("subindex: %d", subIndex); - Scalpel3DOMoviePlay(movieFilename.c_str(), Common::Point(5, 5)); + bool result = vm.play3doMovie(movieFilename, get3doPortraitPosition(), true); // Restore screen HACK _vm->_screen->makeAllDirty(); + + return result; +} + +Common::Point ScalpelTalk::get3doPortraitPosition() const { + // TODO: This current method is only an assumption of how the original figured + // out where to place each character's portrait movie. + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + const int PORTRAIT_W = 100; + const int PORTRAIT_H = 76; + + if (_speaker == -1) + return Common::Point(); + + // Get the position of the character + Common::Point pt; + if (_speaker == HOLMES) { + pt = Common::Point(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER, + people[HOLMES]._position.y / FIXED_INT_MULTIPLIER); + } else { + int objNum = people.findSpeaker(_speaker); + if (objNum == -1) + return Common::Point(); + + pt = scene._bgShapes[objNum]._position; + } + + // Adjust the top-left so the center of the portrait will be on the character, + // but ensure the portrait will be entirely on-screen + pt -= Common::Point(PORTRAIT_W / 2, PORTRAIT_H / 2); + pt.x = CLIP((int)pt.x, 10, SHERLOCK_SCREEN_WIDTH - 10 - PORTRAIT_W); + pt.y = CLIP((int)pt.y, 10, CONTROLS_Y - PORTRAIT_H - 10); + + return pt; } void ScalpelTalk::drawInterface() { - FixedText &fixedText = *_vm->_fixedText; ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen; - Surface &bb = *screen._backBuffer; + Surface &bb = *screen.getBackBuffer(); bb.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 10), BORDER_COLOR); bb.fillRect(Common::Rect(0, CONTROLS_Y + 10, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR); @@ -607,26 +696,25 @@ void ScalpelTalk::drawInterface() { SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND); if (_talkTo != -1) { - Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit); - Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up); - Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down); + Common::String fixedText_Exit = FIXED(Window_Exit); + Common::String fixedText_Up = FIXED(Window_Up); + Common::String fixedText_Down = FIXED(Window_Down); screen.makeButton(Common::Rect(99, CONTROLS_Y, 139, CONTROLS_Y + 10), - 119 - screen.stringWidth(fixedText_Exit) / 2, fixedText_Exit); + 119, fixedText_Exit); screen.makeButton(Common::Rect(140, CONTROLS_Y, 180, CONTROLS_Y + 10), - 159 - screen.stringWidth(fixedText_Up) / 2, fixedText_Up); + 159, fixedText_Up); screen.makeButton(Common::Rect(181, CONTROLS_Y, 221, CONTROLS_Y + 10), - 200 - screen.stringWidth(fixedText_Down) / 2, fixedText_Down); + 200, fixedText_Down); } else { - int strWidth = screen.stringWidth(Scalpel::PRESS_KEY_TO_CONTINUE); + Common::String fixedText_PressKeyToContinue = FIXED(PressKey_ToContinue); + screen.makeButton(Common::Rect(46, CONTROLS_Y, 273, CONTROLS_Y + 10), - 160 - strWidth / 2, Scalpel::PRESS_KEY_TO_CONTINUE); - screen.gPrint(Common::Point(160 - strWidth / 2, CONTROLS_Y), COMMAND_FOREGROUND, "P"); + 160, fixedText_PressKeyToContinue); } } bool ScalpelTalk::displayTalk(bool slamIt) { - FixedText &fixedText = *_vm->_fixedText; ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen; int yp = CONTROLS_Y + 14; int lineY = -1; @@ -644,22 +732,20 @@ bool ScalpelTalk::displayTalk(bool slamIt) { } // Display the up arrow and enable Up button if the first option is scrolled off-screen - Common::String fixedText_Up = fixedText.getText(kFixedText_Window_Up); - Common::String fixedText_Down = fixedText.getText(kFixedText_Window_Down); if (_moreTalkUp) { if (slamIt) { screen.print(Common::Point(5, CONTROLS_Y + 13), INV_FOREGROUND, "~"); - screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Up); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextWindowUp); } else { screen.gPrint(Common::Point(5, CONTROLS_Y + 12), INV_FOREGROUND, "~"); - screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, false, fixedText_Up); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, false, _fixedTextWindowUp); } } else { if (slamIt) { - screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, fixedText_Up); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, _fixedTextWindowUp); screen.vgaBar(Common::Rect(5, CONTROLS_Y + 11, 15, CONTROLS_Y + 22), INV_BACKGROUND); } else { - screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, fixedText_Up); + screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowUp); screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11, 15, CONTROLS_Y + 22), INV_BACKGROUND); } @@ -694,17 +780,17 @@ bool ScalpelTalk::displayTalk(bool slamIt) { if (slamIt) { screen.print(Common::Point(5, 190), INV_FOREGROUND, "|"); - screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Down); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, _fixedTextWindowDown); } else { screen.gPrint(Common::Point(5, 189), INV_FOREGROUND, "|"); - screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, false, fixedText_Down); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, false, _fixedTextWindowDown); } } else { if (slamIt) { - screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, fixedText_Down); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, _fixedTextWindowDown); screen.vgaBar(Common::Rect(5, 189, 16, 199), INV_BACKGROUND); } else { - screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down); + screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, _fixedTextWindowDown); screen._backBuffer1.fillRect(Common::Rect(5, 189, 16, 199), INV_BACKGROUND); } } @@ -801,15 +887,14 @@ int ScalpelTalk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool } void ScalpelTalk::showTalk() { - FixedText &fixedText = *_vm->_fixedText; + People &people = *_vm->_people; ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen; ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui; - Common::String fixedText_Exit = fixedText.getText(kFixedText_Window_Exit); byte color = ui._endKeyActive ? COMMAND_FOREGROUND : COMMAND_NULL; clearSequences(); pushSequence(_talkTo); - setStillSeq(_talkTo); + people.setListenSequence(_talkTo); ui._selector = ui._oldSelector = -1; @@ -824,9 +909,9 @@ void ScalpelTalk::showTalk() { // If the window is already 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, fixedText_Exit); + screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, true, _fixedTextWindowExit); } else { - screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, fixedText_Exit); + screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, _fixedTextWindowExit); if (!ui._slideWindows) { screen.slamRect(Common::Rect(0, CONTROLS_Y, @@ -839,6 +924,93 @@ void ScalpelTalk::showTalk() { } } +OpcodeReturn ScalpelTalk::cmdCallTalkFile(const byte *&str) { + Common::String tempString; + + ++str; + for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) + tempString += str[idx]; + str += 8; + + int scriptCurrentIndex = str - _scriptStart; + + // Save the current script position and new talk file + if (_scriptStack.size() < 9) { + ScriptStackEntry rec1; + rec1._name = _scriptName; + rec1._currentIndex = scriptCurrentIndex; + rec1._select = _scriptSelect; + _scriptStack.push(rec1); + + // Push the new talk file onto the stack + ScriptStackEntry rec2; + rec2._name = tempString; + rec2._currentIndex = 0; + rec2._select = 100; + _scriptStack.push(rec2); + } else { + error("Script stack overflow"); + } + + _scriptMoreFlag = 1; + _endStr = true; + _wait = 0; + + return RET_SUCCESS; +} + +void ScalpelTalk::pushSequenceEntry(Object *obj) { + Scene &scene = *_vm->_scene; + SequenceEntry seqEntry; + seqEntry._objNum = scene._bgShapes.indexOf(*obj); + + if (seqEntry._objNum != -1) { + for (uint idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) + seqEntry._sequences.push_back(obj->_sequences[idx]); + + seqEntry._frameNumber = obj->_frameNumber; + seqEntry._seqTo = obj->_seqTo; + } + + _sequenceStack.push(seqEntry); + if (_scriptStack.size() >= 5) + error("script stack overflow"); +} + +void ScalpelTalk::pullSequence(int slot) { + Scene &scene = *_vm->_scene; + + if (_sequenceStack.empty()) + return; + + SequenceEntry seq = _sequenceStack.pop(); + if (seq._objNum != -1) { + Object &obj = scene._bgShapes[seq._objNum]; + + if (obj._seqSize < MAX_TALK_SEQUENCES) { + warning("Tried to restore too few frames"); + } else { + for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) + obj._sequences[idx] = seq._sequences[idx]; + + obj._frameNumber = seq._frameNumber; + obj._seqTo = seq._seqTo; + } + } +} + +void ScalpelTalk::clearSequences() { + _sequenceStack.clear(); +} + +void ScalpelTalk::skipBadText(const byte *&msgP) { + // WORKAROUND: Skip over bad text in the original game + const char *BAD_PHRASE1 = "Change Speaker to Sherlock Holmes "; + + if (!strncmp((const char *)msgP, BAD_PHRASE1, strlen(BAD_PHRASE1))) + msgP += strlen(BAD_PHRASE1); +} + } // End of namespace Scalpel } // End of namespace Sherlock |