mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
505 lines
10 KiB
C++
505 lines
10 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#ifndef MADS_CONVERSATIONS_H
|
|
#define MADS_CONVERSATIONS_H
|
|
|
|
#include "common/scummsys.h"
|
|
#include "common/array.h"
|
|
#include "common/str-array.h"
|
|
#include "mads/screen.h"
|
|
#include "mads/dialogs.h"
|
|
|
|
namespace MADS {
|
|
|
|
#define MAX_CONVERSATIONS 5
|
|
#define MAX_SPEAKERS 5
|
|
|
|
enum ConversationMode {
|
|
CONVMODE_NONE = -1,
|
|
CONVMODE_NEXT = 0,
|
|
CONVMODE_WAIT_AUTO = 1,
|
|
CONVMODE_WAIT_ENTRY = 2,
|
|
CONVMODE_EXECUTE = 3,
|
|
CONVMODE_REPLY = 4,
|
|
CONVMODE_5 = 5,
|
|
CONVMODE_6 = 6,
|
|
CONVMODE_7 = 7,
|
|
CONVMODE_8 = 8,
|
|
CONVMODE_9 = 9,
|
|
CONVMODE_STOP = 10
|
|
};
|
|
|
|
enum DialogCommand {
|
|
CMD_END = 0,
|
|
CMD_1 = 1,
|
|
CMD_HIDE = 2,
|
|
CMD_UNHIDE = 3,
|
|
CMD_MESSAGE1 = 4,
|
|
CMD_MESSAGE2 = 5,
|
|
CMD_ERROR = 6,
|
|
CMD_NODE = 7,
|
|
CMD_GOTO = 8,
|
|
CMD_ASSIGN = 9,
|
|
CMD_DIALOG_END = 255
|
|
};
|
|
|
|
enum ConvEntryFlag {
|
|
ENTRYFLAG_2 = 2,
|
|
ENTRYFLAG_4000 = 0x4000,
|
|
ENTRYFLAG_8000 = 0x8000
|
|
};
|
|
|
|
enum ConditionalOperation {
|
|
CONDOP_NONE = 0xff,
|
|
CONDOP_VALUE = 0,
|
|
CONDOP_ADD = 1,
|
|
CONDOP_SUBTRACT = 2,
|
|
CONDOP_MULTIPLY = 3,
|
|
CONDOP_DIVIDE = 4,
|
|
CONDOP_MODULUS = 5,
|
|
CONDOP_LTEQ = 6,
|
|
CONDOP_GTEQ = 7,
|
|
CONDOP_LT = 8,
|
|
CONDOP_GT = 9,
|
|
CONDOP_NEQ = 10,
|
|
CONDOP_EQ = 11,
|
|
CONDOP_AND = 12,
|
|
CONDOP_OR = 13,
|
|
CONDOP_ABORT = 0xff
|
|
};
|
|
|
|
|
|
struct ConversationVar {
|
|
bool _isPtr;
|
|
int _val;
|
|
int *_valPtr;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
ConversationVar() : _isPtr(false), _val(0), _valPtr(nullptr) {}
|
|
|
|
/**
|
|
* Sets a numeric value
|
|
*/
|
|
void setValue(int val);
|
|
|
|
/**
|
|
* Sets a pointer value
|
|
*/
|
|
void setValue(int *val);
|
|
|
|
/**
|
|
* Return either the variable's pointer, or a pointer to it's direct value
|
|
*/
|
|
int *getValue() { return _isPtr ? _valPtr : &_val; }
|
|
|
|
/**
|
|
* Returns true if variable is a pointer
|
|
*/
|
|
bool isPtr() const { return _isPtr; }
|
|
|
|
/**
|
|
* Returns true if variable is numeric
|
|
*/
|
|
bool isNumeric() const { return !_isPtr; }
|
|
};
|
|
|
|
struct ScriptEntry {
|
|
struct Conditional {
|
|
struct CondtionalParamEntry {
|
|
bool _isVariable;
|
|
int _val;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
CondtionalParamEntry() : _isVariable(false), _val(0) {}
|
|
};
|
|
|
|
static Common::Array<ConversationVar> *_vars;
|
|
ConditionalOperation _operation;
|
|
CondtionalParamEntry _param1;
|
|
CondtionalParamEntry _param2;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Conditional() : _operation(CONDOP_NONE) {}
|
|
|
|
/**
|
|
* Loads data from a passed stream into the parameters structure
|
|
*/
|
|
void load(Common::SeekableReadStream &s);
|
|
|
|
/**
|
|
* Gets the value
|
|
*/
|
|
int get(int paramNum) const;
|
|
|
|
/**
|
|
* Evaluates the conditional
|
|
*/
|
|
int evaluate() const;
|
|
};
|
|
|
|
struct MessageEntry {
|
|
int _size;
|
|
int _v2;
|
|
|
|
MessageEntry() : _size(0), _v2(0) {}
|
|
};
|
|
|
|
DialogCommand _command;
|
|
Conditional _conditionals[3];
|
|
|
|
// Extra parameters for different opcodes
|
|
int _index;
|
|
Common::Array<int> _entries;
|
|
Common::Array<MessageEntry> _entries2;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
ScriptEntry() : _command(CMD_END), _index(0) {}
|
|
|
|
/**
|
|
* Loads data from a passed stream into the parameters structure
|
|
*/
|
|
void load(Common::SeekableReadStream &s);
|
|
};
|
|
|
|
/**
|
|
* Representation of scripts associated with a dialog
|
|
*/
|
|
class DialogScript : public Common::Array<ScriptEntry> {
|
|
public:
|
|
/**
|
|
* Loads a script from the passed stream
|
|
*/
|
|
void load(Common::SeekableReadStream &s, uint startingOffset);
|
|
};
|
|
|
|
/**
|
|
* Reperesents the data for a dialog to be displayed in a conversation
|
|
*/
|
|
struct ConvDialog {
|
|
struct ScriptEntry {
|
|
DialogCommand _command;
|
|
};
|
|
|
|
int16 _textLineIndex; // 0-based
|
|
int16 _speechIndex; // 1-based
|
|
uint16 _scriptOffset; // offset of script entry
|
|
uint16 _scriptSize; // size of script entry
|
|
|
|
DialogScript _script;
|
|
};
|
|
|
|
/**
|
|
* Represents a node within the conversation control logic
|
|
*/
|
|
struct ConvNode {
|
|
uint16 _index;
|
|
uint16 _dialogCount;
|
|
int16 _unk1;
|
|
bool _active;
|
|
int16 _unk3;
|
|
|
|
Common::Array<ConvDialog> _dialogs;
|
|
};
|
|
|
|
/**
|
|
* Represents a message entry
|
|
*/
|
|
struct ConvMessage {
|
|
uint _stringIndex;
|
|
uint _count;
|
|
|
|
ConvMessage() : _stringIndex(0), _count(0) {}
|
|
};
|
|
|
|
/**
|
|
* Represents the static, non-changing data for a conversation
|
|
*/
|
|
struct ConversationData {
|
|
uint16 _nodeCount; // conversation nodes, each one containing several dialog options and messages
|
|
uint16 _dialogCount; // messages (non-selectable) + texts (selectable)
|
|
uint16 _messageCount; // messages (non-selectable)
|
|
uint16 _textLineCount;
|
|
uint16 _unk2;
|
|
uint16 _maxImports;
|
|
uint16 _speakerCount;
|
|
int _textSize;
|
|
int _commandsSize;
|
|
|
|
Common::Path _portraits[MAX_SPEAKERS];
|
|
int _speakerFrame[MAX_SPEAKERS];
|
|
Common::Path _speechFile;
|
|
Common::Array<ConvMessage> _messages;
|
|
Common::StringArray _textLines;
|
|
Common::Array<ConvNode> _nodes;
|
|
Common::Array<ConvDialog> _dialogs;
|
|
|
|
/**
|
|
* Load the specified conversation resource file
|
|
*/
|
|
void load(const Common::Path &filename);
|
|
};
|
|
|
|
/**
|
|
* Conditional (i.e. changeable) data for the conversation
|
|
*/
|
|
struct ConversationConditionals {
|
|
Common::Array<uint> _importVariables;
|
|
Common::Array<uint> _entryFlags;
|
|
Common::Array<ConversationVar> _vars;
|
|
int _numImports;
|
|
|
|
int _currentNode;
|
|
Common::Array<int> _playerMessageList;
|
|
Common::Array<int> _actorMessageList;
|
|
Common::Array<int> _playerSpeechList;
|
|
Common::Array<int> _actorSpeechList;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
ConversationConditionals();
|
|
|
|
/**
|
|
* Load the specified conversation conditionals resource file
|
|
*/
|
|
void load(const Common::Path &filename);
|
|
};
|
|
|
|
/**
|
|
* Represents all the data needed for a particular loaded conversation
|
|
*/
|
|
struct ConversationEntry {
|
|
int _convId;
|
|
ConversationData _data;
|
|
ConversationConditionals _cnd;
|
|
};
|
|
|
|
class MADSEngine;
|
|
|
|
/**
|
|
* Manager for loading and running conversations
|
|
*/
|
|
class GameConversations {
|
|
private:
|
|
MADSEngine *_vm;
|
|
ConversationEntry _conversations[MAX_CONVERSATIONS];
|
|
bool _speakerActive[MAX_SPEAKERS];
|
|
int _speakerSeries[MAX_SPEAKERS];
|
|
int _speakerFrame[MAX_SPEAKERS];
|
|
int _popupX[MAX_SPEAKERS];
|
|
int _popupY[MAX_SPEAKERS];
|
|
int _popupMaxLen[MAX_SPEAKERS];
|
|
InputMode _inputMode;
|
|
bool _popupVisible;
|
|
ConversationMode _currentMode;
|
|
ConversationMode _priorMode;
|
|
int _verbId;
|
|
int _speakerVal;
|
|
int _heroTrigger;
|
|
TriggerMode _heroTriggerMode;
|
|
int _interlocutorTrigger;
|
|
TriggerMode _interlocutorTriggerMode;
|
|
ConversationEntry *_runningConv;
|
|
int _restoreRunning;
|
|
bool _playerEnabled;
|
|
uint32 _startFrameNumber;
|
|
ConversationVar *_vars;
|
|
ConversationVar *_nextStartNode;
|
|
int _currentNode;
|
|
int _dialogNodeOffset, _dialogNodeSize;
|
|
int _personSpeaking;
|
|
TextDialog *_dialog;
|
|
bool _dialogAltFlag;
|
|
|
|
/**
|
|
* Returns the record for the specified conversation, if it's loaded
|
|
*/
|
|
ConversationEntry *getConv(int convId);
|
|
|
|
/**
|
|
* Start a specified conversation slot
|
|
*/
|
|
void start();
|
|
|
|
/**
|
|
* Remove any currently active dialog window
|
|
*/
|
|
void removeActiveWindow();
|
|
|
|
/**
|
|
* Flags a conversation option/entry
|
|
*/
|
|
void flagEntry(DialogCommand mode, int entryIndex);
|
|
|
|
/**
|
|
* Generate a menu
|
|
*/
|
|
ConversationMode generateMenu();
|
|
|
|
/**
|
|
* Generate text
|
|
*/
|
|
void generateText(int textLineIndex, Common::Array<int> &messages);
|
|
|
|
/**
|
|
* Generate message
|
|
*/
|
|
void generateMessage(Common::Array<int> &messageList, Common::Array<int> &voiecList);
|
|
|
|
/**
|
|
* Gets the next node
|
|
*/
|
|
bool nextNode();
|
|
|
|
/**
|
|
* Executes a conversation entry
|
|
*/
|
|
int executeEntry(int index);
|
|
|
|
/**
|
|
* Handle messages
|
|
*/
|
|
void scriptMessage(ScriptEntry &scrEntry);
|
|
|
|
/**
|
|
* Handle node changes
|
|
*/
|
|
bool scriptNode(ScriptEntry &scrEntry);
|
|
public:
|
|
/**
|
|
* Constructor
|
|
*/
|
|
GameConversations(MADSEngine *vm);
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
virtual ~GameConversations();
|
|
|
|
/**
|
|
* Gets the specified conversation and loads into into a free slot
|
|
* in the conversation list
|
|
*/
|
|
void load(int id);
|
|
|
|
/**
|
|
* Run a specified conversation number. The conversation must have
|
|
* previously been loaded by calling the load method
|
|
*/
|
|
void run(int id);
|
|
|
|
/**
|
|
* Sets a variable to a numeric value
|
|
*/
|
|
void setVariable(uint idx, int val);
|
|
|
|
/**
|
|
* Sets a variable to a pointer value
|
|
*/
|
|
void setVariable(uint idx, int *val);
|
|
|
|
/**
|
|
* Sets the starting node index
|
|
*/
|
|
void setStartNode(uint nodeIndex);
|
|
|
|
/**
|
|
* Set the hero trigger
|
|
*/
|
|
void setHeroTrigger(int val);
|
|
|
|
/**
|
|
* Set the interlocutor trigger
|
|
*/
|
|
void setInterlocutorTrigger(int val);
|
|
|
|
/**
|
|
* Returns either the pointer value of a variable, or if the variable
|
|
* contains a numeric value directly, returns a pointer to it
|
|
*/
|
|
int *getVariable(int idx);
|
|
|
|
/**
|
|
* Hold the current mode value
|
|
*/
|
|
void hold();
|
|
|
|
/**
|
|
* Release the prevoiusly held mode value
|
|
*/
|
|
void release();
|
|
|
|
/**
|
|
* Stop any currently running conversation
|
|
*/
|
|
void stop();
|
|
|
|
/**
|
|
* Adds the passed pointer into the list of import variables for the given conversation
|
|
*/
|
|
void exportPointer(int *ptr);
|
|
|
|
/**
|
|
* Adds the passed value into the list of import variables for the given conversation
|
|
*/
|
|
void exportValue(int val);
|
|
|
|
void reset(int id);
|
|
|
|
/**
|
|
* Handles updating the conversation display
|
|
*/
|
|
void update(bool flag);
|
|
|
|
/**
|
|
* Returns true if any conversation is currently atcive
|
|
*/
|
|
bool active() const { return _runningConv != nullptr; }
|
|
|
|
/**
|
|
* Returns the currently active conversation Id
|
|
*/
|
|
int activeConvId() const { return !active() ? -1 : _runningConv->_convId; }
|
|
|
|
/**
|
|
* Returns _restoreRunning value
|
|
*/
|
|
int restoreRunning() const { return _restoreRunning; }
|
|
|
|
/**
|
|
* Returns the current conversation mode
|
|
*/
|
|
ConversationMode currentMode() const { return _currentMode; }
|
|
};
|
|
|
|
} // End of namespace MADS
|
|
|
|
#endif /* MADS_CONVERSATIONS_H */
|