aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlyssa Milburn2010-12-05 16:19:35 +0000
committerAlyssa Milburn2010-12-05 16:19:35 +0000
commit9e6fe3bd888625de33c029998b0403ca7f0b48da (patch)
tree744d67f6f608d1e05ba890e6ae8b21d4be27c2cf
parent24a0b50ac399e71634725ddaaf4ac87288916d3c (diff)
downloadscummvm-rg350-9e6fe3bd888625de33c029998b0403ca7f0b48da.tar.gz
scummvm-rg350-9e6fe3bd888625de33c029998b0403ca7f0b48da.tar.bz2
scummvm-rg350-9e6fe3bd888625de33c029998b0403ca7f0b48da.zip
MOHAWK: add runCommand/checkCondition routines for LB 2/3
svn-id: r54777
-rw-r--r--engines/mohawk/livingbooks.cpp272
-rw-r--r--engines/mohawk/livingbooks.h23
2 files changed, 295 insertions, 0 deletions
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 7a97616360..d874da7676 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -2061,6 +2061,278 @@ void LBItem::setNextTime(uint16 min, uint16 max, uint32 start) {
debug(9, "nextTime is now %d frames away", _nextTime - (uint)(_vm->_system->getMillis() / 16));
}
+bool LBValue::operator==(const LBValue &x) const {
+ if (type != x.type) return false;
+
+ switch (type) {
+ case kLBValueString:
+ return string == x.string;
+
+ case kLBValueInteger:
+ return integer == x.integer;
+ }
+
+ error("internal error in LBValue");
+}
+
+bool LBValue::operator!=(const LBValue &x) const {
+ return !(*this == x);
+}
+
+enum LBTokenType {
+ kLBNoToken,
+ kLBNameToken,
+ kLBStringToken,
+ kLBOperatorToken,
+ kLBIntegerToken,
+ kLBEndToken
+};
+
+static Common::String readToken(const Common::String &source, uint &pos, LBTokenType &type) {
+ Common::String token;
+ type = kLBNoToken;
+
+ bool done = false;
+ while (pos < source.size() && !done) {
+ if (type == kLBStringToken) {
+ if (source[pos] == '"') {
+ pos++;
+ return token;
+ }
+
+ token += source[pos];
+ pos++;
+ continue;
+ }
+
+ switch (source[pos]) {
+ case ' ':
+ pos++;
+ done = true;
+ break;
+
+ case ')':
+ if (type == kLBNoToken) {
+ type = kLBEndToken;
+ return Common::String();
+ }
+ done = true;
+ break;
+
+ case ';':
+ if (type == kLBNoToken) {
+ pos++;
+ type = kLBEndToken;
+ return Common::String();
+ }
+ done = true;
+ break;
+
+ case '@':
+ // FIXME
+ error("found @ in string '%s', not supported yet", source.c_str());
+
+ case '+':
+ case '-':
+ case '!':
+ case '=':
+ case '>':
+ case '<':
+ if (type == kLBNoToken)
+ type = kLBOperatorToken;
+ if (type == kLBOperatorToken)
+ token += source[pos];
+ else
+ done = true;
+ break;
+
+ case '"':
+ if (type == kLBNoToken)
+ type = kLBStringToken;
+ else
+ done = true;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (type == kLBNoToken)
+ type = kLBIntegerToken;
+ if (type == kLBNameToken || type == kLBIntegerToken)
+ token += source[pos];
+ else
+ done = true;
+ break;
+
+ default:
+ if (type == kLBNoToken)
+ type = kLBNameToken;
+ if (type == kLBNameToken)
+ token += source[pos];
+ else
+ done = true;
+ break;
+ }
+
+ if (!done)
+ pos++;
+ }
+
+ if (type == kLBStringToken)
+ error("readToken: ran out of input while parsing string from '%s'", source.c_str());
+
+ if (!token.size()) {
+ assert(type == kLBNoToken);
+ type = kLBEndToken;
+ }
+
+ return token;
+}
+
+LBValue LBItem::parseValue(const Common::String &source, uint &pos) {
+ LBTokenType type, postOpType;
+ Common::String preOp, postOp;
+
+ Common::String str = readToken(source, pos, type);
+ if (type == kLBOperatorToken) {
+ preOp = str;
+ str = readToken(source, pos, type);
+ }
+
+ LBValue value;
+ if (type == kLBStringToken) {
+ value.type = kLBValueString;
+ value.string = str;
+ } else if (type == kLBIntegerToken) {
+ value.type = kLBValueInteger;
+ value.integer = atoi(str.c_str());
+ } else if (type == kLBNameToken) {
+ value = _vm->_variables[str];
+ } else {
+ error("expected string/integer as value in '%s', got '%s'", source.c_str(), str.c_str());
+ }
+
+ uint readAheadPos = pos;
+ postOp = readToken(source, readAheadPos, postOpType);
+ if (postOpType != kLBEndToken) {
+ if (postOpType != kLBOperatorToken)
+ error("expected operator after '%s' in '%s', got '%s'", str.c_str(), source.c_str(), postOp.c_str());
+ // might be a comparison operator, caller will handle other cases if valid
+ if (postOp == "-" || postOp == "+") {
+ pos = readAheadPos;
+ LBValue nextValue = parseValue(source, pos);
+ if (value.type != kLBValueInteger || nextValue.type != kLBValueInteger)
+ error("expected integer for arthmetic operator in '%s'", source.c_str());
+ if (postOp == "+")
+ value.integer += nextValue.integer;
+ else if (postOp == "-")
+ value.integer -= nextValue.integer;
+ else
+ error("internal error in parseValue");
+ }
+ }
+
+ if (preOp.size()) {
+ if (preOp == "!") {
+ if (value.type == kLBValueInteger)
+ value.integer = !value.integer;
+ else
+ error("expected integer after ! operator in '%s'", source.c_str());
+ } else {
+ error("expected valid operator before '%s' in '%s', got '%s'", str.c_str(), source.c_str(), preOp.c_str());
+ }
+ }
+
+ return value;
+}
+
+void LBItem::runCommand(const Common::String &command) {
+ uint pos = 0;
+ LBTokenType type;
+
+ debug(2, "running command '%s'", command.c_str());
+
+ while (pos < command.size()) {
+ Common::String varname = readToken(command, pos, type);
+ if (type != kLBNameToken)
+ error("expected name as lvalue of command '%s', got '%s'", command.c_str(), varname.c_str());
+ Common::String op = readToken(command, pos, type);
+ if (type != kLBOperatorToken || (op != "=" && op != "++" && op != "--"))
+ error("expected assignment/postincrement/postdecrement operator for command '%s', got '%s'", command.c_str(), op.c_str());
+
+ if (op == "=") {
+ LBValue value = parseValue(command, pos);
+ _vm->_variables[varname] = value;
+ } else {
+ if (_vm->_variables[varname].type != kLBValueInteger)
+ error("expected integer after postincrement/postdecrement operator in '%s'", command.c_str());
+ if (op == "++")
+ _vm->_variables[varname].integer++;
+ else if (op == "--")
+ _vm->_variables[varname].integer--;
+ else
+ error("internal error in runCommand");
+ }
+ }
+}
+
+bool LBItem::checkCondition(const Common::String &condition) {
+ uint pos = 0;
+ LBTokenType type;
+
+ debug(3, "checking condition '%s'", condition.c_str());
+
+ if (condition.size() <= pos || condition[pos] != '(')
+ error("bad condition '%s' (started wrong)", condition.c_str());
+ pos++;
+
+ LBValue value1 = parseValue(condition, pos);
+
+ Common::String op = readToken(condition, pos, type);
+ if (type == kLBEndToken) {
+ if (condition.size() != pos + 1 || condition[pos] != ')')
+ error("bad condition '%s' (ended wrong)", condition.c_str());
+
+ if (value1.type == kLBValueInteger)
+ return value1.integer;
+ else
+ error("expected comparison operator for condition '%s'", condition.c_str());
+ }
+ if (type != kLBOperatorToken || (op != "!=" && op != "==" && op != ">" && op != "<" && op != ">=" && op != "<="))
+ error("expected comparison operator for condition '%s', got '%s'", condition.c_str(), op.c_str());
+
+ LBValue value2 = parseValue(condition, pos);
+
+ if (condition.size() != pos + 1 || condition[pos] != ')')
+ error("bad condition '%s' (ended wrong)", condition.c_str());
+
+ if (op == "!=")
+ return (value1 != value2);
+ else if (op == "==")
+ return (value1 == value2);
+
+ if (value1.type != kLBValueInteger || value2.type != kLBValueInteger)
+ error("evaluation operator %s in condition '%s' expected two integer operands!", op.c_str(), condition.c_str());
+
+ if (op == ">")
+ return (value1.integer > value2.integer);
+ else if (op == ">=")
+ return (value1.integer >= value2.integer);
+ else if (op == "<")
+ return (value1.integer < value2.integer);
+ else if (op == "<=")
+ return (value1.integer <= value2.integer);
+
+ error("internal error in checkCondition");
+}
+
LBSoundItem::LBSoundItem(MohawkEngine_LivingBooks *vm, Common::Rect rect) : LBItem(vm, rect) {
debug(3, "new LBSoundItem");
_running = false;
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 47bd586c6c..862c682048 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -224,6 +224,22 @@ protected:
Common::Array<Common::Point> _shapeOffsets;
};
+enum LBValueType {
+ kLBValueString,
+ kLBValueInteger
+};
+
+struct LBValue {
+ LBValue() { type = kLBValueInteger; integer = 0; }
+
+ LBValueType type;
+ Common::String string;
+ int integer;
+
+ bool operator==(const LBValue &x) const;
+ bool operator!=(const LBValue &x) const;
+};
+
class LBItem {
public:
LBItem(MohawkEngine_LivingBooks *vm, Common::Rect rect);
@@ -280,6 +296,10 @@ protected:
Common::Array<LBScriptEntry *> _scriptEntries;
void runScript(uint id);
+
+ LBValue parseValue(const Common::String &command, uint &pos);
+ void runCommand(const Common::String &command);
+ bool checkCondition(const Common::String &condition);
};
class LBSoundItem : public LBItem {
@@ -460,6 +480,9 @@ public:
void prevPage();
void nextPage();
+ // TODO: make private
+ Common::HashMap<Common::String, LBValue> _variables;
+
private:
LivingBooksConsole *_console;
Common::ConfigFile _bookInfoFile;