1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef SHERLOCK_TALK_H 24 #define SHERLOCK_TALK_H 25 26 #include "common/scummsys.h" 27 #include "common/array.h" 28 #include "common/rect.h" 29 #include "common/stream.h" 30 #include "common/stack.h" 31 #include "sherlock/objects.h" 32 #include "sherlock/saveload.h" 33 34 namespace Sherlock { 35 36 #define SPEAKER_REMOVE 0x80 37 #define MAX_TALK_SEQUENCES 11 38 39 enum { 40 OP_SWITCH_SPEAKER = 0, 41 OP_RUN_CANIMATION = 1, 42 OP_ASSIGN_PORTRAIT_LOCATION = 2, 43 OP_PAUSE = 3, 44 OP_REMOVE_PORTRAIT = 4, 45 OP_CLEAR_WINDOW = 5, 46 OP_ADJUST_OBJ_SEQUENCE = 6, 47 OP_WALK_TO_COORDS = 7, 48 OP_PAUSE_WITHOUT_CONTROL = 8, 49 OP_BANISH_WINDOW = 9, 50 OP_SUMMON_WINDOW = 10, 51 OP_SET_FLAG = 11, 52 OP_SFX_COMMAND = 12, 53 OP_TOGGLE_OBJECT = 13, 54 OP_STEALTH_MODE_ACTIVE = 14, 55 OP_IF_STATEMENT = 15, 56 OP_ELSE_STATEMENT = 16, 57 OP_END_IF_STATEMENT = 17, 58 OP_STEALTH_MODE_DEACTIVATE = 18, 59 OP_TURN_HOLMES_OFF = 19, 60 OP_TURN_HOLMES_ON = 20, 61 OP_GOTO_SCENE = 21, 62 OP_PLAY_PROLOGUE = 22, 63 OP_ADD_ITEM_TO_INVENTORY = 23, 64 OP_SET_OBJECT = 24, 65 OP_CALL_TALK_FILE = 25, 66 OP_MOVE_MOUSE = 26, 67 OP_DISPLAY_INFO_LINE = 27, 68 OP_CLEAR_INFO_LINE = 28, 69 OP_WALK_TO_CANIMATION = 29, 70 OP_REMOVE_ITEM_FROM_INVENTORY = 30, 71 OP_ENABLE_END_KEY = 31, 72 OP_DISABLE_END_KEY = 32, 73 OP_END_TEXT_WINDOW = 33, 74 75 OP_MOUSE_OFF_ON = 34, 76 OP_SET_WALK_CONTROL = 35, 77 OP_SET_TALK_SEQUENCE = 36, 78 OP_PLAY_SONG = 37, 79 OP_WALK_HOLMES_AND_NPC_TO_CANIM = 38, 80 OP_SET_NPC_PATH_DEST = 39, 81 OP_NEXT_SONG = 40, 82 OP_SET_NPC_PATH_PAUSE = 41, 83 OP_NEED_PASSWORD = 42, 84 OP_SET_SCENE_ENTRY_FLAG = 43, 85 OP_WALK_NPC_TO_CANIM = 44, 86 OP_WALK_NPC_TO_COORDS = 45, 87 OP_WALK_HOLMES_AND_NPC_TO_COORDS = 46, 88 OP_SET_NPC_TALK_FILE = 47, 89 OP_TURN_NPC_OFF = 48, 90 OP_TURN_NPC_ON = 49, 91 OP_NPC_DESC_ON_OFF = 50, 92 OP_NPC_PATH_PAUSE_TAKING_NOTES = 51, 93 OP_NPC_PATH_PAUSE_LOOKING_HOLMES = 52, 94 OP_ENABLE_TALK_INTERRUPTS = 53, 95 OP_DISABLE_TALK_INTERRUPTS = 54, 96 OP_SET_NPC_INFO_LINE = 55, 97 OP_SET_NPC_POSITION = 56, 98 OP_NPC_PATH_LABEL = 57, 99 OP_PATH_GOTO_LABEL = 58, 100 OP_PATH_IF_FLAG_GOTO_LABEL = 59, 101 OP_NPC_WALK_GRAPHICS = 60, 102 OP_NPC_VERB = 61, 103 OP_NPC_VERB_CANIM = 62, 104 OP_NPC_VERB_SCRIPT = 63, 105 OP_RESTORE_PEOPLE_SEQUENCE = 64, 106 OP_NPC_VERB_TARGET = 65, 107 OP_TURN_SOUNDS_OFF = 66, 108 OP_NULL = 67 109 }; 110 111 enum OpcodeReturn { RET_EXIT = -1, RET_SUCCESS = 0, RET_CONTINUE = 1 }; 112 113 class SherlockEngine; 114 class Talk; 115 namespace Scalpel { class ScalpelUserInterface; } 116 117 typedef OpcodeReturn(Talk::*OpcodeMethod)(const byte *&str); 118 119 struct SequenceEntry { 120 int _objNum; 121 Common::Array<byte> _sequences; 122 Object *_obj; // Pointer to the bgshape that these values go to 123 short _frameNumber; // Frame number in frame sequence to draw 124 short _sequenceNumber; // Start frame of sequences that are repeated 125 int _seqStack; // Allows gosubs to return to calling frame 126 int _seqTo; // Allows 1-5, 8-3 type sequences encoded 127 int _seqCounter; // How many times this sequence has been executed 128 int _seqCounter2; 129 130 SequenceEntry(); 131 }; 132 133 struct ScriptStackEntry { 134 Common::String _name; 135 int _currentIndex; 136 int _select; 137 }; 138 139 struct Statement { 140 Common::String _statement; 141 Common::String _reply; 142 Common::String _linkFile; 143 Common::String _voiceFile; 144 Common::Array<int> _required; 145 Common::Array<int> _modified; 146 int _portraitSide; 147 int _quotient; 148 int _talkMap; 149 Common::Rect _talkPos; 150 int _journal; 151 152 /** 153 * Load the data for a single statement within a talk file 154 */ 155 void load(Common::SeekableReadStream &s, bool isRoseTattoo); 156 }; 157 158 struct TalkHistoryEntry { 159 bool _data[16]; 160 161 TalkHistoryEntry(); 162 bool &operator[](int index) { return _data[index]; } 163 }; 164 165 class Talk { 166 friend class Scalpel::ScalpelUserInterface; 167 private: 168 /** 169 * Remove any voice commands from a loaded statement list 170 */ 171 void stripVoiceCommands(); 172 protected: 173 SherlockEngine *_vm; 174 OpcodeMethod *_opcodeTable; 175 Common::Stack<SequenceEntry> _savedSequences; 176 Common::Stack<ScriptStackEntry> _scriptStack; 177 Common::Array<TalkHistoryEntry> _talkHistory; 178 int _talkIndex; 179 int _scriptSelect; 180 int _talkStealth; 181 int _talkToFlag; 182 int _scriptSaveIndex; 183 int _3doSpeechIndex; 184 185 // These fields are used solely by doScript, but are fields because all the script opcodes are 186 // separate methods now, and need access to these fields 187 int _yp; 188 int _charCount; 189 int _line; 190 int _wait; 191 bool _pauseFlag; 192 bool _endStr, _noTextYet; 193 int _seqCount; 194 const byte *_scriptStart, *_scriptEnd; 195 protected: 196 Talk(SherlockEngine *vm); 197 198 OpcodeReturn cmdAddItemToInventory(const byte *&str); 199 OpcodeReturn cmdAdjustObjectSequence(const byte *&str); 200 OpcodeReturn cmdBanishWindow(const byte *&str); 201 OpcodeReturn cmdDisableEndKey(const byte *&str); 202 OpcodeReturn cmdEnableEndKey(const byte *&str); 203 OpcodeReturn cmdEndTextWindow(const byte *&str); 204 OpcodeReturn cmdHolmesOff(const byte *&str); 205 OpcodeReturn cmdHolmesOn(const byte *&str); 206 OpcodeReturn cmdPause(const byte *&str); 207 OpcodeReturn cmdPauseWithoutControl(const byte *&str); 208 OpcodeReturn cmdRemoveItemFromInventory(const byte *&str); 209 OpcodeReturn cmdRunCAnimation(const byte *&str); 210 OpcodeReturn cmdSetFlag(const byte *&str); 211 OpcodeReturn cmdSetObject(const byte *&str); 212 OpcodeReturn cmdStealthModeActivate(const byte *&str); 213 OpcodeReturn cmdStealthModeDeactivate(const byte *&str); 214 OpcodeReturn cmdToggleObject(const byte *&str); 215 OpcodeReturn cmdWalkToCAnimation(const byte *&str); 216 protected: 217 /** 218 * Checks if a character is an opcode 219 */ 220 bool isOpcode(byte checkCharacter); 221 222 /** 223 * Form a table of the display indexes for statements 224 */ 225 void setTalkMap(); 226 227 /** 228 * When the talk window has been displayed, waits a period of time proportional to 229 * the amount of text that's been displayed 230 */ 231 virtual int waitForMore(int delay); 232 233 /** 234 * Display the talk interface window 235 */ 236 virtual void talkInterface(const byte *&str) = 0; 237 238 /** 239 * Pause when displaying a talk dialog on-screen 240 */ 241 virtual void talkWait(const byte *&str); 242 243 /** 244 * Show the talk display 245 */ 246 virtual void showTalk() = 0; 247 248 /** 249 * Called when a character being spoken to has no talk options to display 250 */ 251 virtual void nothingToSay() = 0; 252 253 /** 254 * Called when the active speaker is switched 255 */ switchSpeaker()256 virtual void switchSpeaker() {} 257 public: 258 Common::Array<Statement> _statements; 259 bool _talkToAbort; 260 int _talkCounter; 261 int _talkTo; 262 int _scriptMoreFlag; 263 bool _openTalkWindow; 264 Common::String _scriptName; 265 bool _moreTalkUp, _moreTalkDown; 266 int _converseNum; 267 const byte *_opcodes; 268 int _speaker; 269 public: 270 static Talk *init(SherlockEngine *vm); ~Talk()271 virtual ~Talk() {} 272 273 /** 274 * Return a given talk statement 275 */ 276 Statement &operator[](int idx) { return _statements[idx]; } 277 278 /** 279 * Called whenever a conversation or item script needs to be run. For standard conversations, 280 * it opens up a description window similar to how 'talk' does, but shows a 'reply' directly 281 * instead of waiting for a statement option. 282 * @remarks It seems that at some point, all item scripts were set up to use this as well. 283 * In their case, the conversation display is simply suppressed, and control is passed on to 284 * doScript to implement whatever action is required. 285 */ 286 virtual void talkTo(const Common::String filename); 287 288 /** 289 * Parses a reply for control codes and display text. The found text is printed within 290 * the text window, handles delays, animations, and animating portraits. 291 */ 292 void doScript(const Common::String &script); 293 294 /** 295 * Main method for handling conversations when a character to talk to has been 296 * selected. It will make Holmes walk to the person to talk to, draws the 297 * interface window for the conversation and passes on control to give the 298 * player a list of options to make a selection from 299 */ 300 void initTalk(int objNum); 301 302 /** 303 * Clear loaded talk data 304 */ 305 void freeTalkVars(); 306 307 /** 308 * Opens the talk file 'talk.tlk' and searches the index for the specified 309 * conversation. If found, the data for that conversation is loaded 310 */ 311 virtual void loadTalkFile(const Common::String &filename); 312 313 /** 314 * Push the sequence of a background object that's an NPC that needs to be 315 * saved onto the sequence stack. 316 */ 317 void pushSequence(int speaker); 318 319 /** 320 * Push the details of a passed object onto the saved sequences stack 321 */ 322 virtual void pushSequenceEntry(Object *obj) = 0; 323 324 /** 325 * Clears the stack of pending object sequences associated with speakers in the scene 326 */ 327 virtual void clearSequences() = 0; 328 329 /** 330 * Pops an entry off of the script stack 331 */ 332 void popStack(); 333 334 /** 335 * Synchronize the data for a savegame 336 */ 337 void synchronize(Serializer &s); 338 339 /** 340 * Draws the interface for conversation display 341 */ drawInterface()342 virtual void drawInterface() {} 343 344 /** 345 * Display a list of statements in a window at the bottom of the screen that the 346 * player can select from. 347 */ displayTalk(bool slamIt)348 virtual bool displayTalk(bool slamIt) { return false; } 349 350 /** 351 * Prints a single conversation option in the interface window 352 */ talkLine(int lineNum,int stateNum,byte color,int lineY,bool slamIt)353 virtual int talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt) { return 0; } 354 355 /** 356 * Pulls a background object sequence from the sequence stack and restore's the 357 * object's sequence 358 */ 359 virtual void pullSequence(int slot = -1) = 0; 360 361 /** 362 * Returns true if the script stack is empty 363 */ 364 virtual bool isSequencesEmpty() const = 0; 365 }; 366 367 } // End of namespace Sherlock 368 369 #endif 370