MADS: Implement conversation conditionals evaluation

This commit is contained in:
Paul Gilbert 2016-01-15 08:19:42 -05:00
parent 9e672dab60
commit a0eacd0537
2 changed files with 132 additions and 94 deletions

View File

@ -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) {
}
}
void ScriptEntry::Conditional::load(Common::SeekableReadStream &s) {
_paramsFlag = s.readUint16LE();
/*------------------------------------------------------------------------*/
if (_paramsFlag == 0xff) {
Common::Array<ConversationVar> *ScriptEntry::Conditional::_vars = nullptr;
void ScriptEntry::Conditional::load(Common::SeekableReadStream &s) {
_operation = (ConditionalOperation)s.readUint16LE();
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;
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");
}
}
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);
int ScriptEntry::Conditional::get(int paramNum) const {
const CondtionalParamEntry &p = (paramNum == 0) ? _param1 : _param2;
return p._isVariable ? *(*_vars)[p._val].getValue() : p._val;
}
}
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);
*/
} // End of namespace MADS

View File

@ -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
*/