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 MADS_CONVERSATIONS_H 24 #define MADS_CONVERSATIONS_H 25 26 #include "common/scummsys.h" 27 #include "common/array.h" 28 #include "common/str-array.h" 29 #include "mads/screen.h" 30 #include "mads/dialogs.h" 31 32 namespace MADS { 33 34 #define MAX_CONVERSATIONS 5 35 #define MAX_SPEAKERS 5 36 37 enum ConversationMode { 38 CONVMODE_NONE = -1, 39 CONVMODE_0 = 0, 40 CONVMODE_1 = 1, 41 CONVMODE_2 = 2, 42 CONVMODE_3 = 3, 43 CONVMODE_4 = 4, 44 CONVMODE_5 = 5, 45 CONVMODE_6 = 6, 46 CONVMODE_7 = 7, 47 CONVMODE_8 = 8, 48 CONVMODE_9 = 9, 49 CONVMODE_STOP = 10 50 }; 51 52 enum DialogCommand { 53 CMD_END = 0, 54 CMD_1 = 1, 55 CMD_HIDE = 2, 56 CMD_UNHIDE = 3, 57 CMD_MESSAGE1 = 4, 58 CMD_MESSAGE2 = 5, 59 CMD_ERROR = 6, 60 CMD_NODE = 7, 61 CMD_GOTO = 8, 62 CMD_ASSIGN = 9, 63 CMD_DIALOG_END = 255 64 }; 65 66 enum ConvEntryFlag { 67 ENTRYFLAG_2 = 2, 68 ENTRYFLAG_4000 = 0x4000, 69 ENTRYFLAG_8000 = 0x8000 70 }; 71 72 enum ConditionalOperation { 73 CONDOP_NONE = 0xff, 74 CONDOP_VALUE = 0, 75 CONDOP_ADD = 1, 76 CONDOP_SUBTRACT = 2, 77 CONDOP_MULTIPLY = 3, 78 CONDOP_DIVIDE = 4, 79 CONDOP_MODULUS = 5, 80 CONDOP_LTEQ = 6, 81 CONDOP_GTEQ = 7, 82 CONDOP_LT = 8, 83 CONDOP_GT = 9, 84 CONDOP_NEQ = 10, 85 CONDOP_EQ = 11, 86 CONDOP_AND = 12, 87 CONDOP_OR = 13, 88 CONDOP_ABORT = 0xff 89 }; 90 91 92 struct ConversationVar { 93 bool _isPtr; 94 int _val; 95 int *_valPtr; 96 97 /** 98 * Constructor 99 */ ConversationVarConversationVar100 ConversationVar() : _isPtr(false), _val(0), _valPtr(nullptr) {} 101 102 /** 103 * Sets a numeric value 104 */ 105 void setValue(int val); 106 107 /** 108 * Sets a pointer value 109 */ 110 void setValue(int *val); 111 112 /** 113 * Return either the variable's pointer, or a pointer to it's direct value 114 */ getValueConversationVar115 int *getValue() { return _isPtr ? _valPtr : &_val; } 116 117 /** 118 * Returns true if variable is a pointer 119 */ isPtrConversationVar120 bool isPtr() const { return _isPtr; } 121 122 /** 123 * Returns true if variable is numeric 124 */ isNumericConversationVar125 bool isNumeric() const { return !_isPtr; } 126 }; 127 128 struct ScriptEntry { 129 struct Conditional { 130 struct CondtionalParamEntry { 131 bool _isVariable; 132 int _val; 133 134 /** 135 * Constructor 136 */ CondtionalParamEntryScriptEntry::Conditional::CondtionalParamEntry137 CondtionalParamEntry() : _isVariable(false), _val(0) {} 138 }; 139 140 static Common::Array<ConversationVar> *_vars; 141 ConditionalOperation _operation; 142 CondtionalParamEntry _param1; 143 CondtionalParamEntry _param2; 144 145 /** 146 * Constructor 147 */ ConditionalScriptEntry::Conditional148 Conditional() : _operation(CONDOP_NONE) {} 149 150 /** 151 * Loads data from a passed stream into the parameters structure 152 */ 153 void load(Common::SeekableReadStream &s); 154 155 /** 156 * Gets the value 157 */ 158 int get(int paramNum) const; 159 160 /** 161 * Evaluates the conditional 162 */ 163 int evaluate() const; 164 }; 165 166 struct MessageEntry { 167 int _size; 168 int _v2; 169 MessageEntryScriptEntry::MessageEntry170 MessageEntry() : _size(0), _v2(0) {} 171 }; 172 173 DialogCommand _command; 174 Conditional _conditionals[3]; 175 176 // Extra parameters for different opcodes 177 int _index; 178 Common::Array<int> _entries; 179 Common::Array<MessageEntry> _entries2; 180 181 /** 182 * Constructor 183 */ ScriptEntryScriptEntry184 ScriptEntry() : _command(CMD_END), _index(0) {} 185 186 /** 187 * Loads data from a passed stream into the parameters structure 188 */ 189 void load(Common::SeekableReadStream &s); 190 }; 191 192 /** 193 * Representation of scripts associated with a dialog 194 */ 195 class DialogScript : public Common::Array<ScriptEntry> { 196 public: 197 /** 198 * Loads a script from the passed stream 199 */ 200 void load(Common::SeekableReadStream &s, uint startingOffset); 201 }; 202 203 /** 204 * Reperesents the data for a dialog to be displayed in a conversation 205 */ 206 struct ConvDialog { 207 struct ScriptEntry { 208 DialogCommand _command; 209 }; 210 211 int16 _textLineIndex; // 0-based 212 int16 _speechIndex; // 1-based 213 uint16 _scriptOffset; // offset of script entry 214 uint16 _scriptSize; // size of script entry 215 216 DialogScript _script; 217 }; 218 219 /** 220 * Represents a node within the conversation control logic 221 */ 222 struct ConvNode { 223 uint16 _index; 224 uint16 _dialogCount; 225 int16 _unk1; 226 bool _active; 227 int16 _unk3; 228 229 Common::Array<ConvDialog> _dialogs; 230 }; 231 232 /** 233 * Represents a message entry 234 */ 235 struct ConvMessage { 236 uint _stringIndex; 237 uint _count; 238 ConvMessageConvMessage239 ConvMessage() : _stringIndex(0), _count(0) {} 240 }; 241 242 /** 243 * Represents the static, non-changing data for a conversation 244 */ 245 struct ConversationData { 246 uint16 _nodeCount; // conversation nodes, each one containing several dialog options and messages 247 uint16 _dialogCount; // messages (non-selectable) + texts (selectable) 248 uint16 _messageCount; // messages (non-selectable) 249 uint16 _textLineCount; 250 uint16 _unk2; 251 uint16 _maxImports; 252 uint16 _speakerCount; 253 int _textSize; 254 int _commandsSize; 255 256 Common::String _portraits[MAX_SPEAKERS]; 257 int _speakerFrame[MAX_SPEAKERS]; 258 Common::String _speechFile; 259 Common::Array<ConvMessage> _messages; 260 Common::StringArray _textLines; 261 Common::Array<ConvNode> _nodes; 262 Common::Array<ConvDialog> _dialogs; 263 264 /** 265 * Load the specified conversation resource file 266 */ 267 void load(const Common::String &filename); 268 }; 269 270 /** 271 * Conditional (i.e. changeable) data for the conversation 272 */ 273 struct ConversationConditionals { 274 Common::Array<uint> _importVariables; 275 Common::Array<uint> _entryFlags; 276 Common::Array<ConversationVar> _vars; 277 int _numImports; 278 279 int _currentNode; 280 Common::Array<int> _messageList1; 281 Common::Array<int> _messageList2; 282 Common::Array<int> _messageList3; 283 Common::Array<int> _messageList4; 284 285 /** 286 * Constructor 287 */ 288 ConversationConditionals(); 289 290 /** 291 * Load the specified conversation conditionals resource file 292 */ 293 void load(const Common::String &filename); 294 }; 295 296 /** 297 * Represents all the data needed for a particular loaded conversation 298 */ 299 struct ConversationEntry { 300 int _convId; 301 ConversationData _data; 302 ConversationConditionals _cnd; 303 }; 304 305 class MADSEngine; 306 307 /** 308 * Manager for loading and running conversations 309 */ 310 class GameConversations { 311 private: 312 MADSEngine *_vm; 313 ConversationEntry _conversations[MAX_CONVERSATIONS]; 314 bool _speakerActive[MAX_SPEAKERS]; 315 int _speakerSeries[MAX_SPEAKERS]; 316 int _speakerFrame[MAX_SPEAKERS]; 317 int _popupX[MAX_SPEAKERS]; 318 int _popupY[MAX_SPEAKERS]; 319 int _popupMaxLen[MAX_SPEAKERS]; 320 InputMode _inputMode; 321 bool _popupVisible; 322 ConversationMode _currentMode; 323 ConversationMode _priorMode; 324 int _verbId; 325 int _speakerVal; 326 int _heroTrigger; 327 TriggerMode _heroTriggerMode; 328 int _interlocutorTrigger; 329 TriggerMode _interlocutorTriggerMode; 330 ConversationEntry *_runningConv; 331 int _restoreRunning; 332 bool _playerEnabled; 333 uint32 _startFrameNumber; 334 ConversationVar *_vars; 335 ConversationVar *_nextStartNode; 336 int _currentNode; 337 int _dialogNodeOffset, _dialogNodeSize; 338 int _personSpeaking; 339 TextDialog *_dialog; 340 bool _dialogAltFlag; 341 342 /** 343 * Returns the record for the specified conversation, if it's loaded 344 */ 345 ConversationEntry *getConv(int convId); 346 347 /** 348 * Start a specified conversation slot 349 */ 350 void start(); 351 352 /** 353 * Remove any currently active dialog window 354 */ 355 void removeActiveWindow(); 356 357 /** 358 * Flags a conversation option/entry 359 */ 360 void flagEntry(DialogCommand mode, int entryIndex); 361 362 /** 363 * Generate a menu 364 */ 365 ConversationMode generateMenu(); 366 367 /** 368 * Generate text 369 */ 370 void generateText(int textLineIndex, Common::Array<int> &messages); 371 372 /** 373 * Generate message 374 */ 375 void generateMessage(Common::Array<int> &messageList, Common::Array<int> &voiecList); 376 377 /** 378 * Gets the next node 379 */ 380 bool nextNode(); 381 382 /** 383 * Executes a conversation entry 384 */ 385 int executeEntry(int index); 386 387 /** 388 * Handle messages 389 */ 390 void scriptMessage(ScriptEntry &scrEntry); 391 392 /** 393 * Handle node changes 394 */ 395 bool scriptNode(ScriptEntry &scrEntry); 396 public: 397 /** 398 * Constructor 399 */ 400 GameConversations(MADSEngine *vm); 401 402 /** 403 * Destructor 404 */ 405 virtual ~GameConversations(); 406 407 /** 408 * Gets the specified conversation and loads into into a free slot 409 * in the conversation list 410 */ 411 void load(int id); 412 413 /** 414 * Run a specified conversation number. The conversation must have 415 * previously been loaded by calling the load method 416 */ 417 void run(int id); 418 419 /** 420 * Sets a variable to a numeric value 421 */ 422 void setVariable(uint idx, int val); 423 424 /** 425 * Sets a variable to a pointer value 426 */ 427 void setVariable(uint idx, int *val); 428 429 /** 430 * Sets the starting node index 431 */ 432 void setStartNode(uint nodeIndex); 433 434 /** 435 * Set the hero trigger 436 */ 437 void setHeroTrigger(int val); 438 439 /** 440 * Set the interlocutor trigger 441 */ 442 void setInterlocutorTrigger(int val); 443 444 /** 445 * Returns either the pointer value of a variable, or if the variable 446 * contains a numeric value directly, returns a pointer to it 447 */ 448 int *getVariable(int idx); 449 450 /** 451 * Hold the current mode value 452 */ 453 void hold(); 454 455 /** 456 * Release the prevoiusly held mode value 457 */ 458 void release(); 459 460 /** 461 * Stop any currently running conversation 462 */ 463 void stop(); 464 465 /** 466 * Adds the passed pointer into the list of import variables for the given conversation 467 */ 468 void exportPointer(int *ptr); 469 470 /** 471 * Adds the passed value into the list of import variables for the given conversation 472 */ 473 void exportValue(int val); 474 475 void reset(int id); 476 477 /** 478 * Handles updating the conversation display 479 */ 480 void update(bool flag); 481 482 /** 483 * Returns true if any conversation is currently atcive 484 */ active()485 bool active() const { return _runningConv != nullptr; } 486 487 /** 488 * Returns the currently active conversation Id 489 */ activeConvId()490 int activeConvId() const { return !active() ? -1 : _runningConv->_convId; } 491 492 /** 493 * Returns _restoreRunning value 494 */ restoreRunning()495 int restoreRunning() const { return _restoreRunning; } 496 497 /** 498 * Returns the current conversation mode 499 */ currentMode()500 ConversationMode currentMode() const { return _currentMode; } 501 }; 502 503 } // End of namespace MADS 504 505 #endif /* MADS_CONVERSATIONS_H */ 506