aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2016-01-15 08:19:42 -0500
committerPaul Gilbert2016-01-15 08:19:42 -0500
commita0eacd0537a1fc10d2a29a435d59b31412daa0f6 (patch)
tree15009f928a804b6c92d9b126ad3c3700ff01cef5
parent9e672dab60540f0a981c65cf5ca9f536b8c0e6a0 (diff)
downloadscummvm-rg350-a0eacd0537a1fc10d2a29a435d59b31412daa0f6.tar.gz
scummvm-rg350-a0eacd0537a1fc10d2a29a435d59b31412daa0f6.tar.bz2
scummvm-rg350-a0eacd0537a1fc10d2a29a435d59b31412daa0f6.zip
MADS: Implement conversation conditionals evaluation
-rw-r--r--engines/mads/conversations.cpp127
-rw-r--r--engines/mads/conversations.h107
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<ConversationVar> *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<ConversationVar> *_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
*/