From a0eacd0537a1fc10d2a29a435d59b31412daa0f6 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 15 Jan 2016 08:19:42 -0500 Subject: MADS: Implement conversation conditionals evaluation --- engines/mads/conversations.cpp | 127 ++++++++++++++++++++++------------------- engines/mads/conversations.h | 107 ++++++++++++++++++++++------------ 2 files changed, 136 insertions(+), 98 deletions(-) diff --git a/engines/mads/conversations.cpp b/engines/mads/conversations.cpp index 2ae07ba0bf..f065ac217d 100644 --- a/engines/mads/conversations.cpp +++ b/engines/mads/conversations.cpp @@ -151,6 +151,9 @@ void GameConversations::start() { _runningConv->_cnd._currentNode = -1; _runningConv->_cnd._numImports = 0; _runningConv->_cnd._vars[0].setValue(_nextStartNode->_val); + + // Store a reference to the variables list in the script handler for later reference + ScriptEntry::Conditional::_vars = &_runningConv->_cnd._vars; } void GameConversations::setVariable(uint idx, int val) { @@ -441,7 +444,16 @@ int GameConversations::executeEntry(int index) { bool flag = true; for (uint scriptIdx = 0; scriptIdx < dlg._script.size(); ++scriptIdx) { DialogCommand cmd = dlg._script[scriptIdx]._command; - // TODO + + switch (cmd) { + case CMD_1: + case CMD_HIDE: + case CMD_UNHIDE: + break; + + default: + error("Unknown script opcode"); + } } if (flag) { @@ -774,10 +786,14 @@ void ScriptEntry::load(Common::SeekableReadStream &s) { } } +/*------------------------------------------------------------------------*/ + +Common::Array *ScriptEntry::Conditional::_vars = nullptr; + void ScriptEntry::Conditional::load(Common::SeekableReadStream &s) { - _paramsFlag = s.readUint16LE(); + _operation = (ConditionalOperation)s.readUint16LE(); - if (_paramsFlag == 0xff) { + if (_operation == CNVOP_ABORT) { _param1._isVariable = false; _param1._val = 0; _param2._isVariable = false; @@ -790,62 +806,53 @@ void ScriptEntry::Conditional::load(Common::SeekableReadStream &s) { } } -/* -do { -command = convFile->readByte(); -chk = convFile->readUint16BE(); -if (chk != 0xFF00 && chk != 0x0000) { -warning("Error while reading conversation node entries - bailing out"); -break; -} - -switch (command) { -case cmdNodeEnd: -//debug("Node end"); -break; -case cmdDialogEnd: -//debug("Dialog end"); -break; -case cmdHide: { -byte count = convFile->readByte(); -for (byte k = 0; k < count; k++) { -//uint16 nodeRef = convFile->readUint16LE(); -//debug("Hide node %d", nodeRef); -} - -} -break; -case cmdUnhide: { -byte count = convFile->readByte(); -for (byte k = 0; k < count; k++) { -//uint16 nodeRef = convFile->readUint16LE(); -//debug("Unhide node %d", nodeRef); -} - -} -break; -case cmdMessage: -//debug("Message"); -convFile->skip(7); // TODO -break; -case cmdGoto: { -convFile->skip(3); // unused? -//byte nodeRef = convFile->readByte(); -//debug("Goto %d", nodeRef); -} -break; -case cmdAssign: { -convFile->skip(3); // unused? -//uint16 value = convFile->readUint16LE(); -//uint16 variable = convFile->readUint16LE(); -//debug("Variable %d = %d", variable, value); -} -break; -default: -error("Unknown conversation command %d", command); -break; -} -} while (command != cmdNodeEnd && command != cmdDialogEnd); -*/ +int ScriptEntry::Conditional::evaluate() const { + if (_operation == CNVOP_NONE) + return -1; + + int param1 = get(0); + if (_operation == CNVOP_VALUE) + return param1; + int param2 = get(1); + + switch (_operation) { + case CNVOP_ADD: + return param1 + param2; + case CNVOP_SUBTRACT: + return param1 - param2; + case CNVOP_MULTIPLY: + return param1 * param2; + case CNVOP_DIVIDE: + return param1 / param2; + case CNVOP_MODULUS: + return param1 % param2; + case CNVOP_LTEQ: + return (param1 <= param2) ? 1 : 0; + case CNVOP_GTEQ: + return (param1 < param2) ? 1 : 0; + case CNVOP_LT: + return (param1 < param2) ? 1 : 0; + case CNVOP_GT: + return (param1 > param2) ? 1 : 0; + case CNVOP_NEQ: + return (param1 != param2) ? 1 : 0; + case CNVOP_EQ: + return (param1 == param2) ? 1 : 0; + case CNVOP_AND: + return (param1 || param2) ? 1 : 0; + case CNVOP_OR: + return (param1 && param2) ? 1 : 0; + default: + error("Unknown conditional operation"); + } +} + +int ScriptEntry::Conditional::get(int paramNum) const { + const CondtionalParamEntry &p = (paramNum == 0) ? _param1 : _param2; + return p._isVariable ? *(*_vars)[p._val].getValue() : p._val; +} + +/*------------------------------------------------------------------------*/ + } // End of namespace MADS diff --git a/engines/mads/conversations.h b/engines/mads/conversations.h index 188f074749..688fac7c5e 100644 --- a/engines/mads/conversations.h +++ b/engines/mads/conversations.h @@ -68,6 +68,62 @@ enum ConvEntryFlag { ENTRYFLAG_8000 = 0x8000 }; +enum ConditionalOperation { + CNVOP_NONE = 0xff, + CNVOP_VALUE = 0, + CNVOP_ADD = 1, + CNVOP_SUBTRACT = 2, + CNVOP_MULTIPLY = 3, + CNVOP_DIVIDE = 4, + CNVOP_MODULUS = 5, + CNVOP_LTEQ = 6, + CNVOP_GTEQ = 7, + CNVOP_LT = 8, + CNVOP_GT = 9, + CNVOP_NEQ = 10, + CNVOP_EQ = 11, + CNVOP_AND = 12, + CNVOP_OR = 13, + CNVOP_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 { @@ -80,19 +136,30 @@ struct ScriptEntry { CondtionalParamEntry() : _isVariable(false), _val(0) {} }; - uint _paramsFlag; + static Common::Array *_vars; + ConditionalOperation _operation; CondtionalParamEntry _param1; CondtionalParamEntry _param2; /** * Constructor */ - Conditional() : _paramsFlag(false) {} + Conditional() : _operation(CNVOP_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; }; DialogCommand _command; @@ -178,42 +245,6 @@ struct ConversationData { void load(const Common::String &filename); }; -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; } -}; - /** * Conditional (i.e. changeable) data for the conversation */ -- cgit v1.2.3